웹서버를 마스터 슬레이브 구조로 구성하기 위해 nginx를 이용해 reverse proxy 구성을 했다. 이전에 포스팅했던 내용이 있긴 하지만 이번에는 테스트 환경이 아니라 실제 서비스에 적용하는 것으로 보안서버 관련 설정도 추가됐다. 아직 실제 서비스에 적용은 되지 않았지만 hosts 파일에서 ip를 변경해서 테스트해보니 제대로 작동이 되는 듯 하다. 좀 더 테스트를 진행해보고 실제 서비스에 적용해야할 것이다. 아래는 nginx.conf 파일의 설정이다.
#user nobody; worker_processes 4; #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; error_log logs/error.log error; pid logs/nginx.pid; events { multi_accept on; worker_connections 1024; } http { include mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; #access_log logs/access.log main; sendfile on; #tcp_nopush on; server_tokens off; keepalive_disable msie6; keepalive_timeout 180s; keepalive_requests 100; open_file_cache max=1000 inactive=20s; open_file_cache_valid 30s; open_file_cache_min_uses 2; open_file_cache_errors on; gzip on; gzip_http_version 1.1; gzip_vary on; gzip_comp_level 1; gzip_proxied any; gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript text/x-js; gzip_buffers 16 8k; gzip_disable "MSIE [1-6]\.(?!.*SV1)"; upstream web { server 192.168.0.2:80 max_fails=3 fail_timeout=10s; server 127.0.0.1:8080 backup; #server 127.0.0.1:8080; } upstream web-ssl { server 192.168.0.2:443 max_fails=3 fail_timeout=10s; server 127.0.0.1:8083 backup; } # reverse proxy server { listen 80; server_name example.com www.example.com; #charset koi8-r; #access_log logs/host.access.log main; log_not_found off; client_max_body_size 30m; large_client_header_buffers 4 16k; location / { proxy_pass http://web; proxy_set_header Accept-Encoding ""; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_redirect off; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # #error_page 500 502 503 504 /50x.html; #location = /50x.html { # root html; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # location ~ /\.ht { deny all; } } server { listen 443; server_name example.com www.example.com; ssl on; ssl_certificate cert.pem; ssl_certificate_key cert.key; ssl_session_timeout 5m; #ssl_protocols SSLv2 SSLv3 TLSv1; #ssl_ciphers HIGH:!aNULL:!MD5; #ssl_prefer_server_ciphers on; #charset koi8-r; #access_log logs/host.access.log main; log_not_found off; client_max_body_size 30m; large_client_header_buffers 4 16k; location / { proxy_pass https://web-ssl; proxy_set_header Accept-Encoding ""; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_redirect off; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # #error_page 500 502 503 504 /50x.html; #location = /50x.html { # root html; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # location ~ /\.ht { deny all; } } # virtual host server { listen 8080; server_name example.com www.example.com; #charset koi8-r; access_log logs/exampl.com.access.log main; log_not_found off; root /home/example/www; index index.html index.htm index.php; client_max_body_size 30m; #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # #error_page 500 502 503 504 /50x.html; #location = /50x.html { # root html; #} # php in data execution block location ~* /(?:data)/.*\.php$ { deny all; } location ~* \.(jpg|jpeg|png|gif|js|css)$ { expires max; access_log off; valid_referers none blocked example.com www.example.com; if ($invalid_referer) { return 444; } } location ~* .(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|css|rss|atom|js|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ { expires max; access_log off; } # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(.*)$; fastcgi_index index.php; include fastcgi_params; #fastcgi_pass 127.0.0.1:9000; fastcgi_pass unix:/var/run/fpm-default.sock; include mime.types; } # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # location ~ /\.ht { deny all; } } # https virtual host server { listen 8083; server_name example.com www.example.com; ssl on; ssl_certificate cert.pem; ssl_certificate_key cert.key; ssl_session_timeout 5m; #ssl_protocols SSLv2 SSLv3 TLSv1; #ssl_ciphers HIGH:!aNULL:!MD5; #ssl_prefer_server_ciphers on; access_log logs/example.com.access.log main; log_not_found off; root /home/example/www; index index.html index.htm index.php; client_max_body_size 30m; #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # #error_page 500 502 503 504 /50x.html; #location = /50x.html { # root html; #} # php in data execution block location ~* /(?:data)/.*\.php$ { deny all; } location ~* \.(jpg|jpeg|png|gif|js|css)$ { expires max; access_log off; valid_referers none blocked example.com www.example.com; if ($invalid_referer) { return 444; } } location ~* .(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|css|rss|atom|js|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ { expires max; access_log off; } # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(.*)$; fastcgi_index index.php; include fastcgi_params; #fastcgi_pass 127.0.0.1:9000; fastcgi_pass unix:/var/run/fpm-default.sock; include mime.types; } # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # location ~ /\.ht { deny all; } } }
위 설정은 Linux Virtual Server(LVS)의 ip가 192.168.0.1 이고 연결 도메인이 exampl.com이라면 example.com 으로 접속시 lvs에서 192.168.0.2 웹서버로 요청을 넘기고 192.168.0.2 서버에서 처리 후 사용자에게 전송하는 것이다. 만약 192.168.0.2 서버가 다운되어 접속이 안되면 lvs 에서 요청을 직접 처리하도록 되어 있는데 127.0.0.1 즉 로컬 호스트로 요청을 넘긴다. 요청 처리후 사용자에게 전송한다. 이렇게 구성하면 일단 서버가 한대만 살아있어도 접속은 된다. 물론 문제는 남아있는데 마스터 서버와 슬레이브 서버의 첨부파일 등의 data 동기화 문제이다. 이 부분은 직접 수동으로 처리하는 수 밖에 없을 듯 하다. 단순 웹서버 데몬의 다운이라면 rsync 등으로 동기화 시켜두면 해결되지만 네트웍이나 기기의 문제라면 동기화는 안될테니까 말이다.
upstream 블록에서 80포트와 443 포트를 따로 분리해둔 것은 reverse proxy에서 백엔드 서버로 요청을 넘길 때 포트 번호를 지정해주지 않으면 특히 https 접속시에는 포트 번호가 없으면 502 bad gateway 에러를 뿜어낸다. 이 부분때문에 꽤 많은 시간을 낭비했는데 미리 포트 번호를 지정해주는 것이 여러모로 나와 같은 삽질을 피할 수 있는 길이 아닐까 싶다. 로컬 호스트의 포트를 8080이나 8083을 사용한 것은 lvs에서 이미 80포트와 443포트를 사용하기 있기 때문이다. 이런 식으로 구성을 해서 테스트를 해보고 있는데 아직까지는 문제가 없는 듯 하다. 실제로 방문자가 많거나 했을 때는 어떻게 작동할 지는 내일 적용해서 테스트를 해보는 수 밖에 없을 것 같다.