Skip to content

Instantly share code, notes, and snippets.

@eliyas5044
Created December 13, 2023 17:38
Show Gist options
  • Save eliyas5044/6b6d61296a7b4a7737c619b023f25dd1 to your computer and use it in GitHub Desktop.
Save eliyas5044/6b6d61296a7b4a7737c619b023f25dd1 to your computer and use it in GitHub Desktop.
Nginx config file for the Nuxt SSR

nginx.conf

  • Modify nginx.conf into /etc/nginx/nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
  worker_connections 1024; # Adjusted for higher capacity
  multi_accept on;
}

http {
  sendfile on;
  tcp_nopush on;
  tcp_nodelay on;
  keepalive_timeout 65;
  types_hash_max_size 2048;
  server_tokens off;

  server_names_hash_bucket_size 64;
  server_name_in_redirect off;
  client_max_body_size 512M;

  include /etc/nginx/mime.types;
  default_type application/octet-stream;

  # Updated SSL Settings
  ssl_protocols TLSv1.2 TLSv1.3; # Dropping older protocols
  ssl_prefer_server_ciphers on;

  # Logging Settings
  access_log /var/log/nginx/access.log;
  error_log /var/log/nginx/error.log;

  # Connection header for WebSocket reverse proxy
  map $http_upgrade $connection_upgrade {
    default upgrade;
    ""      close;
  }

  map $remote_addr $proxy_forwarded_elem {

    # IPv4 addresses can be sent as-is
    ~^[0-9.]+$        "for=$remote_addr";

    # IPv6 addresses need to be bracketed and quoted
    ~^[0-9A-Fa-f:.]+$ "for=\"[$remote_addr]\"";

    # Unix domain socket names cannot be represented in RFC 7239 syntax
    default           "for=unknown";
  }

  map $http_forwarded $proxy_add_forwarded {

    # If the incoming Forwarded header is syntactically valid, append to it
    "~^(,[ \\t]*)*([!#$%&'*+.^_`|~0-9A-Za-z-]+=([!#$%&'*+.^_`|~0-9A-Za-z-]+|\"([\\t \\x21\\x23-\\x5B\\x5D-\\x7E\\x80-\\xFF]|\\\\[\\t \\x21-\\x7E\\x80-\\xFF])*\"))?(;([!#$%&'*+.^_`|~0-9A-Za-z-]+=([!#$%&'*+.^_`|~0-9A-Za-z-]+|\"([\\t \\x21\\x23-\\x5B\\x5D-\\x7E\\x80-\\xFF]|\\\\[\\t \\x21-\\x7E\\x80-\\xFF])*\"))?)*([ \\t]*,([ \\t]*([!#$%&'*+.^_`|~0-9A-Za-z-]+=([!#$%&'*+.^_`|~0-9A-Za-z-]+|\"([\\t \\x21\\x23-\\x5B\\x5D-\\x7E\\x80-\\xFF]|\\\\[\\t \\x21-\\x7E\\x80-\\xFF])*\"))?(;([!#$%&'*+.^_`|~0-9A-Za-z-]+=([!#$%&'*+.^_`|~0-9A-Za-z-]+|\"([\\t \\x21\\x23-\\x5B\\x5D-\\x7E\\x80-\\xFF]|\\\\[\\t \\x21-\\x7E\\x80-\\xFF])*\"))?)*)?)*$" "$http_forwarded, $proxy_forwarded_elem";

    # Otherwise, replace it
    default "$proxy_forwarded_elem";
  }

  # Recommended Security Headers
  add_header X-Frame-Options "SAMEORIGIN" always;
  add_header X-Content-Type-Options "nosniff" always;
  add_header X-XSS-Protection "1; mode=block" always;
  add_header Referrer-Policy "no-referrer-when-downgrade" always;
  add_header Content-Security-Policy "default-src 'self';" always;
}

web.conf

  • Add web.conf into /etc/nginx/conf.d folder
# Enhanced SSL Configuration
ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM';
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;

# Rate Limiting
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;

# gzip Compression
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

proxy_cache_path /var/cache/frontend levels=1:2 keys_zone=cache:25m max_size=1g inactive=60m use_temp_path=off;

map $sent_http_content_type $expires {
  "text/html" 10m; # Shorter expiration for HTML
  "text/css" 1d;   # Daily update for CSS
  "application/javascript" 1d; # Daily update for JavaScript
  default 1y;      # Long-term caching for other types
}

upstream backend {
  zone upstreams 64K;
  server 127.0.0.1:3000;
  keepalive 50;
}

server {
  listen 80;
  listen 443 ssl http2;
  server_name example.com www.example.com;

  # Redirect HTTP to HTTPS
  if ( $scheme = "http" ) {
    return 301 https://$host$request_uri;
  }

  # SSL Certificates
  ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

  # Security Headers
  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;
  add_header Content-Security-Policy "default-src 'self' http: https: ws: wss: data: blob: 'unsafe-inline'; frame-ancestors 'self';" always;
  add_header Permissions-Policy "interest-cohort=()" always;
  add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
  add_header X-Cache-Status $upstream_cache_status;

  location /api/ {
    expires off;

    proxy_pass http://backend/api/;
    proxy_cache off;
  }

  proxy_redirect off;
  proxy_http_version 1.1;
  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_set_header "Connection" "";
  
  # Proxy timeout
  proxy_send_timeout 10m;
  proxy_read_timeout 10m;
  proxy_connect_timeout 10m;

  location / {
    expires $expires;
    proxy_pass http://backend/;

    # Proxy cache
    proxy_cache cache;
    proxy_cache_revalidate on;
    proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
    proxy_cache_background_update on;
    proxy_cache_lock on;

    proxy_cache_valid 200 302 60m;
    proxy_cache_valid 404 1m;
    
    # Cache bypass conditions
    proxy_cache_bypass $arg_purgecache;
    proxy_cache_bypass $http_x_purge_cache;
    proxy_cache_bypass $cookie_purgecache;

    # Rate Limiting
    limit_req zone=mylimit;
  }

  access_log off;
  error_log /var/log/nginx/example.com-error.log error;

  # ACME-challenge
  location ^~ /.well-known/acme-challenge/ {
    root /var/www/_letsencrypt;
  }

  # Deny access to hidden files
  location ~ /\.(?!well-known).* {
    deny all;
  }

  # Custom Error Pages
  # error_page 404 /custom_404.html;
  # error_page 500 502 503 504 /custom_50x.html;
  # location = /custom_404.html {
  #     root /usr/share/nginx/html;
  #     internal;
  # }
  # location = /custom_50x.html {
  #     root /usr/share/nginx/html;
  #     internal;
  # }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment