chore: remove test trigger file

This commit is contained in:
2025-10-31 04:14:18 +01:00
parent 403205315e
commit 6deca7838e
29 changed files with 4052 additions and 128 deletions

View File

@@ -12,7 +12,10 @@ deployment/ansible/
├── playbooks/
│ ├── setup-production-secrets.yml # Deploy secrets
│ ├── deploy-update.yml # Deploy application updates
── rollback.yml # Rollback deployments
── 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
@@ -112,6 +115,23 @@ 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.
## Ansible Vault Operations
### View Encrypted File

View File

@@ -0,0 +1,284 @@
# WireGuard VPN Setup
WireGuard VPN-Server Installation und Konfiguration via Ansible.
## Übersicht
Dieses Ansible Setup installiert und konfiguriert einen WireGuard VPN-Server auf dem Production-Server, um sicheren Zugriff auf interne Services zu ermöglichen.
## Playbooks
### 1. setup-wireguard.yml
Installiert und konfiguriert den WireGuard VPN-Server.
**Features:**
- Installiert WireGuard und Tools
- Generiert Server-Keys (falls nicht vorhanden)
- Konfiguriert WireGuard-Server
- Aktiviert IP Forwarding
- Konfiguriert NAT (Masquerading)
- Öffnet Firewall-Port (51820/udp)
- Startet WireGuard-Service
**Verwendung:**
```bash
cd deployment/ansible
ansible-playbook -i inventory/production.yml playbooks/setup-wireguard.yml
```
**Variablen:**
- `wireguard_port`: Port für WireGuard (Standard: 51820)
- `wireguard_network`: VPN-Netzwerk (Standard: 10.8.0.0/24)
- `wireguard_server_ip`: Server-IP im VPN (Standard: 10.8.0.1)
**Beispiel mit Custom-Parametern:**
```bash
ansible-playbook -i inventory/production.yml playbooks/setup-wireguard.yml \
-e "wireguard_port=51820" \
-e "wireguard_network=10.8.0.0/24" \
-e "wireguard_server_ip=10.8.0.1"
```
### 2. add-wireguard-client.yml
Fügt einen neuen Client zum WireGuard-Server hinzu.
**Features:**
- Generiert Client-Keys
- Fügt Client zur Server-Config hinzu
- Erstellt Client-Konfigurationsdatei
- Generiert QR-Code (falls qrencode installiert)
- Restartet WireGuard-Service
**Verwendung:**
```bash
cd deployment/ansible
ansible-playbook -i inventory/production.yml playbooks/add-wireguard-client.yml \
-e "client_name=myclient"
```
**Optionale Parameter:**
- `client_ip`: Spezifische Client-IP (Standard: automatisch berechnet)
- `allowed_ips`: Erlaubte IP-Ranges (Standard: gesamtes VPN-Netzwerk)
**Beispiel mit spezifischer IP:**
```bash
ansible-playbook -i inventory/production.yml playbooks/add-wireguard-client.yml \
-e "client_name=myclient" \
-e "client_ip=10.8.0.2"
```
## Wichtige Sicherheitshinweise
### SSH-Zugriff bleibt verfügbar
**WICHTIG**: Die WireGuard-Konfiguration ändert NICHT die SSH-Zugriffsmöglichkeiten:
- ✅ SSH über die normale Server-IP bleibt vollständig funktionsfähig
- ✅ WireGuard routet standardmäßig nur das VPN-Netzwerk (10.8.0.0/24)
- ✅ Normale Internet-Routen werden nicht geändert
- ✅ Firewall-Regeln für SSH (Port 22) werden NICHT entfernt oder blockiert
Die Client-Konfiguration verwendet standardmäßig `AllowedIPs = 10.8.0.0/24`, was bedeutet, dass nur Traffic für das VPN-Netzwerk über WireGuard geroutet wird. Alle anderen Verbindungen (inkl. SSH) nutzen weiterhin die normale Internet-Verbindung.
**Um SSH komplett über VPN zu routen** (nicht empfohlen für die erste Installation):
```bash
ansible-playbook ... -e "allowed_ips=0.0.0.0/0"
```
## Verzeichnisstruktur
Nach der Installation:
```
/etc/wireguard/
├── wg0.conf # Server-Konfiguration
├── wg0_private.key # Server-Private-Key (600)
├── wg0_public.key # Server-Public-Key (644)
└── clients/ # Client-Konfigurationen
├── client1.conf # Client 1 Config
└── client2.conf # Client 2 Config
```
## Client-Konfiguration verwenden
### 1. Config-Datei auf Client kopieren
```bash
# Von Ansible Control Machine
scp -i ~/.ssh/production \
deploy@94.16.110.151:/etc/wireguard/clients/myclient.conf \
~/myclient.conf
```
### 2. WireGuard auf Client installieren
**Linux:**
```bash
sudo apt install wireguard wireguard-tools # Ubuntu/Debian
# oder
sudo yum install wireguard-tools # CentOS/RHEL
```
**macOS:**
```bash
brew install wireguard-tools
```
**Windows:**
Download von https://www.wireguard.com/install/
### 3. VPN verbinden
**Linux/macOS:**
```bash
sudo wg-quick up ~/myclient.conf
# oder
sudo wg-quick up myclient
```
**Windows:**
Importiere die `.conf`-Datei in die WireGuard-App.
### 4. Verbindung testen
```bash
# Ping zum Server
ping 10.8.0.1
# Status prüfen
sudo wg show
# VPN trennen
sudo wg-quick down myclient
```
## QR-Code für Mobile Client
Falls `qrencode` installiert ist, wird beim Hinzufügen eines Clients automatisch ein QR-Code angezeigt:
```bash
ansible-playbook -i inventory/production.yml playbooks/add-wireguard-client.yml \
-e "client_name=myphone"
```
Der QR-Code kann mit der WireGuard Mobile App (iOS/Android) gescannt werden.
## Firewall-Konfiguration
Das Playbook öffnet automatisch den WireGuard-Port (51820/udp) in UFW, falls installiert.
**Manuelle Firewall-Regeln:**
```bash
# UFW
sudo ufw allow 51820/udp comment 'WireGuard VPN'
# iptables direkt
sudo iptables -A INPUT -p udp --dport 51820 -j ACCEPT
```
## Troubleshooting
### WireGuard startet nicht
```bash
# Status prüfen
sudo systemctl status wg-quick@wg0
# Logs anzeigen
sudo journalctl -u wg-quick@wg0 -f
# Manuell starten
sudo wg-quick up wg0
```
### Client kann nicht verbinden
1. **Firewall prüfen:**
```bash
sudo ufw status
sudo iptables -L -n | grep 51820
```
2. **Server-Logs prüfen:**
```bash
sudo journalctl -u wg-quick@wg0 -f
```
3. **Server-Status prüfen:**
```bash
sudo wg show
```
4. **Routing prüfen:**
```bash
sudo ip route show
```
### IP Forwarding nicht aktiv
```bash
# Manuell aktivieren
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
# Permanent machen
echo 'net.ipv4.ip_forward=1' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
```
## Client entfernen
Um einen Client zu entfernen:
```bash
# Auf dem Server
sudo nano /etc/wireguard/wg0.conf
# Entferne den [Peer] Block für den Client
sudo wg-quick down wg0
sudo wg-quick up wg0
# Optional: Client-Config löschen
sudo rm /etc/wireguard/clients/clientname.conf
```
## Server-Public-Key abrufen
```bash
# Auf dem Server
cat /etc/wireguard/wg0_public.key
# oder
sudo cat /etc/wireguard/wg0_private.key | wg pubkey
```
## Best Practices
1. **Backup der Keys**: Speichere Server-Keys sicher:
```bash
sudo tar czf wireguard-backup.tar.gz /etc/wireguard/
```
2. **Regelmäßige Updates:**
```bash
sudo apt update && sudo apt upgrade wireguard wireguard-tools
```
3. **Monitoring**: Überwache VPN-Verbindungen:
```bash
sudo wg show
```
4. **Sicherheit**:
- Verwalte Client-Keys sicher
- Entferne nicht genutzte Clients
- Nutze starke Passwörter für Server-Zugriff
## Support
Bei Problemen:
1. Prüfe Logs: `sudo journalctl -u wg-quick@wg0`
2. Prüfe Status: `sudo wg show`
3. Prüfe Firewall: `sudo ufw status`
4. Teste Connectivity: `ping 10.8.0.1` (vom Client)

View File

@@ -0,0 +1,169 @@
---
- name: Add WireGuard Client
hosts: production
become: yes
gather_facts: yes
vars:
wireguard_interface: "wg0"
wireguard_config_path: "/etc/wireguard"
wireguard_config_file: "{{ wireguard_config_path }}/{{ wireguard_interface }}.conf"
wireguard_client_configs_path: "/etc/wireguard/clients"
pre_tasks:
- name: Set WireGuard network
set_fact:
wireguard_network: "{{ wireguard_network | default('10.8.0.0/24') }}"
- name: Set WireGuard other variables with defaults
set_fact:
wireguard_port: "{{ wireguard_port | default(51820) }}"
client_ip: "{{ client_ip | default('') }}"
# IMPORTANT: Default to VPN network only (not 0.0.0.0/0)
# This ensures SSH access via normal IP remains available
allowed_ips: "{{ allowed_ips | default(wireguard_network) }}"
tasks:
- name: Validate client name
fail:
msg: "client_name is required. Usage: ansible-playbook ... -e 'client_name=myclient'"
when: client_name is not defined or client_name == ""
- name: Get server external IP address
uri:
url: https://api.ipify.org
return_content: yes
register: server_external_ip
changed_when: false
failed_when: false
- name: Set server external IP
set_fact:
server_external_ip_content: "{{ ansible_host | default(server_external_ip.content | default('')) }}"
- name: Check if WireGuard config exists
stat:
path: "{{ wireguard_config_file }}"
register: wireguard_config_exists
- name: Fail if WireGuard not configured
fail:
msg: "WireGuard server not configured. Please run setup-wireguard.yml first."
when: not wireguard_config_exists.stat.exists
- name: Read WireGuard server config
slurp:
src: "{{ wireguard_config_file }}"
register: wireguard_server_config_read
- name: Extract server IP from config
set_fact:
server_vpn_ip: "{{ (wireguard_server_config_read.content | b64decode | regex_search('Address = ([0-9.]+)', '\\1')) | first | default('10.8.0.1') }}"
- name: Count existing clients in config
set_fact:
existing_clients_count: "{{ (wireguard_server_config_read.content | b64decode | regex_findall('\\[Peer\\]') | length) }}"
when: client_ip == ""
- name: Calculate client IP if not provided
set_fact:
client_ip: "{{ server_vpn_ip | regex_replace('^(\\d+\\.\\d+\\.\\d+\\.)\\d+$', '\\1') }}{{ (server_vpn_ip | regex_replace('^(\\d+\\.\\d+\\.\\d+\\.)(\\d+)', '\\2') | int) + (existing_clients_count | default(1)) | int }}"
when: client_ip == ""
- name: Generate client private key
command: "wg genkey"
register: client_private_key
changed_when: true
no_log: yes
- name: Generate client public key
command: "wg pubkey"
args:
stdin: "{{ client_private_key.stdout }}"
register: client_public_key
changed_when: false
no_log: yes
- name: Check if client already exists in config
shell: "grep -q '{{ client_name }}' {{ wireguard_config_file }} || echo 'not found'"
register: client_exists_check
changed_when: false
failed_when: false
- name: Add client to WireGuard server config
blockinfile:
path: "{{ wireguard_config_file }}"
block: |
# Client: {{ client_name }}
[Peer]
PublicKey = {{ client_public_key.stdout }}
AllowedIPs = {{ client_ip }}/32
marker: "# {mark} ANSIBLE MANAGED BLOCK - Client: {{ client_name }}"
when: "'not found' in client_exists_check.stdout"
- name: Ensure client configs directory exists
file:
path: "{{ wireguard_client_configs_path }}"
state: directory
mode: '0700'
owner: root
group: root
- name: Get server public key
shell: "cat {{ wireguard_config_path }}/{{ wireguard_interface }}_private.key | wg pubkey"
register: server_public_key_cmd
changed_when: false
no_log: yes
failed_when: false
- name: Create client configuration file
template:
src: "{{ playbook_dir }}/../templates/wireguard-client.conf.j2"
dest: "{{ wireguard_client_configs_path }}/{{ client_name }}.conf"
mode: '0600'
owner: root
group: root
- name: Read WireGuard server config to find server IP
slurp:
src: "{{ wireguard_config_file }}"
register: wireguard_server_config_read
- name: Restart WireGuard service
systemd:
name: "wg-quick@{{ wireguard_interface }}"
state: restarted
when: "'not found' in client_exists_check.stdout"
- name: Display client configuration
debug:
msg: |
========================================
WireGuard Client Added: {{ client_name }}
========================================
Client Configuration File:
{{ wireguard_client_configs_path }}/{{ client_name }}.conf
Client IP: {{ client_ip }}
Server Endpoint: {{ server_external_ip_content }}:{{ wireguard_port }}
To use this configuration:
1. Copy the config file to your client machine
2. Install WireGuard client
3. Run: sudo wg-quick up {{ client_name }}
Or scan the QR code (if qrencode installed):
qrencode -t ansiutf8 < {{ wireguard_client_configs_path }}/{{ client_name }}.conf
========================================
- name: Generate QR code for client config
command: "qrencode -t ansiutf8 -r {{ wireguard_client_configs_path }}/{{ client_name }}.conf"
register: qr_code
changed_when: false
failed_when: false
- name: Display QR code
debug:
msg: "{{ qr_code.stdout }}"
when: qr_code.rc == 0

