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
77%
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Advisory
Suggest reviewing before use
Optimize this skill with Tessl
npx tessl skill review --optimize ./infrastructure/nginx-config-generator/SKILL.mdGenerate Nginx reverse proxy configurations with SSL/TLS (Let's Encrypt), static file serving, upstream definitions, rate limiting, gzip compression, security headers, and location blocks.
# 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.confnginx/
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 pageconf.d/ for per-site virtual host configs. Keep nginx.conf for global settings only.snippets/ and include them.server_tokens off to hide Nginx version.http block, apply per-location.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;
}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;
}
}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;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;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;upstream app_backend {
least_conn;
server app1:3000 weight=3;
server app2:3000 weight=2;
server app3:3000 backup;
keepalive 32;
}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;
}
}# 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# 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-rundocker-compose-generator skill. Nginx runs as a service with config mounted as a volume.kubernetes-manifests skill for Ingress resources.mkcert to generate trusted local certificates.nginx -t inside a Docker container before deploying.181fcbc
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.