1 changed files with 98 additions and 0 deletions
@ -0,0 +1,98 @@ |
|||||
|
# CamMonitor — production / staging compose file |
||||
|
# |
||||
|
# Copy this file to the target server and run: |
||||
|
# docker compose -f docker-staging-prod.yaml up -d |
||||
|
# |
||||
|
# Mandatory values to change before first run (marked with CHANGE_ME): |
||||
|
# FOOTAGE_ROOT — absolute path to the camera footage directory on this host |
||||
|
# ADMIN_PASS — strong password for the bootstrap admin account |
||||
|
# |
||||
|
# The image is pulled from your local registry; make sure the host can reach |
||||
|
# 192.168.1.11:5000 and has it listed in /etc/docker/daemon.json: |
||||
|
# { "insecure-registries": ["192.168.1.11:5000"] } |
||||
|
|
||||
|
services: |
||||
|
app: |
||||
|
image: 192.168.1.11:5000/cammonitor:latest |
||||
|
restart: unless-stopped |
||||
|
|
||||
|
ports: |
||||
|
- "127.0.0.1:8080:8080" # Bind to loopback only — expose via reverse proxy. |
||||
|
# Change to "0.0.0.0:8080:8080" if you access |
||||
|
# the app directly without a proxy in front. |
||||
|
|
||||
|
environment: |
||||
|
LISTEN_ADDR: ":8080" |
||||
|
|
||||
|
# Absolute path on the HOST that contains the dated footage folders. |
||||
|
# Example: /mnt/cams → /mnt/cams/20260518/images/… |
||||
|
FOOTAGE_ROOT: /footage # CHANGE_ME — set to your real footage path |
||||
|
|
||||
|
DB_PATH: /data/cammonitor.db |
||||
|
|
||||
|
# Bootstrap admin created on first start only (no effect if DB already exists). |
||||
|
ADMIN_USER: admin |
||||
|
ADMIN_PASS: changeme # CHANGE_ME — use a strong password |
||||
|
|
||||
|
SESSION_TTL: 24h # How long a login session lasts |
||||
|
SCAN_INTERVAL: 5m # How often the footage tree is re-scanned |
||||
|
|
||||
|
volumes: |
||||
|
# Footage directory — mounted read-only so the app can never modify recordings. |
||||
|
- /path/to/footage:/footage:ro # CHANGE_ME — replace left side with real path |
||||
|
|
||||
|
# Persistent data (SQLite database). |
||||
|
- cammonitor_data:/data |
||||
|
|
||||
|
# Drop all Linux capabilities the Go binary does not need. |
||||
|
cap_drop: |
||||
|
- ALL |
||||
|
|
||||
|
# The app only needs to bind a TCP port; no other privileges required. |
||||
|
cap_add: |
||||
|
- NET_BIND_SERVICE |
||||
|
|
||||
|
# Read-only root filesystem — the only writable surface is the /data volume. |
||||
|
read_only: true |
||||
|
tmpfs: |
||||
|
- /tmp:size=64m,mode=1777 # Needed by the Go runtime for temp files |
||||
|
|
||||
|
# Prevent the container from gaining new privileges via setuid/setgid binaries. |
||||
|
security_opt: |
||||
|
- no-new-privileges:true |
||||
|
|
||||
|
# Limit CPU and memory so a spike in thumbnail requests does not starve the |
||||
|
# host (tune to your Atom's actual capacity). |
||||
|
deploy: |
||||
|
resources: |
||||
|
limits: |
||||
|
cpus: "1.0" |
||||
|
memory: 256M |
||||
|
reservations: |
||||
|
cpus: "0.25" |
||||
|
memory: 64M |
||||
|
|
||||
|
# Aggressive health-check so the orchestrator restarts a hung container fast. |
||||
|
healthcheck: |
||||
|
test: ["CMD", "cammonitor", "-health-check"] |
||||
|
# Fallback if the binary has no -health-check flag — use wget instead: |
||||
|
# test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:8080/health || exit 1"] |
||||
|
interval: 30s |
||||
|
timeout: 5s |
||||
|
retries: 3 |
||||
|
start_period: 10s |
||||
|
|
||||
|
logging: |
||||
|
driver: json-file |
||||
|
options: |
||||
|
max-size: "10m" |
||||
|
max-file: "5" |
||||
|
|
||||
|
volumes: |
||||
|
cammonitor_data: |
||||
|
driver: local |
||||
|
# Optional: pin the volume to a specific host path so backups are predictable. |
||||
|
# driver_opts: |
||||
|
# type: none |
||||
|
# o: bind |
||||
|
# device: /var/lib/cammonitor/data |
||||
Loading…
Reference in new issue