Updates to Uptime Kuma monitoring setup:
DNS Configuration:
- Added DNS A record for status.vrije.cloud -> 94.130.231.155
- Updated Uptime Kuma container to use status.vrije.cloud domain
- HTTPS access via nginx-proxy with Let's Encrypt SSL
Automated Monitor Management:
- Created scripts/add-client-to-monitoring.sh
- Created scripts/remove-client-from-monitoring.sh
- Integrated monitoring into deploy-client.sh (step 5/5)
- Integrated monitoring into destroy-client.sh (step 0/7)
- Deployment now prompts to add monitors after success
- Destruction now prompts to remove monitors before deletion
Email Notification Setup:
- Created docs/uptime-kuma-email-setup.md with complete guide
- SMTP configuration using smtp.strato.com
- Credentials: server@postxsociety.org
- Alerts sent to mail@postxsociety.org
Documentation:
- Updated docs/monitoring.md with new domain
- Added email setup reference
- Replaced all URLs to use status.vrije.cloud
Benefits:
✅ Friendly domain instead of IP address
✅ HTTPS access with auto-SSL
✅ Automated monitoring reminders on deploy/destroy
✅ Complete email notification guide
✅ Streamlined workflow for monitor management
Note: Monitor creation/deletion currently manual (API automation planned)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Resolves#20
Changes:
- Add hcloud_token to secrets/shared.sops.yaml (encrypted with Age)
- Create scripts/load-secrets-env.sh to automatically load token from SOPS
- Update all management scripts to auto-load token if not set
- Remove plaintext tokens from tofu/terraform.tfvars
- Update documentation in README.md, scripts/README.md, and SECURITY-NOTE-tokens.md
Benefits:
✅ Token encrypted at rest
✅ Can be safely backed up to cloud storage
✅ Consistent with other secrets management
✅ Automatic loading - no manual token management needed
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implement persistent block storage for Nextcloud user data, separating application and data layers:
OpenTofu Changes:
- tofu/volumes.tf: Create and attach Hetzner Volumes per client
- Configurable size per client (default 100 GB for dev)
- ext4 formatted, attached but not auto-mounted
- tofu/variables.tf: Add nextcloud_volume_size to client config
- tofu/terraform.tfvars: Set volume size for dev client (100 GB ~€5.40/mo)
Ansible Changes:
- ansible/roles/nextcloud/tasks/mount-volume.yml: New mount tasks
- Detect volume device automatically
- Format if needed, mount at /mnt/nextcloud-data
- Add to fstab for persistence
- Set correct permissions for www-data
- ansible/roles/nextcloud/tasks/main.yml: Include volume mounting
- ansible/roles/nextcloud/templates/docker-compose.nextcloud.yml.j2:
- Use host mount /mnt/nextcloud-data/data instead of Docker volume
- Keep app code in Docker volume (nextcloud-app)
- User data now on Hetzner Volume
Scripts:
- scripts/resize-client-volume.sh: Online volume resizing
- Resize via Hetzner API
- Expand filesystem automatically
- Show cost impact
- Verify new size
Documentation:
- docs/storage-architecture.md: Complete storage guide
- Architecture diagrams
- Volume specifications
- Sizing guidelines
- Operations procedures
- Performance considerations
- Troubleshooting guide
- docs/volume-migration.md: Step-by-step migration
- Safe migration from Docker volumes
- Rollback procedures
- Verification checklist
- Timeline estimates
Benefits:
✅ Data independent from server instance
✅ Resize storage without rebuilding server
✅ Easy data migration between servers
✅ Better separation of concerns (app vs data)
✅ Simplified backup strategy
✅ Cost-optimized (pay for what you use)
Volume Pricing:
- 50 GB: ~€2.70/month
- 100 GB: ~€5.40/month
- 250 GB: ~€13.50/month
- Resizable online, no downtime
Note: Existing clients require manual migration
Follow docs/volume-migration.md for safe migration procedure
Closes#18🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add comprehensive client registry for tracking all deployed infrastructure:
Registry System:
- Single source of truth in clients/registry.yml
- Tracks status, server specs, versions, maintenance history
- Supports canary deployment workflow
- Automatic updates via deployment scripts
New Scripts:
- scripts/list-clients.sh: List/filter clients (table/json/csv/summary)
- scripts/client-status.sh: Detailed client info with health checks
- scripts/update-registry.sh: Manual registry updates
Updated Scripts:
- scripts/deploy-client.sh: Auto-updates registry on deploy
- scripts/rebuild-client.sh: Auto-updates registry on rebuild
- scripts/destroy-client.sh: Marks clients as destroyed
Documentation:
- docs/client-registry.md: Complete registry reference
- clients/README.md: Quick start guide
Status tracking: pending → deployed → maintenance → destroyed
Role support: canary (dev) and production clients
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixes three critical regressions from previous deployment:
1. **Mailgun SMTP Credentials**
- Added mailgun_api_key to secrets/shared.sops.yaml
- Updated deploy.yml to load and merge shared secrets
- Mailgun credentials now created automatically per client
2. **Nextcloud OIDC Integration**
- OIDC provider creation now works (was timing issue)
- "Login with Authentik" button restored on Nextcloud login
3. **Infrastructure Deployment**
- Fixed deploy-client.sh to create full infrastructure (DNS + server)
- Removed -target flag that caused incomplete deployments
Changes:
- ansible/playbooks/deploy.yml: Load shared secrets and merge into client_secrets
- secrets/shared.sops.yaml: Add Mailgun API key for all clients
- secrets/clients/dev.sops.yaml: Add dev client configuration
- scripts/deploy-client.sh: Apply full infrastructure without -target flag
All services now functional:
✅ Traefik reverse proxy with auto SSL
✅ Authentik SSO with email configuration
✅ Nextcloud with OIDC login and email
✅ Mailgun SMTP credentials (dev@mg.vrije.cloud)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed email FROM address formatting that was breaking Django's email parser.
The display name contained an '@' symbol which violated RFC 5322 format.
Changes:
- Fix Authentik email FROM address (remove @ from display name)
- Add Mailgun SMTP credential cleanup on server destruction
- Fix Mailgun delete task to use EU API endpoint
- Add cleanup playbook for graceful resource removal
This ensures:
✓ Recovery emails work immediately on new deployments
✓ SMTP credentials are automatically cleaned up when destroying servers
✓ Email configuration works correctly across all environments
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
GitGuardian detected high-entropy secret in test-oidc-provider.py.
This was a development/testing script with hardcoded credentials.
Actions taken:
1. Removed test-oidc-provider.py from repository
2. Token will be rotated in separate commit
3. Production deployment uses proper Ansible role with SOPS-encrypted secrets
The exposed token was only used for test environment and will be
rotated immediately.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>