105 lines
4.1 KiB
Plaintext
105 lines
4.1 KiB
Plaintext
# ── Bastebin — Nginx reverse-proxy configuration ─────────────────────────────
|
|
#
|
|
# Copy to /etc/nginx/sites-available/bastebin and symlink:
|
|
# sudo ln -s /etc/nginx/sites-available/bastebin /etc/nginx/sites-enabled/
|
|
# sudo nginx -t && sudo systemctl reload nginx
|
|
#
|
|
# Assumes:
|
|
# - Gunicorn is bound to a Unix socket at /run/bastebin/gunicorn.sock
|
|
# - Your TLS certificates are managed by Certbot / Let's Encrypt
|
|
# - Static files live at /path/to/bastebin/static/
|
|
#
|
|
# Replace every occurrence of:
|
|
# bastebin.com → your actual domain
|
|
# /path/to/bastebin → absolute path to your project directory
|
|
|
|
server {
|
|
listen 80;
|
|
listen [::]:80;
|
|
server_name bastebin.com www.bastebin.com;
|
|
|
|
# Redirect all HTTP → HTTPS
|
|
return 301 https://$host$request_uri;
|
|
}
|
|
|
|
server {
|
|
listen 443 ssl http2;
|
|
listen [::]:443 ssl http2;
|
|
server_name bastebin.com www.bastebin.com;
|
|
|
|
# ── TLS (managed by Certbot — do not edit manually) ──────────────────────
|
|
ssl_certificate /etc/letsencrypt/live/bastebin.com/fullchain.pem;
|
|
ssl_certificate_key /etc/letsencrypt/live/bastebin.com/privkey.pem;
|
|
include /etc/letsencrypt/options-ssl-nginx.conf;
|
|
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
|
|
|
|
# ── Security headers (supplement Flask's own headers) ────────────────────
|
|
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
|
|
add_header X-Robots-Tag "noindex, nofollow" always;
|
|
|
|
# ── Block access to sensitive paths ──────────────────────────────────────
|
|
# These should NEVER be served, even accidentally.
|
|
location ~* \.(py|json|db|sqlite|sqlite3|log|cfg|ini|toml|env|sh|conf|bak|orig)$ {
|
|
deny all;
|
|
return 404;
|
|
}
|
|
|
|
# Block dot-files / hidden files (e.g. .env, .git)
|
|
location ~ /\. {
|
|
deny all;
|
|
return 404;
|
|
}
|
|
|
|
# Block __pycache__ and similar Python internals
|
|
location ~* /__pycache__/ {
|
|
deny all;
|
|
return 404;
|
|
}
|
|
|
|
# ── Static files served directly by Nginx (fast path) ───────────────────
|
|
# Nginx serves these without hitting Gunicorn at all.
|
|
location /static/ {
|
|
alias /path/to/bastebin/static/;
|
|
|
|
# No directory listings
|
|
autoindex off;
|
|
|
|
# Cache busting — serve with long expiry; filename includes hash in prod
|
|
expires 7d;
|
|
add_header Cache-Control "public, max-age=604800, immutable";
|
|
|
|
# Only allow known file extensions; block anything else
|
|
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
|
# Passthrough — let the alias serve it
|
|
}
|
|
location / {
|
|
# Anything under /static/ that doesn't match above is denied
|
|
deny all;
|
|
return 404;
|
|
}
|
|
}
|
|
|
|
# ── Gunicorn (Flask application) ─────────────────────────────────────────
|
|
location / {
|
|
proxy_pass http://unix:/run/bastebin/gunicorn.sock;
|
|
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;
|
|
|
|
# Timeouts
|
|
proxy_connect_timeout 10s;
|
|
proxy_read_timeout 60s;
|
|
proxy_send_timeout 60s;
|
|
|
|
# Body size limit — match config.json max_size_bytes (2 MB) + overhead
|
|
client_max_body_size 3m;
|
|
}
|
|
|
|
# ── Logging ───────────────────────────────────────────────────────────────
|
|
access_log /var/log/nginx/bastebin.access.log;
|
|
error_log /var/log/nginx/bastebin.error.log warn;
|
|
}
|