Files
michaelschiemer/deployment/ansible
Michael Schiemer 51fda6b732
Some checks failed
🚀 Build & Deploy Image / Determine Build Necessity (push) Successful in 27s
🚀 Build & Deploy Image / Build Runtime Base Image (push) Successful in 13s
🚀 Build & Deploy Image / Build Docker Image (push) Successful in 4m6s
Security Vulnerability Scan / Check for Dependency Changes (push) Successful in 27s
🚀 Build & Deploy Image / Run Tests & Quality Checks (push) Successful in 56s
Security Vulnerability Scan / Composer Security Audit (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Staging (push) Failing after 56s
🚀 Build & Deploy Image / Auto-deploy to Production (push) Has been skipped
fix: unify Docker registry URLs to localhost:5000
- Change docker-compose.staging.yml: git.michaelschiemer.de:5000 -> localhost:5000
- Update deploy-image.yml playbook to:
  - Pull images from registry.michaelschiemer.de (source registry)
  - Tag and push to localhost:5000 (local registry) for local containers
  - Remove hardcoded git.michaelschiemer.de:5000 logic
  - Use local_registry from compose files for deployment

This ensures:
- Workflow pushes to registry.michaelschiemer.de (external, HTTPS)
- Containers use localhost:5000 (local, faster, no HTTPS overhead)
- Consistent registry usage across staging and production
2025-11-09 00:29:20 +01:00
..
2025-11-01 19:02:09 +01:00

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
  1. SSH Access:

    • SSH key configured at ~/.ssh/production
    • Key added to production server's authorized_keys for deploy user
  2. 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

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

  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:

# 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 - 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

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