CtrlK
BlogDocsLog inGet started
Tessl Logo

nginx-config-generator

Generate Nginx reverse proxy configurations with SSL/TLS (Let's Encrypt), static file serving, upstream definitions, rate limiting, gzip compression, security headers, and location blocks.

83

Quality

77%

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Advisory

Suggest reviewing before use

Optimize this skill with Tessl

npx tessl skill review --optimize ./infrastructure/nginx-config-generator/SKILL.md
SKILL.md
Quality
Evals
Security

Nginx Config Generator

Generate Nginx reverse proxy configurations with SSL/TLS (Let's Encrypt), static file serving, upstream definitions, rate limiting, gzip compression, security headers, and location blocks.

Prerequisites

  • Nginx >= 1.27 (or nginx:1.27-alpine Docker image)
  • Certbot (for Let's Encrypt SSL) or pre-existing certificates
  • DNS records pointing to the server

Scaffold Command

# Standalone Nginx
mkdir -p /etc/nginx/{conf.d,snippets,ssl}
touch /etc/nginx/nginx.conf
touch /etc/nginx/conf.d/default.conf

# Docker / project-local config
mkdir -p nginx/{conf.d,snippets,ssl,html}
touch nginx/nginx.conf
touch nginx/conf.d/app.conf

Project Structure

nginx/
  nginx.conf                      # Main config (worker processes, events, http block)
  conf.d/
    app.conf                      # Virtual host for the application
    static.conf                   # Static file serving (optional)
  snippets/
    ssl-params.conf               # Shared SSL parameters
    security-headers.conf         # Shared security headers
    proxy-params.conf             # Shared proxy settings
    rate-limit.conf               # Rate limiting zone definitions
  ssl/
    fullchain.pem                 # SSL certificate (gitignored)
    privkey.pem                   # SSL private key (gitignored)
  html/
    50x.html                      # Custom error page

Key Conventions

  • Use conf.d/ for per-site virtual host configs. Keep nginx.conf for global settings only.
  • Extract reusable config into snippets/ and include them.
  • Always redirect HTTP to HTTPS in production.
  • Set server_tokens off to hide Nginx version.
  • Use upstream blocks for backend services to enable load balancing.
  • Define rate limiting zones globally in http block, apply per-location.
  • Enable gzip for text-based content types.
  • Set security headers on every response.

Essential Patterns

Main Config (nginx.conf)

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
    multi_accept on;
}

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

    # Logging
    log_format main '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent" '
                    '$request_time';
    access_log /var/log/nginx/access.log main;

    # Performance
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;

    # Security
    server_tokens off;

    # Gzip
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 4;
    gzip_min_length 256;
    gzip_types
        text/plain
        text/css
        text/javascript
        application/javascript
        application/json
        application/xml
        image/svg+xml
        font/woff2;

    # Rate limiting zones
    limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
    limit_req_zone $binary_remote_addr zone=api:10m rate=30r/s;
    limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;

    # Virtual hosts
    include /etc/nginx/conf.d/*.conf;
}

Reverse Proxy with SSL (conf.d/app.conf)

upstream app_backend {
    server app:3000;
    keepalive 32;
}

# Redirect HTTP to HTTPS
server {
    listen 80;
    listen [::]:80;
    server_name myapp.example.com;

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

# HTTPS server
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name myapp.example.com;

    # SSL
    ssl_certificate /etc/nginx/ssl/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/privkey.pem;
    include /etc/nginx/snippets/ssl-params.conf;

    # Security headers
    include /etc/nginx/snippets/security-headers.conf;

    # API proxy
    location /api/ {
        limit_req zone=api burst=20 nodelay;
        include /etc/nginx/snippets/proxy-params.conf;
        proxy_pass http://app_backend;
    }

    # Auth endpoints — stricter rate limit
    location /api/auth/login {
        limit_req zone=login burst=3 nodelay;
        include /etc/nginx/snippets/proxy-params.conf;
        proxy_pass http://app_backend;
    }

    # WebSocket support
    location /ws {
        include /etc/nginx/snippets/proxy-params.conf;
        proxy_pass http://app_backend;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_read_timeout 86400s;
    }

    # Static files (if served by Nginx directly)
    location /static/ {
        alias /var/www/static/;
        expires 30d;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

    # SPA fallback — serve index.html for client-side routing
    location / {
        root /var/www/html;
        try_files $uri $uri/ /index.html;
        expires 1h;
    }

    # Custom error pages
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /etc/nginx/html;
    }
}

SSL Parameters (snippets/ssl-params.conf)

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;
ssl_prefer_server_ciphers off;

ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;

ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s;
resolver_timeout 5s;

Security Headers (snippets/security-headers.conf)

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 "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self' https://api.example.com; frame-ancestors 'self';" always;

Proxy Parameters (snippets/proxy-params.conf)

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_connect_timeout 5s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;

Load Balancing Multiple Backends

upstream app_backend {
    least_conn;
    server app1:3000 weight=3;
    server app2:3000 weight=2;
    server app3:3000 backup;
    keepalive 32;
}

Static File Server (conf.d/static.conf)

server {
    listen 80;
    server_name static.example.com;

    root /var/www/static;
    index index.html;

    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2|woff|ttf)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

    location / {
        try_files $uri $uri/ =404;
    }
}

Let's Encrypt with Certbot (Docker)

# Add to docker-compose.yml
services:
  certbot:
    image: certbot/certbot:latest
    volumes:
      - certbot_conf:/etc/letsencrypt
      - certbot_www:/var/www/certbot
    entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h; done'"

  nginx:
    volumes:
      - certbot_conf:/etc/nginx/ssl:ro
      - certbot_www:/var/www/certbot:ro

volumes:
  certbot_conf:
  certbot_www:
# Initial certificate generation
docker compose run --rm certbot certonly --webroot -w /var/www/certbot -d myapp.example.com --agree-tos --email admin@example.com

Common Commands

# Test configuration syntax
nginx -t

# Reload configuration (no downtime)
nginx -s reload

# Start Nginx
nginx

# Stop Nginx
nginx -s stop

# View access logs
tail -f /var/log/nginx/access.log

# View error logs
tail -f /var/log/nginx/error.log

# Docker: test config
docker compose exec nginx nginx -t

# Docker: reload
docker compose exec nginx nginx -s reload

# Certbot: obtain certificate
certbot --nginx -d myapp.example.com

# Certbot: renew all certificates
certbot renew --dry-run

Integration Notes

  • Docker Compose: Pair with docker-compose-generator skill. Nginx runs as a service with config mounted as a volume.
  • Kubernetes: In Kubernetes, use an Ingress controller (nginx-ingress) instead of manually configured Nginx. Pair with kubernetes-manifests skill for Ingress resources.
  • SSL/TLS: For production, use Let's Encrypt via certbot. For local dev, use mkcert to generate trusted local certificates.
  • CI/CD: Nginx config changes can be validated in CI with nginx -t inside a Docker container before deploying.
Repository
achreftlili/deep-dev-skills
Last updated
Created

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.