feat: add production container support with health check endpoint
Implements Phase 5 containerization specification: - Add /health endpoint for container monitoring - Create multi-stage Containerfile (Podman/Docker compatible) - Add compose.yaml for orchestration - Add Caddyfile.example for reverse proxy (auto-HTTPS) - Add nginx.conf.example as alternative - Update .env.example with container and RSS feed variables - Add gunicorn WSGI server to requirements.txt Container features: - Multi-stage build for smaller image size - Non-root user (starpunk:1000) - Health check with database connectivity test - Volume mount for data persistence - Resource limits and logging configuration - Security headers and HTTPS configuration examples Health check endpoint: - Tests database connectivity - Verifies filesystem access - Returns JSON with status, version, and environment Following Phase 5 design in docs/designs/phase-5-rss-and-container.md
This commit is contained in:
188
nginx.conf.example
Normal file
188
nginx.conf.example
Normal file
@@ -0,0 +1,188 @@
|
||||
# Nginx Configuration for StarPunk
|
||||
# Alternative to Caddy for reverse proxy
|
||||
#
|
||||
# Installation:
|
||||
# 1. Install Nginx: sudo apt install nginx
|
||||
# 2. Install Certbot: sudo apt install certbot python3-certbot-nginx
|
||||
# 3. Copy this file: sudo cp nginx.conf.example /etc/nginx/sites-available/starpunk
|
||||
# 4. Update your-domain.com to your actual domain
|
||||
# 5. Create symlink: sudo ln -s /etc/nginx/sites-available/starpunk /etc/nginx/sites-enabled/
|
||||
# 6. Test config: sudo nginx -t
|
||||
# 7. Get SSL cert: sudo certbot --nginx -d your-domain.com
|
||||
# 8. Reload: sudo systemctl reload nginx
|
||||
|
||||
# Upstream definition for StarPunk container
|
||||
upstream starpunk {
|
||||
server localhost:8000;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
# HTTP server - redirect to HTTPS
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name your-domain.com;
|
||||
|
||||
# ACME challenge for Let's Encrypt
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/html;
|
||||
}
|
||||
|
||||
# Redirect all other HTTP to HTTPS
|
||||
location / {
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
# HTTPS server
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
server_name your-domain.com;
|
||||
|
||||
# SSL certificates (managed by certbot)
|
||||
# Update paths after running certbot
|
||||
ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
|
||||
|
||||
# SSL configuration (Mozilla Intermediate)
|
||||
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:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
|
||||
ssl_prefer_server_ciphers off;
|
||||
|
||||
# SSL session cache
|
||||
ssl_session_timeout 1d;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_tickets off;
|
||||
|
||||
# OCSP stapling
|
||||
ssl_stapling on;
|
||||
ssl_stapling_verify on;
|
||||
ssl_trusted_certificate /etc/letsencrypt/live/your-domain.com/chain.pem;
|
||||
|
||||
# Security headers
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-Frame-Options "DENY" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-ancestors 'none';" always;
|
||||
|
||||
# Logging
|
||||
access_log /var/log/nginx/starpunk-access.log;
|
||||
error_log /var/log/nginx/starpunk-error.log;
|
||||
|
||||
# Max upload size (for future media uploads)
|
||||
client_max_body_size 10M;
|
||||
|
||||
# Root location - proxy to StarPunk
|
||||
location / {
|
||||
# Proxy to upstream
|
||||
proxy_pass http://starpunk;
|
||||
|
||||
# Proxy headers
|
||||
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 X-Forwarded-Host $host;
|
||||
proxy_set_header X-Forwarded-Port $server_port;
|
||||
|
||||
# WebSocket support (for future features)
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
# Timeouts
|
||||
proxy_connect_timeout 30s;
|
||||
proxy_send_timeout 30s;
|
||||
proxy_read_timeout 30s;
|
||||
|
||||
# Buffering
|
||||
proxy_buffering on;
|
||||
proxy_buffer_size 4k;
|
||||
proxy_buffers 8 4k;
|
||||
proxy_busy_buffers_size 8k;
|
||||
|
||||
# No caching for dynamic content
|
||||
add_header Cache-Control "no-cache, private" always;
|
||||
}
|
||||
|
||||
# Static files - aggressive caching
|
||||
location /static/ {
|
||||
proxy_pass http://starpunk;
|
||||
proxy_set_header Host $host;
|
||||
|
||||
# Long-term caching for static assets
|
||||
add_header Cache-Control "public, max-age=31536000, immutable";
|
||||
|
||||
# Compression
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_types text/css application/javascript image/svg+xml;
|
||||
}
|
||||
|
||||
# RSS feed - short-term caching
|
||||
location /feed.xml {
|
||||
proxy_pass http://starpunk;
|
||||
proxy_set_header Host $host;
|
||||
|
||||
# Cache for 5 minutes
|
||||
add_header Cache-Control "public, max-age=300";
|
||||
|
||||
# Compression
|
||||
gzip on;
|
||||
gzip_types application/rss+xml application/xml;
|
||||
}
|
||||
|
||||
# Health check endpoint - no caching
|
||||
location /health {
|
||||
proxy_pass http://starpunk;
|
||||
proxy_set_header Host $host;
|
||||
|
||||
# No caching
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate" always;
|
||||
|
||||
# Allow monitoring systems access
|
||||
# Optional: restrict to specific IPs
|
||||
# allow 10.0.0.0/8; # Internal network
|
||||
# deny all;
|
||||
}
|
||||
|
||||
# Admin routes - no caching, security
|
||||
location /admin/ {
|
||||
proxy_pass http://starpunk;
|
||||
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;
|
||||
|
||||
# No caching for admin
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate" always;
|
||||
|
||||
# Optional: IP whitelist for admin
|
||||
# allow 1.2.3.4; # Your IP
|
||||
# deny all;
|
||||
}
|
||||
|
||||
# Deny access to hidden files
|
||||
location ~ /\. {
|
||||
deny all;
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
}
|
||||
}
|
||||
|
||||
# Optional: Redirect www to non-www
|
||||
# server {
|
||||
# listen 80;
|
||||
# listen [::]:80;
|
||||
# listen 443 ssl http2;
|
||||
# listen [::]:443 ssl http2;
|
||||
# server_name www.your-domain.com;
|
||||
#
|
||||
# ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
|
||||
# ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
|
||||
#
|
||||
# return 301 https://your-domain.com$request_uri;
|
||||
# }
|
||||
Reference in New Issue
Block a user