# Proxmox Container Deployment Runbook For LLM Operators This document is written for an LLM or automation agent that is deploying Daybook into a Linux container on a Proxmox host. The recommended deployment target is a Proxmox LXC or VM running Debian/Ubuntu with Docker and Docker Compose. Daybook itself runs as a Docker container inside that guest. ## Deployment Model ```text Proxmox host Debian/Ubuntu LXC or VM Docker Engine daybook container /app application code baked into image /data persistent mounted volume ``` Persistent runtime data lives outside the image in `deploy/data` on the guest: ```text deploy/data/ db.sqlite3 artifacts_store/ ``` Do not store runtime data inside the image. ## Files In This Directory | File | Purpose | |---|---| | `Dockerfile` | Builds the Daybook image. | | `docker-compose.yml` | Runs Daybook with a persistent `./data:/data` bind mount. | | `entrypoint.sh` | Runs migrations, collects static files, then starts Gunicorn. | | `env.example` | Template for deployment environment variables. | | `proxmox_llm_deploy.md` | This runbook. | ## Prerequisites On The Proxmox Guest The guest OS should have: - Docker Engine - Docker Compose plugin - Git - Network access to pull Python base images and Python packages For Debian/Ubuntu guests, install basics: ```bash sudo apt-get update sudo apt-get install -y ca-certificates curl git ``` Install Docker using Docker's current official instructions for the guest OS. Then verify: ```bash docker --version docker compose version ``` ## Clone Or Copy The Project Choose a stable application path on the guest: ```bash sudo mkdir -p /opt/daybook sudo chown "$USER:$USER" /opt/daybook ``` If using Git: ```bash git clone /opt/daybook cd /opt/daybook ``` If files were copied by another mechanism, ensure the project root contains: ```text manage.py requirements.txt deploy/docker-compose.yml deploy/Dockerfile ``` ## Create The Environment File From the project root: ```bash cd /opt/daybook cp deploy/env.example deploy/.env ``` Generate secrets: ```bash python3 - <<'PY' import secrets print('DJANGO_SECRET_KEY=' + secrets.token_urlsafe(50)) print('DAYBOOK_API_TOKEN=' + secrets.token_urlsafe(32)) PY ``` Edit `deploy/.env`: ```bash nano deploy/.env ``` Set at minimum: ```text DJANGO_DEBUG=0 DJANGO_SECRET_KEY= DJANGO_ALLOWED_HOSTS=,,localhost,127.0.0.1 DAYBOOK_API_TOKEN= DAYBOOK_DATA_DIR=/data DATABASE_PATH=/data/db.sqlite3 ARTIFACTS_ROOT=/data/artifacts_store ``` Important: - Do not commit `deploy/.env`. - Do not use the development token `dev-token` for a real deployment. - Include the actual IP or DNS name users will use in `DJANGO_ALLOWED_HOSTS`. ## Create Persistent Data Directory From the project root: ```bash mkdir -p deploy/data ``` The compose file mounts this path into the container as `/data`. ## Build And Start From the project root: ```bash docker compose -f deploy/docker-compose.yml up -d --build ``` Watch logs: ```bash docker compose -f deploy/docker-compose.yml logs -f daybook ``` Expected startup behavior: - Django migrations run. - Static files are collected. - Gunicorn starts on port `8000` inside the container. - Host port `8000` maps to container port `8000`. ## Verify Deployment Check container state: ```bash docker compose -f deploy/docker-compose.yml ps ``` Check capabilities endpoint from the guest: ```bash curl -fsS http://127.0.0.1:8000/api/capabilities ``` Expected JSON includes: ```json { "artifact_kinds": ["html_fragment", "html_full", "markdown", "deck", "image", "pdf", "binary"], "auth": "bearer_token" } ``` Open the app from another machine: ```text http://:8000/ ``` If this fails: - Confirm the Proxmox guest firewall allows TCP `8000`. - Confirm any Proxmox firewall rules allow TCP `8000`. - Confirm `DJANGO_ALLOWED_HOSTS` includes the hostname/IP being used. ## Publish A Smoke-Test Artifact Replace `` with `DAYBOOK_API_TOKEN` from `deploy/.env`. ```bash curl -fsS -X POST http://127.0.0.1:8000/api/artifacts \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "persona": "deploy-smoke", "source_type": "agent", "source_name": "Deployment Smoke Agent", "kind": "markdown", "title": "Deployment Smoke Test", "content": "# Deployment Smoke Test\n\nDaybook accepted an artifact.", "tags": ["deploy", "smoke"], "metadata": {"run_id": "deploy-smoke-001"} }' ``` Then refresh: ```text http://:8000/ ``` ## Operational Commands Stop: ```bash docker compose -f deploy/docker-compose.yml down ``` Start: ```bash docker compose -f deploy/docker-compose.yml up -d ``` Rebuild after code changes: ```bash docker compose -f deploy/docker-compose.yml up -d --build ``` View logs: ```bash docker compose -f deploy/docker-compose.yml logs -f daybook ``` Run Django management command: ```bash docker compose -f deploy/docker-compose.yml exec daybook python manage.py check ``` Open shell: ```bash docker compose -f deploy/docker-compose.yml exec daybook sh ``` ## Backup Back up the guest directory: ```text /opt/daybook/deploy/data ``` It contains: - SQLite database - Artifact files Simple backup command: ```bash tar -czf daybook-data-$(date +%Y%m%d-%H%M%S).tar.gz -C /opt/daybook/deploy data ``` For consistent backups during heavy writes, stop the container first: ```bash docker compose -f /opt/daybook/deploy/docker-compose.yml down tar -czf daybook-data-$(date +%Y%m%d-%H%M%S).tar.gz -C /opt/daybook/deploy data docker compose -f /opt/daybook/deploy/docker-compose.yml up -d ``` ## Restore Stop Daybook: ```bash docker compose -f /opt/daybook/deploy/docker-compose.yml down ``` Replace `/opt/daybook/deploy/data` with the restored data directory, then start: ```bash docker compose -f /opt/daybook/deploy/docker-compose.yml up -d ``` ## Updating The App If deployed from Git: ```bash cd /opt/daybook git pull docker compose -f deploy/docker-compose.yml up -d --build ``` The container entrypoint runs migrations on startup. ## Reverse Proxy Notes If putting Daybook behind Nginx, Caddy, Traefik, or a Proxmox-level reverse proxy: - Proxy to `http://:8000`. - Add the public hostname to `DJANGO_ALLOWED_HOSTS`. - Terminate TLS at the proxy. - Keep `DJANGO_DEBUG=0`. Example `DJANGO_ALLOWED_HOSTS`: ```text DJANGO_ALLOWED_HOSTS=daybook.example.com,localhost,127.0.0.1 ``` ## LLM Deployment Checklist Before declaring deployment complete, verify all items: - `deploy/.env` exists and does not use placeholder secrets. - `DJANGO_DEBUG=0`. - `DJANGO_ALLOWED_HOSTS` includes the access hostname/IP. - `deploy/data/` exists. - `docker compose -f deploy/docker-compose.yml ps` shows `daybook` running or healthy. - `curl -fsS http://127.0.0.1:8000/api/capabilities` succeeds on the guest. - Browser opens `http://:8000/`. - Smoke-test artifact POST succeeds with the configured bearer token. - `deploy/data/db.sqlite3` exists after startup. - `deploy/data/artifacts_store/` exists after posting an artifact. ## Known MVP Constraints - SQLite is used by default. This is acceptable for local/self-hosted MVP usage. - The API uses a single shared bearer token. - No reader authentication is implemented yet. - Manual drag/drop upload is deferred. - Content revisions are deferred.