# Deploy and update First deploy, updates, environment, and rollback for the production stack. See also [Production overview](/docs/production.html) and [nginx and networking](/docs/production-nginx.html). ## Prerequisites - Docker with the Compose plugin. - The repository checked out on the **same host** that runs (or will run) the development server, so they share one database. ## Environment Configuration is a single `.env` file in the project root (git-ignored), loaded both by Compose (`env_file`) and by the app at startup (`python-dotenv`). Copy the committed template and edit it: ```bash cp .env.example .env ``` | Variable | Default | Purpose | |----------|---------|---------| | `SECRET_KEY` | insecure placeholder | Session signing. **Change this.** | | `DEVPLACE_DATABASE_URL` | unset | Leave unset to share the project-root `devplace.db`. Set only to point elsewhere. | | `DEVPLACE_SITE_URL` | empty | Public origin for absolute URLs (SEO, canonical, push). Empty derives from the request. | | `PORT` | `10500` | Host port the nginx front door binds. | | `NGINX_MAX_BODY_SIZE` | `50m` | nginx upload ceiling. Must be >= `max_upload_size_mb`. | | `NGINX_CACHE_ENABLED` | `false` | Enable the nginx micro-cache for proxied GETs. | | `NGINX_CACHE_MAX_SIZE` | `1g` | Cache size cap when enabled. | | `DEVPLACE_UID` / `DEVPLACE_GID` | `1000` | Host user the app container runs as, so shared files keep dev ownership. Match `id -u` / `id -g`. | Operational behavior (rate limits, registration, maintenance mode, upload size, news cadence) is tuned live from **Admin -> Settings** and stored in `site_settings`; it needs no redeploy. ## First deploy ```bash cp .env.example .env # set SECRET_KEY, PORT, DEVPLACE_SITE_URL make docker-build # build the image (installs the docker CLI) make docker-up # start (creates ./var, mounts the socket) ``` Open `http://:`. Useful targets: `make docker-logs` (tail), `make docker-down` (stop), `make docker-clean` (down). The make targets always apply the `docker-compose.containers.yml` overlay, so the admin-only Container Manager works with no extra setup. Always update through the make targets - a plain `docker compose up -d` drops the overlay and silently removes the docker socket and CLI the manager needs. ## Updating Code is bind-mounted, so most updates need no rebuild: ```bash git pull make docker-up # restart workers on the new code ``` Rebuild the image only when dependencies change: ```bash make docker-build && make docker-up ``` ## Release branch `make deploy` fast-forwards the release branch: ```bash git checkout production && git merge master && git push origin production ``` On the server, pull `production` and run the update steps above. CI (`.gitea/workflows/test.yaml`) runs the full test suite on every push/PR to `master`, so only tested commits reach `production`. ## Rollback Because the container runs host source, rolling back is a git operation: ```bash git checkout make docker-up ``` Back up `devplace.db` (and its `-wal`/`-shm`) before a risky change; the schema auto-syncs forward but is not auto-downgraded. ## Bare-metal alternative `make prod` runs the same app without containers (`uvicorn ... --workers 2 --proxy-headers`) from the project root, sharing the identical database and files. It binds port 10500 directly, so it conflicts with the Docker front door on the same port - run one or the other, or set a different `PORT`. Keep `DEVPLACE_WEB_WORKERS` in lockstep with `--workers`; see [Multi-worker and concurrency](/docs/production-concurrency.html) for why.