# Unraid-deployment Deze handleiding gebruikt `docker-compose.unraid.yml` als declaratieve bron van waarheid. De Unraid-variant bundelt web, worker, scheduler, PostgreSQL en Redis bewust in één Dockerman-container met Supervisor als procesbewaker. De gewone `docker-compose.yml` behoudt de gescheiden productieprocessen voor andere hosts. ## Vooraf Maak deze directories: ```text /mnt/user/appdata/vacatureradar/config /mnt/user/appdata/vacatureradar/media /mnt/user/appdata/vacatureradar/logs /mnt/user/appdata/vacatureradar/source/local/postgres-aio17 /mnt/user/appdata/vacatureradar/source/local/redis-aio /mnt/user/appdata/vacatureradar/ollama # alleen bij lokale AI /mnt/user/backups/vacatureradar ``` Gebruik bij voorkeur een cache-backed `appdata`-share en neem die afzonderlijk in je back-upregime op. De PostgreSQL-datadir mag niet gelijktijdig door file-syncsoftware worden gemuteerd. ## Dockerman De container verschijnt als **VacatureRadar** en bevat metadata voor: - WebUI: `http://[IP]:1226/`; - icoon: het lokale 256×256 VacatureRadar-PNG op `/static/img/vacatureradar-docker.png`; - één herstart- en healthcheckpunt voor alle interne processen. Dockerman haalt het tegelicoon via de gepubliceerde webpoort op en cachet het. De PNG is daarom een afzonderlijke rasterasset met een stabiel pad; de SVG-favicon blijft voor browsers behouden. Het icoonlabel gebruikt bewust de concrete server-side URL `http://127.0.0.1:1226/...`: Dockerman vervangt `[IP]` en `[PORT:...]` alleen voor de WebUI, niet voordat het een icoon downloadt. Na een upgrade waarbij het oude icoon nog zichtbaar is, herlaad de Docker-pagina zodat Dockerman de lokale cache opbouwt. ## Imagekeuze De Unraid-compose bouwt lokaal met `Dockerfile.unraid` en tagt de image als `vacatureradar:unraid`. Pin voor reproduceerbare releases aanvullend een commitgebonden tag. 1. bouw lokaal op de Unraid-host en vervang `image:` door een vaste lokale tag; 2. publiceer vanuit CI naar een private registry en pin op een immutable digest; 3. gebruik `build:`, mits de gekozen Compose-plugin builds betrouwbaar ondersteunt. Gebruik in productie geen zwevende `latest` zonder gecontroleerd rollbackpad. ## Configuratiebestand Kopieer of genereer `.env` naar: De deploy-helper `scripts/deploy_docker.sh` vult ontbrekende sleutels op basis van veilige defaults. Zet voor publieke productie vooraf de gewenste variabelen: ```text /mnt/user/appdata/vacatureradar/config/.env APP_HOST=jobs.example.be APP_SCHEME=https DJANGO_DEBUG=0 SESSION_COOKIE_SECURE=1 CSRF_COOKIE_SECURE=1 SECURE_SSL_REDIRECT=1 ``` Gebruik daarna de helper (zie hieronder). Beperk de bestandsrechten van `.env` tot de beheerder. Voeg geen secrets toe aan de ZIP, Git, screenshots of supportlogs. ## Eerste uitrol 1. Controleer alle `CHANGE_ME`-waarden. 2. Gebruik de deploy-helper voor een snelle eerste start: ```bash cd /app/VacatureRadar APP_HOST=jobs.example.be APP_SCHEME=https DJANGO_DEBUG=0 \ SESSION_COOKIE_SECURE=1 CSRF_COOKIE_SECURE=1 SECURE_SSL_REDIRECT=1 \ bash scripts/deploy_docker.sh ``` 3. Start de ene appcontainer; de entrypoint initialiseert PostgreSQL, voert migraties uit en start daarna alle processen onder Supervisor. 6. Controleer `GET /health/live/` en `GET /health/ready/`. 6. Voer eenmalig in de webcontainer uit: ```bash python manage.py bootstrap_instance python manage.py collectstatic --noinput ``` 7. Meld lokaal aan en wijzig het bootstrapwachtwoord. 8. Activeer nog geen live bron of mailbox voordat bronbeleid, retentie en back-up zijn gecontroleerd. ## Beheerverbinding en heruitrol Gebruik vanaf een beheerwerkstation altijd een benoemde SSH-hostalias met een afzonderlijke deploysleutel. Een rechtstreekse verbinding naar het IP-adres kan de lokale standaardgebruiker en standaardsleutel kiezen en daardoor ten onrechte als een server-side authenticatiefout lijken. ```sshconfig Host unraid-itworx HostName 192.168.10.150 Port 22 User root IdentityFile ~/.ssh/itworx_unraid_deploy IdentitiesOnly yes ``` Controleer de verbinding zonder wachtwoordprompt en voer daarna de beveiligde synchronisatie, imagebuild, containervervanging en health-smoke uit: ```bash ssh -o BatchMode=yes unraid-itworx 'id -un && docker info >/dev/null' bash scripts/deploy_unraid.sh ``` `deploy_unraid.sh` weigert een IP-adres, niet-rootprofiel of generieke standaardsleutel. Alleen door Git gekende of niet-genegeerde projectbestanden worden verpakt; `.env`, `local/`, databasebestanden en andere genegeerde runtimegegevens worden niet verzonden. De helper wacht op Docker-health en controleert `/health/ready/` voordat hij succes meldt. Een afwijkende veilige alias kan expliciet via `UNRAID_SSH_HOST` worden ingesteld. ## Releaseverificatie en upgradepad VR-117 voegt `./scripts/release_verify.sh` toe als release-check met artifacts voor package, checksum, configdiff, sbom en upgrade/rollback. Het script bewaart: - `release-artifacts//artifacts/release-smoke.json` - `release-artifacts//artifacts/smoke-restored-validate.json` - `release-artifacts//artifacts/upgrade-rollback.md` - `release-artifacts//artifacts/checksums.txt` - `release-artifacts//artifacts/config-diff.txt` De restorecontrole vergelijkt primaire en gerestoreerde modelcounts in beide smoke-rapporten. ## Reverse proxy en TLS Expose de applicatie niet rechtstreeks op internet. Plaats Nginx Proxy Manager, Traefik, Caddy of een gelijkwaardig beheerd reverse-proxyprofiel voor poort 1226. Vereisten: - geldig TLS-certificaat; - alleen HTTPS extern; - `X-Forwarded-Proto` correct doorgeven; - request-bodylimiet klein houden; er is geen algemene upload-API; - optioneel extra access control/VPN voor persoonlijke installatie; - geen publieke toegang tot PostgreSQL, Redis of Ollama. Wanneer een proxy op hetzelfde Docker-netwerk draait, publiceer poort 1226 alleen intern. Wanneer Unraid routing een hostpoort vereist, beperk die via firewall/VLAN tot de proxy of het beheernetwerk. ## Mailbox Gebruik per vacatureplatform een aparte mailbox of alias, niet de hoofdmailbox. Genereer eerst buiten Git een Fernet-sleutel: ```bash python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())" ``` Plaats de uitvoer uitsluitend in de Unraid-secretconfiguratie: ```dotenv MAILBOX_CREDENTIAL_KEYS= IMAP_CONNECT_TIMEOUT_SECONDS=15 IMAP_MAX_MESSAGES_PER_POLL=200 IMAP_MAX_MESSAGE_BYTES=1000000 ``` Herstart web, worker en scheduler. Open daarna **Bronnen → Platformmailboxen** en koppel ieder gewenst platform afzonderlijk: VDAB, Indeed, LinkedIn, ictjob.be, Jobat, StepStone, Careerjet, Randstad of Robert Half. Kies Gmail, Outlook / Microsoft 365 of een aangepaste publieke IMAP-host, gebruik een app-wachtwoord en laat `INBOX` geselecteerd tenzij de alert naar een aparte map wordt gefilterd. De scheduler controleert iedere vijf minuten welke mailbox volgens haar eigen interval verschuldigd is. Voor sleutelrotatie zet je `nieuwe-sleutel,oude-sleutel` in `MAILBOX_CREDENTIAL_KEYS`, herstart je de processen en draai je: ```bash python manage.py rotate_mailbox_credentials ``` Verwijder de oude sleutel pas na een geslaagde sync. Een rollback van migratie `0005` verwijdert de mailboxkoppelingen; maak daarom eerst een versleutelde databaseback-up en pauzeer de scheduler. ## Ollama Ollama is optioneel. Start de composeprofile pas wanneer de deterministische kern goed werkt: ```bash docker compose -f docker-compose.unraid.yml --profile ai up -d ``` Pin een modelnaam in `OLLAMA_MODEL`; zonder model blijft `OLLAMA_ENABLED=0`. Stel Ollama niet extern bloot. Modeloutput wordt als onbetrouwbare gestructureerde data behandeld en mag geen harde regel of sollicitatieactie uitvoeren. ## Upgraden 1. Maak en verifieer een database- en configuratieback-up. 2. Lees `CHANGELOG.md` en de releaseartefacten. 3. Als de release nog niet geverifieerd is, voer `./scripts/release_verify.sh` lokaal uit. 4. Pull/bouw de nieuwe immutable image. 5. Stop de appcontainer. 6. Start de nieuwe appcontainer en laat de entrypoint migraties uitvoeren. 7. Controleer health, login en release-smoke-rapport. 8. Controleer in de containerlogs dat web, worker en scheduler actief zijn. 9. Bewaar de vorige image/digest totdat één volledige schedulercyclus goed verliep. ## Rollback Bij een codefout zonder incompatibele migratie: pin de vorige image en herstart web/worker/scheduler. Bij een incompatibele datamigratie: stop alle schrijvers, herstel de vooraf gemaakte databaseback-up en gebruik de overeenkomende vorige image. Voer nooit een restore uit terwijl de worker of scheduler schrijft. ## Productiechecklist - [ ] alle `CHANGE_ME`-waarden verwijderd; - [ ] debug uit en secure cookies aan; - [ ] TLS en host/origin exact ingesteld; - [ ] PostgreSQL/Redis/Ollama niet publiek; - [ ] dagelijkse back-up plus periodieke hersteltest; - [ ] aparte IMAP-mailbox met minimale rechten; - [ ] bronpolicy per actieve bron op `allow` met reviewdatum; - [ ] adminwachtwoord gewijzigd; - [ ] healthmonitoring en vrije schijfruimtebewaking; - [ ] retentiejob en logrotatie gecontroleerd.