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
설치 단계 요약
nginx 설치 및 디렉토리 생성
nginx 로그 관리 설정 (LogRotate)
nginx 설정 생성 및 QueryPie 설정 변경
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