vigilar/remote/nginx/vigilar.conf
Aaron D. Lee 845a85d618 Initial commit: Vigilar DIY home security system
Phase 1 (Foundation): project skeleton, TOML config + Pydantic validation,
MQTT bus wrapper, SQLite schema (9 tables), Click CLI, process supervisor.

Phase 2 (Camera): RTSP capture via OpenCV, MOG2 motion detection with
configurable sensitivity/zones, adaptive FPS recording (2fps idle/30fps
motion) via FFmpeg subprocess, HLS live streaming, pre-motion ring buffer.

Phase 3 (Web UI): Flask + Bootstrap 5 dark theme, 6 blueprints, Jinja2
templates (dashboard, kiosk 2x2 grid, events, sensors, recordings, settings),
PWA with service worker + Web Push, full admin settings UI with config
persistence.

Remote Access: WireGuard tunnel configs, nginx reverse proxy with HLS
caching + rate limiting, bandwidth-optimized remote HLS stream (426x240
@ 500kbps), DO droplet setup script, certbot TLS.

29 tests passing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 23:11:27 -04:00

166 lines
5.5 KiB
Plaintext

# Nginx reverse proxy config for Digital Ocean droplet
# Proxies HTTPS traffic to Vigilar at home via WireGuard tunnel
#
# Install: cp vigilar.conf /etc/nginx/sites-available/vigilar
# ln -s /etc/nginx/sites-available/vigilar /etc/nginx/sites-enabled/
# nginx -t && systemctl reload nginx
#
# TLS: certbot --nginx -d vigilar.yourdomain.com
# Rate limiting zones
limit_req_zone $binary_remote_addr zone=api:10m rate=30r/s;
limit_req_zone $binary_remote_addr zone=stream:10m rate=5r/s;
limit_conn_zone $binary_remote_addr zone=connlimit:10m;
# HLS segment cache — reduces repeat requests hitting the home uplink
proxy_cache_path /var/cache/nginx/vigilar_hls
levels=1:2
keys_zone=hls_cache:10m
max_size=256m
inactive=30s
use_temp_path=off;
# Upstream: Vigilar on home server via WireGuard tunnel
upstream vigilar_home {
server 10.99.0.2:49735;
# If home server goes down, fail fast
keepalive 4;
}
# Redirect HTTP → HTTPS
server {
listen 80;
server_name vigilar.yourdomain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name vigilar.yourdomain.com;
# TLS (managed by certbot)
ssl_certificate /etc/letsencrypt/live/vigilar.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/vigilar.yourdomain.com/privkey.pem;
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_cache shared:SSL:10m;
ssl_session_timeout 1d;
# Security headers
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header Referrer-Policy strict-origin-when-cross-origin always;
# Connection limits — protect 22 Mbps home uplink
# Max 10 simultaneous connections per IP
limit_conn connlimit 10;
# --- HLS streams (bandwidth-critical path) ---
# Cache .ts segments on the droplet to avoid re-fetching from home
# when multiple remote viewers request the same segment
location ~ ^/cameras/.+/hls/.+\.ts$ {
proxy_pass http://vigilar_home;
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;
# Cache segments for 10s — they're 2s segments, so this covers
# multiple viewers watching the same feed without re-fetching
proxy_cache hls_cache;
proxy_cache_valid 200 10s;
proxy_cache_key $uri;
add_header X-Cache-Status $upstream_cache_status;
# Rate limit: 5 segment requests/sec per IP
limit_req zone=stream burst=20 nodelay;
}
# HLS playlists — don't cache (they update every segment)
location ~ ^/cameras/.+/hls/.+\.m3u8$ {
proxy_pass http://vigilar_home;
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 cache — playlists must be fresh
proxy_cache off;
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
# --- SSE event stream ---
location /events/stream {
proxy_pass http://vigilar_home;
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;
# SSE: disable buffering, long timeout
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
chunked_transfer_encoding on;
proxy_set_header Connection '';
proxy_http_version 1.1;
}
# --- API endpoints ---
location ~ ^/system/api/ {
proxy_pass http://vigilar_home;
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;
limit_req zone=api burst=10 nodelay;
}
# --- Static assets (cache aggressively on droplet) ---
location /static/ {
proxy_pass http://vigilar_home;
proxy_set_header Host $host;
proxy_cache hls_cache;
proxy_cache_valid 200 1h;
add_header X-Cache-Status $upstream_cache_status;
}
# --- Service worker (must not be cached stale) ---
location = /static/sw.js {
proxy_pass http://vigilar_home;
proxy_set_header Host $host;
proxy_cache off;
add_header Cache-Control "no-cache";
}
# --- Everything else (pages, PWA manifest, etc.) ---
location / {
proxy_pass http://vigilar_home;
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_http_version 1.1;
limit_req zone=api burst=20 nodelay;
}
# Deny access to config/sensitive paths
location ~ ^/(config|migrations|scripts|tests) {
deny all;
}
# Max upload size (for config changes, etc.)
client_max_body_size 1m;
# Logging
access_log /var/log/nginx/vigilar_access.log;
error_log /var/log/nginx/vigilar_error.log;
}