From agent-almanac
Configures Nginx as web server and reverse proxy with static file serving, SSL/TLS via Let's Encrypt, load balancing, rate limiting, and security headers for production deployments.
npx claudepluginhub pjt222/agent-almanacThis skill uses the workspace's default tool permissions.
---
Provides Nginx configuration references, directive inheritance rules, reverse proxy decision trees, SSL/TLS hardening, load balancing, and performance tuning for production web servers.
Configures Nginx for reverse proxy, load balancing, SSL/TLS termination, caching, rate limiting, DDoS protection, and API gateway in production web servers.
Configures reverse proxies using Nginx, Traefik, or ShinyProxy for path/host-based routing, WebSocket proxying, SSL termination, and Docker label auto-discovery. Use for multi-service routing behind a single entry point.
Share bugs, ideas, or general feedback.
Set up Nginx as a web server and reverse proxy with SSL termination and security hardening.
nginx.conf:
events {
worker_connections 1024;
}
http {
upstream app {
server app:3000;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://app;
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;
}
}
}
Docker Compose service:
services:
nginx:
image: nginx:1.27-alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- app
Expected: Requests to port 80 are forwarded to the app service.
server {
listen 80;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ {
expires 6M;
add_header Cache-Control "public";
}
}
Using certbot with the webroot method:
server {
listen 80;
server_name example.com;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://app;
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;
}
}
Docker Compose with certbot:
services:
nginx:
image: nginx:1.27-alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- certbot-webroot:/var/www/certbot:ro
- certbot-certs:/etc/letsencrypt:ro
certbot:
image: certbot/certbot
volumes:
- certbot-webroot:/var/www/certbot
- certbot-certs:/etc/letsencrypt
volumes:
certbot-webroot:
certbot-certs:
Initial certificate:
docker compose run --rm certbot certonly \
--webroot -w /var/www/certbot \
-d example.com --email admin@example.com --agree-tos
Expected: HTTPS works with valid Let's Encrypt certificate.
On failure: Check DNS points to the server. Verify port 80 is open for ACME challenges.
server {
# ... SSL config above ...
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 Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline';" always;
# Hide Nginx version
server_tokens off;
}
http {
# Define rate limit zones
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
server {
location /api/ {
limit_req zone=api burst=20 nodelay;
proxy_pass http://app;
}
location /login {
limit_req zone=login burst=5;
proxy_pass http://app;
}
}
}
upstream app {
least_conn;
server app1:3000;
server app2:3000;
server app3:3000 backup;
}
| Method | Directive | Behavior |
|---|---|---|
| Round robin | (default) | Equal distribution |
| Least connections | least_conn | Routes to least busy |
| IP hash | ip_hash | Sticky sessions |
| Weighted | server app:3000 weight=3 | Proportional |
# Test config syntax
docker compose exec nginx nginx -t
# Reload without downtime
docker compose exec nginx nginx -s reload
# Check response headers
curl -I https://example.com
Expected: nginx -t reports syntax OK. Headers include security headers.
nginx -t reports configuration is validproxy_set_header Host: Backend receives wrong host header, breaking virtual hosts and redirects.location order matters: Nginx uses the most specific match. Exact (=) > prefix (^~) > regex (~) > general prefix.certbot renew and reload Nginx.client_max_body_size is 1MB. Increase for file uploads: client_max_body_size 50m;.configure-reverse-proxy for the pattern.configure-reverse-proxy - multi-tool proxy patterns including WebSocket and Traefiksetup-compose-stack - compose stack that includes Nginxdeploy-searxng - uses Nginx as frontend for SearXNGconfigure-ingress-networking - Kubernetes ingress (NGINX Ingress Controller)