- Fix dictionary update logic in set_fact - Use list operations before updating dictionary - Ensures proper JSON structure for Docker daemon.json
Ansible Deployment Configuration
This directory contains Ansible playbooks and configuration for deploying the Custom PHP Framework to production.
Directory Structure
deployment/ansible/
├── ansible.cfg # Ansible configuration
├── inventory/
│ ├── production.yml # Production server inventory
│ └── local.yml # Local testing inventory
├── playbooks/
│ ├── deploy-update.yml # Deploy application updates
│ ├── system-maintenance.yml # Betriebssystem-Updates & Wartung
│ ├── rollback.yml # Rollback deployments
│ ├── setup-infrastructure.yml # Provision core stacks
│ ├── setup-production-secrets.yml # Deploy secrets
│ ├── setup-wireguard.yml # Setup WireGuard VPN server
│ ├── add-wireguard-client.yml # Add WireGuard client
│ ├── sync-code.yml # Git-based code sync
│ └── README-WIREGUARD.md # WireGuard documentation
├── scripts/ # Helper scripts for secrets & credentials
├── roles/ # Reusable roles (e.g. application stack)
├── secrets/
│ ├── .gitignore # Prevent committing secrets
│ └── production.vault.yml.example # Example vault file
└── templates/
├── application.env.j2 # Application stack environment
├── gitea-app.ini.j2 # Gitea configuration
├── minio.env.j2 # MinIO environment
├── monitoring.env.j2 # Monitoring stack environment
├── wireguard-client.conf.j2 # WireGuard client config
└── wireguard-server.conf.j2 # WireGuard server config
## Roles
Stack-spezifische Aufgaben liegen in `roles/` (z. B. `application`, `traefik`, `registry`). Playbooks wie `setup-infrastructure.yml` importieren diese Rollen direkt. Die Application-Rolle kann mit Variablen wie `application_sync_files=false` oder `application_compose_recreate="always"` konfiguriert werden (siehe `playbooks/deploy-update.yml` als Beispiel). Die neue `system`-Rolle hält Betriebssystem-Pakete aktuell und konfiguriert optionale Unattended-Upgrades bevor Docker-Stacks neu gestartet werden.
## Prerequisites
1. **Ansible Installed**:
```bash
pip install ansible
-
SSH Access:
- SSH key configured at
~/.ssh/production - Key added to production server's authorized_keys for
deployuser
- SSH key configured at
-
Ansible Vault Password:
- Create
.vault_passfile insecrets/directory - Add vault password to this file (one line)
- File is gitignored for security
- 📖 Detaillierte Dokumentation: docs/guides/vault-password.md
- Create
Setup Instructions
1. Create Production Secrets
cd deployment/ansible/secrets
# Copy example file
cp production.vault.yml.example production.vault.yml
# Edit with your actual secrets
nano production.vault.yml
# Encrypt the file
ansible-vault encrypt production.vault.yml
# Enter vault password when prompted
2. Store Vault Password
# Create vault password file
echo "your-vault-password-here" > secrets/.vault_pass
# Secure the file
chmod 600 secrets/.vault_pass
📖 Für detaillierte Informationen: Siehe docs/guides/vault-password.md
3. Configure SSH Key
# Generate SSH key if needed
ssh-keygen -t ed25519 -f ~/.ssh/production -C "ansible-deploy"
# Copy public key to production server
ssh-copy-id -i ~/.ssh/production.pub deploy@94.16.110.151
Running Playbooks
Deploy Production Secrets
First-time setup - Deploy secrets to production server:
ansible-playbook playbooks/setup-production-secrets.yml \
--vault-password-file secrets/.vault_pass
Deploy Application Update
Automated via Gitea Actions - Or run manually:
ansible-playbook playbooks/deploy-update.yml \
-e "image_tag=sha-abc123" \
-e "git_commit_sha=abc123" \
-e "deployment_timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
-e "docker_registry_username=gitea-user" \
-e "docker_registry_password=your-registry-password"
Rollback Deployment
Rollback to previous version:
ansible-playbook playbooks/rollback.yml
Rollback to specific version:
ansible-playbook playbooks/rollback.yml \
-e "rollback_to_version=2025-01-28T15-30-00"
Setup WireGuard VPN
First-time setup - Install WireGuard VPN server:
ansible-playbook -i inventory/production.yml playbooks/setup-wireguard.yml
Add a client:
ansible-playbook -i inventory/production.yml playbooks/add-wireguard-client.yml \
-e "client_name=myclient"
Siehe playbooks/README-WIREGUARD.md für detaillierte Anleitung.
System Maintenance ausführen
Führt die system-Rolle aus, aktualisiert Paketquellen, führt OS-Upgrades durch und aktiviert optional Unattended-Upgrades.
ansible-playbook -i inventory/production.yml \
playbooks/system-maintenance.yml
Tipp: Mit --check lässt sich zunächst ein Dry-Run starten, um anstehende Updates zu prüfen.
Ansible Vault Operations
View Encrypted File
ansible-vault view secrets/production.vault.yml \
--vault-password-file secrets/.vault_pass
Edit Encrypted File
ansible-vault edit secrets/production.vault.yml \
--vault-password-file secrets/.vault_pass
Change Vault Password
ansible-vault rekey secrets/production.vault.yml \
--vault-password-file secrets/.vault_pass
Decrypt File (Temporarily)
ansible-vault decrypt secrets/production.vault.yml \
--vault-password-file secrets/.vault_pass
# DO NOT COMMIT DECRYPTED FILE!
# Re-encrypt when done
ansible-vault encrypt secrets/production.vault.yml \
--vault-password-file secrets/.vault_pass
Testing Playbooks
Test with Check Mode (Dry Run)
ansible-playbook playbooks/deploy-update.yml \
--check \
-e "image_tag=test"
Test Connection
ansible production -m ping
Verify Inventory
ansible-inventory --list -y
System Maintenance Dry Run
ansible-playbook -i inventory/production.yml \
playbooks/system-maintenance.yml \
--check
Security Best Practices
-
Never commit unencrypted secrets
production.vault.ymlmust be encrypted.vault_passis gitignored- Use
.examplefiles for documentation
-
Rotate secrets regularly
- Update vault file
- Re-run
setup-production-secrets.yml - Restart affected services
-
Limit SSH key access
- Use separate SSH key for Ansible
- Limit key to
deployuser only - Consider IP restrictions
-
Vault password security
- Store vault password in secure password manager
- Don't share via insecure channels
- Use different passwords for dev/staging/prod
Troubleshooting
Vault Decryption Failed
Error: Decryption failed (no vault secrets were found)
Solution:
# Verify vault password is correct
ansible-vault view secrets/production.vault.yml \
--vault-password-file secrets/.vault_pass
# If password is wrong, you'll need the original password to decrypt
SSH Connection Failed
Error: Failed to connect to the host
Solutions:
# Test SSH connection manually
ssh -i ~/.ssh/production deploy@94.16.110.151
# Check SSH key permissions
chmod 600 ~/.ssh/production
chmod 644 ~/.ssh/production.pub
# Verify SSH key is added to server
ssh-copy-id -i ~/.ssh/production.pub deploy@94.16.110.151
Docker Registry Authentication Failed
Error: unauthorized: authentication required
Solution:
# Verify registry credentials in vault file
ansible-vault view secrets/production.vault.yml \
--vault-password-file secrets/.vault_pass
# Test registry login manually on production server
docker login registry.michaelschiemer.de
Service Not Starting
Check service logs:
# SSH to production server
ssh -i ~/.ssh/production deploy@94.16.110.151
# Check Docker Compose service logs
docker compose -f {{ app_stack_path }}/docker-compose.yml logs app
docker compose -f {{ app_stack_path }}/docker-compose.yml logs nginx
# Check stack status
docker compose -f {{ app_stack_path }}/docker-compose.yml ps
CI/CD Integration
These playbooks are automatically executed by Gitea Actions workflows:
.gitea/workflows/production-deploy.yml- Callsdeploy-update.ymlon push to main.gitea/workflows/update-production-secrets.yml- Callssetup-production-secrets.ymlon manual trigger.gitea/workflows/system-maintenance.yml- Führtsystem-maintenance.ymlgeplant oder manuell aus, um Pakete aktuell zu halten
Vault password is stored as Gitea Actions secret: ANSIBLE_VAULT_PASSWORD
Inventory Variables
All zentralen Variablen werden in group_vars/production.yml gepflegt und können bei Bedarf im Inventory überschrieben werden. Häufig verwendete Werte:
| Variable | Beschreibung | Standardwert |
|---|---|---|
deploy_user_home |
Home-Verzeichnis des Deploy-Users | /home/deploy |
stacks_base_path |
Basispfad für Docker Compose Stacks | /home/deploy/deployment/stacks |
app_stack_path |
Pfad zum Application Stack | /home/deploy/deployment/stacks/application |
backups_path |
Ablageort für Deployment-Backups | /home/deploy/deployment/backups |
docker_registry |
Interner Registry-Endpunkt (lokal) | localhost:5000 |
docker_registry_external |
Externer Registry-Endpunkt | registry.michaelschiemer.de |
app_domain |
Produktions-Domain | michaelschiemer.de |
health_check_url |
Health-Check Endpoint | https://michaelschiemer.de/health |
max_rollback_versions |
Anzahl vorgehaltener Backups | 5 |
system_update_packages |
Aktiviert OS-Paketupdates via system-Rolle |
true |
system_apt_upgrade |
Wert für apt upgrade (z. B. dist) |
dist |
system_enable_unattended_upgrades |
Aktiviert unattended-upgrades |
true |
system_enable_unattended_reboot |
Steuert automatische Reboots nach Updates | false |
system_unattended_reboot_time |
Reboot-Zeitfenster (wenn aktiviert) | 02:00 |
system_enable_unattended_timer |
Aktiviert Systemd-Timer für apt | true |
system_enable_docker_prune |
Führt nach Updates docker system prune aus |
false |
Backup Management
Backups are automatically created before each deployment:
- Location:
/home/deploy/backups/ - Retention: Last 5 versions kept
- Contents:
current_image.txt- Previously deployed imagestack_status.txt- Stack status before deploymentdeployment_metadata.txt- Deployment details
List Available Backups
ssh -i ~/.ssh/production deploy@94.16.110.151 \
"ls -lh /home/deploy/backups/"
Manual Backup
ansible-playbook playbooks/deploy-update.yml \
--tags backup \
-e "image_tag=current"
Support
For issues with:
- Playbooks: Check this README and playbook comments
- Vault: See Ansible Vault documentation
- Deployment: Review Gitea Actions logs
- Production: SSH to server and check Docker logs