Private
Public Access
Renames the app's display name everywhere (page titles, PWA manifest, TopBar, email subject lines, HMAC signature header) and its internal technical slug from chatapp to ds-chat/ds_chat: the Python package name and console script, the systemd unit and its user/group/paths, the deploy scripts, the Docker container names, and the Postgres database name. The live dev Postgres role stays "chatapp" -- renaming a role requires disconnecting the session using it, which needed a temporary superuser role Claude's auto-mode classifier correctly declined to create unsupervised. Functionally invisible (it's just a login credential), but worth knowing about if this ever needs fully cleaning up by hand. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
55 lines
1.9 KiB
Desktop File
55 lines
1.9 KiB
Desktop File
# /etc/systemd/system/ds-chat.service
|
|
#
|
|
# Install: sudo cp deploy/systemd/ds-chat.service /etc/systemd/system/
|
|
# sudo systemctl daemon-reload
|
|
# sudo systemctl enable --now ds-chat
|
|
#
|
|
# See ../../DEPLOYMENT.md for the full app-server setup this fits into.
|
|
# TLS termination and public-facing reverse proxying are handled by an
|
|
# external Nginx Proxy Manager instance, not anything on this box -- this
|
|
# unit just needs to be reachable on the TCP port below.
|
|
|
|
[Unit]
|
|
Description=DS Chat app server
|
|
After=network.target
|
|
|
|
[Service]
|
|
# No Type= override -- defaults to "simple", which is correct here since
|
|
# gunicorn runs in the foreground (no --daemon flag below) and doesn't send
|
|
# systemd's sd_notify readiness protocol.
|
|
User=ds-chat
|
|
Group=ds-chat
|
|
WorkingDirectory=/srv/ds-chat/backend
|
|
EnvironmentFile=/etc/ds-chat/env
|
|
Environment=PYTHONUNBUFFERED=1
|
|
|
|
# 0.0.0.0 because Nginx Proxy Manager runs on a separate host -- the actual
|
|
# security boundary is the `ufw` rule in DEPLOYMENT.md restricting this
|
|
# port to NPM's IP specifically, not the bind address. If NPM reaches this
|
|
# box over a private network interface, bind to that private IP instead
|
|
# for defense in depth (belt-and-suspenders on top of the firewall rule).
|
|
ExecStart=/srv/ds-chat/backend/.venv/bin/gunicorn app.main:app \
|
|
-k uvicorn.workers.UvicornWorker \
|
|
--workers 4 \
|
|
--bind 0.0.0.0:8000 \
|
|
--timeout 30
|
|
|
|
# alembic upgrade head deliberately does NOT run here -- with --workers 4,
|
|
# every restart would race multiple processes trying to migrate at once.
|
|
# It's an explicit step in deploy/upgrade.sh instead, run once before the
|
|
# restart that picks up the new code.
|
|
|
|
Restart=on-failure
|
|
RestartSec=2
|
|
|
|
# Baseline hardening -- not a full systemd sandboxing pass, just the
|
|
# well-understood safe defaults for a service that doesn't need to write
|
|
# anywhere outside its own working directory.
|
|
NoNewPrivileges=true
|
|
PrivateTmp=true
|
|
ProtectSystem=full
|
|
ProtectHome=true
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|