# Main process configuration
worker_processes 1;

events {
    worker_connections 1024;
}

http {
    geo $frontend_whitelist {
        default 1;
        127.0.0.1 1;
        172.20.0.0/16 1;      # Frontend Docker subnet
        5.75.153.161 1;       # Grafana or monitoring
        167.235.254.4 1;      # Ansible server IP
    }

    geo $backend_whitelist {
        default 1;
        127.0.0.1 1;
        172.19.0.0/16 1;      # Backend Docker subnet
        5.75.153.161 1;       # Grafana or monitoring
        167.235.254.4 1;      # Ansible server IP
    }
    
    # These settings ensure that $remote_addr reflects the real client IP forwarded by https-portal, which is needed for your allow rules to work correctly
    # Recommended for resolving client IP behind proxy
    # Docker networks where both frontend and backend containers communicate through NGINX.
    # To avoid potential misclassification of real client IPs from backend routes.
    # The set_real_ip_from directive doesn’t allow access — it just instructs NGINX to trust the X-Forwarded-For header from those IPs.
    set_real_ip_from 172.20.0.0/16;  # Replace with your Docker network subnet (matches your `frontend` network)
    set_real_ip_from 172.19.0.0/16;  # Replace with your Docker network subnet (matches your `backend` network)
    real_ip_header X-Forwarded-For;
    real_ip_recursive on;

    resolver 127.0.0.11 valid=10s;
    resolver_timeout 5s;

    upstream phoenix_system_cluster {
        zone phoenix_system_cluster 64k;
        least_conn;
        server phoenix-system:3000 resolve fail_timeout=1s max_fails=0;
        # ADD_SYSTEM_SERVERS_HERE
    }

    upstream phoenix_worker_cluster {
        zone phoenix_worker_cluster 64k;
        least_conn;
        server phoenix-worker:3001 resolve fail_timeout=1s max_fails=0;
        # ADD_WORKER_SERVERS_HERE
    }

    server_tokens off; # Disable NGINX version tokens to avoid leaking NGINX version.

    # File handling & upload limits
    sendfile on;
    client_max_body_size 64m;

    # Prevent warning when setting many proxy headers, like we do
    proxy_headers_hash_max_size 1024;
    proxy_headers_hash_bucket_size 128;

    # Gzip compression (for better bandwidth efficiency)
    gzip on;
    gzip_min_length 1000;
    gzip_proxied expired no-cache no-store private auth;
    gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;

    # Trust the protocol from upstream proxy/load balancer
    map $http_x_forwarded_proto $forwarded_proto {
        default $scheme;
        https https;
        http http;
    }

    # File types and default mime type
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    # 🧩 Logs
    map $request_uri $loggable {
        default             1;
        ~^/stub_status       0;
        ~^/health/system     0;
        ~^/health/worker     0;
    }

    log_format main_with_realip '$remote_addr - $realip_remote_addr [$time_local] '
                                '"$request" $status $body_bytes_sent '
                                '"$http_referer" "$http_user_agent"';

    log_format json_compatible escape=json '{'
        '"time":"$time_iso8601",'
        '"remote_addr":"$remote_addr",'
        '"proxy_addr":"$proxy_protocol_addr",'
        '"x_forwarded_for":"$http_x_forwarded_for",'
        '"request_method":"$request_method",'
        '"request_uri":"$request_uri",'
        '"status":$status,'
        '"body_bytes_sent":$body_bytes_sent,'
        '"request_time":$request_time,'
        '"upstream_response_time":"$upstream_response_time",'
        '"http_referer":"$http_referer",'
        '"http_user_agent":"$http_user_agent",'
        '"host":"$host",'
        '"realip":"$realip_remote_addr"'
    '}';

    access_log /var/log/nginx/access_json.log json_compatible if=$loggable; # JSON format for Loki
    access_log /var/log/nginx/access.log main_with_realip if=$loggable;
    # End of logs

    ##################################################################
    # 🧩 HTTP Server Block
    ##################################################################
    server {
        listen 80;
        server_name _;

        # Security headers
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-XSS-Protection "1; mode=block" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header Referrer-Policy "no-referrer-when-downgrade" always;

        root /usr/share/nginx/html;
        index index.html index.htm;

        # Frontend SPA fallback
        location / {
            try_files $uri $uri/ /index.html;
        }

        # Backend API routes
        location /backend-api/ {
            proxy_pass http://phoenix_system_cluster/;
            # Include headers for proxying
            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-Host $host;
            proxy_set_header X-Forwarded-Proto $forwarded_proto;
            # End of headers
        }

        location /admin-api {
            proxy_pass http://phoenix_system_cluster/admin-api;
            # Include headers for proxying
            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-Host $host;
            proxy_set_header X-Forwarded-Proto $forwarded_proto;
            # End of headers
        }

        location /remote-assets {
            proxy_pass http://phoenix_system_cluster/remote-assets;
            # Include headers for proxying
            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-Host $host;
            proxy_set_header X-Forwarded-Proto $forwarded_proto;
            # End of headers
        }

        location /sti {
            proxy_pass http://phoenix_system_cluster/sti;
            # Include headers for proxying
            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-Host $host;
            proxy_set_header X-Forwarded-Proto $forwarded_proto;
            # End of headers
        }

        # WebSocket support
        location /ws {
            proxy_pass http://phoenix_system_cluster/graphql;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            # Include headers for proxying
            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-Host $host;
            proxy_set_header X-Forwarded-Proto $forwarded_proto;
            # End of headers
        }

        # Reverse proxy for pgAdmin (subpath support)
        include /etc/nginx/includes/*.conf;

        # Health check endpoints -> used by the health check exporter
        location /health/system {
            proxy_pass http://phoenix_system_cluster/health;
            # Secure the health check endpoint
            if ($backend_whitelist = 0) {
                return 403;
            }
            # End of security
            # Include headers for proxying
            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 $forwarded_proto;
            # End of headers
        }

        # location /health/system/metrics {
        #     proxy_pass http://phoenix_system_cluster/health/metrics;
        #     # Secure the health check endpoint
        #     # if ($backend_whitelist = 0) {
        #     #     return 403;
        #     # }
        #     # End of security
        #     # Include headers for proxying
        #     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 $forwarded_proto;
        #     # End of headers
        # }

        location /health/worker {
            proxy_pass http://phoenix_worker_cluster/health;
            # Secure the health check endpoint
            if ($backend_whitelist = 0) {
                return 403;
            }
            # End of security
            # Include headers for proxying
            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 $forwarded_proto;
            # End of headers
        }

        # location /health/worker/metrics {
        #     proxy_pass http://phoenix_worker_cluster/health/metrics;
        #     # Secure the health check endpoint
        #     # if ($backend_whitelist = 0) {
        #     #     return 403;
        #     # }
        #     # End of security
        #     # Include headers for proxying
        #     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 $forwarded_proto;
        #     # End of headers
        # }

        location /stub_status {
            stub_status;
            # Secure the stub status endpoint
            if ($frontend_whitelist = 0) {
                return 403;
            }
            # End of security
        }
    }

    ##################################################################
    # 🔐 HTTPS Server Block
    ##################################################################
    server {
        listen 443 ssl;
        http2 on;
        server_name _;

        # Security headers
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-XSS-Protection "1; mode=block" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header Referrer-Policy "no-referrer-when-downgrade" always;

        ssl_certificate     /etc/nginx/external-certificate/certificate.crt;
        ssl_certificate_key /etc/nginx/external-certificate/certificate.key;

        root /usr/share/nginx/html;
        index index.html index.htm;

        location / {
            try_files $uri $uri/ /index.html;
        }

        # Secure API routes
        location /backend-api/ {
            proxy_pass http://phoenix_system_cluster/;
            # Include headers for proxying
            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-Host $host;
            proxy_set_header X-Forwarded-Proto $forwarded_proto;
            # End of headers
        }

        location /admin-api {
            proxy_pass http://phoenix_system_cluster/admin-api;
            # Include headers for proxying
            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-Host $host;
            proxy_set_header X-Forwarded-Proto $forwarded_proto;
            # End of headers
        }

        location /remote-assets {
            proxy_pass http://phoenix_system_cluster/remote-assets;
            # Include headers for proxying
            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-Host $host;
            proxy_set_header X-Forwarded-Proto $forwarded_proto;
            # End of headers
        }

        location /sti {
            proxy_pass http://phoenix_system_cluster/sti;
            # Include headers for proxying
            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-Host $host;
            proxy_set_header X-Forwarded-Proto $forwarded_proto;
            # End of headers
        }

        location /ws {
            proxy_pass http://phoenix_system_cluster/graphql;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            # Include headers for proxying
            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-Host $host;
            proxy_set_header X-Forwarded-Proto $forwarded_proto;
            # End of headers
        }

        # Reverse proxy for pgAdmin (subpath support)
        include /etc/nginx/includes/*.conf;

        location /health/system {
            proxy_pass http://phoenix_system_cluster/health;
            # Secure the health check endpoint
            if ($backend_whitelist = 0) {
                return 403;
            }
            # End of security
            # Include headers for proxying
            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 $forwarded_proto;
            # End of headers
        }

        location /health/worker {
            proxy_pass http://phoenix_worker_cluster/health;
            # Secure the health check endpoint
            if ($backend_whitelist = 0) {
                return 403;
            }
            # End of security
            # Include headers for proxying
            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 $forwarded_proto;
            # End of headers
        }

        location /stub_status {
            stub_status;
            # Secure the stub status endpoint
            if ($frontend_whitelist = 0) {
                return 403;
            }
            # End of security
        }
    }
}