Sanitized mirror from private repository - 2026-03-12 11:25:06 UTC
Some checks failed
Documentation / Build Docusaurus (push) Failing after 8s
Documentation / Deploy to GitHub Pages (push) Has been skipped

This commit is contained in:
Gitea Mirror Bot
2026-03-12 11:25:06 +00:00
commit a184aa99f6
1172 changed files with 299450 additions and 0 deletions

206
ansible/homelab/README.md Normal file
View File

@@ -0,0 +1,206 @@
# Homelab Ansible Playbooks
Automated deployment and management of all homelab services across all hosts.
## 📁 Directory Structure
```
ansible/homelab/
├── ansible.cfg # Ansible configuration
├── inventory.yml # All hosts inventory
├── site.yml # Master playbook
├── generate_playbooks.py # Script to regenerate playbooks from compose files
├── group_vars/ # Variables by group
│ ├── all.yml # Global variables
│ ├── synology.yml # Synology NAS specific
│ └── vms.yml # Virtual machines specific
├── host_vars/ # Variables per host (auto-generated)
│ ├── atlantis.yml # 53 services
│ ├── calypso.yml # 24 services
│ ├── homelab_vm.yml # 33 services
│ └── ...
├── playbooks/ # Individual playbooks
│ ├── common/ # Shared playbooks
│ │ ├── install_docker.yml
│ │ └── setup_directories.yml
│ ├── deploy_atlantis.yml
│ ├── deploy_calypso.yml
│ └── ...
└── roles/ # Reusable roles
├── docker_stack/ # Deploy docker-compose stacks
└── directory_setup/ # Create directory structures
```
## 🚀 Quick Start
### Prerequisites
- Ansible 2.12+
- SSH access to all hosts (via Tailscale)
- Python 3.8+
### Installation
```bash
pip install ansible
```
### Deploy Everything
```bash
cd ansible/homelab
ansible-playbook site.yml
```
### Deploy to Specific Host
```bash
ansible-playbook site.yml --limit atlantis
```
### Deploy by Category
```bash
# Deploy all Synology hosts
ansible-playbook site.yml --tags synology
# Deploy all VMs
ansible-playbook site.yml --tags vms
```
### Check Mode (Dry Run)
```bash
ansible-playbook site.yml --check --diff
```
## 📋 Host Inventory
| Host | Category | Services | Description |
|------|----------|----------|-------------|
| atlantis | synology | 53 | Primary NAS (DS1823xs+) |
| calypso | synology | 24 | Secondary NAS (DS920+) |
| setillo | synology | 2 | Remote NAS |
| guava | physical | 8 | TrueNAS Scale |
| concord_nuc | physical | 11 | Intel NUC |
| homelab_vm | vms | 33 | Primary VM |
| rpi5_vish | edge | 3 | Raspberry Pi 5 |
## 🔧 Configuration
### Vault Secrets
Sensitive data should be stored in Ansible Vault:
```bash
# Create vault password file (DO NOT commit this)
echo "your-vault-password" > .vault_pass
# Encrypt a variable
ansible-vault encrypt_string 'my-secret' --name 'api_key'
# Run playbook with vault
ansible-playbook site.yml --vault-password-file .vault_pass
```
### Environment Variables
Create a `.env` file for each service or use host_vars:
```yaml
# host_vars/atlantis.yml
vault_plex_claim_token: !vault |
$ANSIBLE_VAULT;1.1;AES256
...
```
## 📝 Adding New Services
### Method 1: Add docker-compose file
1. Add your `docker-compose.yml` to `hosts/<category>/<host>/<service>/`
2. Run the generator:
```bash
python3 generate_playbooks.py
```
### Method 2: Manual addition
1. Add service to `host_vars/<host>.yml`:
```yaml
host_services:
- name: my_service
stack_dir: my_service
compose_file: hosts/synology/atlantis/my_service.yaml
enabled: true
```
## 🏷️ Tags
| Tag | Description |
|-----|-------------|
| `synology` | All Synology NAS hosts |
| `vms` | All virtual machines |
| `physical` | Physical servers |
| `edge` | Edge devices (RPi, etc.) |
| `arr-suite` | Media management (Sonarr, Radarr, etc.) |
| `monitoring` | Prometheus, Grafana, etc. |
## 📊 Service Categories
### Media & Entertainment
- Plex, Jellyfin, Tautulli
- Sonarr, Radarr, Lidarr, Prowlarr
- Jellyseerr, Overseerr
### Productivity
- Paperless-ngx, Stirling PDF
- Joplin, Dokuwiki
- Syncthing
### Infrastructure
- Nginx Proxy Manager
- Traefik, Cloudflare Tunnel
- AdGuard Home, Pi-hole
### Monitoring
- Prometheus, Grafana
- Uptime Kuma, Dozzle
- Node Exporter
### Security
- Vaultwarden
- Authentik
- Headscale
## 🔄 Regenerating Playbooks
If you modify docker-compose files directly:
```bash
python3 generate_playbooks.py
```
This will:
1. Scan all `hosts/` directories for compose files
2. Update `host_vars/` with service lists
3. Regenerate individual host playbooks
4. Update the master `site.yml`
## 🐛 Troubleshooting
### Test connectivity
```bash
ansible all -m ping
```
### Test specific host
```bash
ansible atlantis -m ping
```
### Verbose output
```bash
ansible-playbook site.yml -vvv
```
### List tasks without running
```bash
ansible-playbook site.yml --list-tasks
```
## 📚 Resources
- [Ansible Documentation](https://docs.ansible.com/)
- [Docker Compose Reference](https://docs.docker.com/compose/compose-file/)
- [Tailscale Documentation](https://tailscale.com/kb/)

View File

@@ -0,0 +1,18 @@
[defaults]
inventory = inventory.yml
roles_path = roles
host_key_checking = False
retry_files_enabled = False
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts_cache
fact_caching_timeout = 86400
stdout_callback = yaml
interpreter_python = auto_silent
[privilege_escalation]
become = False
[ssh_connection]
pipelining = True
ssh_args = -o ControlMaster=auto -o ControlPersist=60s

View File

@@ -0,0 +1,296 @@
#!/usr/bin/env python3
"""
Generate Ansible playbooks from existing docker-compose files in the homelab repo.
This script scans the hosts/ directory and creates deployment playbooks.
"""
import os
import yaml
from pathlib import Path
from collections import defaultdict
REPO_ROOT = Path(__file__).parent.parent.parent
HOSTS_DIR = REPO_ROOT / "hosts"
ANSIBLE_DIR = Path(__file__).parent
PLAYBOOKS_DIR = ANSIBLE_DIR / "playbooks"
HOST_VARS_DIR = ANSIBLE_DIR / "host_vars"
# Mapping of directory names to ansible host names
HOST_MAPPING = {
"atlantis": "atlantis",
"calypso": "calypso",
"setillo": "setillo",
"guava": "guava",
"concord-nuc": "concord_nuc",
"anubis": "anubis",
"homelab-vm": "homelab_vm",
"chicago-vm": "chicago_vm",
"bulgaria-vm": "bulgaria_vm",
"contabo-vm": "contabo_vm",
"rpi5-vish": "rpi5_vish",
"tdarr-node": "tdarr_node",
}
# Host categories for grouping
HOST_CATEGORIES = {
"synology": ["atlantis", "calypso", "setillo"],
"physical": ["guava", "concord-nuc", "anubis"],
"vms": ["homelab-vm", "chicago-vm", "bulgaria-vm", "contabo-vm", "matrix-ubuntu-vm"],
"edge": ["rpi5-vish", "nvidia_shield"],
"proxmox": ["tdarr-node"],
}
def find_compose_files():
"""Find all docker-compose files in the hosts directory."""
compose_files = defaultdict(list)
for yaml_file in HOSTS_DIR.rglob("*.yaml"):
if ".git" in str(yaml_file):
continue
compose_files[yaml_file.parent].append(yaml_file)
for yml_file in HOSTS_DIR.rglob("*.yml"):
if ".git" in str(yml_file):
continue
compose_files[yml_file.parent].append(yml_file)
return compose_files
def get_host_from_path(file_path):
"""Extract REDACTED_APP_PASSWORD path."""
parts = file_path.relative_to(HOSTS_DIR).parts
# Structure: hosts/<category>/<host>/...
if len(parts) >= 2:
category = parts[0]
host = parts[1]
return category, host
return None, None
def extract_service_name(file_path):
"""Extract service name from file path."""
# Get the service name from parent directory or filename
if file_path.name in ["docker-compose.yml", "docker-compose.yaml"]:
return file_path.parent.name
else:
return file_path.stem.replace("-", "_").replace(".", "_")
def is_compose_file(file_path):
"""Check if file looks like a docker-compose file."""
try:
with open(file_path, 'r') as f:
content = yaml.safe_load(f)
if content and isinstance(content, dict):
return 'services' in content or 'version' in content
except:
pass
return False
def generate_service_vars(host, services):
"""Generate host_vars with service definitions."""
service_list = []
for service_path, service_name in services:
rel_path = service_path.relative_to(REPO_ROOT)
# Determine the stack directory name
if service_path.name in ["docker-compose.yml", "docker-compose.yaml"]:
stack_dir = service_path.parent.name
else:
stack_dir = service_name
service_entry = {
"name": service_name,
"stack_dir": stack_dir,
"compose_file": str(rel_path),
"enabled": True,
}
# Check for .env file
env_file = service_path.parent / ".env"
stack_env = service_path.parent / "stack.env"
if env_file.exists():
service_entry["env_file"] = str(env_file.relative_to(REPO_ROOT))
elif stack_env.exists():
service_entry["env_file"] = str(stack_env.relative_to(REPO_ROOT))
service_list.append(service_entry)
return service_list
def generate_host_playbook(host_name, ansible_host, services, category):
"""Generate a playbook for a specific host."""
# Create header comment
header = f"""---
# Deployment playbook for {host_name}
# Category: {category}
# Services: {len(services)}
#
# Usage:
# ansible-playbook playbooks/deploy_{ansible_host}.yml
# ansible-playbook playbooks/deploy_{ansible_host}.yml -e "stack_deploy=false"
# ansible-playbook playbooks/deploy_{ansible_host}.yml --check
"""
playbook = [
{
"name": f"Deploy services to {host_name}",
"hosts": ansible_host,
"gather_facts": True,
"vars": {
"services": "{{ host_services | default([]) }}"
},
"tasks": [
{
"name": "Display deployment info",
"ansible.builtin.debug": {
"msg": "Deploying {{ services | length }} services to {{ inventory_hostname }}"
}
},
{
"name": "Ensure docker data directory exists",
"ansible.builtin.file": {
"path": "{{ docker_data_path }}",
"state": "directory",
"mode": "0755"
}
},
{
"name": "Deploy each enabled service",
"ansible.builtin.include_role": {
"name": "docker_stack"
},
"vars": {
"stack_name": "{{ item.stack_dir }}",
"stack_compose_file": "{{ item.compose_file }}",
"stack_env_file": "{{ item.env_file | default(omit) }}"
},
"loop": "{{ services }}",
"loop_control": {
"label": "{{ item.name }}"
},
"when": "item.enabled | default(true)"
}
]
}
]
return header, playbook
def main():
"""Main function to generate all playbooks."""
print("=" * 60)
print("Generating Ansible Playbooks from Homelab Repository")
print("=" * 60)
# Ensure directories exist
PLAYBOOKS_DIR.mkdir(parents=True, exist_ok=True)
HOST_VARS_DIR.mkdir(parents=True, exist_ok=True)
# Find all compose files
compose_files = find_compose_files()
# Organize by host
hosts_services = defaultdict(list)
for directory, files in compose_files.items():
category, host = get_host_from_path(directory)
if not host:
continue
for f in files:
if is_compose_file(f):
service_name = extract_service_name(f)
hosts_services[(category, host)].append((f, service_name))
# Generate playbooks and host_vars
all_hosts = {}
for (category, host), services in sorted(hosts_services.items()):
ansible_host = HOST_MAPPING.get(host, host.replace("-", "_"))
print(f"\n[{category}/{host}] Found {len(services)} services:")
for service_path, service_name in services:
print(f" - {service_name}")
# Generate host_vars
service_vars = generate_service_vars(host, services)
host_vars = {
"host_services": service_vars
}
host_vars_file = HOST_VARS_DIR / f"{ansible_host}.yml"
with open(host_vars_file, 'w') as f:
f.write("---\n")
f.write(f"# Auto-generated host variables for {host}\n")
f.write(f"# Services deployed to this host\n\n")
yaml.dump(host_vars, f, default_flow_style=False, sort_keys=False)
# Generate individual host playbook
header, playbook = generate_host_playbook(host, ansible_host, services, category)
playbook_file = PLAYBOOKS_DIR / f"deploy_{ansible_host}.yml"
with open(playbook_file, 'w') as f:
f.write(header)
yaml.dump(playbook, f, default_flow_style=False, sort_keys=False)
all_hosts[ansible_host] = {
"category": category,
"host": host,
"services": len(services)
}
# Generate master playbook
master_playbook = [
{
"name": "Deploy all homelab services",
"hosts": "localhost",
"gather_facts": False,
"tasks": [
{
"name": "Display deployment plan",
"ansible.builtin.debug": {
"msg": "Deploying services to all hosts. Use --limit to target specific hosts."
}
}
]
}
]
# Add imports for each host
for ansible_host, info in sorted(all_hosts.items()):
master_playbook.append({
"name": f"Deploy to {info['host']} ({info['services']} services)",
"ansible.builtin.import_playbook": f"playbooks/deploy_{ansible_host}.yml",
"tags": [info['category'], ansible_host]
})
master_file = ANSIBLE_DIR / "site.yml"
with open(master_file, 'w') as f:
f.write("---\n")
f.write("# Master Homelab Deployment Playbook\n")
f.write("# Auto-generated from docker-compose files\n")
f.write("#\n")
f.write("# Usage:\n")
f.write("# Deploy everything: ansible-playbook site.yml\n")
f.write("# Deploy specific host: ansible-playbook site.yml --limit atlantis\n")
f.write("# Deploy by category: ansible-playbook site.yml --tags synology\n")
f.write("#\n\n")
yaml.dump(master_playbook, f, default_flow_style=False, sort_keys=False)
print(f"\n{'=' * 60}")
print(f"Generated playbooks for {len(all_hosts)} hosts")
print(f"Master playbook: {master_file}")
print("=" * 60)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,35 @@
---
# Global variables for all hosts
# Timezone
timezone: "America/Los_Angeles"
# Domain settings
base_domain: "vish.local"
external_domain: "vish.gg"
# Common labels for Docker containers
default_labels:
maintainer: "vish"
managed_by: "ansible"
# Docker restart policy
docker_restart_policy: "unless-stopped"
# Common network settings
docker_default_network: "proxy"
# Traefik settings (if used)
traefik_enabled: false
traefik_network: "proxy"
# Portainer settings
portainer_url: "http://vishinator.synology.me:10000"
# Monitoring settings
prometheus_enabled: true
grafana_enabled: true
# Backup settings
backup_enabled: true
backup_path: "/backup"

View File

@@ -0,0 +1,33 @@
---
# Synology NAS specific variables
# Docker path on Synology
docker_data_path: "/volume1/docker"
# Synology doesn't use sudo
ansible_become: false
# Docker socket location
docker_socket: "/var/run/docker.sock"
# PUID/PGID for Synology (typically admin user)
puid: 1026
pgid: 100
# Media paths
media_path: "/volume1/media"
downloads_path: "/volume1/downloads"
photos_path: "/volume1/photos"
documents_path: "/volume1/documents"
# Common volume mounts for arr suite
arr_common_volumes:
- "{{ downloads_path }}:/downloads"
- "{{ media_path }}/movies:/movies"
- "{{ media_path }}/tv:/tv"
- "{{ media_path }}/music:/music"
- "{{ media_path }}/anime:/anime"
# Synology specific ports (avoid conflicts with DSM)
port_range_start: 8000
port_range_end: 9999

View File

@@ -0,0 +1,20 @@
---
# Virtual machine specific variables
# Docker path on VMs
docker_data_path: "/opt/docker"
# Use sudo for privilege escalation
ansible_become: true
ansible_become_method: sudo
# Docker socket location
docker_socket: "/var/run/docker.sock"
# PUID/PGID for VMs (typically 1000:1000)
puid: 1000
pgid: 1000
# VM-specific port ranges
port_range_start: 3000
port_range_end: 9999

View File

@@ -0,0 +1,37 @@
---
# Auto-generated host variables for anubis
# Services deployed to this host
host_services:
- name: element
stack_dir: element
compose_file: hosts/physical/anubis/element.yml
enabled: true
- name: photoprism
stack_dir: photoprism
compose_file: hosts/physical/anubis/photoprism.yml
enabled: true
- name: draw_io
stack_dir: draw_io
compose_file: hosts/physical/anubis/draw.io.yml
enabled: true
- name: conduit
stack_dir: conduit
compose_file: hosts/physical/anubis/conduit.yml
enabled: true
- name: archivebox
stack_dir: archivebox
compose_file: hosts/physical/anubis/archivebox.yml
enabled: true
- name: chatgpt
stack_dir: chatgpt
compose_file: hosts/physical/anubis/chatgpt.yml
enabled: true
- name: pialert
stack_dir: pialert
compose_file: hosts/physical/anubis/pialert.yml
enabled: true
- name: proxitok
stack_dir: proxitok
compose_file: hosts/physical/anubis/proxitok.yml
enabled: true

View File

@@ -0,0 +1,219 @@
---
# Auto-generated host variables for atlantis
# Services deployed to this host
host_services:
- name: redlib
stack_dir: redlib
compose_file: hosts/synology/atlantis/redlib.yaml
enabled: true
- name: repo_nginx
stack_dir: repo_nginx
compose_file: hosts/synology/atlantis/repo_nginx.yaml
enabled: true
- name: fenrus
stack_dir: fenrus
compose_file: hosts/synology/atlantis/fenrus.yaml
enabled: true
- name: iperf3
stack_dir: iperf3
compose_file: hosts/synology/atlantis/iperf3.yaml
enabled: true
- name: vaultwarden
stack_dir: vaultwarden
compose_file: hosts/synology/atlantis/vaultwarden.yaml
enabled: true
- name: dynamicdnsupdater
stack_dir: dynamicdnsupdater
compose_file: hosts/synology/atlantis/dynamicdnsupdater.yaml
enabled: true
- name: wireguard
stack_dir: wireguard
compose_file: hosts/synology/atlantis/wireguard.yaml
enabled: true
- name: youtubedl
stack_dir: youtubedl
compose_file: hosts/synology/atlantis/youtubedl.yaml
enabled: true
- name: termix
stack_dir: termix
compose_file: hosts/synology/atlantis/termix.yaml
enabled: true
- name: cloudflare_tunnel
stack_dir: cloudflare_tunnel
compose_file: hosts/synology/atlantis/cloudflare-tunnel.yaml
enabled: true
- name: ntfy
stack_dir: ntfy
compose_file: hosts/synology/atlantis/ntfy.yml
enabled: true
- name: grafana
stack_dir: grafana
compose_file: hosts/synology/atlantis/grafana.yml
enabled: true
- name: it_tools
stack_dir: it_tools
compose_file: hosts/synology/atlantis/it_tools.yml
enabled: true
- name: calibre_books
stack_dir: calibre_books
compose_file: hosts/synology/atlantis/calibre-books.yml
enabled: true
- name: mastodon
stack_dir: mastodon
compose_file: hosts/synology/atlantis/mastodon.yml
enabled: true
- name: firefly
stack_dir: firefly
compose_file: hosts/synology/atlantis/firefly.yml
enabled: true
- name: invidious
stack_dir: invidious
compose_file: hosts/synology/atlantis/invidious.yml
enabled: true
- name: dokuwiki
stack_dir: dokuwiki
compose_file: hosts/synology/atlantis/dokuwiki.yml
enabled: true
- name: watchtower
stack_dir: watchtower
compose_file: hosts/synology/atlantis/watchtower.yml
enabled: true
- name: netbox
stack_dir: netbox
compose_file: hosts/synology/atlantis/netbox.yml
enabled: true
- name: llamagpt
stack_dir: llamagpt
compose_file: hosts/synology/atlantis/llamagpt.yml
enabled: true
- name: synapse
stack_dir: synapse
compose_file: hosts/synology/atlantis/synapse.yml
enabled: true
- name: uptimekuma
stack_dir: uptimekuma
compose_file: hosts/synology/atlantis/uptimekuma.yml
enabled: true
- name: matrix
stack_dir: matrix
compose_file: hosts/synology/atlantis/matrix.yml
enabled: true
- name: gitlab
stack_dir: gitlab
compose_file: hosts/synology/atlantis/gitlab.yml
enabled: true
- name: jdownloader2
stack_dir: jdownloader2
compose_file: hosts/synology/atlantis/jdownloader2.yml
enabled: true
- name: piped
stack_dir: piped
compose_file: hosts/synology/atlantis/piped.yml
enabled: true
- name: syncthing
stack_dir: syncthing
compose_file: hosts/synology/atlantis/syncthing.yml
enabled: true
- name: dockpeek
stack_dir: dockpeek
compose_file: hosts/synology/atlantis/dockpeek.yml
enabled: true
- name: paperlessngx
stack_dir: paperlessngx
compose_file: hosts/synology/atlantis/paperlessngx.yml
enabled: true
- name: stirlingpdf
stack_dir: stirlingpdf
compose_file: hosts/synology/atlantis/stirlingpdf.yml
enabled: true
- name: pihole
stack_dir: pihole
compose_file: hosts/synology/atlantis/pihole.yml
enabled: true
- name: joplin
stack_dir: joplin
compose_file: hosts/synology/atlantis/joplin.yml
enabled: true
- name: nginxproxymanager
stack_dir: nginxproxymanager
compose_file: hosts/synology/atlantis/nginxproxymanager/nginxproxymanager.yaml
enabled: true
- name: baikal
stack_dir: baikal
compose_file: hosts/synology/atlantis/baikal/baikal.yaml
enabled: true
- name: turnserver_docker_compose
stack_dir: turnserver_docker_compose
compose_file: hosts/synology/atlantis/matrix_synapse_docs/turnserver_docker_compose.yml
enabled: true
- name: whisparr
stack_dir: whisparr
compose_file: hosts/synology/atlantis/arr-suite/whisparr.yaml
enabled: true
- name: jellyseerr
stack_dir: jellyseerr
compose_file: hosts/synology/atlantis/arr-suite/jellyseerr.yaml
enabled: true
- name: sabnzbd
stack_dir: sabnzbd
compose_file: hosts/synology/atlantis/arr-suite/sabnzbd.yaml
enabled: true
- name: arrs_compose
stack_dir: arrs_compose
compose_file: hosts/synology/atlantis/arr-suite/docker-compose.yml
enabled: true
- name: wizarr
stack_dir: wizarr
compose_file: hosts/synology/atlantis/arr-suite/wizarr.yaml
enabled: true
- name: prowlarr_flaresolverr
stack_dir: prowlarr_flaresolverr
compose_file: hosts/synology/atlantis/arr-suite/prowlarr_flaresolverr.yaml
enabled: true
- name: plex
stack_dir: plex
compose_file: hosts/synology/atlantis/arr-suite/plex.yaml
enabled: true
- name: tautulli
stack_dir: tautulli
compose_file: hosts/synology/atlantis/arr-suite/tautulli.yaml
enabled: true
- name: homarr
stack_dir: homarr
compose_file: hosts/synology/atlantis/homarr/docker-compose.yaml
enabled: true
- name: atlantis_node_exporter
stack_dir: atlantis_node_exporter
compose_file: hosts/synology/atlantis/grafana_prometheus/atlantis_node_exporter.yaml
enabled: true
- name: monitoring_stack
stack_dir: monitoring_stack
compose_file: hosts/synology/atlantis/grafana_prometheus/monitoring-stack.yaml
enabled: true
- name: dozzle
stack_dir: dozzle
compose_file: hosts/synology/atlantis/dozzle/dozzle.yaml
enabled: true
- name: documenso
stack_dir: documenso
compose_file: hosts/synology/atlantis/documenso/documenso.yaml
enabled: true
- name: theme_park
stack_dir: theme_park
compose_file: hosts/synology/atlantis/theme-park/theme-park.yaml
enabled: true
- name: jitsi
stack_dir: jitsi
compose_file: hosts/synology/atlantis/jitsi/jitsi.yml
enabled: true
env_file: hosts/synology/atlantis/jitsi/.env
- name: immich
stack_dir: immich
compose_file: hosts/synology/atlantis/immich/docker-compose.yml
enabled: true
env_file: hosts/synology/atlantis/immich/stack.env
- name: ollama
stack_dir: ollama
compose_file: hosts/synology/atlantis/ollama/docker-compose.yml
enabled: true

View File

@@ -0,0 +1,45 @@
---
# Auto-generated host variables for bulgaria-vm
# Services deployed to this host
host_services:
- name: mattermost
stack_dir: mattermost
compose_file: hosts/vms/bulgaria-vm/mattermost.yml
enabled: true
- name: nginx_proxy_manager
stack_dir: nginx_proxy_manager
compose_file: hosts/vms/bulgaria-vm/nginx_proxy_manager.yml
enabled: true
- name: navidrome
stack_dir: navidrome
compose_file: hosts/vms/bulgaria-vm/navidrome.yml
enabled: true
- name: invidious
stack_dir: invidious
compose_file: hosts/vms/bulgaria-vm/invidious.yml
enabled: true
- name: watchtower
stack_dir: watchtower
compose_file: hosts/vms/bulgaria-vm/watchtower.yml
enabled: true
- name: metube
stack_dir: metube
compose_file: hosts/vms/bulgaria-vm/metube.yml
enabled: true
- name: syncthing
stack_dir: syncthing
compose_file: hosts/vms/bulgaria-vm/syncthing.yml
enabled: true
- name: yourspotify
stack_dir: yourspotify
compose_file: hosts/vms/bulgaria-vm/yourspotify.yml
enabled: true
- name: fenrus
stack_dir: fenrus
compose_file: hosts/vms/bulgaria-vm/fenrus.yml
enabled: true
- name: rainloop
stack_dir: rainloop
compose_file: hosts/vms/bulgaria-vm/rainloop.yml
enabled: true

View File

@@ -0,0 +1,103 @@
---
# Auto-generated host variables for calypso
# Services deployed to this host
host_services:
- name: adguard
stack_dir: adguard
compose_file: hosts/synology/calypso/adguard.yaml
enabled: true
- name: gitea_server
stack_dir: gitea_server
compose_file: hosts/synology/calypso/gitea-server.yaml
enabled: true
- name: headscale
stack_dir: headscale
compose_file: hosts/synology/calypso/headscale.yaml
enabled: true
- name: arr_suite_wip
stack_dir: arr_suite_wip
compose_file: hosts/synology/calypso/arr-suite-wip.yaml
enabled: true
- name: rustdesk
stack_dir: rustdesk
compose_file: hosts/synology/calypso/rustdesk.yaml
enabled: true
- name: seafile_server
stack_dir: seafile_server
compose_file: hosts/synology/calypso/seafile-server.yaml
enabled: true
- name: wireguard_server
stack_dir: wireguard_server
compose_file: hosts/synology/calypso/wireguard-server.yaml
enabled: true
- name: openspeedtest
stack_dir: openspeedtest
compose_file: hosts/synology/calypso/openspeedtest.yaml
enabled: true
- name: syncthing
stack_dir: syncthing
compose_file: hosts/synology/calypso/syncthing.yaml
enabled: true
- name: gitea_runner
stack_dir: gitea_runner
compose_file: hosts/synology/calypso/gitea-runner.yaml
enabled: true
- name: node_exporter
stack_dir: node_exporter
compose_file: hosts/synology/calypso/node-exporter.yaml
enabled: true
- name: rackula
stack_dir: rackula
compose_file: hosts/synology/calypso/rackula.yml
enabled: true
- name: arr_suite_with_dracula
stack_dir: arr_suite_with_dracula
compose_file: hosts/synology/calypso/arr_suite_with_dracula.yml
enabled: true
- name: actualbudget
stack_dir: actualbudget
compose_file: hosts/synology/calypso/actualbudget.yml
enabled: true
- name: iperf3
stack_dir: iperf3
compose_file: hosts/synology/calypso/iperf3.yml
enabled: true
- name: prometheus
stack_dir: prometheus
compose_file: hosts/synology/calypso/prometheus.yml
enabled: true
- name: firefly
stack_dir: firefly
compose_file: hosts/synology/calypso/firefly/firefly.yaml
enabled: true
env_file: hosts/synology/calypso/firefly/stack.env
- name: tdarr-node
stack_dir: tdarr-node
compose_file: hosts/synology/calypso/tdarr-node/docker-compose.yaml
enabled: true
- name: authentik
stack_dir: authentik
compose_file: hosts/synology/calypso/authentik/docker-compose.yaml
enabled: true
- name: apt_cacher_ng
stack_dir: apt_cacher_ng
compose_file: hosts/synology/calypso/apt-cacher-ng/apt-cacher-ng.yml
enabled: true
- name: immich
stack_dir: immich
compose_file: hosts/synology/calypso/immich/docker-compose.yml
enabled: true
env_file: hosts/synology/calypso/immich/stack.env
- name: reactive_resume_v4
stack_dir: reactive_resume_v4
compose_file: hosts/synology/calypso/reactive_resume_v4/docker-compose.yml
enabled: true
- name: paperless_ai
stack_dir: paperless_ai
compose_file: hosts/synology/calypso/paperless/paperless-ai.yml
enabled: true
- name: paperless
stack_dir: paperless
compose_file: hosts/synology/calypso/paperless/docker-compose.yml
enabled: true

View File

@@ -0,0 +1,33 @@
---
# Auto-generated host variables for chicago-vm
# Services deployed to this host
host_services:
- name: watchtower
stack_dir: watchtower
compose_file: hosts/vms/chicago-vm/watchtower.yml
enabled: true
- name: matrix
stack_dir: matrix
compose_file: hosts/vms/chicago-vm/matrix.yml
enabled: true
- name: gitlab
stack_dir: gitlab
compose_file: hosts/vms/chicago-vm/gitlab.yml
enabled: true
- name: jdownloader2
stack_dir: jdownloader2
compose_file: hosts/vms/chicago-vm/jdownloader2.yml
enabled: true
- name: proxitok
stack_dir: proxitok
compose_file: hosts/vms/chicago-vm/proxitok.yml
enabled: true
- name: jellyfin
stack_dir: jellyfin
compose_file: hosts/vms/chicago-vm/jellyfin.yml
enabled: true
- name: neko
stack_dir: neko
compose_file: hosts/vms/chicago-vm/neko.yml
enabled: true

View File

@@ -0,0 +1,49 @@
---
# Auto-generated host variables for concord-nuc
# Services deployed to this host
host_services:
- name: adguard
stack_dir: adguard
compose_file: hosts/physical/concord-nuc/adguard.yaml
enabled: true
- name: yourspotify
stack_dir: yourspotify
compose_file: hosts/physical/concord-nuc/yourspotify.yaml
enabled: true
- name: wireguard
stack_dir: wireguard
compose_file: hosts/physical/concord-nuc/wireguard.yaml
enabled: true
- name: piped
stack_dir: piped
compose_file: hosts/physical/concord-nuc/piped.yaml
enabled: true
- name: syncthing
stack_dir: syncthing
compose_file: hosts/physical/concord-nuc/syncthing.yaml
enabled: true
- name: dyndns_updater
stack_dir: dyndns_updater
compose_file: hosts/physical/concord-nuc/dyndns_updater.yaml
enabled: true
- name: homeassistant
stack_dir: homeassistant
compose_file: hosts/physical/concord-nuc/homeassistant.yaml
enabled: true
- name: plex
stack_dir: plex
compose_file: hosts/physical/concord-nuc/plex.yaml
enabled: true
- name: node_exporter
stack_dir: node_exporter
compose_file: hosts/physical/concord-nuc/node-exporter.yaml
enabled: true
- name: invidious
stack_dir: invidious
compose_file: hosts/physical/concord-nuc/invidious/invidious.yaml
enabled: true
- name: invidious
stack_dir: invidious
compose_file: hosts/physical/concord-nuc/invidious/invidious_old/invidious.yaml
enabled: true

View File

@@ -0,0 +1,9 @@
---
# Auto-generated host variables for contabo-vm
# Services deployed to this host
host_services:
- name: ollama
stack_dir: ollama
compose_file: hosts/vms/contabo-vm/ollama/docker-compose.yml
enabled: true

View File

@@ -0,0 +1,9 @@
---
# Auto-generated host variables for guava
# Services deployed to this host
host_services:
- name: tdarr-node
stack_dir: tdarr-node
compose_file: hosts/truenas/guava/tdarr-node/docker-compose.yaml
enabled: true

View File

@@ -0,0 +1,137 @@
---
# Auto-generated host variables for homelab-vm
# Services deployed to this host
host_services:
- name: binternet
stack_dir: binternet
compose_file: hosts/vms/homelab-vm/binternet.yaml
enabled: true
- name: gitea_ntfy_bridge
stack_dir: gitea_ntfy_bridge
compose_file: hosts/vms/homelab-vm/gitea-ntfy-bridge.yaml
enabled: true
- name: alerting
stack_dir: alerting
compose_file: hosts/vms/homelab-vm/alerting.yaml
enabled: true
- name: libreddit
stack_dir: libreddit
compose_file: hosts/vms/homelab-vm/libreddit.yaml
enabled: true
- name: roundcube
stack_dir: roundcube
compose_file: hosts/vms/homelab-vm/roundcube.yaml
enabled: true
- name: ntfy
stack_dir: ntfy
compose_file: hosts/vms/homelab-vm/ntfy.yaml
enabled: true
- name: watchyourlan
stack_dir: watchyourlan
compose_file: hosts/vms/homelab-vm/watchyourlan.yaml
enabled: true
- name: l4d2_docker
stack_dir: l4d2_docker
compose_file: hosts/vms/homelab-vm/l4d2_docker.yaml
enabled: true
- name: proxitok
stack_dir: proxitok
compose_file: hosts/vms/homelab-vm/proxitok.yaml
enabled: true
- name: redlib
stack_dir: redlib
compose_file: hosts/vms/homelab-vm/redlib.yaml
enabled: true
- name: hoarder
stack_dir: hoarder
compose_file: hosts/vms/homelab-vm/hoarder.yaml
enabled: true
- name: roundcube_protonmail
stack_dir: roundcube_protonmail
compose_file: hosts/vms/homelab-vm/roundcube_protonmail.yaml
enabled: true
- name: perplexica
stack_dir: perplexica
compose_file: hosts/vms/homelab-vm/perplexica.yaml
enabled: true
- name: webcheck
stack_dir: webcheck
compose_file: hosts/vms/homelab-vm/webcheck.yaml
enabled: true
- name: archivebox
stack_dir: archivebox
compose_file: hosts/vms/homelab-vm/archivebox.yaml
enabled: true
- name: openhands
stack_dir: openhands
compose_file: hosts/vms/homelab-vm/openhands.yaml
enabled: true
- name: dashdot
stack_dir: dashdot
compose_file: hosts/vms/homelab-vm/dashdot.yaml
enabled: true
- name: satisfactory
stack_dir: satisfactory
compose_file: hosts/vms/homelab-vm/satisfactory.yaml
enabled: true
- name: paperminecraft
stack_dir: paperminecraft
compose_file: hosts/vms/homelab-vm/paperminecraft.yaml
enabled: true
- name: signal_api
stack_dir: signal_api
compose_file: hosts/vms/homelab-vm/signal_api.yaml
enabled: true
- name: cloudflare_tunnel
stack_dir: cloudflare_tunnel
compose_file: hosts/vms/homelab-vm/cloudflare-tunnel.yaml
enabled: true
- name: monitoring
stack_dir: monitoring
compose_file: hosts/vms/homelab-vm/monitoring.yaml
enabled: true
- name: drawio
stack_dir: drawio
compose_file: hosts/vms/homelab-vm/drawio.yml
enabled: true
- name: mattermost
stack_dir: mattermost
compose_file: hosts/vms/homelab-vm/mattermost.yml
enabled: true
- name: openproject
stack_dir: openproject
compose_file: hosts/vms/homelab-vm/openproject.yml
enabled: true
- name: ddns
stack_dir: ddns
compose_file: hosts/vms/homelab-vm/ddns.yml
enabled: true
- name: podgrab
stack_dir: podgrab
compose_file: hosts/vms/homelab-vm/podgrab.yml
enabled: true
- name: webcord
stack_dir: webcord
compose_file: hosts/vms/homelab-vm/webcord.yml
enabled: true
- name: syncthing
stack_dir: syncthing
compose_file: hosts/vms/homelab-vm/syncthing.yml
enabled: true
- name: shlink
stack_dir: shlink
compose_file: hosts/vms/homelab-vm/shlink.yml
enabled: true
- name: gotify
stack_dir: gotify
compose_file: hosts/vms/homelab-vm/gotify.yml
enabled: true
- name: node_exporter
stack_dir: node_exporter
compose_file: hosts/vms/homelab-vm/node-exporter.yml
enabled: true
- name: romm
stack_dir: romm
compose_file: hosts/vms/homelab-vm/romm/romm.yaml
enabled: true

View File

@@ -0,0 +1,9 @@
---
# Auto-generated host variables for lxc
# Services deployed to this host
host_services:
- name: tdarr-node
stack_dir: tdarr-node
compose_file: hosts/proxmox/lxc/tdarr-node/docker-compose.yaml
enabled: true

View File

@@ -0,0 +1,13 @@
---
# Auto-generated host variables for matrix-ubuntu-vm
# Services deployed to this host
host_services:
- name: mattermost
stack_dir: mattermost
compose_file: hosts/vms/matrix-ubuntu-vm/mattermost/docker-compose.yml
enabled: true
- name: mastodon
stack_dir: mastodon
compose_file: hosts/vms/matrix-ubuntu-vm/mastodon/docker-compose.yml
enabled: true

View File

@@ -0,0 +1,17 @@
---
# Auto-generated host variables for rpi5-vish
# Services deployed to this host
host_services:
- name: uptime_kuma
stack_dir: uptime_kuma
compose_file: hosts/edge/rpi5-vish/uptime-kuma.yaml
enabled: true
- name: glances
stack_dir: glances
compose_file: hosts/edge/rpi5-vish/glances.yaml
enabled: true
- name: immich
stack_dir: immich
compose_file: hosts/edge/rpi5-vish/immich/docker-compose.yml
enabled: true

View File

@@ -0,0 +1,13 @@
---
# Auto-generated host variables for setillo
# Services deployed to this host
host_services:
- name: compose
stack_dir: compose
compose_file: hosts/synology/setillo/prometheus/compose.yaml
enabled: true
- name: adguard_stack
stack_dir: adguard_stack
compose_file: hosts/synology/setillo/adguard/adguard-stack.yaml
enabled: true

View File

@@ -0,0 +1,116 @@
---
# Homelab Ansible Inventory
# All hosts are accessible via Tailscale IPs
all:
vars:
ansible_python_interpreter: /usr/bin/python3
docker_compose_version: "2"
children:
# Synology NAS devices
synology:
vars:
docker_data_path: /volume1/docker
ansible_become: false
docker_socket: /var/run/docker.sock
hosts:
atlantis:
ansible_host: 100.83.230.112
ansible_user: vish
ansible_port: 60000
hostname: atlantis.vish.local
description: "Primary NAS - Synology DS1823xs+"
calypso:
ansible_host: 100.103.48.78
ansible_user: vish
ansible_port: 62000
hostname: calypso.vish.local
description: "Secondary NAS - Synology DS920+"
setillo:
ansible_host: 100.125.0.20
ansible_user: vish
ansible_port: 22
hostname: setillo.vish.local
description: "Remote NAS - Synology"
# Physical servers
physical:
vars:
docker_data_path: /opt/docker
ansible_become: true
hosts:
guava:
ansible_host: 100.75.252.64
ansible_user: vish
hostname: guava.vish.local
description: "TrueNAS Scale Server"
docker_data_path: /mnt/pool/docker
concord_nuc:
ansible_host: 100.67.40.126
ansible_user: homelab
hostname: concord-nuc.vish.local
description: "Intel NUC"
anubis:
ansible_host: 100.100.100.100 # Update with actual IP
ansible_user: vish
hostname: anubis.vish.local
description: "Physical server"
# Virtual machines
vms:
vars:
docker_data_path: /opt/docker
ansible_become: true
hosts:
homelab_vm:
ansible_host: 100.67.40.126
ansible_user: homelab
hostname: homelab-vm.vish.local
description: "Primary VM"
chicago_vm:
ansible_host: 100.100.100.101 # Update with actual IP
ansible_user: vish
hostname: chicago-vm.vish.local
description: "Chicago VPS"
bulgaria_vm:
ansible_host: 100.100.100.102 # Update with actual IP
ansible_user: vish
hostname: bulgaria-vm.vish.local
description: "Bulgaria VPS"
contabo_vm:
ansible_host: 100.100.100.103 # Update with actual IP
ansible_user: vish
hostname: contabo-vm.vish.local
description: "Contabo VPS"
# Edge devices
edge:
vars:
docker_data_path: /opt/docker
ansible_become: true
hosts:
rpi5_vish:
ansible_host: 100.100.100.104 # Update with actual IP
ansible_user: vish
hostname: rpi5-vish.vish.local
description: "Raspberry Pi 5"
# Proxmox LXC containers
proxmox_lxc:
vars:
docker_data_path: /opt/docker
ansible_become: true
hosts:
tdarr_node:
ansible_host: 100.100.100.105 # Update with actual IP
ansible_user: root
hostname: tdarr-node.vish.local
description: "Tdarr transcoding node"

View File

@@ -0,0 +1,48 @@
---
# Backup all docker-compose configs and data
- name: Backup Docker configurations
hosts: "{{ target_host | default('all') }}"
gather_facts: true
vars:
backup_dest: "{{ backup_path | default('/backup') }}"
backup_timestamp: "{{ ansible_date_time.date }}_{{ ansible_date_time.hour }}{{ ansible_date_time.minute }}"
tasks:
- name: Create backup directory
ansible.builtin.file:
path: "{{ backup_dest }}/{{ inventory_hostname }}"
state: directory
mode: '0755'
become: "{{ ansible_become | default(false) }}"
delegate_to: localhost
- name: Find all docker-compose files
ansible.builtin.find:
paths: "{{ docker_data_path }}"
patterns: "docker-compose.yml,docker-compose.yaml,.env"
recurse: true
register: compose_files
- name: Archive docker configs
ansible.builtin.archive:
path: "{{ docker_data_path }}"
dest: "/tmp/{{ inventory_hostname }}_configs_{{ backup_timestamp }}.tar.gz"
format: gz
exclude_path:
- "*/data/*"
- "*/logs/*"
- "*/cache/*"
become: "{{ ansible_become | default(false) }}"
- name: Fetch backup to control node
ansible.builtin.fetch:
src: "/tmp/{{ inventory_hostname }}_configs_{{ backup_timestamp }}.tar.gz"
dest: "{{ backup_dest }}/{{ inventory_hostname }}/"
flat: true
- name: Clean up remote archive
ansible.builtin.file:
path: "/tmp/{{ inventory_hostname }}_configs_{{ backup_timestamp }}.tar.gz"
state: absent
become: "{{ ansible_become | default(false) }}"

View File

@@ -0,0 +1,55 @@
---
# Install Docker on a host (for non-Synology systems)
- name: Install Docker
hosts: "{{ target_host | default('all:!synology') }}"
become: true
gather_facts: true
tasks:
- name: Install prerequisites
ansible.builtin.apt:
name:
- apt-transport-https
- ca-certificates
- curl
- gnupg
- lsb-release
- python3-pip
state: present
update_cache: true
when: ansible_os_family == "Debian"
- name: Add Docker GPG key
ansible.builtin.apt_key:
url: https://download.docker.com/linux/{{ ansible_distribution | lower }}/gpg
state: present
when: ansible_os_family == "Debian"
- name: Add Docker repository
ansible.builtin.apt_repository:
repo: "deb https://download.docker.com/linux/{{ ansible_distribution | lower }} {{ ansible_distribution_release }} stable"
state: present
when: ansible_os_family == "Debian"
- name: Install Docker
ansible.builtin.apt:
name:
- docker-ce
- docker-ce-cli
- containerd.io
- docker-compose-plugin
state: present
update_cache: true
when: ansible_os_family == "Debian"
- name: Ensure Docker service is running
ansible.builtin.service:
name: docker
state: started
enabled: true
- name: Add user to docker group
ansible.builtin.user:
name: "{{ ansible_user }}"
groups: docker
append: true

View File

@@ -0,0 +1,27 @@
---
# View logs for a specific service
# Usage: ansible-playbook playbooks/common/logs.yml -e "service_name=plex" -e "target_host=atlantis"
- name: View service logs
hosts: "{{ target_host }}"
gather_facts: false
vars:
log_lines: 100
follow_logs: false
tasks:
- name: Validate service_name is provided
ansible.builtin.fail:
msg: "service_name variable is required. Use -e 'service_name=<name>'"
when: service_name is not defined
- name: Get service logs
ansible.builtin.command:
cmd: "docker compose logs --tail={{ log_lines }} {{ '--follow' if follow_logs else '' }}"
chdir: "{{ docker_data_path }}/{{ service_name }}"
register: logs_result
become: "{{ ansible_become | default(false) }}"
- name: Display logs
ansible.builtin.debug:
msg: "{{ logs_result.stdout }}"

View File

@@ -0,0 +1,23 @@
---
# Restart a specific service
# Usage: ansible-playbook playbooks/common/restart_service.yml -e "service_name=plex" -e "target_host=atlantis"
- name: Restart Docker service
hosts: "{{ target_host }}"
gather_facts: false
tasks:
- name: Validate service_name is provided
ansible.builtin.fail:
msg: "service_name variable is required. Use -e 'service_name=<name>'"
when: service_name is not defined
- name: Restart service
ansible.builtin.command:
cmd: docker compose restart
chdir: "{{ docker_data_path }}/{{ service_name }}"
register: restart_result
become: "{{ ansible_become | default(false) }}"
- name: Display result
ansible.builtin.debug:
msg: "Service {{ service_name }} restarted on {{ inventory_hostname }}"

View File

@@ -0,0 +1,34 @@
---
# Setup base directories for Docker services
- name: Setup Docker directories
hosts: "{{ target_host | default('all') }}"
gather_facts: true
tasks:
- name: Create base docker directory
ansible.builtin.file:
path: "{{ docker_data_path }}"
state: directory
mode: '0755'
become: "{{ ansible_become | default(false) }}"
- name: Create common directories
ansible.builtin.file:
path: "{{ docker_data_path }}/{{ item }}"
state: directory
mode: '0755'
loop:
- configs
- data
- logs
- backups
become: "{{ ansible_become | default(false) }}"
- name: Create service directories from host_services
ansible.builtin.file:
path: "{{ docker_data_path }}/{{ item.stack_dir }}"
state: directory
mode: '0755'
loop: "{{ host_services | default([]) }}"
when: host_services is defined
become: "{{ ansible_become | default(false) }}"

View File

@@ -0,0 +1,49 @@
---
# Check status of all Docker containers
- name: Check container status
hosts: "{{ target_host | default('all') }}"
gather_facts: true
tasks:
- name: Get list of running containers
ansible.builtin.command:
cmd: docker ps --format "table {{ '{{' }}.Names{{ '}}' }}\t{{ '{{' }}.Status{{ '}}' }}\t{{ '{{' }}.Image{{ '}}' }}"
register: docker_ps
changed_when: false
become: "{{ ansible_become | default(false) }}"
- name: Display running containers
ansible.builtin.debug:
msg: |
=== {{ inventory_hostname }} ===
{{ docker_ps.stdout }}
- name: Get stopped/exited containers
ansible.builtin.command:
cmd: docker ps -a --filter "status=exited" --format "table {{ '{{' }}.Names{{ '}}' }}\t{{ '{{' }}.Status{{ '}}' }}"
register: docker_exited
changed_when: false
become: "{{ ansible_become | default(false) }}"
- name: Display stopped containers
ansible.builtin.debug:
msg: |
=== Stopped containers on {{ inventory_hostname }} ===
{{ docker_exited.stdout }}
when: docker_exited.stdout_lines | length > 1
- name: Get disk usage
ansible.builtin.command:
cmd: docker system df
register: docker_df
changed_when: false
become: "{{ ansible_become | default(false) }}"
- name: Display disk usage
ansible.builtin.debug:
msg: |
=== Docker disk usage on {{ inventory_hostname }} ===
{{ docker_df.stdout }}

View File

@@ -0,0 +1,46 @@
---
# Update all Docker containers (pull new images and recreate)
- name: Update Docker containers
hosts: "{{ target_host | default('all') }}"
gather_facts: true
vars:
services: "{{ host_services | default([]) }}"
tasks:
- name: Display update info
ansible.builtin.debug:
msg: "Updating {{ services | length }} services on {{ inventory_hostname }}"
- name: Pull latest images for each service
ansible.builtin.command:
cmd: docker compose pull
chdir: "{{ docker_data_path }}/{{ item.stack_dir }}"
loop: "{{ services }}"
loop_control:
label: "{{ item.name }}"
when: item.enabled | default(true)
register: pull_result
changed_when: "'Downloaded' in pull_result.stdout"
failed_when: false
become: "{{ ansible_become | default(false) }}"
- name: Recreate containers with new images
ansible.builtin.command:
cmd: docker compose up -d --remove-orphans
chdir: "{{ docker_data_path }}/{{ item.stack_dir }}"
loop: "{{ services }}"
loop_control:
label: "{{ item.name }}"
when: item.enabled | default(true)
register: up_result
changed_when: "'Started' in up_result.stdout or 'Recreated' in up_result.stdout"
failed_when: false
become: "{{ ansible_become | default(false) }}"
- name: Clean up unused images
ansible.builtin.command:
cmd: docker image prune -af
when: prune_images | default(true)
changed_when: false
become: "{{ ansible_become | default(false) }}"

View File

@@ -0,0 +1,35 @@
---
# Deployment playbook for anubis
# Category: physical
# Services: 8
#
# Usage:
# ansible-playbook playbooks/deploy_anubis.yml
# ansible-playbook playbooks/deploy_anubis.yml -e "stack_deploy=false"
# ansible-playbook playbooks/deploy_anubis.yml --check
- name: Deploy services to anubis
hosts: anubis
gather_facts: true
vars:
services: '{{ host_services | default([]) }}'
tasks:
- name: Display deployment info
ansible.builtin.debug:
msg: Deploying {{ services | length }} services to {{ inventory_hostname }}
- name: Ensure docker data directory exists
ansible.builtin.file:
path: '{{ docker_data_path }}'
state: directory
mode: '0755'
- name: Deploy each enabled service
ansible.builtin.include_role:
name: docker_stack
vars:
stack_name: '{{ item.stack_dir }}'
stack_compose_file: '{{ item.compose_file }}'
stack_env_file: '{{ item.env_file | default(omit) }}'
loop: '{{ services }}'
loop_control:
label: '{{ item.name }}'
when: item.enabled | default(true)

View File

@@ -0,0 +1,35 @@
---
# Deployment playbook for atlantis
# Category: synology
# Services: 53
#
# Usage:
# ansible-playbook playbooks/deploy_atlantis.yml
# ansible-playbook playbooks/deploy_atlantis.yml -e "stack_deploy=false"
# ansible-playbook playbooks/deploy_atlantis.yml --check
- name: Deploy services to atlantis
hosts: atlantis
gather_facts: true
vars:
services: '{{ host_services | default([]) }}'
tasks:
- name: Display deployment info
ansible.builtin.debug:
msg: Deploying {{ services | length }} services to {{ inventory_hostname }}
- name: Ensure docker data directory exists
ansible.builtin.file:
path: '{{ docker_data_path }}'
state: directory
mode: '0755'
- name: Deploy each enabled service
ansible.builtin.include_role:
name: docker_stack
vars:
stack_name: '{{ item.stack_dir }}'
stack_compose_file: '{{ item.compose_file }}'
stack_env_file: '{{ item.env_file | default(omit) }}'
loop: '{{ services }}'
loop_control:
label: '{{ item.name }}'
when: item.enabled | default(true)

View File

@@ -0,0 +1,35 @@
---
# Deployment playbook for bulgaria-vm
# Category: vms
# Services: 10
#
# Usage:
# ansible-playbook playbooks/deploy_bulgaria_vm.yml
# ansible-playbook playbooks/deploy_bulgaria_vm.yml -e "stack_deploy=false"
# ansible-playbook playbooks/deploy_bulgaria_vm.yml --check
- name: Deploy services to bulgaria-vm
hosts: bulgaria_vm
gather_facts: true
vars:
services: '{{ host_services | default([]) }}'
tasks:
- name: Display deployment info
ansible.builtin.debug:
msg: Deploying {{ services | length }} services to {{ inventory_hostname }}
- name: Ensure docker data directory exists
ansible.builtin.file:
path: '{{ docker_data_path }}'
state: directory
mode: '0755'
- name: Deploy each enabled service
ansible.builtin.include_role:
name: docker_stack
vars:
stack_name: '{{ item.stack_dir }}'
stack_compose_file: '{{ item.compose_file }}'
stack_env_file: '{{ item.env_file | default(omit) }}'
loop: '{{ services }}'
loop_control:
label: '{{ item.name }}'
when: item.enabled | default(true)

View File

@@ -0,0 +1,35 @@
---
# Deployment playbook for calypso
# Category: synology
# Services: 24
#
# Usage:
# ansible-playbook playbooks/deploy_calypso.yml
# ansible-playbook playbooks/deploy_calypso.yml -e "stack_deploy=false"
# ansible-playbook playbooks/deploy_calypso.yml --check
- name: Deploy services to calypso
hosts: calypso
gather_facts: true
vars:
services: '{{ host_services | default([]) }}'
tasks:
- name: Display deployment info
ansible.builtin.debug:
msg: Deploying {{ services | length }} services to {{ inventory_hostname }}
- name: Ensure docker data directory exists
ansible.builtin.file:
path: '{{ docker_data_path }}'
state: directory
mode: '0755'
- name: Deploy each enabled service
ansible.builtin.include_role:
name: docker_stack
vars:
stack_name: '{{ item.stack_dir }}'
stack_compose_file: '{{ item.compose_file }}'
stack_env_file: '{{ item.env_file | default(omit) }}'
loop: '{{ services }}'
loop_control:
label: '{{ item.name }}'
when: item.enabled | default(true)

View File

@@ -0,0 +1,35 @@
---
# Deployment playbook for chicago-vm
# Category: vms
# Services: 7
#
# Usage:
# ansible-playbook playbooks/deploy_chicago_vm.yml
# ansible-playbook playbooks/deploy_chicago_vm.yml -e "stack_deploy=false"
# ansible-playbook playbooks/deploy_chicago_vm.yml --check
- name: Deploy services to chicago-vm
hosts: chicago_vm
gather_facts: true
vars:
services: '{{ host_services | default([]) }}'
tasks:
- name: Display deployment info
ansible.builtin.debug:
msg: Deploying {{ services | length }} services to {{ inventory_hostname }}
- name: Ensure docker data directory exists
ansible.builtin.file:
path: '{{ docker_data_path }}'
state: directory
mode: '0755'
- name: Deploy each enabled service
ansible.builtin.include_role:
name: docker_stack
vars:
stack_name: '{{ item.stack_dir }}'
stack_compose_file: '{{ item.compose_file }}'
stack_env_file: '{{ item.env_file | default(omit) }}'
loop: '{{ services }}'
loop_control:
label: '{{ item.name }}'
when: item.enabled | default(true)

View File

@@ -0,0 +1,35 @@
---
# Deployment playbook for concord-nuc
# Category: physical
# Services: 11
#
# Usage:
# ansible-playbook playbooks/deploy_concord_nuc.yml
# ansible-playbook playbooks/deploy_concord_nuc.yml -e "stack_deploy=false"
# ansible-playbook playbooks/deploy_concord_nuc.yml --check
- name: Deploy services to concord-nuc
hosts: concord_nuc
gather_facts: true
vars:
services: '{{ host_services | default([]) }}'
tasks:
- name: Display deployment info
ansible.builtin.debug:
msg: Deploying {{ services | length }} services to {{ inventory_hostname }}
- name: Ensure docker data directory exists
ansible.builtin.file:
path: '{{ docker_data_path }}'
state: directory
mode: '0755'
- name: Deploy each enabled service
ansible.builtin.include_role:
name: docker_stack
vars:
stack_name: '{{ item.stack_dir }}'
stack_compose_file: '{{ item.compose_file }}'
stack_env_file: '{{ item.env_file | default(omit) }}'
loop: '{{ services }}'
loop_control:
label: '{{ item.name }}'
when: item.enabled | default(true)

View File

@@ -0,0 +1,35 @@
---
# Deployment playbook for contabo-vm
# Category: vms
# Services: 1
#
# Usage:
# ansible-playbook playbooks/deploy_contabo_vm.yml
# ansible-playbook playbooks/deploy_contabo_vm.yml -e "stack_deploy=false"
# ansible-playbook playbooks/deploy_contabo_vm.yml --check
- name: Deploy services to contabo-vm
hosts: contabo_vm
gather_facts: true
vars:
services: '{{ host_services | default([]) }}'
tasks:
- name: Display deployment info
ansible.builtin.debug:
msg: Deploying {{ services | length }} services to {{ inventory_hostname }}
- name: Ensure docker data directory exists
ansible.builtin.file:
path: '{{ docker_data_path }}'
state: directory
mode: '0755'
- name: Deploy each enabled service
ansible.builtin.include_role:
name: docker_stack
vars:
stack_name: '{{ item.stack_dir }}'
stack_compose_file: '{{ item.compose_file }}'
stack_env_file: '{{ item.env_file | default(omit) }}'
loop: '{{ services }}'
loop_control:
label: '{{ item.name }}'
when: item.enabled | default(true)

View File

@@ -0,0 +1,35 @@
---
# Deployment playbook for guava
# Category: truenas
# Services: 1
#
# Usage:
# ansible-playbook playbooks/deploy_guava.yml
# ansible-playbook playbooks/deploy_guava.yml -e "stack_deploy=false"
# ansible-playbook playbooks/deploy_guava.yml --check
- name: Deploy services to guava
hosts: guava
gather_facts: true
vars:
services: '{{ host_services | default([]) }}'
tasks:
- name: Display deployment info
ansible.builtin.debug:
msg: Deploying {{ services | length }} services to {{ inventory_hostname }}
- name: Ensure docker data directory exists
ansible.builtin.file:
path: '{{ docker_data_path }}'
state: directory
mode: '0755'
- name: Deploy each enabled service
ansible.builtin.include_role:
name: docker_stack
vars:
stack_name: '{{ item.stack_dir }}'
stack_compose_file: '{{ item.compose_file }}'
stack_env_file: '{{ item.env_file | default(omit) }}'
loop: '{{ services }}'
loop_control:
label: '{{ item.name }}'
when: item.enabled | default(true)

View File

@@ -0,0 +1,35 @@
---
# Deployment playbook for homelab-vm
# Category: vms
# Services: 33
#
# Usage:
# ansible-playbook playbooks/deploy_homelab_vm.yml
# ansible-playbook playbooks/deploy_homelab_vm.yml -e "stack_deploy=false"
# ansible-playbook playbooks/deploy_homelab_vm.yml --check
- name: Deploy services to homelab-vm
hosts: homelab_vm
gather_facts: true
vars:
services: '{{ host_services | default([]) }}'
tasks:
- name: Display deployment info
ansible.builtin.debug:
msg: Deploying {{ services | length }} services to {{ inventory_hostname }}
- name: Ensure docker data directory exists
ansible.builtin.file:
path: '{{ docker_data_path }}'
state: directory
mode: '0755'
- name: Deploy each enabled service
ansible.builtin.include_role:
name: docker_stack
vars:
stack_name: '{{ item.stack_dir }}'
stack_compose_file: '{{ item.compose_file }}'
stack_env_file: '{{ item.env_file | default(omit) }}'
loop: '{{ services }}'
loop_control:
label: '{{ item.name }}'
when: item.enabled | default(true)

View File

@@ -0,0 +1,35 @@
---
# Deployment playbook for lxc
# Category: proxmox
# Services: 1
#
# Usage:
# ansible-playbook playbooks/deploy_lxc.yml
# ansible-playbook playbooks/deploy_lxc.yml -e "stack_deploy=false"
# ansible-playbook playbooks/deploy_lxc.yml --check
- name: Deploy services to lxc
hosts: lxc
gather_facts: true
vars:
services: '{{ host_services | default([]) }}'
tasks:
- name: Display deployment info
ansible.builtin.debug:
msg: Deploying {{ services | length }} services to {{ inventory_hostname }}
- name: Ensure docker data directory exists
ansible.builtin.file:
path: '{{ docker_data_path }}'
state: directory
mode: '0755'
- name: Deploy each enabled service
ansible.builtin.include_role:
name: docker_stack
vars:
stack_name: '{{ item.stack_dir }}'
stack_compose_file: '{{ item.compose_file }}'
stack_env_file: '{{ item.env_file | default(omit) }}'
loop: '{{ services }}'
loop_control:
label: '{{ item.name }}'
when: item.enabled | default(true)

View File

@@ -0,0 +1,35 @@
---
# Deployment playbook for matrix-ubuntu-vm
# Category: vms
# Services: 2
#
# Usage:
# ansible-playbook playbooks/deploy_matrix_ubuntu_vm.yml
# ansible-playbook playbooks/deploy_matrix_ubuntu_vm.yml -e "stack_deploy=false"
# ansible-playbook playbooks/deploy_matrix_ubuntu_vm.yml --check
- name: Deploy services to matrix-ubuntu-vm
hosts: matrix_ubuntu_vm
gather_facts: true
vars:
services: '{{ host_services | default([]) }}'
tasks:
- name: Display deployment info
ansible.builtin.debug:
msg: Deploying {{ services | length }} services to {{ inventory_hostname }}
- name: Ensure docker data directory exists
ansible.builtin.file:
path: '{{ docker_data_path }}'
state: directory
mode: '0755'
- name: Deploy each enabled service
ansible.builtin.include_role:
name: docker_stack
vars:
stack_name: '{{ item.stack_dir }}'
stack_compose_file: '{{ item.compose_file }}'
stack_env_file: '{{ item.env_file | default(omit) }}'
loop: '{{ services }}'
loop_control:
label: '{{ item.name }}'
when: item.enabled | default(true)

View File

@@ -0,0 +1,35 @@
---
# Deployment playbook for rpi5-vish
# Category: edge
# Services: 3
#
# Usage:
# ansible-playbook playbooks/deploy_rpi5_vish.yml
# ansible-playbook playbooks/deploy_rpi5_vish.yml -e "stack_deploy=false"
# ansible-playbook playbooks/deploy_rpi5_vish.yml --check
- name: Deploy services to rpi5-vish
hosts: rpi5_vish
gather_facts: true
vars:
services: '{{ host_services | default([]) }}'
tasks:
- name: Display deployment info
ansible.builtin.debug:
msg: Deploying {{ services | length }} services to {{ inventory_hostname }}
- name: Ensure docker data directory exists
ansible.builtin.file:
path: '{{ docker_data_path }}'
state: directory
mode: '0755'
- name: Deploy each enabled service
ansible.builtin.include_role:
name: docker_stack
vars:
stack_name: '{{ item.stack_dir }}'
stack_compose_file: '{{ item.compose_file }}'
stack_env_file: '{{ item.env_file | default(omit) }}'
loop: '{{ services }}'
loop_control:
label: '{{ item.name }}'
when: item.enabled | default(true)

View File

@@ -0,0 +1,35 @@
---
# Deployment playbook for setillo
# Category: synology
# Services: 2
#
# Usage:
# ansible-playbook playbooks/deploy_setillo.yml
# ansible-playbook playbooks/deploy_setillo.yml -e "stack_deploy=false"
# ansible-playbook playbooks/deploy_setillo.yml --check
- name: Deploy services to setillo
hosts: setillo
gather_facts: true
vars:
services: '{{ host_services | default([]) }}'
tasks:
- name: Display deployment info
ansible.builtin.debug:
msg: Deploying {{ services | length }} services to {{ inventory_hostname }}
- name: Ensure docker data directory exists
ansible.builtin.file:
path: '{{ docker_data_path }}'
state: directory
mode: '0755'
- name: Deploy each enabled service
ansible.builtin.include_role:
name: docker_stack
vars:
stack_name: '{{ item.stack_dir }}'
stack_compose_file: '{{ item.compose_file }}'
stack_env_file: '{{ item.env_file | default(omit) }}'
loop: '{{ services }}'
loop_control:
label: '{{ item.name }}'
when: item.enabled | default(true)

View File

@@ -0,0 +1,30 @@
---
# Directory Setup Role
# Creates necessary directories for Docker services
- name: Create base docker directory
ansible.builtin.file:
path: "{{ docker_data_path }}"
state: directory
mode: '0755'
when: create_base_dir | default(true)
- name: Create service directories
ansible.builtin.file:
path: "{{ docker_data_path }}/{{ item.name }}"
state: directory
mode: "{{ item.mode | default('0755') }}"
owner: "{{ item.owner | default(omit) }}"
group: "{{ item.group | default(omit) }}"
loop: "{{ service_directories | default([]) }}"
when: service_directories is defined
- name: Create nested service directories
ansible.builtin.file:
path: "{{ docker_data_path }}/{{ item.0.name }}/{{ item.1 }}"
state: directory
mode: "{{ item.0.mode | default('0755') }}"
owner: "{{ item.0.owner | default(omit) }}"
group: "{{ item.0.group | default(omit) }}"
loop: "{{ service_directories | default([]) | subelements('subdirs', skip_missing=True) }}"
when: service_directories is defined

View File

@@ -0,0 +1,6 @@
---
# Default variables for docker_stack role
stack_deploy: true
stack_pull_images: true
stack_health_wait: 10

View File

@@ -0,0 +1,107 @@
---
# Docker Stack Deployment Role
# Deploys docker-compose stacks to hosts
#
# Required variables:
# stack_name: Name of the stack/directory
# stack_compose_file: Path to the compose file (relative to repo root)
#
# Optional variables:
# stack_env_file: Path to .env file (relative to repo root)
# stack_config_files: List of additional config files to copy
# stack_deploy: Whether to deploy the stack (default: true)
# stack_pull_images: Whether to pull images first (default: true)
- name: Ensure stack directory exists
ansible.builtin.file:
path: "{{ docker_data_path }}/{{ stack_name }}"
state: directory
mode: '0755'
become: "{{ ansible_become | default(false) }}"
- name: Ensure stack subdirectories exist
ansible.builtin.file:
path: "{{ docker_data_path }}/{{ stack_name }}/{{ item }}"
state: directory
mode: '0755'
loop: "{{ stack_subdirs | default(['config', 'data']) }}"
become: "{{ ansible_become | default(false) }}"
- name: Copy docker-compose file from repo
ansible.builtin.copy:
src: "{{ playbook_dir }}/../../{{ stack_compose_file }}"
dest: "{{ docker_data_path }}/{{ stack_name }}/docker-compose.yml"
mode: '0644'
backup: true
register: compose_file_result
when: stack_compose_file is defined
become: "{{ ansible_become | default(false) }}"
- name: Copy docker-compose content directly
ansible.builtin.copy:
content: "{{ stack_compose_content }}"
dest: "{{ docker_data_path }}/{{ stack_name }}/docker-compose.yml"
mode: '0644'
backup: true
register: compose_content_result
when:
- stack_compose_content is defined
- stack_compose_file is not defined
become: "{{ ansible_become | default(false) }}"
- name: Copy environment file from repo
ansible.builtin.copy:
src: "{{ playbook_dir }}/../../{{ stack_env_file }}"
dest: "{{ docker_data_path }}/{{ stack_name }}/.env"
mode: '0600'
backup: true
when: stack_env_file is defined
become: "{{ ansible_become | default(false) }}"
- name: Copy environment content directly
ansible.builtin.copy:
content: "{{ stack_env_content }}"
dest: "{{ docker_data_path }}/{{ stack_name }}/.env"
mode: '0600'
when:
- stack_env_content is defined
- stack_env_file is not defined
become: "{{ ansible_become | default(false) }}"
- name: Copy additional config files
ansible.builtin.copy:
src: "{{ playbook_dir }}/../../{{ item.src }}"
dest: "{{ docker_data_path }}/{{ stack_name }}/{{ item.dest }}"
mode: "{{ item.mode | default('0644') }}"
backup: true
loop: "{{ stack_config_files | default([]) }}"
when: stack_config_files is defined
become: "{{ ansible_become | default(false) }}"
- name: Pull Docker images
ansible.builtin.command:
cmd: docker compose pull
chdir: "{{ docker_data_path }}/{{ stack_name }}"
register: pull_result
when: stack_pull_images | default(true)
changed_when: "'Downloaded' in pull_result.stdout"
failed_when: false
become: "{{ ansible_become | default(false) }}"
- name: Deploy stack with docker compose
ansible.builtin.command:
cmd: docker compose up -d --remove-orphans
chdir: "{{ docker_data_path }}/{{ stack_name }}"
register: deploy_result
when: stack_deploy | default(true)
changed_when:
- "'Started' in deploy_result.stdout or 'Created' in deploy_result.stdout"
- compose_file_result.changed | default(false) or compose_content_result.changed | default(false)
become: "{{ ansible_become | default(false) }}"
- name: Wait for stack to be healthy
ansible.builtin.pause:
seconds: "{{ stack_health_wait | default(5) }}"
when:
- stack_deploy | default(true)
- stack_health_wait | default(5) > 0

82
ansible/homelab/site.yml Normal file
View File

@@ -0,0 +1,82 @@
---
# Master Homelab Deployment Playbook
# Auto-generated from docker-compose files
#
# Usage:
# Deploy everything: ansible-playbook site.yml
# Deploy specific host: ansible-playbook site.yml --limit atlantis
# Deploy by category: ansible-playbook site.yml --tags synology
#
- name: Deploy all homelab services
hosts: localhost
gather_facts: false
tasks:
- name: Display deployment plan
ansible.builtin.debug:
msg: Deploying services to all hosts. Use --limit to target specific hosts.
- name: Deploy to anubis (8 services)
ansible.builtin.import_playbook: playbooks/deploy_anubis.yml
tags:
- physical
- anubis
- name: Deploy to atlantis (53 services)
ansible.builtin.import_playbook: playbooks/deploy_atlantis.yml
tags:
- synology
- atlantis
- name: Deploy to bulgaria-vm (10 services)
ansible.builtin.import_playbook: playbooks/deploy_bulgaria_vm.yml
tags:
- vms
- bulgaria_vm
- name: Deploy to calypso (24 services)
ansible.builtin.import_playbook: playbooks/deploy_calypso.yml
tags:
- synology
- calypso
- name: Deploy to chicago-vm (7 services)
ansible.builtin.import_playbook: playbooks/deploy_chicago_vm.yml
tags:
- vms
- chicago_vm
- name: Deploy to concord-nuc (11 services)
ansible.builtin.import_playbook: playbooks/deploy_concord_nuc.yml
tags:
- physical
- concord_nuc
- name: Deploy to contabo-vm (1 services)
ansible.builtin.import_playbook: playbooks/deploy_contabo_vm.yml
tags:
- vms
- contabo_vm
- name: Deploy to guava (1 services)
ansible.builtin.import_playbook: playbooks/deploy_guava.yml
tags:
- truenas
- guava
- name: Deploy to homelab-vm (33 services)
ansible.builtin.import_playbook: playbooks/deploy_homelab_vm.yml
tags:
- vms
- homelab_vm
- name: Deploy to lxc (1 services)
ansible.builtin.import_playbook: playbooks/deploy_lxc.yml
tags:
- proxmox
- lxc
- name: Deploy to matrix-ubuntu-vm (2 services)
ansible.builtin.import_playbook: playbooks/deploy_matrix_ubuntu_vm.yml
tags:
- vms
- matrix_ubuntu_vm
- name: Deploy to rpi5-vish (3 services)
ansible.builtin.import_playbook: playbooks/deploy_rpi5_vish.yml
tags:
- edge
- rpi5_vish
- name: Deploy to setillo (2 services)
ansible.builtin.import_playbook: playbooks/deploy_setillo.yml
tags:
- synology
- setillo