No description
Find a file
Pieter 14256bcbce feat: Add Nextcloud major version upgrade playbook (v30→v32)
Created: 2026-01-23

Add automated playbook to safely upgrade Nextcloud from v30 (EOL) to v32
through staged upgrades, respecting Nextcloud's no-version-skip policy.

Features:
- Pre-upgrade validation (version, disk space, maintenance mode)
- Automatic full backup (database + volumes)
- Staged upgrades: v30 → v31 → v32
- Per-stage app disabling/enabling
- Database migrations (indices, bigint conversion)
- Post-upgrade validation and system checks
- Rollback instructions in case of failure
- Updates docker-compose.yml to 'latest' tag after success

Files:
- playbooks/260123-upgrade-nextcloud.yml (main playbook)
- playbooks/260123-upgrade-nextcloud-stage.yml (stage tasks)

Usage:
  cd ansible/
  HCLOUD_TOKEN="..." ansible-playbook -i hcloud.yml \
    playbooks/260123-upgrade-nextcloud.yml --limit kikker

Safety:
- Creates timestamped backup before any changes
- Stops containers during volume backup
- Verifies version after each stage
- Provides rollback commands in output

Ready to upgrade kikker from v30.0.17 to v32.x

🤖 Generated with Claude Code (https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-23 20:58:25 +01:00
.claude/agents feat: Implement per-client SSH key isolation 2026-01-17 19:50:30 +01:00
ansible feat: Add Nextcloud major version upgrade playbook (v30→v32) 2026-01-23 20:58:25 +01:00
clients docs: Remove Zitadel references and update documentation 2026-01-20 20:19:04 +01:00
keys chore: Post-workshop state - January 23rd, 2026 2026-01-23 20:36:31 +01:00
scripts chore: Post-workshop state - January 23rd, 2026 2026-01-23 20:36:31 +01:00
secrets chore: Post-workshop state - January 23rd, 2026 2026-01-23 20:36:31 +01:00
tofu chore: Clean up Terraform/Tofu artifacts and improve .gitignore 2026-01-23 20:45:48 +01:00
.gitignore chore: Clean up Terraform/Tofu artifacts and improve .gitignore 2026-01-23 20:45:48 +01:00
.sops.yaml Complete SOPS secrets management setup (#5) 2025-12-27 14:23:36 +01:00
README.md docs: Remove Zitadel references and update documentation 2026-01-20 20:19:04 +01:00

Post-X Society Multi-Tenant Infrastructure

Infrastructure as Code for a scalable multi-tenant VPS platform running Nextcloud (file sync/share) on Hetzner Cloud.

🏗️ Architecture

  • Provisioning: OpenTofu (open source Terraform fork)
  • Configuration: Ansible with dynamic inventory
  • Secrets: SOPS + Age encryption
  • Hosting: Hetzner Cloud (EU-based, GDPR-compliant)
  • Identity: Authentik (OAuth2/OIDC SSO, MIT license)
  • Storage: Nextcloud (German company, AGPL 3.0)

📁 Repository Structure

infrastructure/
├── .claude/agents/          # AI agent definitions for specialized tasks
├── docs/                    # Architecture decisions and runbooks
├── tofu/                    # OpenTofu configurations for Hetzner
├── ansible/                 # Ansible playbooks and roles
├── secrets/                 # SOPS-encrypted secrets (git-safe)
├── docker/                  # Docker Compose configurations
└── scripts/                 # Deployment and management scripts

🚀 Quick Start

Prerequisites

The fastest way to deploy a client:

# 1. Ensure SOPS Age key is available (if not set)
export SOPS_AGE_KEY_FILE="./keys/age-key.txt"

# 2. Add client to terraform.tfvars
# clients = {
#   newclient = {
#     server_type = "cx22"
#     location    = "fsn1"
#     subdomain   = "newclient"
#     apps        = ["authentik", "nextcloud"]
#   }
# }

# 3. Deploy client (fully automated, ~10-15 minutes)
# The script automatically loads the Hetzner API token from SOPS
./scripts/deploy-client.sh newclient

Note: The Hetzner API token is now stored encrypted in secrets/shared.sops.yaml and loaded automatically by all scripts. No need to manually set HCLOUD_TOKEN.

The script will automatically:

  • Generate unique SSH key pair (if missing)
  • Create secrets file from template (if missing, opens in editor)
  • Provision VPS on Hetzner Cloud
  • Deploy Authentik (SSO/identity provider)
  • Deploy Nextcloud (file storage)
  • Configure OAuth2/OIDC integration
  • Set up SSL certificates
  • Create admin accounts

Result: Fully functional system, ready to use immediately!

Management Scripts

# Deploy a fresh client
./scripts/deploy-client.sh <client_name>

# Rebuild existing client (destroy + redeploy)
./scripts/rebuild-client.sh <client_name>

# Destroy client infrastructure
./scripts/destroy-client.sh <client_name>

See scripts/README.md for detailed documentation.

Manual Setup (Advanced)

Click to expand manual setup instructions
  1. Clone repository:

    git clone <repo-url>
    cd infrastructure
    
  2. Generate Age encryption key:

    age-keygen -o keys/age-key.txt
    # Store securely in password manager!
    
  3. Configure OpenTofu variables:

    cp tofu/terraform.tfvars.example tofu/terraform.tfvars
    # Edit with your Hetzner API token and configuration
    
  4. Create client secrets:

    cp secrets/clients/test.sops.yaml secrets/clients/<client>.sops.yaml
    sops secrets/clients/<client>.sops.yaml
    # Update client_name, domains, regenerate all passwords
    
  5. Provision infrastructure:

    cd tofu
    tofu init
    tofu apply
    
  6. Deploy applications:

    cd ../ansible
    export HCLOUD_TOKEN="your-token"
    export SOPS_AGE_KEY_FILE="../keys/age-key.txt"
    
    ansible-playbook -i hcloud.yml playbooks/setup.yml --limit <client>
    ansible-playbook -i hcloud.yml playbooks/deploy.yml --limit <client>
    

🎯 Project Principles

  1. EU/GDPR-first: European vendors and data residency
  2. Truly open source: Avoid source-available or restrictive licenses
  3. Client isolation: Full separation between tenants
  4. Infrastructure as Code: All changes via version control
  5. Security by default: Encryption, hardening, least privilege

📖 Documentation

🤝 Contributing

This project uses specialized AI agents for development:

  • Architect: High-level design decisions
  • Infrastructure: OpenTofu + Ansible implementation
  • Authentik: Identity provider and SSO configuration
  • Nextcloud: File sync/share configuration

See individual agent files in .claude/agents/ for responsibilities.

🔒 Security

  • Secrets are encrypted with SOPS + Age before committing
  • Age private keys are NEVER stored in this repository
  • See .gitignore for protected files

📝 License

TBD

🙋 Support

For issues or questions, please create a GitHub issue with the appropriate label:

  • agent:architect - Architecture/design questions
  • agent:infrastructure - IaC implementation
  • agent:authentik - Identity provider/SSO
  • agent:nextcloud - File sync/share