[Unit] Description=MES Dashboard Gunicorn Service (Conda Runtime) Documentation=https://github.com/your-org/mes-dashboard After=network.target redis-server.service Wants=redis-server.service [Service] Type=simple User=www-data Group=www-data WorkingDirectory=/opt/mes-dashboard EnvironmentFile=-/opt/mes-dashboard/.env Environment="PYTHONPATH=/opt/mes-dashboard/src" RuntimeDirectory=mes-dashboard StateDirectory=mes-dashboard PIDFile=/run/mes-dashboard/gunicorn.pid ExecStart=/usr/bin/env bash -lc 'exec "${CONDA_BIN:-/opt/miniconda3/bin/conda}" run --no-capture-output -n "${CONDA_ENV_NAME:-mes-dashboard}" gunicorn --config gunicorn.conf.py --pid "${WATCHDOG_PID_FILE:-/run/mes-dashboard/gunicorn.pid}" --capture-output "mes_dashboard:create_app()"' KillSignal=SIGTERM TimeoutStopSec=30 Restart=always RestartSec=5 StandardOutput=journal StandardError=journal SyslogIdentifier=mes-dashboard # Memory protection (cgroup v2): prevents OOM from killing entire VM. # MemoryHigh: soft limit — kernel starts reclaiming when exceeded (service stays alive). # MemoryMax: hard limit — OOM kills only this service (host OS survives). # Adjust based on VM RAM: MemoryHigh ≈ 70% of VM RAM, MemoryMax ≈ 85% of VM RAM. # For 7GB VM: MemoryHigh=5G, MemoryMax=6G (leaves ~1GB for OS + Redis). MemoryHigh=5G MemoryMax=6G NoNewPrivileges=yes PrivateTmp=yes ProtectSystem=strict ReadWritePaths=/run/mes-dashboard /var/lib/mes-dashboard /opt/mes-dashboard/logs [Install] WantedBy=multi-user.target