ALB 가 제공되지 않는 환경을 위한 외부 nginx 설정 가이드

ALB 가 제공되지 않는 환경을 위한 외부 nginx 설정 가이드

 

  • Rootless Docker 를 사용하고 있으며, ALB 의 도움을 받지 못하는 경우에 사용자 권한으로 nginx 를 설치하여 서비스하는 내용입니다.

  • Rootless Docker 를 이용하는 경우 외부에서 접속하더라도 Rootless Docker 의 특성상 내부 Container 에는 해당 Docker 의 네트워크 IP 가 인식되기 때문에, 외부에서 IP 를 전달해줘야 합니다.

  • ALB 가 없이 NLB 만 구축하고 QueryPie 에서 https 를 지원하는 형태인 경우 ALB 가 없으므로 외부에서 X-Forwarded-For 등을 주입할 수 없으므로, QueryPie 는 사용자의 IP 를 인식할 수 없습니다.

  • 접속한 사용자의 IP 가 서버에서 인식되는 경우에만 Nginx 를 외부에 하나 더 설치해 https 처리 및 X-Forwarded-For 를 추가해주는 역할을 하도록 구성할 수 있습니다.

 

개요

이 가이드는 보안을 강화한 Rootless Docker 환경에서 ALB 의 도움 없이 사용자의 IP 를 QueryPie 에 전달할 수 있도록 Nginx 를 특정 사용자의 계정을 통해 구성하는 방법을 제공합니다.

 

설치 환경

  • Amazon Linux 2023

  • QueryPie > v10.2.0

⚠️주의사항

  • ALB 에 대한 보완 사항이며, Agent 를 사용하기 위한 방안은 이 문서에서 설명하지 않습니다. (추가 설정 필요)

사전 요구사항

  • 최초 설치 시 sudo 권한

    • 설치 단계 요약 2번까지 필요

  • Rootless Docker 기반의 QueryPie 가 설치되어 있어야 함

    • 사용자 이름: querypie

    • querypie 설치 디렉토리: /home/querypie/querypie

설치 단계 요약

  1. nginx 설치 및 디렉토리 생성

  2. nginx 로그 관리 설정 (LogRotate)

  3. nginx 설정 생성 및 QueryPie 설정 변경

  4. nginx 자동 시작 설정


1. nginx 설치 및 디렉토리 생성

패키지 관리자를 통해 nginx 를 설치합니다.

# nginx 설치 sudo yum install nginx # 필요 디렉토리 생성 mkdir -p /home/querypie/querypie/external_nginx/log chmod 750 /home/querypie/querypie/external_nginx/log mkdir -p /home/querypie/querypie/tmp

 

2. nginx 로그 관리 설정 (LogRotate)

로그 파일이 과도하게 커지는 것을 방지하기 위해 LogRotate 설정을 추가합니다.

# user id 확인 [querypie@ip-172-31-50-123 ~]$ id querypie uid=1001(querypie) gid=1001(querypie) groups=1001(querypie) # 일시적으로 root 사용자로 전환하여 logrotate 설정 sudo tee /etc/logrotate.d/external_nginx > /dev/null <<EOF /home/querypie/querypie/external_nginx/log/*.log { create 0600 querypie querypie daily missingok rotate 180 compress delaycompress notifempty dateformat .%Y-%m-%d.log dateext sharedscripts postrotate /bin/kill -USR1 $(cat /home/querypie/querypie/external_nginx/nginx.pid 2>/dev/null) 2>/dev/null || true endscript } EOF

 

3. nginx 설정 생성 및 QueryPie 설정 변경

  • 기존 Rootless Docker 기반의 QueryPie 가 8080 포트로 서비스 중이며, 아래 설정을 변경하여 8082 로 동작하도록 변경합니다. 8443 포트로 서비스하던 https 는 서비스에서 제거합니다.

services: app: ports: - 8082:80 # - 8443:443 # QueryPie 자체 https 는 따로 포트를 열지 않습니다.

 

http 를 8080으로 서비스하는 경우

  • 아래 설정을 /home/querypie/querypie/external_nginx/nginx.conf 에 저장합니다.

    • access log 는 기본적으로 꺼져있습니다. 필요할 때만 켜서 확인하도록 합니다.

