######################################################################## # systemd unit for the QC Recognition ML service (FastAPI + FAISS + torch) # # Install: # sudo cp deploy/qc-ml.service /etc/systemd/system/qc-ml.service # # edit User/paths below to match your account, then: # sudo systemctl daemon-reload # sudo systemctl enable --now qc-ml # sudo systemctl status qc-ml # # The service binds ONLY to 127.0.0.1:8001 — it is never reachable from the # internet. The PHP admin panel on the same box calls it over loopback and # authenticates with ML_SERVICE_TOKEN (read from the app's own .env). ######################################################################## [Unit] Description=QC Recognition ML service (FastAPI/FAISS/torch) After=network-online.target Wants=network-online.target [Service] Type=simple # --- change these three to match your cPanel account --------------------- User=qcuser Group=qcuser WorkingDirectory=/home/qcuser/qc-ml # ------------------------------------------------------------------------ # torchvision caches the ~100MB resnet50 weights here on first start. # Must be writable by User above. Keeps it out of a locked-down HOME. Environment=TORCH_HOME=/home/qcuser/qc-ml/.torch Environment=HOME=/home/qcuser # Keep CPU thread count sane on shared cores (avoids torch grabbing every core). Environment=OMP_NUM_THREADS=2 # app.main:app reads HOST/PORT/TOKEN/DATA_DIR from ./.env via pydantic-settings. # One worker only: the torch model is a per-process singleton — extra workers # just multiply RAM with no throughput gain (inference is serialised by a lock). ExecStart=/home/qcuser/qc-ml/.venv/bin/uvicorn app.main:app --host 127.0.0.1 --port 8001 --workers 1 Restart=always RestartSec=3 # torch import + model load is slow; don't let systemd kill a healthy startup. TimeoutStartSec=180 # Light hardening (service holds no secrets beyond the shared token). NoNewPrivileges=true ProtectSystem=full PrivateTmp=true [Install] WantedBy=multi-user.target