Claude_Homelab/114_koillection_deployment.md

432 lines
11 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 114 — Koillection Deployment Guide
> Status: **IN PROGRESS** — CT created 2026-08-11, base setup + Docker install done, NAS mount pending (Phase 4+)
> CT ID: 114 · IP: 192.168.1.114
> Domain: `collections.spendlik.sk`
> Last updated: 2026-08-11
---
## 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) — created from `13.1-2` (current template at time of creation; `13.6-1` is now the default for new deployments, but this doesn't matter post-creation — see `Proxmox LXC Templates.md`) |
| **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/<service>`). Be consistent.
---
## Phase 1 — Create LXC Container ✅ DONE (2026-08-11)
```bash
pct create 114 local:vztmpl/debian-13-standard_13.1-2_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 ✅ DONE (2026-08-11)
```bash
apt update && apt upgrade -y
apt install -y nano curl ca-certificates gnupg lsb-release
```
---
## Phase 3 — Install Docker ✅ DONE (2026-08-11)
```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
> **Updated 2026-08-10**: All `*.spendlik.sk` subdomains are now **CNAME** records pointing at the root `spendlik.sk`. Only the root `spendlik.sk` A record holds an IP — WebSupport rejects any duplicate IP value elsewhere in the zone. Do **not** create an A record for this subdomain.
In WebSupport admin panel:
1. Add **CNAME** record: `collections``spendlik.sk`
2. Check both DNS management pages
3. Note the numeric record ID
4. Add to `00_index.md` DNS table
> ✅ No DDNS updater step is needed for this subdomain. `ddns-update.sh` on CT 108 only updates the root A record on IP change; this CNAME resolves through automatically.
---
## Phase 9 — 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 10 — 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 11 — 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 |
| DNS record type | Use CNAME → `spendlik.sk`, never a per-subdomain A record (see Phase 8) |
| Wrong template filename | Verify exact template string with `pveam list local` before `pct create` — versions bump periodically |