# 필요에 따라 커멘트를 풀어야 할 수 있음 # include /etc/nginx/modules/*.conf; worker_processes auto; error_log /home/querypie/querypie/external_nginx/log/error.log notice; pid /home/querypie/querypie/external_nginx/nginx.pid; worker_rlimit_nofile 1047552; events { multi_accept on; worker_connections 16384; use epoll; } http { log_format logger-json escape=json '{"source": "nginx", "time": $msec, "resp_body_size": $body_bytes_sent, "host": "$http_host", "address": "$remote_addr", "request_length": $request_length, "method": "$request_method", "uri": "$request_uri", "status": $status, "user_agent": "$http_user_agent", "resp_time": $request_time, "upstream_addr": "$upstream_addr"}'; # access_log /home/querypie/querypie/external_nginx/log/access.log logger-json; access_log /dev/null; include /etc/nginx/mime.types; default_type application/octet-stream; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 75s; keepalive_requests 1000; reset_timedout_connection on; gzip on; gzip_vary on; gzip_comp_level 5; gzip_min_length 1024; gzip_proxied expired no-cache no-store private auth; gzip_types text/plain application/x-javascript text/xml text/css application/xml application/javascript; # Temp Path client_body_temp_path /home/querypie/querypie/tmp/client_body_temp; proxy_temp_path /home/querypie/querypie/tmp/proxy; fastcgi_temp_path /home/querypie/querypie/tmp/fastcgi; uwsgi_temp_path /home/querypie/querypie/tmp/uwsgi; scgi_temp_path /home/querypie/querypie/tmp/scgi; map $http_upgrade $connection_upgrade { default upgrade; '' close; } map $http_x_request_id $req_id { default $http_x_request_id; "" $request_id; } # QueryPie upstream upstream_querypie { server 127.0.0.1:8082; keepalive 320; keepalive_time 1h; keepalive_timeout 60s; keepalive_requests 10000; } server { listen 8080 default_server; root /home/querypie/querypie/not_exist; index proxy_only.html; location / { proxy_pass http://upstream_querypie; # This file contains the default proxy settings for the nginx server # Check how this file being used on /docker-entrypoint.sh # HTTP Default Headers proxy_set_header Host $http_host; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; # mitigate HTTProxy Vulnerability # https://www.nginx.com/blog/mitigating-the-httpoxy-vulnerability-with-nginx/ proxy_set_header Proxy ""; # X-Forwarded-For: client, proxy1, proxy2, nginx proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Host $http_host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Request-ID $req_id; proxy_set_header X-Real-IP $remote_addr; proxy_connect_timeout 5s; proxy_send_timeout 60s; proxy_read_timeout 60s; proxy_buffering off; proxy_buffer_size 4k; proxy_buffers 4 4k; proxy_max_temp_file_size 0; proxy_request_buffering on; proxy_http_version 1.1; proxy_cookie_domain off; proxy_cookie_path off; # In case of errors try the next upstream server before returning an error proxy_next_upstream error timeout; proxy_next_upstream_timeout 0; proxy_next_upstream_tries 3; proxy_redirect off; client_max_body_size 0; } } }

 

https 를 8443으로 서비스하는 경우

  • https 서비스를 제공하기 위해 /home/querypie/querypie/external_nginx/certs 디렉토리를 만들고, 인증서 (server.crt, server.key) 를 해당 디렉토리에 저장합니다.

mkdir -p /home/querypie/querypie/external_nginx/certs ls /home/querypie/querypie/external_nginx/certs server.crt server.key
  • 아래 설정을 /home/querypie/querypie/external_nginx/nginx.conf 에 저장합니다.

    • access log 는 기본적으로 꺼져있습니다. 필요할 때만 켜서 확인하도록 합니다.

