This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This is a Docker-based reverse proxy setup using jwilder/nginx-proxy for automatic service discovery and routing. The proxy monitors Docker containers and automatically generates nginx configurations based on environment variables.
Core Components:
docker-compose.yml: Defines the reverse-proxy service with Docker socket binding for automatic container discoverynginx/conf.d/00-proxy.conf: Global nginx proxy settings including:- Client limits and timeouts (20s client timeout, 120s proxy timeout)
- Rate limiting (10 requests/second per IP, burst of 20)
- Connection limiting (max 10 concurrent connections per IP)
- Gzip compression for text and JSON content
- Unlimited client body size
- Default server blocks (HTTP and HTTPS) that serve a fallback page when no VIRTUAL_HOST matches
nginx/vhost.d/default: Security headers and CORS configuration including:- Security headers (X-Frame-Options, X-Content-Type-Options, X-XSS-Protection, Referrer-Policy)
- CORS for cross-origin requests with credentials
- Blocks access to hidden files (.env, .git, etc.)
nginx/html/index.html: Custom default page with instructions shown when accessing unconfigured domainsnginx/certs/default.crtandnginx/certs/default.key: Self-signed fallback SSL certificate (10-year validity) used by the default HTTPS server block. This ensures the SSL handshake succeeds even when no VIRTUAL_HOST is configured, preventing Cloudflare error 525. These files are versioned in git.
Network Configuration:
The setup uses an external Docker network named reverse-proxy. Services that need to be proxied must:
- Connect to the
reverse-proxynetwork - Set the
VIRTUAL_HOSTenvironment variable to their domain name - Optionally set
VIRTUAL_PORTif the service doesn't use port 80
SSL/HTTPS Configuration:
By default, SSL/HTTPS is handled by Cloudflare. The reverse proxy listens on ports 80 and 443. A self-signed fallback certificate (nginx/certs/default.crt and default.key) is included in the project to ensure the default HTTPS server block can complete the SSL handshake when no VIRTUAL_HOST is configured.
For production domains, use Cloudflare Origin Certificates:
- Generate an Origin Certificate in Cloudflare dashboard (SSL/TLS > Origin Server)
- Save the certificate and key in
nginx/certs/as<domain>.crtand<domain>.key - Uncomment the
./nginx/certsvolume mount in docker-compose.yml - The nginx-proxy will automatically use the certificate matching the
VIRTUAL_HOSTdomain - Set Cloudflare SSL mode to "Full (strict)"
Optional Let's Encrypt (commented out by default):
The acme-companion service is included but commented out in docker-compose.yml. To use Let's Encrypt instead of Cloudflare:
- Uncomment the
acme-companionservice in docker-compose.yml - Uncomment the
./nginx/certsvolume mount in the reverse-proxy service - Update
DEFAULT_EMAILwith your email address - Ensure ports 80 and 443 are publicly accessible (not proxied through Cloudflare)
- Certificates will be stored in
nginx/certs/and ACME files innginx/acme/(both directories are gitignored)
Key Settings:
TRUST_DOWNSTREAM_PROXY=true: Enables proper client IP forwarding through proxy chains- Server tokens hidden for security (nginx version not exposed)
- CORS enabled for cross-origin requests with credentials support
- Rate limiting: 10 req/s per IP with burst of 20 (prevents DDoS)
- Connection limiting: Max 10 concurrent connections per IP
- Timeouts configured to prevent slow clients from holding resources
- Gzip compression enabled for better performance
Start the reverse proxy:
docker compose up -dStop the reverse proxy:
docker compose downView logs:
docker compose logs -f reverse-proxyRestart to apply configuration changes:
docker compose restart reverse-proxyCreate the external network (if not exists):
docker network create reverse-proxyDirectory Structure:
All nginx-related files are organized under the nginx/ directory:
conf.d/- Nginx configuration filesvhost.d/- Virtual host specific configurationshtml/- Default web page filescerts/- SSL certificates (default.crtanddefault.keyare versioned; domain-specific certs are gitignored)acme/- ACME challenge files (created when using Let's Encrypt, gitignored)
Modifying nginx settings:
- Global proxy settings: Edit
nginx/conf.d/00-proxy.conf- Adjust
client_max_body_sizeif you need larger uploads - Modify rate limiting (
limit_req_zone) based on your traffic patterns - Change timeouts if your applications need more time to respond
- Adjust
- CORS and vhost-specific settings: Edit
nginx/vhost.d/default- Uncomment HSTS header if using Let's Encrypt (not needed with Cloudflare)
- Modify CORS origins if you want to whitelist specific domains
- Adjust security headers based on your requirements
- Default page: Edit
nginx/html/index.htmlto customize the fallback page - After changes, restart the container to apply
Adding new proxied services: Services should be added in separate docker-compose files with:
services:
your-service:
environment:
- VIRTUAL_HOST=yourdomain.com
- VIRTUAL_PORT=8080 # if not using port 80
networks:
- reverse-proxy
networks:
reverse-proxy:
external: trueIf using Let's Encrypt (acme-companion enabled): Add these additional environment variables to your services:
environment:
- LETSENCRYPT_HOST=yourdomain.com
- LETSENCRYPT_EMAIL=your-email@example.com # optional, overrides DEFAULT_EMAILImportant notes:
- When using Cloudflare, configure SSL mode to "Full" or "Full (strict)" in Cloudflare dashboard
- If using Let's Encrypt directly, ports 80 and 443 must be publicly accessible without Cloudflare proxy