7.3 KiB
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
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:
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:
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:
docker --version
docker compose version
Clone Or Copy The Project
Choose a stable application path on the guest:
sudo mkdir -p /opt/daybook
sudo chown "$USER:$USER" /opt/daybook
If using Git:
git clone <REPO_URL> /opt/daybook
cd /opt/daybook
If files were copied by another mechanism, ensure the project root contains:
manage.py
requirements.txt
deploy/docker-compose.yml
deploy/Dockerfile
Create The Environment File
From the project root:
cd /opt/daybook
cp deploy/env.example deploy/.env
Generate secrets:
python3 - <<'PY'
import secrets
print('DJANGO_SECRET_KEY=' + secrets.token_urlsafe(50))
print('DAYBOOK_API_TOKEN=' + secrets.token_urlsafe(32))
PY
Edit deploy/.env:
nano deploy/.env
Set at minimum:
DJANGO_DEBUG=0
DJANGO_SECRET_KEY=<generated-secret>
DJANGO_ALLOWED_HOSTS=<container-ip>,<dns-name-if-any>,localhost,127.0.0.1
DAYBOOK_API_TOKEN=<generated-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-tokenfor 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:
mkdir -p deploy/data
The compose file mounts this path into the container as /data.
Build And Start
From the project root:
docker compose -f deploy/docker-compose.yml up -d --build
Watch logs:
docker compose -f deploy/docker-compose.yml logs -f daybook
Expected startup behavior:
- Django migrations run.
- Static files are collected.
- Gunicorn starts on port
8000inside the container. - Host port
8000maps to container port8000.
Verify Deployment
Check container state:
docker compose -f deploy/docker-compose.yml ps
Check capabilities endpoint from the guest:
curl -fsS http://127.0.0.1:8000/api/capabilities
Expected JSON includes:
{
"artifact_kinds": ["html_fragment", "html_full", "markdown", "deck", "image", "pdf", "binary"],
"auth": "bearer_token"
}
Open the app from another machine:
http://<guest-ip>:8000/
If this fails:
- Confirm the Proxmox guest firewall allows TCP
8000. - Confirm any Proxmox firewall rules allow TCP
8000. - Confirm
DJANGO_ALLOWED_HOSTSincludes the hostname/IP being used.
Publish A Smoke-Test Artifact
Replace <TOKEN> with DAYBOOK_API_TOKEN from deploy/.env.
curl -fsS -X POST http://127.0.0.1:8000/api/artifacts \
-H "Authorization: Bearer <TOKEN>" \
-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:
http://<guest-ip>:8000/
Operational Commands
Stop:
docker compose -f deploy/docker-compose.yml down
Start:
docker compose -f deploy/docker-compose.yml up -d
Rebuild after code changes:
docker compose -f deploy/docker-compose.yml up -d --build
View logs:
docker compose -f deploy/docker-compose.yml logs -f daybook
Run Django management command:
docker compose -f deploy/docker-compose.yml exec daybook python manage.py check
Open shell:
docker compose -f deploy/docker-compose.yml exec daybook sh
Backup
Back up the guest directory:
/opt/daybook/deploy/data
It contains:
- SQLite database
- Artifact files
Simple backup command:
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:
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:
docker compose -f /opt/daybook/deploy/docker-compose.yml down
Replace /opt/daybook/deploy/data with the restored data directory, then start:
docker compose -f /opt/daybook/deploy/docker-compose.yml up -d
Updating The App
If deployed from Git:
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://<guest-ip>:8000. - Add the public hostname to
DJANGO_ALLOWED_HOSTS. - Terminate TLS at the proxy.
- Keep
DJANGO_DEBUG=0.
Example DJANGO_ALLOWED_HOSTS:
DJANGO_ALLOWED_HOSTS=daybook.example.com,localhost,127.0.0.1
LLM Deployment Checklist
Before declaring deployment complete, verify all items:
deploy/.envexists and does not use placeholder secrets.DJANGO_DEBUG=0.DJANGO_ALLOWED_HOSTSincludes the access hostname/IP.deploy/data/exists.docker compose -f deploy/docker-compose.yml psshowsdaybookrunning or healthy.curl -fsS http://127.0.0.1:8000/api/capabilitiessucceeds on the guest.- Browser opens
http://<guest-ip>:8000/. - Smoke-test artifact POST succeeds with the configured bearer token.
deploy/data/db.sqlite3exists 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.