View File

@@ -118,7 +118,7 @@
changed_when: false
ignore_errors: yes
?? - name: Get deployed image information
- name: Get deployed image information
shell: |
docker compose -f {{ app_stack_path }}/docker-compose.yml config | grep -E "^\s+image:" | head -1 | awk '{print $2}' || echo "unknown"
args:

View File

@@ -241,6 +241,138 @@
debug:
msg: "Gitea HTTPS check: {{ 'SUCCESS' if gitea_http_check.status == 200 else 'FAILED - Status: ' + (gitea_http_check.status|string) }}"
# 6. Deploy Application Stack
- name: Optionally load application secrets from vault
include_vars:
file: "{{ playbook_dir }}/../secrets/production.vault.yml"
no_log: yes
ignore_errors: yes
delegate_to: localhost
become: no
- name: Check if PostgreSQL .env exists
stat:
path: "{{ stacks_base_path }}/postgresql/.env"
register: postgres_env_file
changed_when: false
- name: Extract PostgreSQL password from .env file
shell: "grep '^POSTGRES_PASSWORD=' {{ stacks_base_path }}/postgresql/.env 2>/dev/null | cut -d'=' -f2- || echo ''"
register: postgres_password_from_file
changed_when: false
failed_when: false
when: postgres_env_file.stat.exists
no_log: yes
- name: Set application database password (from file, vault, or generate)
set_fact:
app_db_password: "{{ postgres_password_from_file.stdout if (postgres_env_file.stat.exists and postgres_password_from_file.stdout != '') else (vault_db_root_password | default(lookup('password', '/dev/null length=32 chars=ascii_letters,digits,punctuation'))) }}"
no_log: yes
- name: Set application redis password from vault or generate
set_fact:
app_redis_password: "{{ vault_redis_password | default(lookup('password', '/dev/null length=32 chars=ascii_letters,digits,punctuation')) }}"
- name: Ensure application stack directory exists
file:
path: "{{ stacks_base_path }}/application"
state: directory
mode: '0755'
- name: Create application stack .env file
template:
src: "{{ playbook_dir }}/../templates/application.env.j2"
dest: "{{ stacks_base_path }}/application/.env"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: '0600'
vars:
db_password: "{{ app_db_password }}"
db_user: "{{ db_user | default('postgres') }}"
db_name: "{{ db_name | default('michaelschiemer') }}"
redis_password: "{{ app_redis_password }}"
app_domain: "{{ app_domain | default('michaelschiemer.de') }}"
no_log: yes
- name: Deploy Application stack
community.docker.docker_compose_v2:
project_src: "{{ stacks_base_path }}/application"
state: present
pull: always
register: application_output
- name: Wait for Application to be ready
wait_for:
timeout: "{{ wait_timeout }}"
when: application_output.changed
- name: Wait for application containers to be healthy
pause:
seconds: 30
when: application_output.changed
- name: Check application container health status
shell: |
docker compose -f {{ stacks_base_path }}/application/docker-compose.yml ps --format json | jq -r '.[] | select(.Health != "healthy" and .Health != "" and .Health != "starting") | "\(.Name): \(.Health)"' || echo "All healthy or no health checks"
args:
executable: /bin/bash
register: app_health_status
changed_when: false
ignore_errors: yes
- name: Display application health status
debug:
msg: "Application health: {{ app_health_status.stdout if app_health_status.stdout != '' else 'All services healthy or starting' }}"
- name: Wait for app container to be ready before migration
wait_for:
timeout: 60
when: application_output.changed
- name: Check if app container is running
shell: |
docker compose -f {{ stacks_base_path }}/application/docker-compose.yml ps app | grep -q "Up" || exit 1
args:
executable: /bin/bash
register: app_container_running
changed_when: false
failed_when: false
when: application_output.changed
- name: Run database migrations
shell: |
docker compose -f {{ stacks_base_path }}/application/docker-compose.yml exec -T app php console.php db:migrate
args:
executable: /bin/bash
register: migration_result
changed_when: true
failed_when: false
ignore_errors: yes
when: application_output.changed and app_container_running.rc == 0
- name: Display migration result
debug:
msg: |
Migration Result:
{{ migration_result.stdout if migration_result.rc == 0 else 'Migration may have failed - check logs with: docker compose -f ' + stacks_base_path + '/application/docker-compose.yml logs app' }}
when: application_output.changed
- name: Verify application accessibility via HTTPS
uri:
url: "https://{{ app_domain | default('michaelschiemer.de') }}/health"
method: GET
validate_certs: no
status_code: [200, 404, 502, 503]
timeout: 10
register: app_health_check
ignore_errors: yes
when: application_output.changed
- name: Display application accessibility status
debug:
msg: "Application health check: {{ 'SUCCESS (HTTP ' + (app_health_check.status|string) + ')' if app_health_check.status == 200 else 'FAILED or not ready yet (HTTP ' + (app_health_check.status|string) + ')' }}"
when: application_output.changed
- name: Summary
debug:
msg:
@@ -250,9 +382,11 @@
- "Docker Registry: {{ 'Deployed' if registry_output.changed else 'Already running' }}"
- "Gitea: {{ 'Deployed' if gitea_output.changed else 'Already running' }}"
- "Monitoring: {{ 'Deployed' if monitoring_output.changed else 'Already running' }}"
- "Application: {{ 'Deployed' if application_output.changed else 'Already running' }}"
- ""
- "Next Steps:"
- "1. Access Gitea at: https://git.michaelschiemer.de"
- "2. Complete Gitea setup wizard if first-time deployment"
- "3. Navigate to Admin > Actions > Runners to get registration token"
- "4. Continue with Phase 1 - Gitea Runner Setup"
- "5. Access Application at: https://{{ app_domain | default('michaelschiemer.de') }}"

