Skip to content

Latest commit

 

History

52 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

nextcloud (k3s homelab)

Deploy

CI-deployed Nextcloud stack for the 3-node k3s-over-Cloudflare-WARP-Mesh cluster. Push to main triggers .github/workflows/deploy.yml on the self-hosted ARC runner arc-itguys-ro-nextcloud.

Cluster operational runbook (outside repo): ~/cloudflare-mesh-k3s-state.md. Design: docs/superpowers/specs/2026-05-25-nextcloud-ci-deployment-design.md.

Layout

.github/workflows/   deploy.yml (push:main) + pr-checks.yml (PR dry-run)
docs/                design specs
helm/                Helm values (committed, secret-free): cert-manager + nextcloud
manifests/           raw k8s YAML (CI-applied: certificate, Valkey, PVC, backup CronJob)
manifests/bootstrap/ one-time, applied manually by cluster-admin (namespace, ClusterIssuer, deployer RBAC)
secrets/             *.example templates only. Real values live in GitHub Actions Secrets.

TLS is terminated by edge-proxy (ns ingress, k3s-cluster repo), not in this namespace. Adding or renaming a vhost means editing it there.

Secrets

Plaintext never committed (.gitignore enforces).

Workflow on rotation:

  1. Update secrets/<name>.yaml locally (gitignored).
  2. gh secret set <NAME> for each affected key (see .github/workflows/deploy.yml for the GH secret names).
  3. Re-run deploy (gh workflow run deploy.yml -f reconcile_all=true).

GitHub Actions Secrets currently set: CF_API_TOKEN, NEXTCLOUD_ADMIN_USERNAME, NEXTCLOUD_ADMIN_PASSWORD, R2_ACCESS_KEY, R2_SECRET_KEY, VALKEY_PASSWORD.

The CF API token must be scoped Zone:DNS:Edit + Zone:Zone:Read on itguys.ro only.

Bootstrap (one-time, per cluster)

Cluster-admin runs these once. CI cannot grant itself rights.

  1. kubectl apply -f manifests/bootstrap/00-namespace.yaml
  2. helm install cert-manager jetstack/cert-manager -n cert-manager --create-namespace --version v1.20.2 -f helm/cert-manager-values.yaml
  3. Create initial cloudflare-api-token Secret in ns cert-manager (CI's narrow Role can update but not create):
    kubectl -n cert-manager create secret generic cloudflare-api-token --from-literal=api-token=<token>
    
  4. kubectl apply -f manifests/bootstrap/10-clusterissuer-letsencrypt.yaml
  5. kubectl apply -f manifests/bootstrap/11-ci-deployer-rbac.yaml
  6. Install ARC scale set (see design doc §4.2 for the helm install command).
  7. gh secret set for all 8 secrets (see above).
  8. Live-edit the shared nginx-tls-proxy ConfigMap to add the cloud.itguys.ro vhost (if not already present).
  9. DNS cloud.itguys.ro A → 100.96.0.2 (DNS-only).
  10. Cloudflare Gateway "Do Not Inspect" rule for the hostname (see Operational dependencies).
  11. Push to main → CI takes over.

Operating

  • Routine change: git push origin main → CI applies path-relevant jobs. No further action needed; secrets job always runs, manifests/helm jobs run only if their paths changed.
  • Rollback: gh workflow disable deploy.yml, then helm rollback nextcloud -n nextcloud manually.

Force full reconcile

gh workflow run deploy.yml -f reconcile_all=true

When to use:

  • Drift suspected (someone ran kubectl edit / helm upgrade against the cluster out-of-band).
  • A GH Actions Secret was rotated but no repo file changed (path filter wouldn't trigger helm/manifests).
  • Workflow was disabled and re-enabled; first run after re-enable.

Not needed after a normal merge — the merge push already triggers all relevant jobs via paths-filter (helm filter includes .github/workflows/deploy.yml, so a workflow edit forces helm reconcile too).

Access: https://cloud.itguys.ro (Mesh participants only).

Operational dependencies (silent-failure if removed)

  • Cloudflare Gateway "Do Not Inspect" ruleitguys org has Gateway tls_decrypt enabled. Rule id df440536-0b50-483d-b5d7-70cd7cbe6230 (action: off, http.conn.hostname == "cloud.itguys.ro") exempts this host. If deleted: clients get the Gateway CA, Nextcloud Android app breaks, file traffic decrypted at Cloudflare's edge. Verify: echo | openssl s_client -connect 100.96.0.2:443 -servername cloud.itguys.ro 2>/dev/null | openssl x509 -noout -issuer must show O = Let's Encrypt. Any new host on :443 needs its own rule. Full context: design doc §5 amendment 2026-05-18.
  • PV reclaim policy = Retainnextcloud-data is patched to persistentVolumeReclaimPolicy: Retain (local-path defaults to Delete), so an accidental kubectl delete pvc does not wipe the hostPath. It now holds only the install directory and the SQLite database; user files are in R2. Real recovery is the nightly SQLite snapshot in r2://nextcloud-data/db/ plus the R2 objects themselves. The nextcloud-db and nextcloud-backups claims were removed with MariaDB on 2026-09-03.

About

Nextcloud k3s deployment infra

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages