diff --git a/Makefile b/Makefile index f1f1c727..3114b9e6 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,14 @@ SERVICE_HOME ?= /opt/danbyte # Where the app writes danbyte.log + gunicorn logs (settings.LOGGING reads # DANBYTE_LOG_DIR from .env; systemd still mirrors process output to journald). LOG_DIR ?= /var/log/danbyte -SERVICES := danbyte-mockups danbyte-infra danbyte-backend danbyte-workers danbyte-docs +# Dev-only units. `danbyte-infra` runs Postgres + Redis in docker compose for a +# workstation; a production install provisions them natively (scripts/install.sh +# creates the role/database with psql), so these must NEVER be linked there — +# doing so left an idle, empty Postgres container on hosts that already had one. +DEV_SERVICES := danbyte-mockups danbyte-infra danbyte-backend +# Units both dev and production run. +SHARED_SERVICES := danbyte-workers danbyte-docs +SERVICES := $(DEV_SERVICES) $(SHARED_SERVICES) # Timer-driven oneshots (monitoring beat). Each has a .service + a .timer; the # timer is what gets enabled. Not part of `up`/`down` (they're not long-running). TIMERS := danbyte-dispatch danbyte-materialise danbyte-prune danbyte-utilization danbyte-alert-maintenance danbyte-discover danbyte-cleanup danbyte-drift-dispatch danbyte-auto-upgrade danbyte-drive-outposts danbyte-digest @@ -298,7 +305,9 @@ collectstatic: # make install-prod-services # systemctl --user stop danbyte-backend danbyte-frontend # the dev units # systemctl --user enable --now danbyte-web danbyte-ws danbyte-frontend-prod -PROD_SERVICES := danbyte-web danbyte-ws danbyte-frontend-prod +# Everything a production host runs — web/ws/frontend plus the shared units. +# scripts/install.sh links ONLY these; it must not pull in DEV_SERVICES. +PROD_SERVICES := danbyte-web danbyte-ws danbyte-frontend-prod $(SHARED_SERVICES) install-prod-services: @mkdir -p $(SYSTEMD_DIR) @@ -306,7 +315,14 @@ install-prod-services: ln -sfn $(PROJECT_DIR)/services/$$s.service $(SYSTEMD_DIR)/$$s.service ; \ echo " linked $$s.service" ; \ done + @for s in $(TIMERS); do \ + ln -sfn $(PROJECT_DIR)/services/$$s.service $(SYSTEMD_DIR)/$$s.service ; \ + ln -sfn $(PROJECT_DIR)/services/$$s.timer $(SYSTEMD_DIR)/$$s.timer ; \ + done @systemctl --user daemon-reload + @for s in $(TIMERS); do \ + systemctl --user enable --now $$s.timer >/dev/null 2>&1 || true ; \ + done @echo "Linked. Build the frontend + collect static, then enable:" @echo " make frontend-build collectstatic" @echo " systemctl --user enable --now $(PROD_SERVICES)" diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md index d9c756c6..6f2ff9eb 100644 --- a/docs/getting-started/installation.md +++ b/docs/getting-started/installation.md @@ -104,7 +104,29 @@ The other tabs cover building from source and a local dev checkout. 3. Deploys the app to `/danbyte` and builds the venv from the bundle's vendored CPython 3.13 + wheelhouse (no internet needed). 4. **Generates secrets** with Python's CSPRNG and writes a `chmod 600`, service-user-owned `.env` — `DJANGO_SECRET_KEY` + `MONITORING_SECRET_KEY` (~400-bit), a 24-char DB password, and a 20-char admin password. 5. Creates the PostgreSQL role + database, runs migrations, and bootstraps the `admin` superuser. - 6. Installs the systemd units (web, workers, websocket, timers), writes logs to `/var/log/danbyte`, and — unless `--no-nginx` — puts nginx + TLS in front. + 6. Installs the systemd units (web, workers, websocket, docs, timers), writes logs to `/var/log/danbyte`, and — unless `--no-nginx` — puts nginx + TLS in front. + 7. Prints the generated **admin password** at the end. + + !!! note "PostgreSQL and Redis are native, not containers" + + A production install uses the distro's `postgresql` and + `redis-server` and creates the role and database with `psql`. The + `docker-compose.yml` in the repo and the `danbyte-infra` unit that + runs it are **development only** — they are never installed on a + production host. If you already run PostgreSQL, the installer uses + it: point `DB_HOST` / `DB_PORT` / `DB_NAME` / `DB_USER` / + `DB_PASSWORD` in `.env` at your server and re-run + `manage.py migrate`. + + Installs made before this was fixed may have a stray + `danbyte-infra` unit and an unused Postgres container. Remove them + with: + + ```bash + sudo -u danbyte systemctl --user disable --now danbyte-infra + rm -f ~danbyte/.config/systemd/user/danbyte-infra.service + ``` + 7. Prints the generated **admin password** at the end. **Where things land** diff --git a/scripts/install.sh b/scripts/install.sh index 7f7f9102..683311ff 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -254,7 +254,11 @@ as_user bash -lc "cd '$APP' && .venv/bin/python manage.py migrate --noinput \ # ── 9. systemd units ───────────────────────────────────────────────────────── step "Installing + (re)starting services" -as_user bash -lc "cd '$APP' && make install-services install-prod-services >/dev/null" +# ONLY the production unit set. This used to also run `install-services`, which +# links the dev units — including danbyte-infra, the docker-compose Postgres + +# Redis stack. On a host that already ran Postgres that left an idle, empty +# container competing for 5432 (issue #14). +as_user bash -lc "cd '$APP' && make install-prod-services >/dev/null" DANBYTE_UNITS="danbyte-web danbyte-ws danbyte-frontend-prod danbyte-workers danbyte-docs" # enable = start at boot; restart = pick up freshly-deployed code (a plain # `enable --now` is a no-op on already-running units, so a re-install/upgrade diff --git a/services/danbyte-web.service b/services/danbyte-web.service index 8f3fb4f2..2e145328 100644 --- a/services/danbyte-web.service +++ b/services/danbyte-web.service @@ -4,7 +4,6 @@ # WebSockets are served by danbyte-ws (daphne), not here. Description=Danbyte web (gunicorn WSGI, 127.0.0.1:8000) After=network.target -Wants=danbyte-infra.service StartLimitIntervalSec=0 [Service] diff --git a/services/danbyte-workers.service b/services/danbyte-workers.service index 9a1277aa..9100cec8 100644 --- a/services/danbyte-workers.service +++ b/services/danbyte-workers.service @@ -1,7 +1,6 @@ [Unit] Description=Danbyte RQ worker pool (default, high, low queues) After=network.target -Wants=danbyte-infra.service [Service] Type=simple