3.5 KiB
3.5 KiB
Deployment
Fuller command reference: deploy/README.md. This document covers deployment models and production requirements.
Options
| Environment | Tooling | TLS | Data |
|---|---|---|---|
| Laptop | Compose + compose.dev.yaml |
Traefik default cert | Postgres/Redis/RustFS in compose |
| Single-host VPS | Compose + compose.prod.yaml |
Let's Encrypt HTTP-01 | Same + no published DB ports |
| Local k3s | Helm values-k3s.yaml |
Chart self-signed | In-cluster |
| Production K8s | Helm values-prod.yaml |
cert-manager | Usually external DB/Redis/S3 |
Routing
| Path | Service |
|---|---|
/api/*, /media/* |
backend |
/api/certificates/*, /c/* |
backend (+ noindex middleware) |
| everything else | frontend |
/api/ws |
backend WebSocket via Traefik |
Compose — development
cp .env.example .env
./scripts/compose-dev.sh up -d --build
- App: https://localhost
- Traefik dashboard: http://127.0.0.1:8088
- DB ports only on
127.0.0.1
Compose — production
cp .env.prod.example .env.prod
./scripts/compose-prod.sh up -d --build
DNS must point at the host. DOMAIN, ACME_EMAIL, and strong secrets are required.
k3s + Helm
# Install k3s and kubeconfig once (see deploy/README.md)
./scripts/k3s-load-images.sh # build and import local images
./scripts/helm-k3s.sh # upgrade --install with values-k3s.yaml
echo "127.0.0.1 pargar.local" | sudo tee -a /etc/hosts # if needed
curl -k https://pargar.local/api/health
Values
| File | Purpose |
|---|---|
deploy/helm/pargar/values.yaml |
Defaults |
values-k3s.yaml |
Local: seed, backup CronJob, self-signed TLS |
values-prod.yaml |
Registry, HPA, PDB, NetworkPolicy, existingSecret |
helm lint ./deploy/helm/pargar -f ./deploy/helm/pargar/values-k3s.yaml
helm template pargar ./deploy/helm/pargar -f ./deploy/helm/pargar/values-k3s.yaml
Helm 4 rejects negation patterns in .helmignore (!…); do not add them.
Chart secrets
- Without
backend.existingSecret: the chart generate-once vialookup+randAlphaNumand keeps values across upgrades. change-me-*placeholders in values are ignored.- An existing Postgres password is never rotated (data depends on it).
- Production: always pre-create the Secret and set
backend.existingSecret.
Read a generated admin password:
kubectl -n pargar get secret pargar-app -o jsonpath='{.data.admin-password}' | base64 -d; echo
DB/Redis wiring in Helm
Instead of a raw URL with an unencoded password, the backend builds from parts:
POSTGRES_USER/POSTGRES_PASSWORD/POSTGRES_HOST/POSTGRES_DB/POSTGRES_SSLMODEREDIS_HOST/REDIS_PASSWORD
Or for external production: DATABASE_URL / REDIS_URL inside the Secret.
In-cluster backup
With postgres.enabled and backup.enabled=true (on for k3s): daily CronJob pg_dump | gzip onto a PVC with retention. For managed Postgres in production, set backup.enabled=false.
Production checklist
DEV_MODE=false- Strong
JWT_SECRETandADMIN_PASSWORD(no placeholders) — otherwiseconfig.Validate()refuses to boot - Exact public
PUBLIC_URLandFRONTEND_ORIGINS TRUSTED_PROXY_CIDRSlimited to the proxy networkMETRICS_TOKENto expose/metrics- Images from a private registry +
imagePullSecrets - cert-manager / real TLS
- DB and object-storage backups defined
PHYSICAL_CERT_ENABLEDonly if the offline payment process is ready- NetworkPolicy / HPA per
values-prod.yaml