본문으로 건너뛰기

"nginx" 태그로 연결된 7개 게시물개의 게시물이 있습니다.

모든 태그 보기

· 약 1분

git pull을 hook으로 실행하는데 계속 nginx 502 gateway timeout 오류가 발생해 pm2 logs 앱 또는 nginx log를 계속 추적해도 별다른 에러 로그가 없었다. (exec: Internal Server error 라고만 적혀있었다.)

삽질 끝에 watch 속성을 사용하고 있는게 문제였다.

해결

ecosystem.config.js
module.exports = {
apps: [
{
name: "server",
script: "server.js",
env_production: {
NODE_ENV: "production",
},
watch: true,
ignore_watch: ["node_modules", ".git", "yarn.lock", "package-lock.json"],
exec_mode: "cluster",
instances: "max",
},
],
};

ignore_watch 속성에 .git 폴더와 다른 폴더들이 제대로 예외처리 되었는지 확인해보자.

· 약 1분

centos7 기준

$ vi /etc/yum.repos.d/nginx.repo

[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1

$ yum makecache
$ yum install -y nginx

$ vi /etc/nginx/conf.d/default.conf
# server_name에 도메인 연결

# 문법 체크
$ nginx -t

# nginx 시작
$ systemctl enable nginx
$ systemctl start nginx

certbot 설치

$ yum install -y epel-release
$ yum install -y certbot-nginx

# 인증
$ certbot --nginx -d my.domain.com

ssl nginx 설정

기존 포스트 nginx 연동 탭 참조

renew 설정

$ crontab -e

1 0 1 * * certbot renew --nginx

$ systemctl restart crond

systemctl restart nginx 하면 완료

· 약 2분

이 포스트 전에 웹서버 세팅을 하나씩 설치해서 띄워보는 걸 권장하고 Docker, SSH Login, LetsEncrypt, sed 명령어의 사용법을 알고 있어야 한다. 구성할 서버 스택은 다음과 같다.

  • Docker
  • Docker-compose
  • Host 에 사용될 Linux (Centos7)
  • Alpain Linux
  • Nginx ^1.13
  • MariaDB ^10.2
  • PHP ^7.1
  • Laravel =5.4
  • LetsEncrypt
  • HTTP2
  • Redis

이전 포스트를 참조하자.

Container 쇼핑

Docker Hub에서 마음에 드는 Container 를 사용해도 되지만, 생각처럼 돌아가는 Container 는 다음과 같았다.

Laradock을 안 썼죠?

  1. Laradock 에서 caddy 를 사용하지 않고 nginx 와 certbot 만을 이용해 http2 환경을 구성하는 예제가 없었다.
  2. 그래도 시도해봤으나 certbot 인증시에 DocumentRoot 를 잡지 못하는 현상을 삽질로 매꿀 시간이 없었다.
  3. Git repo 를 Clone 받아서 Docker-compose 로 Container 를 구동하기 때문에 추후 ECS 에 적용할 수가 없는 구조였다.
  4. 직접 구축해보고 싶었다.

세팅

nginx-php-fpm

Laravel 용 및 튜닝을 위해 Docker hub 의 이미지 대신 Git repo 의 이미지를 Clone 해서 세팅을 해보자.

내용 추가 중..

· 약 9분

Linux, Nginx, MariaDB, PHP

Why LEMP instead of LNMP? We go with LEMP due to the pronunciation for Nginx: Engine-X (en-juhn-ecks). Think of how in English, the article an is used instead of a for hour even though it begins with a consonant. The importance is the sound of the first letter rather than its written representation. Besides, LEMP is actually pronounceable and doesn’t sound like reciting the alphabet.

PHP

repo 를 등록하고 설치하는 방법이 있지만 php71 등의 이름으로 설정해야되서 번거롭다. yum 명령어의 --enablerepo 옵션을 사용해 php71 repository 를 가져오자.

# php repo를 가져오기
$ yum -y install http://rpms.famillecollet.com/enterprise/remi-release-7.rpm

$ vi /etc/yum.repos.d/remi-php71.repo

[remi-php71]
name=Remi\'s PHP 7.1 RPM repository for Enterprise Linux 7 - $basearch
#baseurl=http://rpms.remirepo.net/enterprise/7/php71/$basearch/
mirrorlist=http://rpms.remirepo.net/enterprise/7/php71/mirror
# 이 값을 1로 바꿔준다.
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-remi

$ yum -y install php php-fpm php-devel php-curl php-mcrypt php-mysql php-xmlrpc php-mbstring php-zip 등등

$ systemctl start php-fpm
$ systemctl enable php-fpm

Maria

예전 포스팅으로 대체한다. 설치방법은 똑같고 버전만 다르게 해주면 된다. 설치 후 서비스 실행만 systemctl 명령어로 해주자.

Xtrabackup

이제 mysqldump 를 좀 놓아주고 Incremental Backup 을 해주자. 이게 왜 좋은지는 공홈이나 이나 다른 블로그에 자세히 설명되어있다.

# xtrabackup 설치
$ yum -y install xtrabackup

# 증분백업을 위해 전체 백업이 한 번 필요하다.
# root가 아닌 유저일 경우 해당 DB를 백업하기 위해 PROCESS 등 여러 권한을 추가해야한다.
# (로그 메세지로 추가하라고 나온다.)
$ innobackupex --user='root' --password='암호' --databases='DB' --no-timestamp /백업위치

# 증분백업
$ innobackupex --user='root' --password='암호' --incremental --incremental-basedir='/백업위치/xtrabackup_checkpoints' --no-timestamp /증분백업위치

# 증분백업을 전체백업 위에 얹기
$ innobackupex --apply-log --redo-only --incremental-dir='/증분백업위치' /백업위치

# 증분백업 삭제
$ rm -rf /증분백업위치


# 복원
$ systemctl stop mariadb

# 데이터 폴더를 날려야한다. (만약을 대비해 백업)
$ rm -rf /var/lib/mysql/*
$ innobackupex --copy-back /백업위치

# 권한부여
$ chown -R mysql:mysql /var/lib/mysql
$ systemctl start mariadb

Nginx

HTTP2 를 적용하기 위해서는 Nginx 1.9 버전과 Openssl 1.0.2 버전 이상이 필요한데, 기본 repository 에는 이 버전이 적용되어있지 않다. 따라서 검색해보면 컴파일 설치를 해야 된다는 글이 다수다. 모든 패키지는 패키지 매니져로 관리하는게 좋다고 생각하는 나로썬 그냥 넘어갈 수 없다. Nginx 최신 repository 를 관리해주는 나이스한 곳을 찾았다.

$ yum -y install yum-utils
$ yum-config-manager --add-repo https://brouken.com/brouken.repo

# 기존 nginx repo를 사용하지 않는다는 옵션
$ yum-config-manager --save --setopt=epel.exclude=nginx*;
$ yum -y install nginx

$ systemctl start nginx
$ systemctl enable nginx

# nginx 버전 확인
$ Nginx -V
nginx version: nginx/1.13.1
built with OpenSSL 1.0.2k 26 Jan 2017

setopt 가 오류가 날 경우

ngixn.repo 를 만들어주고 연결하자.

$ vi /etc/yum.repos.d/nginx.repo

# vim /etc/yum.repos.d/nginx.repo

[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/mainline/centos/7/$basearch/
gpgcheck=0
enabled=1

# 저장하고 설치 시작

$ yum update
$ yum -y install nginx
$ systemctl start nginx
$ systemctl enable nginx

LetsEncrypt

공짜 SSL 인 LetsEncrypt 의 이름이 certbot 으로 바뀌었다. 공홈을 참조해도 좋다. 인증을 받기위해 먼저 도메인을 따야한다.

$ yum -y install certbot

# 인증
$ certbot certonly --standalone -d example.com -d www.example.com

# 갱신 확인
$ certbot renew --dry-run

# 갱신하면서 nginx 재부팅
# 이 명령어를 적절히 cron에 넣어주자.
$ certbot renew --pre-hook="systemctl stop nginx" --post-hook="systemctl start nginx"

인증이 성공하면 /etc/letsencrypt/live/example.com/ 경로 아래에 키가 떨어질 것이다. 자세한 명령어 옵션은 Docs 참조.

nginx 연동

ssl 을 적용하면서 HTTP2 도 붙혀보자. HTTP2 에서는 bundling 보다 파일을 쪼개서 보내는게 더 효율적이라고 한다. (non-blocking 이니까)

# HTTP
server {
listen 80;
server_name example.com www.example.com;

# certbot --webroot 인증을 받기위한 설정
#location ^~ /.well-known/acme-challenge/ {
# default_type "text/plain";
# root /var/www/letsencrypt;
#}

# 80 접속시 443으로 redirect
location / {
return 301 https://$server_name$request_uri;
}
}

# HTTPS
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
root /var/nginx/www/public;
index index.php index.html;

# 지저분한 보안 옵션은 추천옵션이니 넣어주자.
ssl on;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;

#ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_protocols TLSv1.2;
ssl_ciphers EECDH+AESGCM:EECDH+AES;
ssl_ecdh_curve secp384r1;
ssl_prefer_server_ciphers on;

ssl_stapling on;
ssl_stapling_verify on;

location / {
try_files $uri $uri/ /index.php?$query_string;
}

location ~ \.php {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_index index.php;
fastcgi_pass 127.0.0.1:9000;
}

location ~ /\.ht {
deny all;
}

# 캐싱할 데이터가 있다면 추가
location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc|woff)$ {
expires 1M;
add_header Cache-Control "public";
}

location ~* \.(?:css|js)$ {
expires 7d;
add_header Cache-Control "public";
}
}

해당 세팅은 Laravel5.4 용이다.

nginx.conf 에는 해당 옵션들도 추가해주자.

nginx.conf
  # CPU 물리 코어에 따라 설정한다.
# 1코어에선 1로 나머지는 auto로 설정하면 된다.
# grep ^processor /proc/cpuinfo | wc -l 로 확인 가능
worker_processes 1;

events {
# 각 worker process에서 한 번에 처리할 수 있는 최대 연결 수
# ulimit -n의 값과 같게 설정하자.
worker_connections 1024;
# I/O event 노티 방식을 epoll로 사용. (poll보다 발전한 방식)
use epoll;
# worker가 한 번에 모든 연결을 수용할 수 있도록 설정
multi_accept on;
}

http {
# access_log 제거
access_log off;
server_tokens off;

# iframe 보안 이슈 DENY
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";

# PHP 서버라는 header 제거
fastcgi_hide_header X-Powered-By;
# static file 제공 최적화
sendfile on;
# TCP multiple buffer를 individual packet으로 전송하게 변경
tcp_nopush on;
# TCP에서 TCP_CORK 옵션을 활성화
# MTU에서 IP 헤더의 40-60 Byte를 뺀값과 같다는데 뭐라는건지 모르겠다.
tcp_nodelay on;
# keep alive 설정
keepalive_timeout 65;
# keepalive_requests 100000;

# gzip 압축설정
gzip on;
gzip_min_length 1000;
gzip_types application/x-javascript text/css application/javascript text/javascript text/plain text/xml application/json application/vnd.ms-fontobject application/x-font-opentype application/x-font-truetype application/x-font-ttf application/xml font/eot font/opentype font/otf image/svg+xml image/vnd.microsoft.icon;
gzip_disable "MSIE [1-6]\.";
}

적용 후에 HTTP2 확인 확장프로그램 설치 후 이 프로그램에 파란불이 들어오면 성공이다.

파일 백업

소스는 git 으로 관리가 되는데 static 파일은 주기적으로 백업이 필요하다.

file_backup.sh
NOW_DATE=`date`
BACKUP_DATE=`date +"%Y%m%d"`
FILE_DIR=백업할 폴더 경로
BACKUP_DIR=백업된 파일 경로

# gz 압축
tar zcvf ${BACKUP_DIR}/${BACKUP_DATE}.tar.gz ${FILE_DIR}

# 3일 이상된 백업파일은 제거
find ${BACKUP_DIR}/ -mtime +3 -exec rm -f {} \;
# find ${BACKUP_DIR}/ -mtime 3 -delete

여담

다음부터 Ubuntu 쓸까 생각했는데, Nginx 최신 Repo 를 찾은게 컸다. 하지만 빨리 Docker 책 읽자. Nginx, Reverse Proxy, Redis, PHP, Jenkins 를 한 번에 해결해주겠지. 이제 DockerFile 이 잘 읽히긴 하는데, 언제쯤 갈아탈 수 있으려나

· 약 2분

Nginx - 2. PHP 연동에서 이어집니다.

conf\nginx.conf 파일에서 쉽게 추가가 가능하다.

nginx.conf
http {
# 기존에 있던 default 설정
server {
...
}

# 이렇게 server 구문을 하나 더 추가한다.
server {
listen 8000;
# 서버 주소
server_name local.test.com;
index index.php;
# 서버 경로
root D:/workspace/testphp/;

location / {
try_files $uri /index.php$is_args$args;
}

# php 사용을 개별로 추가해야한다.
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 127.0.0.1:9123;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
...
}

위 소스는 index.php를 라우터로 사용하기 위해 설정되었으므로, 17, 22, 23줄의 구문은 없어도 된다.

Host 파일 수정

Apache Virtual Host 설정 문서의 Host 파일 수정 메뉴를 따라 진행하면 된다.

연동 확인

nginx 서비스를 재시작하고 확인한다.

· 약 3분

Nginx 설치에서 이어집니다.

Nginx를 설치했으니 PHP와 연동을 해보자.

이전 포스트로 대체한다. Apache버전은 상관이 없으니 x64 Thread Safe 버전으로 3번까지만 따라서 설치하면된다.

연동

nginx 설정

Nginx 폴더에서 conf/nginx.conf를 수정한다.

http {
...
server {
...
location / {
root html;

# index.php를 추가
index index.html index.htm index.php;
}
...
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
# 이 부분 주석을 모두 제거해준다.
location ~ \.php$ {
root html;

# nginx에서 9123포트를 추천한다.
fastcgi_pass 127.0.0.1:9123;
fastcgi_index index.php;

# SCIPRT를 $document_root 로 변경
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
...
}
}

php-cgi 설정

nssm을 사용하는 방법과 배치 파일을 만드는 방법이 있는데 전자를 추천한다. bat 파일은 nginx restart를 할 때마다 따로 실행해줘야한다.

다른 포스팅에는 php-cgi 서비를 cmd에서 sc create 명령어를 사용하여 등록하는 부분이 있는데 windows10 환경에서 서비스가 1053 오류를 뱉으며 죽는다. 시간 낭비하지 말자.

nssm

nginx에 지난 스텝에서 설치한 nssm을 사용한다. nginx\nssm\win64 폴더로 이동해 php 등록 커맨드를 입력한다.

./nssm.exe install php

php-cgi 경로를 선택한 뒤 아래 명령어를 Arguments 필드에 넣어준다.

# 경로를 알맞게 수정해주자.
D:\php7\php-cgi.exe -b 127.0.0.1:9123 -c D:\php7\php.ini

image from hexo

서비스를 실행한다. image from hexo

실행이 안되는 경우 arguments에 앞의 경로를 제거하고 -b 127.0.0.1:9123 -c D:\php7\php.ini 만 입력해준다.

bat

배치 파일을 만들어 nginx가 실행 되기전만 php-cgi를 킬 수도 있다.

@ECHO OFF
ECHO Starting PHP CGI...
set PATH=D:\php7;%PATH%
D:\php7\php-cgi.exe -b 127.0.0.1:9123 -c D:\php7\php.ini

위 소스의 경로를 알맞게 수정한 뒤 start-php-cgi.bat으로 저장 후 실행한다.

확인

**nginx\html\**에 index.php를 만든다.

index.php
<?php
phpinfo();

localhost:88/index.php로 접속한다. image from hexo

여담

한 방에 설치하는 방법도 있지만 현재 버전까지는 C:\말고 D:\에 php를 설치한 사람에 대한 배려는 없다. (bat 파일을 건드려봐도 dll 안에 로깅하는 부분에서 오류 발생)

· 약 2분

Windows에서 Nginx로 로컬 웹서버를 돌려보자.

다운로드

Nginx 홈페이지에서 Windows 버전을 다운로드 받는다. image from hexo

압축을 풀어 원하는 위치(D:\nginx)로 옮겨주자

설정

apache, iis가 중복이 된다면 conf/nginx.conf 파일을 열어 포트 설정을 바꿔준다.

nginx.conf
http {
...
server {
listen 88; # 여기를 수정해주자.
server_name localhost;
...
}
...
}

실행

nginx.exe를 더블 클릭한다.

서비스 등록

실행은 되었지만 서비스를 등록해야 자동으로 실행되고 on/off를 관리하기가 쉽다. 다른 포스트에 있는 github의 2011년 엔진엑스 서비스 등록 소스는 찾아봐도 없길래 새로운 방법으로 등록한다.

nssm

nssm에서 서비스 등록 프로그램을 다운받는다. image from hexo

압축을 풀어주고(D:\nginx\nssm-2.24) 자신의 windows bit에 맞는 폴더에서 nssm.exe를 커맨드로 실행하면 된다.

$ ./nssm.exe install nginx

nginx 경로를 잡아주고 Install Service 버튼을 클릭한다. image from hexo

실행

services.msc를 실행해 서비스 창을 열어 nginx를 실행한다. image from hexo

확인

image from hexo

Nginx - 2. PHP 연동으로 이어집니다.