# 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 ``` 2. **SSH Access**: - SSH key configured at `~/.ssh/production` - Key added to production server's authorized_keys for `deploy` user 3. **Ansible Vault Password**: - Create `.vault_pass` file in `secrets/` directory - Add vault password to this file (one line) - File is gitignored for security - 📖 **Detaillierte Dokumentation:** [docs/guides/vault-password.md](../docs/guides/vault-password.md) ## Setup Instructions ### 1. Create Production Secrets ```bash 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 ```bash # 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](../docs/guides/vault-password.md) ### 3. Configure SSH Key ```bash # 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: ```bash ansible-playbook playbooks/setup-production-secrets.yml \ --vault-password-file secrets/.vault_pass ``` ### Deploy Application Update **Automated via Gitea Actions** - Or run manually: ```bash 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**: ```bash ansible-playbook playbooks/rollback.yml ``` **Rollback to specific version**: ```bash ansible-playbook playbooks/rollback.yml \ -e "rollback_to_version=2025-01-28T15-30-00" ``` ### Setup WireGuard VPN **First-time setup** - Install WireGuard VPN server: ```bash ansible-playbook -i inventory/production.yml playbooks/setup-wireguard.yml ``` **Add a client**: ```bash ansible-playbook -i inventory/production.yml playbooks/add-wireguard-client.yml \ -e "client_name=myclient" ``` Siehe [playbooks/README-WIREGUARD.md](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. ```bash 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 ```bash ansible-vault view secrets/production.vault.yml \ --vault-password-file secrets/.vault_pass ``` ### Edit Encrypted File ```bash ansible-vault edit secrets/production.vault.yml \ --vault-password-file secrets/.vault_pass ``` ### Change Vault Password ```bash ansible-vault rekey secrets/production.vault.yml \ --vault-password-file secrets/.vault_pass ``` ### Decrypt File (Temporarily) ```bash 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) ```bash ansible-playbook playbooks/deploy-update.yml \ --check \ -e "image_tag=test" ``` ### Test Connection ```bash ansible production -m ping ``` ### Verify Inventory ```bash ansible-inventory --list -y ``` ### System Maintenance Dry Run ```bash ansible-playbook -i inventory/production.yml \ playbooks/system-maintenance.yml \ --check ``` ## Security Best Practices 1. **Never commit unencrypted secrets** - `production.vault.yml` must be encrypted - `.vault_pass` is gitignored - Use `.example` files for documentation 2. **Rotate secrets regularly** - Update vault file - Re-run `setup-production-secrets.yml` - Restart affected services 3. **Limit SSH key access** - Use separate SSH key for Ansible - Limit key to `deploy` user only - Consider IP restrictions 4. **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**: ```bash # 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**: ```bash # 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**: ```bash # 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**: ```bash # 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`** - Calls `deploy-update.yml` on push to main - **`.gitea/workflows/update-production-secrets.yml`** - Calls `setup-production-secrets.yml` on manual trigger - **`.gitea/workflows/system-maintenance.yml`** - Führt `system-maintenance.yml` geplant 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 image - `stack_status.txt` - Stack status before deployment - `deployment_metadata.txt` - Deployment details ### List Available Backups ```bash ssh -i ~/.ssh/production deploy@94.16.110.151 \ "ls -lh /home/deploy/backups/" ``` ### Manual Backup ```bash 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