- Ensure docker-compose.yml always uses localhost:5000 for registry access - Fixes 'no basic auth credentials' error when docker-compose tries to pull images - Registry only accessible via localhost, not external interface
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
├── playbooks/
│ ├── setup-production-secrets.yml # Deploy secrets
│ ├── deploy-update.yml # Deploy application updates
│ ├── rollback.yml # Rollback deployments
│ ├── setup-wireguard.yml # Setup WireGuard VPN server
│ ├── add-wireguard-client.yml # Add WireGuard client
│ └── README-WIREGUARD.md # WireGuard documentation
├── secrets/
│ ├── .gitignore # Prevent committing secrets
│ └── production.vault.yml.example # Example vault file
└── templates/
└── .env.production.j2 # Environment file template
## 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
- 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
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.
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
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 git.michaelschiemer.de:5000
Service Not Starting
Check service logs:
# SSH to production server
ssh -i ~/.ssh/production deploy@94.16.110.151
# Check Docker service logs
docker service logs app_app
# Check stack status
docker stack ps app
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
Vault password is stored as Gitea Actions secret: ANSIBLE_VAULT_PASSWORD
Inventory Variables
All deployment variables are defined in inventory/production.yml:
| Variable | Description | Default |
|---|---|---|
docker_registry |
Docker registry URL | git.michaelschiemer.de:5000 |
app_name |
Application name | framework |
app_domain |
Production domain | michaelschiemer.de |
stack_name |
Docker stack name | app |
compose_file |
Docker Compose file path | /home/deploy/docker-compose.prod.yml |
secrets_path |
Secrets directory | /home/deploy/secrets |
backups_path |
Backups directory | /home/deploy/backups |
max_rollback_versions |
Backup retention | 5 |
health_check_url |
Health check endpoint | https://michaelschiemer.de/health |
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