# ============================================================================
# AUTO-GENERATED NGINX UPSTREAM CONFIGURATION
# Application: {{ app_name }}
# Environment: {{ deploy_env }}{{ env_tag | default('') }}
# Generated: {{ ansible_date_time.iso8601 }}
# Replicas: {{ replica_count }}
# ============================================================================
{% if framework is defined and framework == "nextjs" %}
map $arg_url ${{app_name | regex_replace('[^A-Za-z0-9_]', '_')}}_clean_url {
~^(?.+)%3Fv%3D\d+$ $base; # chỉ có ?v=xxx
~^(?.+)%3Fv%3D\d+%26(?.+)$ $base?$rest; # có ?v=xxx&... → giữ lại phần sau
default $arg_url; # mặc định giữ nguyên
}
{% endif %}
upstream {{ upstream_name | regex_replace('[^A-Za-z0-9_]', '_') }} {
# Load balancing method
{% if load_balancing_method is defined %}
{{ load_balancing_method }};
{% else %}
least_conn;
{% endif %}
# Health check configuration
{% if health_check_interval is defined %}
health_check interval={{ health_check_interval }} fails={{ health_check_fails | default(1) }} passes={{ health_check_passes | default(2) }};
{% endif %}
# Upstream servers (auto-generated from active ports)
{% for port in active_ports %}
server localhost:{{ port }} weight={{ server_weight | default(1) }} max_fails={{ max_fails | default(1) }} fail_timeout={{ fail_timeout | default(10) }}s;
{% endfor %}
# Backup server (optional)
{% if backup_server is defined %}
server {{ backup_server }} backup;
{% endif %}
# Keep-alive connections
keepalive {{ keepalive_connections | default(64) }};
}
{% if framework is defined and framework == "nextjs" %}
proxy_cache_path /var/cache/nginx/{{app_name | regex_replace('[^A-Za-z0-9_]', '_')}}_cache levels=1:2 keys_zone={{app_name | regex_replace('[^A-Za-z0-9_]', '_')}}_cache:512m inactive=30d max_size=100g use_temp_path=off;
#levels=1:2: Tạo cây thư mục theo hash key để phân bổ file.
#keys_zone=tkl_web_img_cache:512m: Tăng RAM dùng cho metadata (1MB chứa được ~8000 keys) → 2G = ~16 triệu keys.
#inactive=30d: Nếu file không được truy cập trong 30 ngày → bị xóa.
#max_size=100g: Giới hạn tối đa 100GB cache disk.
#use_temp_path=off: Ghi thẳng vào cache thay vì ghi tạm → hiệu quả hơn.
{% endif %}
server {
listen {{ base_port }};
server_name localhost;
{% if framework is defined and framework == "nextjs" %}
location ~* /_next/image {
access_log off;
proxy_pass http://{{ upstream_name | regex_replace('[^A-Za-z0-9_]', '_') }}; # upstream load balancing
proxy_cache {{app_name | regex_replace('[^A-Za-z0-9_]', '_')}}_cache;
proxy_cache_key "url=${{app_name | regex_replace('[^A-Za-z0-9_]', '_')}}_clean_url&w=$arg_w&q=$arg_q";
proxy_cache_valid 200 180d;
proxy_cache_use_stale error timeout updating http_502 http_503 http_504;
proxy_next_upstream error timeout http_502 http_503 http_504;
proxy_next_upstream_tries 3;
# Chống cache stampede (bottleneck)
proxy_cache_lock on;
proxy_cache_lock_timeout 10s;
proxy_cache_lock_age 5s;
# Timeout & buffering
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
send_timeout 60s;
# Ignore upstream cache headers (Next.js gửi max-age + vary)
proxy_ignore_headers Cache-Control Vary;
proxy_hide_header Set-Cookie;
proxy_set_header Connection $connection_upgrade;
proxy_http_version 1.1;
# Chuẩn hóa Accept để tránh tạo nhiều cache key khác nhau
proxy_set_header Accept "image/webp,image/*,*/*;q=0.8";
add_header X-Cache-Status $upstream_cache_status;
#add_header X-Cache-Key "url=${{app_name | regex_replace('[^A-Za-z0-9_]', '_')}}_clean_url&w=$arg_w&q=$arg_q";
# Keepalive settings (optional)
keepalive_timeout 64;
}
{% endif %}
location / {
access_log off;
proxy_pass http://{{ upstream_name | regex_replace('[^A-Za-z0-9_]', '_') }};
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 REMOTE-HOST $remote_addr;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_http_version 1.1;
proxy_cache off;
proxy_next_upstream error timeout http_502 http_503 http_504;
proxy_next_upstream_tries 3;
# Timeout & buffering
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
send_timeout 60s;
proxy_buffering on;
client_max_body_size 256M;
# Keepalive settings (optional)
keepalive_timeout 64;
}
}
# ============================================================================
# CONFIGURATION METADATA (for debugging)
# ============================================================================
# Configuration Details:
# - Base Port: {{ base_port }}
# - Load Balancing: {{ load_balancing_method | default('least_conn') }}
# - Max Fails: {{ max_fails | default(1) }}
# - Fail Timeout: {{ fail_timeout | default(10) }}s
# - Health Check: {{ 'enabled' if enable_health_check_endpoint | default(true) else 'disabled' }}
# ============================================================================