View File

@@ -0,0 +1,294 @@
---
- name: Setup WireGuard VPN Server
hosts: production
become: yes
gather_facts: yes
vars:
wireguard_interface: "wg0"
wireguard_config_path: "/etc/wireguard"
wireguard_config_file: "{{ wireguard_config_path }}/{{ wireguard_interface }}.conf"
wireguard_private_key_file: "{{ wireguard_config_path }}/{{ wireguard_interface }}_private.key"
wireguard_public_key_file: "{{ wireguard_config_path }}/{{ wireguard_interface }}_public.key"
wireguard_client_configs_path: "{{ wireguard_config_path }}/clients"
wireguard_enable_ip_forwarding: true
pre_tasks:
- name: Set WireGuard variables with defaults
set_fact:
wireguard_port: "{{ wireguard_port | default(51820) }}"
wireguard_network: "{{ wireguard_network | default('10.8.0.0/24') }}"
wireguard_server_ip: "{{ wireguard_server_ip | default('10.8.0.1') }}"
- name: Optionally load wireguard secrets from vault
include_vars:
file: "{{ playbook_dir }}/../secrets/production.vault.yml"
no_log: yes
ignore_errors: yes
delegate_to: localhost
become: no
tasks:
- name: Check if WireGuard is already installed
command: which wg
register: wireguard_installed
changed_when: false
failed_when: false
- name: Update package cache
apt:
update_cache: yes
cache_valid_time: 3600
when: not wireguard_installed.rc == 0
- name: Install WireGuard
apt:
name:
- wireguard
- wireguard-tools
- qrencode
state: present
when: not wireguard_installed.rc == 0
notify: restart wireguard
- name: Ensure WireGuard config directory exists
file:
path: "{{ wireguard_config_path }}"
state: directory
mode: '0700'
owner: root
group: root
- name: Ensure WireGuard client configs directory exists
file:
path: "{{ wireguard_client_configs_path }}"
state: directory
mode: '0700'
owner: root
group: root
- name: Check if WireGuard server keys exist
stat:
path: "{{ wireguard_private_key_file }}"
register: server_private_key_exists
- name: Generate WireGuard server private key
command: "wg genkey"
register: server_private_key
changed_when: true
when: not server_private_key_exists.stat.exists
no_log: yes
- name: Save WireGuard server private key
copy:
content: "{{ server_private_key.stdout }}"
dest: "{{ wireguard_private_key_file }}"
mode: '0600'
owner: root
group: root
when: not server_private_key_exists.stat.exists
no_log: yes
- name: Read WireGuard server private key
slurp:
src: "{{ wireguard_private_key_file }}"
register: server_private_key_content
when: server_private_key_exists.stat.exists
- name: Generate WireGuard server public key
command: "wg pubkey"
args:
stdin: "{{ server_private_key.stdout if not server_private_key_exists.stat.exists else server_private_key_content.content | b64decode | trim }}"
register: server_public_key
changed_when: false
when: not server_private_key_exists.stat.exists
no_log: yes
- name: Get existing server public key
shell: "cat {{ wireguard_private_key_file }} | wg pubkey"
register: existing_server_public_key
changed_when: false
when: server_private_key_exists.stat.exists
no_log: yes
failed_when: false
- name: Set server public key fact
set_fact:
server_public_key_value: "{{ server_public_key.stdout if not server_private_key_exists.stat.exists else existing_server_public_key.stdout }}"
- name: Save WireGuard server public key
copy:
content: "{{ server_public_key_value }}"
dest: "{{ wireguard_public_key_file }}"
mode: '0644'
owner: root
group: root
- name: Enable IP forwarding
sysctl:
name: net.ipv4.ip_forward
value: '1'
state: present
sysctl_set: yes
reload: yes
when: wireguard_enable_ip_forwarding
- name: Make IP forwarding persistent
lineinfile:
path: /etc/sysctl.conf
regexp: '^net\.ipv4\.ip_forward'
line: 'net.ipv4.ip_forward=1'
state: present
when: wireguard_enable_ip_forwarding
- name: Get server external IP address
uri:
url: https://api.ipify.org
return_content: yes
register: server_external_ip
changed_when: false
failed_when: false
- name: Set server external IP from inventory if API fails
set_fact:
server_external_ip_content: "{{ ansible_host | default(server_external_ip.content | default('')) }}"
when: server_external_ip.content is defined
- name: Get server external IP from ansible_host
set_fact:
server_external_ip_content: "{{ ansible_host }}"
when: server_external_ip.content is not defined
- name: Read server private key for config
slurp:
src: "{{ wireguard_private_key_file }}"
register: server_private_key_file_content
when: server_private_key_exists.stat.exists
- name: Set server private key for template (new key)
set_fact:
server_private_key_for_config: "{{ server_private_key.stdout }}"
when: not server_private_key_exists.stat.exists
- name: Set server private key for template (existing key)
set_fact:
server_private_key_for_config: "{{ server_private_key_file_content.content | b64decode | trim }}"
when: server_private_key_exists.stat.exists
- name: Get network interface name
shell: "ip route | grep default | awk '{print $5}' | head -1"
register: default_interface
changed_when: false
failed_when: false
- name: Set default interface
set_fact:
wireguard_interface_name: "{{ default_interface.stdout | default('eth0') }}"
- name: Check if WireGuard config exists
stat:
path: "{{ wireguard_config_file }}"
register: wireguard_config_exists
- name: Create WireGuard server configuration
template:
src: "{{ playbook_dir }}/../templates/wireguard-server.conf.j2"
dest: "{{ wireguard_config_file }}"
mode: '0600'
owner: root
group: root
notify: restart wireguard
- name: Check if WireGuard service is enabled
systemd:
name: "wg-quick@{{ wireguard_interface }}"
register: wireguard_service_status
failed_when: false
changed_when: false
- name: Enable WireGuard service
systemd:
name: "wg-quick@{{ wireguard_interface }}"
enabled: yes
daemon_reload: yes
when: not wireguard_service_status.status.ActiveState is defined or wireguard_service_status.status.ActiveState != 'active'
- name: Start WireGuard service
systemd:
name: "wg-quick@{{ wireguard_interface }}"
state: started
notify: restart wireguard
- name: Check if UFW firewall is installed
command: which ufw
register: ufw_installed
changed_when: false
failed_when: false
- name: Verify SSH access is allowed in UFW
command: "ufw status | grep -q '22/tcp' || echo 'SSH not found'"
register: ssh_ufw_check
changed_when: false
failed_when: false
when: ufw_installed.rc == 0
- name: Warn if SSH is not explicitly allowed
debug:
msg: |
?? WARNING: SSH (port 22) might not be explicitly allowed in UFW!
Please ensure SSH access is configured before proceeding.
Run: sudo ufw allow 22/tcp
when: ufw_installed.rc == 0 and 'SSH not found' in ssh_ufw_check.stdout
- name: Allow WireGuard port in UFW firewall
ufw:
rule: allow
port: "{{ wireguard_port }}"
proto: udp
comment: "WireGuard VPN"
when: ufw_installed.rc == 0
- name: Allow WireGuard port in UFW firewall (alternative)
shell: "ufw allow {{ wireguard_port }}/udp comment 'WireGuard VPN'"
when: ufw_installed.rc == 0
failed_when: false
changed_when: false
- name: Check WireGuard status
command: "wg show {{ wireguard_interface }}"
register: wireguard_status
changed_when: false
failed_when: false
- name: Display WireGuard status
debug:
msg: |
WireGuard Status:
{{ wireguard_status.stdout if wireguard_status.rc == 0 else 'WireGuard interface not active' }}
- name: Display server public key
debug:
msg: |
========================================
WireGuard Server Setup Complete!
========================================
Server Public Key:
{{ server_public_key_value }}
Server IP: {{ wireguard_server_ip }}
Server Endpoint: {{ server_external_ip_content }}:{{ wireguard_port }}
Network: {{ wireguard_network }}
To add a client, run:
ansible-playbook -i inventory/production.yml playbooks/add-wireguard-client.yml -e "client_name=myclient"
Client configs are stored in:
{{ wireguard_client_configs_path }}/
========================================
handlers:
- name: restart wireguard
systemd:
name: "wg-quick@{{ wireguard_interface }}"
state: restarted

