Add generic deployment docs and fix stale references
Adds docs/deployment.md, a platform-agnostic guide (any Linux host with Docker) built around a git-pull based fast-redeploy workflow, replacing the Proxmox-specific deploy/proxmox_llm_deploy.md which was also stale (old `persona` field, single-shared-token model predating multi-user auth). Also: drops the unused DAYBOOK_API_TOKEN from deploy/env.example, documents the new DELETE endpoint and capabilities `methods` field in docs/api.md and docs/agent_quickstart.md, and fixes CLAUDE.md's OpenCode note now that opencode.json is untracked (machine-specific MCP config). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
940a703cd7
commit
4a5ea8944b
6 changed files with 223 additions and 352 deletions
|
|
@ -72,4 +72,4 @@ The core product principle is: agents publish content, not files. The server own
|
||||||
|
|
||||||
## Claude Code / OpenCode
|
## Claude Code / OpenCode
|
||||||
|
|
||||||
This project uses `CLAUDE.md` for project instructions, compatible with both Claude Code and OpenCode. The `opencode.json` configuration file loads this file. After changing `opencode.json`, `.opencode/`, or this file, restart your AI coding assistant so the updated instructions are loaded.
|
This project uses `CLAUDE.md` for project instructions, compatible with both Claude Code and OpenCode. OpenCode is configured to load this file via a local, untracked `opencode.json` (it contains machine-specific MCP config, so it is not committed — recreate it locally with `{"$schema": "https://opencode.ai/config.json", "instructions": ["CLAUDE.md"], "permission": "allow"}` plus whatever MCP servers you want). After changing `opencode.json`, `.opencode/`, or this file, restart your AI coding assistant so the updated instructions are loaded.
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
DJANGO_DEBUG=0
|
DJANGO_DEBUG=0
|
||||||
DJANGO_SECRET_KEY=replace-with-a-long-random-secret
|
DJANGO_SECRET_KEY=replace-with-a-long-random-secret
|
||||||
DJANGO_ALLOWED_HOSTS=localhost,127.0.0.1,your-proxmox-container-ip,your-domain.example
|
DJANGO_ALLOWED_HOSTS=localhost,127.0.0.1,your-vm-ip,your-domain.example
|
||||||
DAYBOOK_API_TOKEN=replace-with-a-long-random-token
|
|
||||||
DAYBOOK_DATA_DIR=/data
|
DAYBOOK_DATA_DIR=/data
|
||||||
DATABASE_PATH=/data/db.sqlite3
|
DATABASE_PATH=/data/db.sqlite3
|
||||||
ARTIFACTS_ROOT=/data/artifacts_store
|
ARTIFACTS_ROOT=/data/artifacts_store
|
||||||
|
|
|
||||||
|
|
@ -1,348 +0,0 @@
|
||||||
# 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 <REPO_URL> /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=<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-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://<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_HOSTS` includes the hostname/IP being used.
|
|
||||||
|
|
||||||
## Publish A Smoke-Test Artifact
|
|
||||||
|
|
||||||
Replace `<TOKEN>` with `DAYBOOK_API_TOKEN` from `deploy/.env`.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
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:
|
|
||||||
|
|
||||||
```text
|
|
||||||
http://<guest-ip>: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://<guest-ip>: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://<guest-ip>: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.
|
|
||||||
|
|
@ -124,6 +124,17 @@ Invoke-RestMethod `
|
||||||
-Body $body
|
-Body $body
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 8. Delete An Artifact
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Invoke-RestMethod `
|
||||||
|
-Uri "http://127.0.0.1:8001/api/artifacts/$($artifact.id)" `
|
||||||
|
-Method Delete `
|
||||||
|
-Headers @{ Authorization = "Bearer <your-personal-token>" }
|
||||||
|
```
|
||||||
|
|
||||||
|
Deletes the artifact's database row and its files. You can only delete artifacts your own token owns.
|
||||||
|
|
||||||
## Agent Payload Checklist
|
## Agent Payload Checklist
|
||||||
|
|
||||||
Recommended fields for every agent post:
|
Recommended fields for every agent post:
|
||||||
|
|
|
||||||
27
docs/api.md
27
docs/api.md
|
|
@ -333,6 +333,26 @@ Editable fields:
|
||||||
|
|
||||||
You can only PATCH artifacts your own token owns; others return `404`.
|
You can only PATCH artifacts your own token owns; others return `404`.
|
||||||
|
|
||||||
|
## Delete Artifact
|
||||||
|
|
||||||
|
Endpoint:
|
||||||
|
|
||||||
|
```http
|
||||||
|
DELETE /api/artifacts/{id}
|
||||||
|
Authorization: Bearer <your-personal-token>
|
||||||
|
```
|
||||||
|
|
||||||
|
Removes the artifact's database row and its files (primary file, markdown
|
||||||
|
sidecar, and any attached assets). Returns `204` with no body on success.
|
||||||
|
|
||||||
|
You can only delete artifacts your own token owns; others return `404`, as
|
||||||
|
does a second delete of the same id.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X DELETE "http://127.0.0.1:8001/api/artifacts/a1b2c3d4" \
|
||||||
|
-H "Authorization: Bearer <your-personal-token>"
|
||||||
|
```
|
||||||
|
|
||||||
Not editable yet:
|
Not editable yet:
|
||||||
|
|
||||||
| Field | Reason |
|
| Field | Reason |
|
||||||
|
|
@ -403,7 +423,12 @@ Example response:
|
||||||
"views": ["rendered", "raw"],
|
"views": ["rendered", "raw"],
|
||||||
"raw_supported_for": ["markdown", "html_full"],
|
"raw_supported_for": ["markdown", "html_full"],
|
||||||
"source_types": ["agent", "person", "system"],
|
"source_types": ["agent", "person", "system"],
|
||||||
"auth": "bearer_token"
|
"auth": "bearer_token",
|
||||||
|
"methods": {
|
||||||
|
"/api/artifacts": ["GET", "POST"],
|
||||||
|
"/api/artifacts/{id}": ["GET", "PATCH", "DELETE"],
|
||||||
|
"/api/assets": ["POST"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
184
docs/deployment.md
Normal file
184
docs/deployment.md
Normal file
|
|
@ -0,0 +1,184 @@
|
||||||
|
# Deployment
|
||||||
|
|
||||||
|
Daybook deploys the same way on any Linux host with Docker: a cloud VM, a home
|
||||||
|
server, a Proxmox guest, whatever. It runs as a single Docker container
|
||||||
|
(Gunicorn) with all persistent state — the SQLite database and artifact files —
|
||||||
|
on a bind-mounted `./data` directory outside the image.
|
||||||
|
|
||||||
|
```text
|
||||||
|
Target host (cloud VM, home server, ...)
|
||||||
|
Docker Engine
|
||||||
|
daybook container
|
||||||
|
/app application code baked into the image
|
||||||
|
/data persistent volume: db.sqlite3, artifacts_store/
|
||||||
|
```
|
||||||
|
|
||||||
|
## Files In `deploy/`
|
||||||
|
|
||||||
|
| 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. |
|
||||||
|
|
||||||
|
## Prerequisites On The Target Host
|
||||||
|
|
||||||
|
- Docker Engine + the Docker Compose plugin
|
||||||
|
- Git (for the clone-and-pull workflow below)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker --version
|
||||||
|
docker compose version
|
||||||
|
```
|
||||||
|
|
||||||
|
## First-Time Setup
|
||||||
|
|
||||||
|
Clone the repo onto the host at a stable path:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone <REPO_URL> /opt/daybook
|
||||||
|
cd /opt/daybook
|
||||||
|
```
|
||||||
|
|
||||||
|
Create the environment file:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp deploy/env.example deploy/.env
|
||||||
|
```
|
||||||
|
|
||||||
|
Generate a secret key:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 -c "import secrets; print('DJANGO_SECRET_KEY=' + secrets.token_urlsafe(50))"
|
||||||
|
```
|
||||||
|
|
||||||
|
Edit `deploy/.env` and set at minimum:
|
||||||
|
|
||||||
|
```text
|
||||||
|
DJANGO_DEBUG=0
|
||||||
|
DJANGO_SECRET_KEY=<generated-secret>
|
||||||
|
DJANGO_ALLOWED_HOSTS=<vm-ip-or-dns-name>,localhost,127.0.0.1
|
||||||
|
DAYBOOK_DATA_DIR=/data
|
||||||
|
DATABASE_PATH=/data/db.sqlite3
|
||||||
|
ARTIFACTS_ROOT=/data/artifacts_store
|
||||||
|
```
|
||||||
|
|
||||||
|
There is no shared API token to configure — Daybook uses per-user tokens
|
||||||
|
(DRF `Token` model) issued from Settings → Account once a user exists. Do not
|
||||||
|
commit `deploy/.env`.
|
||||||
|
|
||||||
|
Create the persistent data directory and bring the stack up:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p deploy/data
|
||||||
|
docker compose -f deploy/docker-compose.yml up -d --build
|
||||||
|
```
|
||||||
|
|
||||||
|
Create your first login (superuser) so you have something to log in with and
|
||||||
|
a personal API token to post through:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose -f deploy/docker-compose.yml exec daybook python manage.py createsuperuser
|
||||||
|
```
|
||||||
|
|
||||||
|
## Verify Deployment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose -f deploy/docker-compose.yml ps
|
||||||
|
curl -fsS http://127.0.0.1:8000/api/capabilities
|
||||||
|
```
|
||||||
|
|
||||||
|
An unauthenticated capabilities check returns 403 (login/token required) —
|
||||||
|
that's expected; it confirms the app is up and enforcing auth. Open
|
||||||
|
`http://<vm-ip>:8000/` in a browser and log in with the superuser you just
|
||||||
|
created, then grab a personal token from Settings → Account and use it for a
|
||||||
|
smoke-test post:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsS -X POST http://127.0.0.1:8000/api/artifacts \
|
||||||
|
-H "Authorization: Bearer <your-personal-token>" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"source": "deploy-smoke",
|
||||||
|
"kind": "markdown",
|
||||||
|
"title": "Deployment Smoke Test",
|
||||||
|
"content": "# Deployment Smoke Test\n\nDaybook accepted an artifact."
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Fast Redeploys
|
||||||
|
|
||||||
|
Once the host has a git clone, shipping a new version is two commands:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /opt/daybook
|
||||||
|
git pull
|
||||||
|
docker compose -f deploy/docker-compose.yml up -d --build
|
||||||
|
```
|
||||||
|
|
||||||
|
The entrypoint runs Django migrations on every start, so schema changes are
|
||||||
|
picked up automatically. `deploy/.env` and `deploy/data/` are untouched by
|
||||||
|
`git pull` since they aren't tracked in the repo.
|
||||||
|
|
||||||
|
## Operational Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose -f deploy/docker-compose.yml logs -f daybook
|
||||||
|
docker compose -f deploy/docker-compose.yml restart daybook
|
||||||
|
docker compose -f deploy/docker-compose.yml down
|
||||||
|
docker compose -f deploy/docker-compose.yml up -d
|
||||||
|
docker compose -f deploy/docker-compose.yml exec daybook python manage.py check
|
||||||
|
docker compose -f deploy/docker-compose.yml exec daybook sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Backup And Restore
|
||||||
|
|
||||||
|
Back up `deploy/data/` — it contains the SQLite database and all artifact
|
||||||
|
files:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
tar -czf daybook-data-$(date +%Y%m%d-%H%M%S).tar.gz -C /opt/daybook/deploy data
|
||||||
|
```
|
||||||
|
|
||||||
|
For a consistent snapshot during heavy writes, stop the container first:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose -f 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 deploy/docker-compose.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
To restore: stop Daybook, replace `deploy/data/` with the backup contents,
|
||||||
|
then start it again.
|
||||||
|
|
||||||
|
## Reverse Proxy Notes
|
||||||
|
|
||||||
|
If putting Daybook behind Nginx, Caddy, Traefik, or a cloud load balancer:
|
||||||
|
|
||||||
|
- Proxy to `http://<vm-ip>:8000`.
|
||||||
|
- Add the public hostname to `DJANGO_ALLOWED_HOSTS`.
|
||||||
|
- Terminate TLS at the proxy; keep `DJANGO_DEBUG=0`.
|
||||||
|
|
||||||
|
```text
|
||||||
|
DJANGO_ALLOWED_HOSTS=daybook.example.com,localhost,127.0.0.1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Deployment Checklist
|
||||||
|
|
||||||
|
- `deploy/.env` exists with a real (non-placeholder) `DJANGO_SECRET_KEY`.
|
||||||
|
- `DJANGO_DEBUG=0`.
|
||||||
|
- `DJANGO_ALLOWED_HOSTS` includes the hostname/IP being used.
|
||||||
|
- `deploy/data/` exists and persists across `git pull` + rebuild.
|
||||||
|
- `docker compose -f deploy/docker-compose.yml ps` shows `daybook` healthy.
|
||||||
|
- `curl -fsS http://127.0.0.1:8000/api/capabilities` returns 403 without auth,
|
||||||
|
200 with a valid token or session.
|
||||||
|
- At least one superuser exists (`manage.py createsuperuser`) with a token
|
||||||
|
from Settings → Account.
|
||||||
|
|
||||||
|
## Known MVP Constraints
|
||||||
|
|
||||||
|
- SQLite is used by default — fine for a single-VM self-hosted deployment.
|
||||||
|
- Per-user ingest tokens; no shared/global token.
|
||||||
|
- Reader/browser access requires login; feeds are private per user.
|
||||||
|
- Manual drag/drop upload and content revisions are deferred.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue