Paperless-NGX deploy: nomad job + CI for self-hosted document management.
Find a file
tamjid 40abdc2b6b
All checks were successful
Deploy paperless / deploy (push) Successful in 1m19s
bump: paperless-ngx 2.20.0 → 2.20.15
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-13 18:26:52 -04:00
.forgejo/workflows bump: paperless-ngx 2.20.0 → 2.20.15 2026-06-13 18:26:52 -04:00
paperless.nomad bump: paperless-ngx 2.20.0 → 2.20.15 2026-06-13 18:26:52 -04:00
README.md initial: paperless-ngx deploy job + CI 2026-06-13 16:44:41 -04:00

paperless

Self-hosted document management (Paperless-NGX) on the basha cluster.

  • paperless.basha.cloud — LAN + tailnet, gated by Authentik forward_auth for defense-in-depth. Paperless still requires its own login (no REMOTE_USER trust — would let an attacker spoof X-Remote-User on the sibling vhost).
  • paperless.tamjid.io — public, native Paperless auth only. Used by the Paperless Mobile iOS app (App Store) for share-sheet uploads from the iPhone scan flow.

Upstream image: ghcr.io/paperless-ngx/paperless-ngx, pinned in .forgejo/workflows/deploy.yml. Bump manually.

First-deploy bootstrap

Before pushing for the first time, set the two manual Vault secrets:

export VAULT_ADDR=https://vault.basha.cloud
vault login -method=oidc

vault kv put secret/services/paperless/keys \
  secret_key=$(openssl rand -base64 48 | tr -d '/+=' | head -c 50) \
  admin_password=$(openssl rand -base64 18 | tr -d '/+=' | head -c 24)

Then create the Authentik Proxy Provider + Application for the LAN vhost:

  • Provider type: "Forward auth (single application)"
  • External host: https://paperless.basha.cloud
  • Application slug: paperless
  • Bind to the Embedded Outpost

(The sibling paperless.tamjid.io doesn't get an Authentik provider — that's the whole point.)

CI flow

actions-deploy@main (composite action):

  1. Auths to Vault as app-provision (jwt-forgejo)
  2. Idempotently creates paperless role + DB on postgres.basha.cloud
  3. Writes DSN + creds to secret/services/paperless/db
  4. nomad job run -var "tag=$TAG" paperless.nomad

The nomad job then:

  1. Mounts five host volumes from apps:/var/lib/paperless/*
  2. Starts redis as a sidecar prestart task
  3. Starts paperless, which templates DB + secret_key + admin_password from Vault into env vars and boots
  4. Registers two Consul services (paperless for LAN, paperless-public for the sibling vhost); atlas Caddy + Pi-hole pick them up via consul-template

Initial paperless login

After the first deploy:

curl -I https://paperless.tamjid.io/   # should hit Paperless's login page, 200

Visit https://paperless.tamjid.io. Log in as tamjid with the admin_password you put in Vault. Change it from the UI (Paperless's own user model) before relying on it long-term.

Backup

Documents live in /var/lib/paperless/media on the apps VM. The authoritative backup uses Paperless's own exporter (preserves DB tags + correspondents + custom fields, not just blobs):

nomad alloc exec -task paperless $(nomad job allocs -json paperless | jq -r '.[0].ID') \
  document_exporter --use-folder-prefix /usr/src/paperless/export

Output lands in /var/lib/paperless/export on apps. From there, push to Garage on a cron (TODO — wire up rclone systemd timer once volume warrants it).

iPhone path

  1. Install Paperless Mobile (free, by Astubenbord) from the App Store
  2. Server URL: https://paperless.tamjid.io
  3. Username: tamjid, password: whatever you set in Vault → UI
  4. Share-sheet from Notes/Files (scan) → "Save to Paperless"

Resizing the disk

The archive lives on the apps VM root disk (32 GB, ~23 GB free as of 2026-06-13). When df /var/lib/paperless shows the partition past ~75% used, resize the VM disk in Proxmox:

ssh root@pve "qm resize 100 virtio0 +20G"
ssh root@apps.node.consul "growpart /dev/vda 1 && resize2fs /dev/vda1"

If growth becomes sustained, migrate to a dedicated virtio disk via basha_infra/inventory.yaml (the uptime-kuma pattern).