View File

@@ -7,7 +7,7 @@
vault_db_password: "change-me-secure-db-password"
vault_db_root_password: "change-me-secure-root-password"
# Redis Credentials
# Application Stack Credentials
vault_redis_password: "change-me-secure-redis-password"
# Application Secrets

View File

@@ -0,0 +1,40 @@
# Application Stack Environment Configuration
# Generated by Ansible - DO NOT EDIT MANUALLY
# Timezone
TZ={{ timezone | default('Europe/Berlin') }}
# Application Domain
APP_DOMAIN={{ app_domain | default('michaelschiemer.de') }}
# Application Settings
APP_ENV={{ app_env | default('production') }}
APP_DEBUG={{ app_debug | default('false') }}
APP_URL=https://{{ app_domain | default('michaelschiemer.de') }}
# Database Configuration
# Using PostgreSQL from postgres stack
DB_HOST=postgres
DB_PORT={{ db_port | default('5432') }}
DB_NAME={{ db_name | default('michaelschiemer') }}
DB_USER={{ db_user | default('postgres') }}
DB_PASS={{ db_password }}
# Redis Configuration
# Redis runs in this stack
REDIS_PASSWORD={{ redis_password }}
# Cache Configuration
CACHE_DRIVER={{ cache_driver | default('redis') }}
CACHE_PREFIX={{ cache_prefix | default('app') }}
# Session Configuration
SESSION_DRIVER={{ session_driver | default('redis') }}
SESSION_LIFETIME={{ session_lifetime | default('120') }}
# Queue Worker Configuration
QUEUE_DRIVER={{ queue_driver | default('redis') }}
QUEUE_CONNECTION={{ queue_connection | default('default') }}
QUEUE_WORKER_SLEEP={{ queue_worker_sleep | default('3') }}
QUEUE_WORKER_TRIES={{ queue_worker_tries | default('3') }}
QUEUE_WORKER_TIMEOUT={{ queue_worker_timeout | default('60') }}

