| nix | ||
| scripts | ||
| secrets | ||
| templates | ||
| .gitignore | ||
| cloud-init.yaml | ||
| config.yaml.example | ||
| README.md | ||
Dasphere
Rebuildable containerized multi-service single node (VM) deployment
Dasphere is an automated infrastructure-as-code solution for deploying self-hosted services on Hetzner Cloud using NixOS. It provides a complete platform with mandatory baseline services (VPN, firewall, reverse proxy, monitoring, backups, IdP) plus optional applications (Seafile, Jellyfin, Forgejo, etc.).
Status
🎉 Ready to Deploy! - Complete NixOS-based infrastructure with automated deployment to Hetzner Cloud.
What's Implemented
✅ NixOS Configuration (NixOS 25.11)
- Complete flake-based system configuration
- Disk layout with disko (GRUB, ext4, GPT)
- All NixOS modules for services and infrastructure
✅ Security & Networking
- Hardened SSH configuration
- nftables firewall with DDoS protection
- WireGuard VPN server (10.10.10.0/24)
- HAProxy reverse proxy with SNI routing
- Let's Encrypt wildcard certificates (INWX DNS-01)
✅ Infrastructure Services
- PostgreSQL 16 (shared, tuned for cx22)
- Docker/OCI containers via virtualisation.oci-containers
✅ Mandatory Services
- Authentik IdP (identity and access management)
- Prometheus + Grafana monitoring (with exporters)
- Restic encrypted backups to S3 (daily, with retention)
✅ Optional Applications (enable via config.yaml)
- AdGuard Home (ad blocking)
- Seafile (file storage)
- Jellyfin (media server)
- Paperless-NGX (document management)
- Pyload (download manager)
- Matrix/Element (chat)
- Forgejo (git hosting)
✅ Secrets Management
- Agenix for encrypted secrets
- setup-secrets.sh script (generates and encrypts all secrets)
Deployment Scripts - All Functional ✅
- ✅ scripts/setup-secrets.sh - Generate and encrypt all secrets
- ✅ scripts/generate-cloud-init.sh - Create minimal cloud-init with embedded flake
- ✅ scripts/provision.sh - Deploy to Hetzner Cloud via hcloud CLI
- ✅ scripts/teardown.sh - Destroy infrastructure
Optional Enhancements (Nice-to-Have)
- 📝 Detailed documentation (docs/*.md files)
- 🔧 WireGuard client management script
- 🧪 NixOS VM tests for local testing
- 📊 Pre-configured Grafana dashboards
- 🔐 Authentik SSO integration examples
Alternatives
There are already existing implementations of the idea out there, some seem to focus more on local/home deployments rather than cloud VMs.
- https://yunohost.org from France
- https://www.turnkeylinux.org/ - seems AWS focussed?
- https://sandstorm.org/ - seems no longer under active maintenance
- https://www.freedombox.org/
Functional requirements
Management UIs
Central Managemenut UI
-
Step 1
- Select (optional) apps to run
- Files: https://www.seafile.com/
- Document Management: https://docs.paperless-ngx.com/
- Mail: https://stalw.art/
- Ad blocking: https://adguard.com/de/adguard-home/overview.html
- Media Server: https://jellyfin.org/ (integrated sqlite, app must be stopped for backup)
- Media Retrieval: https://pyload.net/
- Chat: https://github.com/element-hq/synapse & https://matrix.org/ecosystem/clients/
- Code hosting: https://forgejo.org (psql ..)
- Per app allow a selection if the app should only be accessible using VPN or publicly available.
- Drop down for estimated number of users (5,10,25,50,75,100,150,200,300,400,500)
- Profile selector (business primary platform, business project platform, private platform)
- Select (optional) apps to run
-
Step 2
- Select cloud provider (Hetzner, Scaleways, AWS lightsail)
- Provide API credentials
- Based on the selected apps, user number and profile pre-select a cloud provider specific VM sizing in a dropdown
- Select domain/hostname and optionally select DNS provider
- Mighty be preselected based on the provider selection (e.g. AWS > Route 53), but also give INWX as an option
- Select S3 provider (Wasabi, Hetzner, AWS)
- Again provide preseletion based on the cloud provider selection
- Provide Bucket credentials
- Select cloud provider (Hetzner, Scaleways, AWS lightsail)
for Development purposes and while the UI isn't avaiable the required data is provided as a YAML file.
dasphere:
admin:
username: "thorsten"
password: "geheim"
apps:
adBlocking:
name: "adguard"
vpnOnly: false
fileStore:
name: "seafile"
vpnOnly: true
mediaServer:
name: "jellyfin"
vpnOnly: false
documentManagement:
name: "paperless-ngx"
vpnOnly: true
mediaLoader:
name: "pyload"
vpnOnly: true
chat:
name: "element"
vpnOnly: false
code:
name: "forgejo"
vpnOnly: false
cloudProvider:
name: "hetzner"
apiKey: "secret"
dnsProvider:
name: "inwx"
username: "test"
password: "secret"
s3Provider:
name: "wasabi"
bucket: "dovecot"
username: "dovecot_user"
secretKey: "secret"
Server Management UI
Currently not in scope, there will be a Server Management UI to
- Add / remove applications
- Check backup status
- Trigger a new backup
- Manage VPN Connections
Baseline
End-to-end automation:
- Bootstrap the VM at the selected cloud provider getting a NixOS (via nix-anywhere) based installation in place.
- In the VM install
- VPN: Wireguard
- Firewall
- Web-Proxy
- SSL termination using Certbot-generated wildcard certificates.
- Sets up SNI routing for selected public access subdomains (others are VPN-only).
- Stick-tables for DDoS mitigation, rate-limiting, and statistics endpoint accessible via VPN.
- Handler for automatic reload after cert renewal based on the selected DNS provider
- certbot_inwx
- We start with INWX DNS plugin.
- Automatic wildcard certificate issuance and renewal.
- Hooks into HAProxy reload handler.
- Container runtime
- PostgreSQL
- Deploy mandatory containers:
- IdP: https://goauthentik.io/ (pgsql)
- Monitoring: Prometheus & Grafana
- Dashboards for Docker containers, WireGuard, HAProxy, and backups.
- Alerting esp. for persistant volumes that might run out of storage.
- Backups: https://restic.net/
- Encrypted Restic backups to S3 (or other storage) for defined resources (e.g exclude media library).
- Ensure proper delta backups, save backup status in versioned S3 file
- Automated backup cron tasks.
- Restore testing scripts to validate backup integrity.
Quick Start
Prerequisites
- Nix package manager (for local testing)
- Hetzner Cloud account
- Domain with DNS access (INWX supported)
- S3-compatible storage (Wasabi, Hetzner, AWS)
Deployment Workflow
# 1. Configure your deployment
cp config.yaml.example config.yaml
# Edit config.yaml with your domain, credentials, selected apps
# 2. Generate and encrypt secrets
./scripts/setup-secrets.sh
# 3. Generate cloud-init deployment artifact
./scripts/generate-cloud-init.sh # TODO: Implement
# 4. Provision Hetzner server
./scripts/provision.sh # TODO: Implement
# 5. Wait ~25-30 minutes for automated installation
# Access services at https://auth.yourdomain.com
Architecture Overview
Internet
↓
[Firewall] (nftables: SSH, HTTP/HTTPS, WireGuard)
↓
[HAProxy] (SNI routing, SSL termination, rate limiting)
├─ auth.domain.com → Authentik (9000)
├─ grafana.domain.com → Grafana (3000) [VPN-only]
├─ prometheus.domain.com → Prometheus (9090) [VPN-only]
├─ git.domain.com → Forgejo (3002)
├─ seafile.domain.com → Seafile (8082) [VPN-only]
└─ ... other apps
↓
[Docker Containers] ← [PostgreSQL 16] → [Restic Backups to S3]
VPN Access: WireGuard VPN (10.10.10.0/24) provides secure access to VPN-only services.
Project Structure
dasphere/
├── config.yaml.example # Configuration template
├── nix/
│ ├── configuration.nix # Main NixOS config
│ ├── disk-config.nix # Disko disk layout
│ ├── generated.nix # Auto-generated from config.yaml
│ └── modules/ # NixOS modules
│ ├── base.nix # SSH, users, hardening
│ ├── firewall.nix # nftables rules
│ ├── wireguard.nix # VPN server
│ ├── haproxy.nix # Reverse proxy
│ ├── certbot.nix # SSL certificates
│ ├── postgresql.nix # Database
│ └── services/ # Container services
│ ├── authentik.nix
│ ├── monitoring.nix
│ ├── restic.nix
│ └── apps.nix # Optional apps
├── secrets/ # Agenix encrypted secrets
│ ├── secrets.nix # Key definitions
│ └── *.age # Encrypted files
├── scripts/
│ ├── setup-secrets.sh # ✅ Generate secrets
│ ├── generate-cloud-init.sh# ❌ TODO: Generate cloud-init.yaml
│ ├── provision.sh # ❌ TODO: Deploy to Hetzner
│ └── teardown.sh # ❌ TODO: Destroy server
└── templates/
├── flake.nix.tpl # NixOS flake template
└── cloud-init.yaml.tpl # Cloud-init template
Configuration
Edit config.yaml to configure:
- Domain: Your domain name (all services will be subdomains)
- Admin: Username, email, SSH public key, password
- Apps: Enable/disable optional applications
- VPN-only: Control which apps require VPN access
- Cloud Provider: Hetzner API key, server type, location
- DNS Provider: INWX credentials for ACME DNS-01
- S3 Storage: Bucket credentials for backups
See config.yaml.example for full documentation.
Security
- Secrets: All sensitive data encrypted with agenix (age encryption)
- SSH: Key-only authentication, hardened settings
- Firewall: Default-drop policy, rate limiting, DDoS protection
- SSL/TLS: TLS 1.2+, modern ciphers, wildcard certificates
- VPN: WireGuard for secure access to internal services
- Containers: Isolated, non-root where possible
- Updates: Automatic security updates (no auto-reboot)
Services
Mandatory (Always Enabled)
- Authentik: Identity provider and SSO for all services
- Prometheus + Grafana: Metrics, dashboards, alerting
- Restic: Encrypted backups to S3 (daily, with retention)
Optional (Enable in config.yaml)
- AdGuard Home: Network-wide ad blocking
- Seafile: File sync and storage (like Dropbox)
- Jellyfin: Media server (movies, music, TV)
- Paperless-NGX: Document management system
- Pyload: Download manager
- Matrix + Element: Self-hosted chat
- Forgejo: Git hosting (like GitHub)
Monitoring
Access Grafana at https://grafana.yourdomain.com (VPN-only) to view:
- System metrics (CPU, memory, disk, network)
- Docker container metrics
- HAProxy request rates and errors
- PostgreSQL performance
- WireGuard VPN status
- Backup success/failure
Alerts configured for:
- Disk usage >95%
- Memory usage >90%
- Service down >5 minutes
- Certificate expiry <7 days
- Backup failures
Backups
Restic performs daily encrypted backups to S3:
- Included: PostgreSQL databases, container volumes, app data
- Excluded: Jellyfin media library (too large), caches, logs
- Retention: 7 daily, 4 weekly, 6 monthly
- Verification: Weekly repository check, monthly restore test
Restore from backup:
ssh root@server
restic -r s3://endpoint/bucket/restic snapshots
restic restore latest --target /restore
Development
See the detailed implementation plan: ~/.claude/plans/luminous-conjuring-charm.md
Local Testing (Optional)
Test NixOS configuration locally before deploying:
# Build the system (requires Nix)
nix build .#nixosConfigurations.dasphere.config.system.build.toplevel
# Run in VM (requires KVM)
nixos-rebuild build-vm -I nixos-config=./nix/configuration.nix
./result/bin/run-nixos-vm
Disaster Recovery
- Provision new server:
./scripts/provision.sh - Wait for NixOS installation (~25-30 min)
- Restore from Restic backup (~1 hour for PostgreSQL + data)
- Update DNS A records to new server IP
RTO: ~2 hours | RPO: 24 hours (daily backups)
Contributing
This is an early-stage project. Key areas needing work:
- generate-cloud-init.sh: Implement cloud-init generation logic
- provision.sh: Complete Hetzner provisioning automation
- Documentation: Create detailed guides in docs/
- Testing: Add NixOS VM tests
- App Modules: Improve app configurations, add more apps
See TODO section above for specific tasks.
Backlog / Archive
- Ad blocking: https://adguard.com/de/adguard-home/overview.html
- Configure with DNSSEC, upstream DNS hardening, and VPN-only access.
- Document management: https://docs.paperless-ngx.com/ (pgsql / directory or S3)
- File store / Office: https://www.seafile.com/ (psql / S3 with client side encryption)
- Mail: https://stalw.art/
- Media Server: https://jellyfin.org/ (integrated sqlite, app must be stopped for backup)
- Media Retrieval: https://pyload.net/
- Chat: https://github.com/element-hq/synapse & https://matrix.org/ecosystem/clients/
- Videoconferencing: tbd
- Code hosting: https://forgejo.org (psql ..)