From 89442b3d109da42f81625c1313a5407a3aeab04b Mon Sep 17 00:00:00 2001 From: Spendlik Date: Fri, 3 Jul 2026 07:46:56 +0000 Subject: [PATCH] Add Koillection deployment guide (CT 114) --- 114_koillection_deployment.md | 433 ++++++++++++++++++++++++++++++++++ 1 file changed, 433 insertions(+) create mode 100644 114_koillection_deployment.md diff --git a/114_koillection_deployment.md b/114_koillection_deployment.md new file mode 100644 index 0000000..5e7293b --- /dev/null +++ b/114_koillection_deployment.md @@ -0,0 +1,433 @@ +# 114 β€” Koillection Deployment Guide + +> Status: **PLANNED** β€” not yet deployed +> CT ID: 114 Β· IP: 192.168.1.114 +> Domain: `collections.spendlik.sk` +> Last updated: 2026-07-03 + +--- + +## Overview + +Koillection is a self-hosted collection manager for tracking physical collections of any kind. No pre-built metadata scrapers β€” metadata is added freely per item, with custom fields via templates. MIT licensed. + +**Collections planned for this instance:** +- πŸš— Hot Wheels (series, year, colour, condition, variants) +- 🧱 LEGO (set number, theme, piece count, minifigures, completion status) +- πŸ¦‡ Batmobiles (source media, scale, manufacturer, condition) +- πŸ“š Comics (title, issue, publisher, language, condition) +- πŸ“„ Paper Models (designer, scale, subject, format β€” physical printed copies) + +Stack: `koillection/koillection` (PHP/Symfony + Vue.js) + PostgreSQL 16. Uploads (item photos) bind-mounted to NAS for data safety. + +--- + +## Resource Allocation + +| Resource | Allocation | +|---|---| +| **CT ID** | 114 | +| **IP** | 192.168.1.114 | +| **CPUs** | 1 | +| **RAM** | 512 MB | +| **Disk** | 8 GB (app + DB only; photos on NAS) | +| **Template** | Debian 13 (trixie) | +| **Privileged** | Yes (Docker requires it) | +| **Nesting** | Enabled (`features: nesting=1`) | + +--- + +## NAS Mount Planning + +Photos uploaded to Koillection land in `/uploads` inside the container. This will be bind-mounted from the NAS at: + +``` +/volume1/proxmox/data/koillection/uploads +``` + +Create this directory on the NAS before deployment: + +```bash +# On the Synology NAS (SSH or File Station) +mkdir -p /volume1/proxmox/data/koillection/uploads +``` + +> ⚠️ The NAS path follows the same convention as Paperless (`/volume1/proxmox/data/`). Be consistent. + +--- + +## Phase 1 β€” Create LXC Container + +In the Proxmox web UI terminal on the host: + +```bash +pct create 114 local:vztmpl/debian-13-standard_13.0-1_amd64.tar.zst \ + --hostname koillection \ + --cores 1 \ + --memory 512 \ + --swap 512 \ + --rootfs local-lvm:8 \ + --net0 name=eth0,bridge=vmbr0,ip=192.168.1.114/24,gw=192.168.1.1 \ + --unprivileged 0 \ + --features nesting=1 \ + --ostype debian \ + --start 1 +``` + +Enter the container: + +```bash +pct enter 114 +``` + +--- + +## Phase 2 β€” Base Setup + +```bash +apt update && apt upgrade -y +apt install -y nano curl ca-certificates gnupg lsb-release +``` + +--- + +## Phase 3 β€” Install Docker + +```bash +install -m 0755 -d /etc/apt/keyrings +curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg +chmod a+r /etc/apt/keyrings/docker.gpg + +echo \ + "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \ + https://download.docker.com/linux/debian \ + $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null + +apt update +apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin +``` + +Verify: + +```bash +docker run --rm hello-world +``` + +--- + +## Phase 4 β€” NAS Bind Mount + +Add the NAS uploads path as a Proxmox bind mount. Exit the container first: + +```bash +exit +``` + +On the Proxmox host: + +```bash +pct set 114 --mp0 /mnt/pve/nas/proxmox/data/koillection/uploads,mp=/uploads +``` + +> ⚠️ Adjust the host-side NAS path to match how the NAS is mounted on the Proxmox host. Verify the mount point with `ls /mnt/pve/` or check `pvesm status` first. If the NAS is not yet mounted at the host level, add it following the same pattern used for CT 111 (Paperless). + +Re-enter the container and verify the mount is visible: + +```bash +pct enter 114 +ls /uploads +``` + +--- + +## Phase 5 β€” Deploy Koillection + +```bash +mkdir -p /opt/koillection +cd /opt/koillection +nano .env +``` + +Paste (fill in a strong password for `DB_PASSWORD`): + +```env +DB_DRIVER=pdo_pgsql +DB_NAME=koillection +DB_HOST=db +DB_PORT=5432 +DB_USER=koillection +DB_PASSWORD=CHANGE_ME +DB_VERSION=16 +APP_ENV=prod +APP_DEBUG=0 +APP_SECRET=CHANGE_ME_32CHAR_RANDOM_STRING +PHP_TZ=Europe/Bratislava +HTTPS_ENABLED=0 +``` + +> Generate `APP_SECRET` with: `openssl rand -hex 16` + +```bash +nano docker-compose.yml +``` + +Paste: + +```yaml +services: + koillection: + image: koillection/koillection:latest + container_name: koillection + restart: unless-stopped + ports: + - "8080:80" + env_file: + - .env + volumes: + - /uploads:/uploads + depends_on: + db: + condition: service_healthy + + db: + image: postgres:16 + container_name: koillection-db + restart: unless-stopped + env_file: + - .env + environment: + - POSTGRES_DB=${DB_NAME} + - POSTGRES_USER=${DB_USER} + - POSTGRES_PASSWORD=${DB_PASSWORD} + volumes: + - ./volumes/postgresql:/var/lib/postgresql/data + healthcheck: + test: ["CMD", "pg_isready", "-q", "-d", "koillection", "-U", "koillection"] + timeout: 45s + interval: 10s + retries: 10 +``` + +Start: + +```bash +docker compose up -d +docker compose logs -f +``` + +Wait until the koillection container logs settle (Symfony app startup). Then verify locally: + +```bash +curl -s http://localhost:8080 | grep -i koillection +``` + +--- + +## Phase 6 β€” nginx Reverse Proxy (CT 101) + +Enter CT 101: + +```bash +pct enter 101 +nano /etc/nginx/sites-available/koillection +``` + +Paste: + +```nginx +server { + listen 80; + server_name collections.spendlik.sk; + + location / { + proxy_pass http://192.168.1.114:8080; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + client_max_body_size 20M; + } +} +``` + +> `client_max_body_size 20M` β€” item photos can be large. Adjust upward if needed. + +Enable and reload: + +```bash +ln -s /etc/nginx/sites-available/koillection /etc/nginx/sites-enabled/ +nginx -t && systemctl reload nginx +``` + +--- + +## Phase 7 β€” SSL Certificate + +Still in CT 101: + +```bash +certbot --nginx -d collections.spendlik.sk +``` + +> ⚠️ Always inspect the config after certbot: + +```bash +cat /etc/nginx/sites-available/koillection +``` + +Check for duplicate `server_name` directives and missing closing braces. Fix manually if needed. + +Also set `HTTPS_ENABLED=1` in `/opt/koillection/.env` in CT 114, then restart: + +```bash +# In CT 114 +cd /opt/koillection +nano .env # set HTTPS_ENABLED=1 +docker compose restart koillection +``` + +--- + +## Phase 8 β€” DNS Record + +In WebSupport admin panel: + +1. Add A record: `collections` β†’ current public IP +2. **Check both DNS management pages** +3. Note the numeric record ID +4. Add to `00_index.md` DNS table + +--- + +## Phase 9 β€” DDNS Updater (CT 108) + +Enter CT 108, add `collections.spendlik.sk` to `/usr/local/bin/ddns-update.sh` using the record ID from Phase 8, following the existing script pattern. + +--- + +## Phase 10 β€” Authelia Protection (CT 102) + +Enter CT 102, edit `/etc/authelia/configuration.yml`. Add to `access_control.rules`: + +```yaml +- domain: collections.spendlik.sk + policy: two_factor +``` + +> Koillection has its own internal login system. Authelia adds a second layer before users even reach the login page. Since this is a personal single-user instance, you may prefer Authelia bypass and rely on Koillection's own login instead β€” your call. + +Restart Authelia after editing: + +```bash +docker compose restart +``` + +Add the Authelia middleware to the nginx vhost in CT 101 (follow the pattern from other protected services). + +--- + +## Phase 11 β€” First Login & Initial Setup + +Open `https://collections.spendlik.sk` from mobile data (hairpin NAT β€” never test from LAN). + +On first load, Koillection will prompt you to create an admin account. Do so, then: + +1. Set your timezone to `Europe/Bratislava` in profile settings +2. Set the display currency if tracking purchase values +3. Set visibility defaults (private by default is fine for a personal instance) + +--- + +## Phase 12 β€” Collection Setup + +Recommended collection structure. Create each as a top-level Collection: + +### πŸš— Hot Wheels +Suggested item fields (via Template): +- Series / Line +- Year of release +- Colour +- Casting name +- Country of manufacture +- Condition (Mint / Good / Played) +- Treasure Hunt (yes/no) + +### 🧱 LEGO +Suggested item fields: +- Set number +- Theme +- Sub-theme +- Piece count +- Minifigure count +- Year +- Completion status (Sealed / Built / Parts only) +- Instruction booklet present (yes/no) + +> πŸ’‘ The set number field makes cross-referencing with kocka-novinky.sk and Brickset API straightforward. + +### πŸ¦‡ Batmobiles +Suggested item fields: +- Source (Film / TV / Comics / Game) +- Year of appearance +- Manufacturer (Hot Wheels / Corgi / LEGO / custom) +- Scale +- Condition + +### πŸ“š Comics +Suggested item fields: +- Title / Series +- Issue number +- Publisher +- Language +- Year +- Condition (Mint / Very Good / Good / Fair) +- Story arc + +### πŸ“„ Paper Models (physical hardcopy) +Suggested item fields: +- Designer / Publisher +- Subject (aircraft, ship, building…) +- Scale +- Format (magazine supplement / standalone / kit) +- Build status (Unbuilt / Built / Display) + +> πŸ’‘ Tags are cross-collection in Koillection β€” tag items with `#display`, `#wishlist`, `#for-sale` etc. to group across all five collections at once. + +--- + +## Backup + +The only things that need backing up: + +1. **PostgreSQL database** β€” contains all collection metadata +2. **NAS uploads directory** β€” contains all item photos (already on NAS, covered by NAS backup) + +Add a daily DB dump to cron in CT 114: + +```bash +crontab -e +``` + +Add: + +```cron +0 3 * * * docker exec koillection-db pg_dump -U koillection koillection > /opt/koillection/backups/koillection-$(date +\%Y\%m\%d).sql 2>/dev/null +``` + +```bash +mkdir -p /opt/koillection/backups +``` + +> ⚠️ Always back up the database before upgrading Koillection β€” the developer notes that data migrations can occasionally have edge cases. + +--- + +## Gotchas + +| Issue | Fix | +|---|---| +| Photos not saving | Verify `/uploads` bind mount is writable inside the container | +| App not starting | Check `docker compose logs koillection` β€” usually a DB connection issue on first boot | +| certbot corrupts nginx config | Always inspect after issuance | +| Large photo uploads rejected | Increase `client_max_body_size` in nginx vhost | +| HTTPS redirect loop | Set `HTTPS_ENABLED=1` in `.env` and restart the koillection container after SSL is in place |