# 필요에 따라 커멘트를 풀어야 할 수 있음 # include /etc/nginx/modules/*.conf; worker_processes auto; error_log /home/querypie/querypie/external_nginx/log/error.log notice; pid /home/querypie/querypie/external_nginx/nginx.pid; worker_rlimit_nofile 1047552; events { multi_accept on; worker_connections 16384; use epoll; } http { log_format logger-json escape=json '{"source": "nginx", "time": $msec, "resp_body_size": $body_bytes_sent, "host": "$http_host", "address": "$remote_addr", "request_length": $request_length, "method": "$request_method", "uri": "$request_uri", "status": $status, "user_agent": "$http_user_agent", "resp_time": $request_time, "upstream_addr": "$upstream_addr"}'; # access_log /home/querypie/querypie/external_nginx/log/access.log logger-json; access_log /dev/null; include /etc/nginx/mime.types; default_type application/octet-stream; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 75s; keepalive_requests 1000; reset_timedout_connection on; gzip on; gzip_vary on; gzip_comp_level 5; gzip_min_length 1024; gzip_proxied expired no-cache no-store private auth; gzip_types text/plain application/x-javascript text/xml text/css application/xml application/javascript; # Temp Path client_body_temp_path /home/querypie/querypie/tmp/client_body_temp; proxy_temp_path /home/querypie/querypie/tmp/proxy; fastcgi_temp_path /home/querypie/querypie/tmp/fastcgi; uwsgi_temp_path /home/querypie/querypie/tmp/uwsgi; scgi_temp_path /home/querypie/querypie/tmp/scgi; map $http_upgrade $connection_upgrade { default upgrade; '' close; } map $http_x_request_id $req_id { default $http_x_request_id; "" $request_id; } # QueryPie upstream upstream_querypie { server 127.0.0.1:8082; keepalive 320; keepalive_time 1h; keepalive_timeout 60s; keepalive_requests 10000; } server { listen 8443 ssl http2; # openssl genpkey -algorithm ec -pkeyopt ec_paramgen_curve:P-256 -out server.key ssl_certificate /home/querypie/querypie/external_nginx/certs/server.crt; # openssl req -new -x509 -days 1 -key server.key -subj "/C=KR/O=QueryPie/CN=QueryPie Fake Certificate" -out server.crt ssl_certificate_key /home/querypie/querypie/external_nginx/certs/server.key; # Reference: https://ssl-config.mozilla.org/#server=nginx&version=1.22.1&config=intermediate&openssl=3.0.15&ocsp=false&guideline=5.7 ssl_session_timeout 1d; ssl_session_cache shared:MozSSL:10m; # about 40000 sessions ssl_session_tickets off; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305; ssl_prefer_server_ciphers off; # HSTS (ngx_http_headers_module is required) (63072000 seconds) add_header Strict-Transport-Security "max-age=63072000" always; root /home/querypie/querypie/not_exist; index proxy_only.html; location / { proxy_pass http://upstream_querypie; # This file contains the default proxy settings for the nginx server # Check how this file being used on /docker-entrypoint.sh # HTTP Default Headers proxy_set_header Host $http_host; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; # mitigate HTTProxy Vulnerability # https://www.nginx.com/blog/mitigating-the-httpoxy-vulnerability-with-nginx/ proxy_set_header Proxy ""; # X-Forwarded-For: client, proxy1, proxy2, nginx proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Host $http_host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Request-ID $req_id; proxy_set_header X-Real-IP $remote_addr; proxy_connect_timeout 5s; proxy_send_timeout 60s; proxy_read_timeout 60s; proxy_buffering off; proxy_buffer_size 4k; proxy_buffers 4 4k; proxy_max_temp_file_size 0; proxy_request_buffering on; proxy_http_version 1.1; proxy_cookie_domain off; proxy_cookie_path off; # In case of errors try the next upstream server before returning an error proxy_next_upstream error timeout; proxy_next_upstream_timeout 0; proxy_next_upstream_tries 3; proxy_redirect off; client_max_body_size 0; } } }

 

4. nginx 자동 시작 설정

QueryPie 사용자의 로그인 세션이 종료되어도 Nginx 서비스가 계속 실행되도록 설정합니다. 일부 명령은 Rootless Docker 기반의 QueryPie 설치 시 진행했을 것으로 보여 제외하였습니다.

# nginx 서비스 파일 생성 cat > ~/.config/systemd/user/external_nginx.service << 'EOF' [Unit] Description=The nginx HTTP and reverse proxy server After=network-online.target remote-fs.target nss-lookup.target [Service] Type=forking PIDFile=/home/querypie/querypie/external_nginx/nginx.pid ExecStartPre=/usr/sbin/nginx -t -c /home/querypie/querypie/external_nginx/nginx.conf ExecStart=/usr/sbin/nginx -c /home/querypie/querypie/external_nginx/nginx.conf ExecReload=/usr/bin/kill -s HUP $MAINPID ExecStop=/usr/bin/kill -s QUIT $MAINPID KillSignal=SIGQUIT TimeoutStopSec=5 KillMode=mixed PrivateTmp=true [Install] WantedBy=multi-user.target EOF # 서비스 등록 및 시작 systemctl --user daemon-reload systemctl --user start external_nginx systemctl --user enable external_nginx # 서비스 상태 확인 systemctl --user status external_nginx

 

웹 접속 확인

설정한 값 (http/https) 에 따라 브라우저를 열고 아래 URL로 접속하여 QueryPie 에 접근할 수 있습니다:

  • http://[서버_IP]:8080

  • https://[서버_IP]:8443