View File

@@ -17,4 +17,5 @@ GRAFANA_PLUGINS={{ grafana_plugins | default('') }}
# Prometheus BasicAuth
# Format: username:hashed_password
PROMETHEUS_AUTH={{ prometheus_auth }}
# Note: Dollar signs are escaped for Docker Compose ($$ becomes $)
PROMETHEUS_AUTH={{ prometheus_auth | replace('$', '$$') }}

View File

@@ -0,0 +1,27 @@
# WireGuard Client Configuration for {{ client_name }}
# Generated by Ansible - DO NOT EDIT MANUALLY
[Interface]
# Client private key
PrivateKey = {{ client_private_key.stdout }}
# Client IP address in VPN network
Address = {{ client_ip }}/24
# DNS server (optional)
DNS = 1.1.1.1, 8.8.8.8
[Peer]
# Server public key
PublicKey = {{ server_public_key_cmd.stdout }}
# Server endpoint
Endpoint = {{ server_external_ip_content }}:{{ wireguard_port }}
# Allowed IPs (routes through VPN)
# IMPORTANT: Only VPN network is routed through VPN by default
# SSH access via normal IP ({{ server_external_ip_content }}) remains available
AllowedIPs = {{ allowed_ips }}
# Keep connection alive
PersistentKeepalive = 25

View File

@@ -0,0 +1,22 @@
# WireGuard Server Configuration
# Generated by Ansible - DO NOT EDIT MANUALLY
[Interface]
# Server private key
PrivateKey = {{ server_private_key_for_config }}
# Server IP address in VPN network
Address = {{ wireguard_server_ip }}/24
# Port to listen on
ListenPort = {{ wireguard_port }}
# Enable NAT for VPN clients to access internet
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o {{ wireguard_interface_name }} -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o {{ wireguard_interface_name }} -j MASQUERADE
# Clients will be added here by the add-wireguard-client playbook
# Example:
# [Peer]
# PublicKey = <client_public_key>
# AllowedIPs = 10.8.0.2/32