/
/
/
Ansible role that deployes services on my runner machine
1---
2# Runner Services Role Defaults
3# Multi-service container deployment with NFS integration
4
5# ==============================================================================
6# GENERAL SETTINGS
7# ==============================================================================
8runner_enabled: true
9# Legacy variables - no longer used with consolidated structure
10# runner_docker_dir: "/docker/runner" # Now each service uses /docker/[service]
11# runner_data_dir: "/docker/runner-data" # Now consolidated into each service directory
12runner_nfs_mount_dir: "/mnt/docker"
13runner_snapshot_dir: "{{ runner_nfs_mount_dir }}/frigate/snapshots"
14runner_user: "{{ ansible_user }}"
15runner_group: "users"
16runner_uid: 1000
17runner_gid: 1000
18
19# Timezone configuration
20runner_timezone: "{{ system_timezone }}"
21
22# Docker network for runner services
23runner_docker_network: "runner-network"
24runner_network_subnet: "172.20.0.0/16"
25
26# NFS Configuration
27runner_nfs_enabled: true
28runner_nas_host: "{{ vault_storage.nas_host | default('storage.home') }}"
29runner_nfs_options: "nfsvers=4.1,proto=tcp,hard,timeo=600,retrans=2,rsize=16777216,wsize=16777216,nconnect=8,noatime,_netdev"
30
31# ==============================================================================
32# NFS MOUNT CONFIGURATION
33# ==============================================================================
34runner_nfs_mounts:
35 - name: "frigate"
36 local_path: "{{ runner_nfs_mount_dir }}/frigate"
37 nfs_path: "/mnt/rstorage/cctv-data"
38 host: "{{ runner_nas_host }}"
39 options: "{{ runner_nfs_options }}"
40
41 - name: "immich"
42 local_path: "{{ runner_nfs_mount_dir }}/immich"
43 nfs_path: "/mnt/rstorage/media/pictures"
44 host: "{{ runner_nas_host }}"
45 options: "{{ runner_nfs_options }}"
46
47 - name: "forgejo"
48 local_path: "{{ runner_nfs_mount_dir }}/forgejo"
49 nfs_path: "/mnt/rstorage/code-repo"
50 host: "{{ runner_nas_host }}"
51 options: "{{ runner_nfs_options }}"
52
53 - name: "harbor"
54 local_path: "{{ runner_nfs_mount_dir }}/harbor"
55 nfs_path: "/mnt/rstorage/registry-data"
56 host: "{{ runner_nas_host }}"
57 options: "{{ runner_nfs_options }}"
58
59 - name: "cvat"
60 local_path: "{{ runner_nfs_mount_dir }}/cvat"
61 nfs_path: "/mnt/rstorage/cvat-datasets"
62 host: "{{ runner_nas_host }}"
63 options: "{{ runner_nfs_options }}"
64
65# ==============================================================================
66# SERVICE CONFIGURATIONS
67# ==============================================================================
68
69# LLM Stack - Unified Local AI Infrastructure
70llm_stack_enabled: true
71llm_stack_config_dir: "/docker/llm-stack"
72
73# Unified LLM Stack Configuration
74llm_stack_ollama_port: 9000
75llm_stack_openwebui_port: 9001
76llm_stack_litellm_port: 9002
77
78# Ollama - Local LLM Server
79llm_stack_ollama_data_dir: "{{ llm_stack_config_dir }}/ollama/data"
80# GPU configuration uses global gpu_enabled parameter
81llm_stack_ollama_default_model: "tinyllama"
82llm_stack_ollama_log_level: "info"
83
84# OpenWebUI - Web Interface for Ollama
85llm_stack_openwebui_data_dir: "{{ llm_stack_config_dir }}/openwebui/data"
86llm_stack_openwebui_name: "Local AI Assistant"
87llm_stack_openwebui_description: "Self-hosted AI chat interface"
88llm_stack_openwebui_author: "Home Assistant"
89llm_stack_openwebui_default_models: "tinyllama"
90llm_stack_openwebui_log_level: "info"
91
92# LiteLLM - Unified LLM Proxy
93llm_stack_litellm_data_dir: "{{ llm_stack_config_dir }}/litellm/data"
94llm_stack_litellm_model_list: "tinyllama"
95llm_stack_litellm_completion_model: "ollama/tinyllama"
96llm_stack_litellm_streaming_enabled: true
97llm_stack_litellm_log_level: "info"
98
99# Frigate - AI NVR System
100frigate_enabled: true
101frigate_port: 5000
102frigate_rtmp_port: 1935
103frigate_rtsp_port: 8554
104frigate_go2rtc_port: 1984
105frigate_config_dir: "/docker/frigate"
106frigate_data_dir: "{{ runner_nfs_mount_dir }}/frigate"
107frigate_mqtt_enabled: true
108mqtt_host: "homeassistant.home"
109mqtt_port: 1883
110frigate_hardware_acceleration: "vaapi" # vaapi, nvdec, nvenc, qsv, or none
111
112# Frigate ONVIF default settings
113frigate_onvif_autotracking: false
114
115# Frigate cameras configuration (from vault)
116frigate_cameras:
117 - name: "dining-room"
118 host: "{{ vault_runner.dining_room_camera_host | default('') }}"
119 username: "{{ vault_runner.dining_room_camera_user | default('') }}"
120 password: "{{ vault_runner.dining_room_camera_pass | default('') }}"
121 path: "/stream1"
122 port: 554
123 onvif_port: 2020
124 enabled: true
125
126 - name: "living-room"
127 host: "{{ vault_runner.living_room_camera_host | default('') }}"
128 username: "{{ vault_runner.living_room_camera_user | default('') }}"
129 password: "{{ vault_runner.living_room_camera_pass | default('') }}"
130 path: "/stream1"
131 port: 554
132 onvif_port: 2020
133 enabled: true
134
135 - name: "bed-room"
136 host: "{{ vault_runner.bed_room_camera_host | default('') }}"
137 username: "{{ vault_runner.bed_room_camera_user | default('') }}"
138 password: "{{ vault_runner.bed_room_camera_pass | default('') }}"
139 path: "/stream1"
140 port: 554
141 onvif_port: 2020
142 enabled: true
143
144 - name: "alina-office"
145 host: "{{ vault_runner.alina_office_camera_host | default('') }}"
146 username: "{{ vault_runner.alina_office_camera_user | default('') }}"
147 password: "{{ vault_runner.alina_office_camera_pass | default('') }}"
148 path: "/stream1"
149 port: 554
150 onvif_port: 2020
151 enabled: true
152
153 - name: "street-cam"
154 host: "{{ vault_runner.street_cam_host | default('') }}"
155 username: "{{ vault_runner.street_cam_user | default('') }}"
156 password: "{{ vault_runner.street_cam_pass | default('') }}"
157 path: "/stream1"
158 port: 554
159 onvif_port: 2020
160 enabled: true
161
162 - name: "pi-cam"
163 host: "{{ vault_runner.pi_cam_host | default('') }}"
164 username: "{{ vault_runner.pi_cam_user | default('') }}"
165 password: "{{ vault_runner.pi_cam_pass | default('') }}"
166 path: "{{ vault_runner.pi_cam_path | default('/doorbell') }}"
167 port: 8554
168 enabled: true
169
170# Cameras with ONVIF support (for PTZ control)
171frigate_onvif_cameras:
172 - name: "dining-room"
173 host: "{{ vault_runner.dining_room_camera_host | default('') }}"
174 port: 2020
175 username: "{{ vault_runner.dining_room_camera_user | default('') }}"
176 password: "{{ vault_runner.dining_room_camera_pass | default('') }}"
177 - name: "living-room"
178 host: "{{ vault_runner.living_room_camera_host | default('') }}"
179 port: 2020
180 username: "{{ vault_runner.living_room_camera_user | default('') }}"
181 password: "{{ vault_runner.living_room_camera_pass | default('') }}"
182 - name: "bed-room"
183 host: "{{ vault_runner.bed_room_camera_host | default('') }}"
184 port: 2020
185 username: "{{ vault_runner.bed_room_camera_user | default('') }}"
186 password: "{{ vault_runner.bed_room_camera_pass | default('') }}"
187 - name: "alina-office"
188 host: "{{ vault_runner.alina_office_camera_host | default('') }}"
189 port: 2020
190 username: "{{ vault_runner.alina_office_camera_user | default('') }}"
191 password: "{{ vault_runner.alina_office_camera_pass | default('') }}"
192 - name: "street-cam"
193 host: "{{ vault_runner.street_cam_host | default('') }}"
194 port: 2020
195 username: "{{ vault_runner.street_cam_user | default('') }}"
196 password: "{{ vault_runner.street_cam_pass | default('') }}"
197
198# Cameras for snapshot capture
199frigate_snapshot_cameras:
200 - "living-room"
201 - "dining-room"
202 - "bed-room"
203 - "alina-office"
204 - "street-cam"
205 - "pi-cam"
206
207# Per-camera record override (cameras listed here have recording disabled)
208frigate_cameras_record_disabled:
209 - "bed-room"
210
211# Frigate profile system (home=record-only, away=full detection)
212frigate_profiles:
213 home:
214 detect_enabled: false
215 detectors_enabled: false
216 cameras:
217 - street-cam
218 - pi-cam
219 hwaccel_override_cameras:
220 - street-cam
221 - pi-cam
222 default_profile: false
223 away:
224 detect_enabled: true
225 detectors_enabled: true
226 cameras:
227 - living-room
228 - dining-room
229 - bed-room
230 - alina-office
231 - street-cam
232 - pi-cam
233 default_profile: true
234
235# Frigate manager service
236frigate_manager_enabled: true
237frigate_snapshot_interval_minutes: 30
238frigate_profile_switch_timeout: 120
239
240# Immich - Photo Management
241immich_enabled: true
242immich_server_port: 2283
243immich_ml_port: 3003
244immich_config_dir: "/docker/immich"
245immich_data_dir: "/docker/immich"
246immich_upload_dir: "{{ runner_nfs_mount_dir }}/immich/library"
247immich_db_name: "{{ vault_runner.postgres_db | default('') }}"
248immich_db_user: "{{ vault_runner.postgres_user | default('') }}"
249immich_redis_enabled: true
250immich_ml_enabled: true
251immich_facial_recognition: true
252immich_hardware_acceleration: "none" # none, vaapi, nvdec, nvenc, or qsv
253
254# External library mounts (read-only photo libraries from NFS)
255immich_external_libraries:
256 - name: "yannick"
257 host_path: "{{ runner_nfs_mount_dir }}/immich/yannick"
258 container_path: "/yannick"
259 - name: "alina"
260 host_path: "{{ runner_nfs_mount_dir }}/immich/alina"
261 container_path: "/alina"
262
263# Forgejo - Git Server
264forgejo_enabled: true
265forgejo_http_port: 3010
266forgejo_ssh_port: 2222
267forgejo_config_dir: "/docker/forgejo"
268forgejo_data_dir: "{{ runner_nfs_mount_dir }}/forgejo"
269forgejo_db_type: "sqlite3"
270forgejo_app_name: "Forgejo Git Service"
271forgejo_domain: "forgejo.home"
272forgejo_ssh_domain: "{{ ansible_default_ipv4.address }}"
273
274# Forgejo Runner Configuration
275forgejo_runner_enabled: true
276forgejo_runner_token: "{{ vault_runner.forgejo_runner_token | default('changeme') }}"
277forgejo_runner_name: "default-runner"
278forgejo_runner_capacity: 2
279forgejo_runner_loglevel: info
280forgejo_runner_base_image: ubuntu:22.04
281forgejo_runner_user: runner
282forgejo_runner_uid: 1000
283forgejo_runner_version: 9.1.1
284
285# Forgejo Ansible Runner (for running Ansible playbooks in CI)
286forgejo_ansible_runner_enabled: true
287forgejo_ansible_runner_token: "{{ vault_runner.forgejo_ansible_runner_token | default('changeme') }}"
288forgejo_ansible_runner_name: "ansible-runner"
289forgejo_ansible_runner_capacity: 1
290forgejo_ansible_runner_version: 9.1.1
291
292# Web Tools - PDF Processing, File Conversion, Data Analysis, Developer Utilities
293web_tools_enabled: true
294web_tools_config_dir: "/docker/web-tools"
295web_tools_data_dir: "/docker/web-tools"
296
297# Stirling-PDF
298web_tools_stirling_port: 8090
299web_tools_stirling_max_file_size: 100
300
301# ConvertX
302web_tools_convertx_port: 8091
303web_tools_convertx_jwt_secret: "{{ vault_runner.web_tools_convertx_jwt_secret | default('changeme-generate-a-real-secret') }}"
304web_tools_convertx_auto_delete_hours: 24
305
306# CyberChef
307web_tools_cyberchef_port: 8092
308
309# IT-Tools
310web_tools_it_tools_port: 8093
311
312# Tandoor - Recipe Manager
313tandoor_enabled: true
314tandoor_port: 8010
315tandoor_config_dir: "/docker/tandoor"
316tandoor_data_dir: "/docker/tandoor"
317tandoor_media_dir: "{{ tandoor_data_dir }}/media"
318tandoor_static_dir: "{{ tandoor_data_dir }}/static"
319tandoor_db_engine: "django.db.backends.postgresql"
320
321# Ghost CMS - Headless CMS
322ghost_enabled: true
323ghost_port: 2368
324ghost_config_dir: "/docker/ghost"
325ghost_data_dir: "/docker/ghost"
326ghost_content_dir: "{{ ghost_data_dir }}/content"
327ghost_db_client: "mysql"
328ghost_db_host: "ghost-mysql"
329ghost_db_name: "ghost"
330ghost_db_user: "ghost"
331ghost_url: "http://ghost.home"
332
333cvat_config_dir: "/docker/cvat"
334# CVAT - Data labeling
335cvat_enabled: true
336
337cvat_repo_url: "https://github.com/cvat-ai/cvat.git"
338cvat_repo_version: "{{ cvat_image_tag }}"
339
340cvat_admin_username: admin
341cvat_admin_password: "{{ vault_runner.cvat_admin_password | default('change-me') }}"
342cvat_admin_email: "{{ vault_runner.cvat_admin_email | default('change-me') }}"
343
344# Networking / access
345cvat_domain: "cvat.home" # used by Traefik routing in CVAT compose
346cvat_http_port: 8990 # Traefik "web" entrypoint in the default compose
347cvat_https_enabled: false # add CVAT's https overlay when true
348
349cvat_share_dir: >-
350 {{ (runner_nfs_mounts
351 | selectattr('name','equalto','cvat')
352 | map(attribute='local_path')
353 | first)
354 | default(runner_nfs_mount_dir ~ '/cvat', true) }}
355
356# Versioning / images
357cvat_image_tag: "v2.44.3" # pulled via CVAT_VERSION; align with the git tag you run
358
359# Optional: serverless auto-annotation overlay (Nuclio/SAM/YOLO assist in CVAT)
360cvat_serverless_enabled: false
361
362# Optional: use an external Postgres instead of the bundled one
363cvat_external_db_enabled: false
364cvat_db_host: "postgres.internal"
365cvat_db_port: 5432
366cvat_db_name: "cvat"
367cvat_db_user: "cvat_user"
368cvat_db_password: "{{ vault_runner.cvat_db_password | default('change-me') }}"
369
370# Optional: expose Traefik dashboard (binds host port below)
371cvat_traefik_dashboard_enabled: false
372cvat_dashboard_port: 8899
373
374# Optional: GPU reservation for CVAT server container (you must have host GPU runtime ready)
375cvat_gpu_enabled: false
376cvat_gpu_driver: "nvidia"
377cvat_gpu_count: "all" # or a number like "1"
378
379# ==============================================================================
380# DATABASE CONFIGURATIONS
381# ==============================================================================
382
383# PostgreSQL (Immich)
384postgres_enabled: "{{ immich_enabled }}"
385postgres_config_dir: "/docker/immich/postgres"
386postgres_db: "{{ vault_runner.postgres_db | default('') }}"
387postgres_user: "{{ vault_runner.postgres_user | default('') }}"
388postgres_version: "14"
389
390# Redis (Immich)
391redis_enabled: "{{ immich_redis_enabled }}"
392redis_config_dir: "/docker/immich/redis"
393redis_port: 6379
394
395# MySQL (Ghost CMS)
396mysql_enabled: "{{ ghost_enabled }}"
397mysql_config_dir: "/docker/ghost/mysql"
398mysql_db: "{{ ghost_db_name }}"
399mysql_user: "{{ ghost_db_user }}"
400mysql_version: "8.0"
401
402# ==============================================================================
403# SECURITY SETTINGS (FROM VAULT)
404# ==============================================================================
405
406# Database passwords
407postgres_password: "{{ vault_runner.postgres_password | default('') }}"
408mysql_password: "{{ vault_runner.mysql_password | default('') }}"
409mysql_root_password: "{{ vault_runner.mysql_root_password | default('') }}"
410
411# Service secrets
412immich_jwt_secret: "{{ vault_runner.immich_jwt_secret | default('') }}"
413ghost_database_password: "{{ vault_runner.ghost_database_password | default('') }}"
414tandoor_secret_key: "{{ vault_runner.tandoor_secret_key | default('') }}"
415
416# MQTT credentials (from vault - top-level, shared across all roles)
417mqtt_username: ""
418mqtt_password: ""
419
420# ==============================================================================
421# DIRECTORY STRUCTURE
422# ==============================================================================
423
424# Local configuration directories
425runner_config_directories:
426 - "{{ llm_stack_config_dir }}"
427 - "{{ llm_stack_ollama_data_dir }}"
428 - "{{ llm_stack_openwebui_data_dir }}"
429 - "{{ llm_stack_litellm_data_dir }}"
430 - "{{ frigate_config_dir }}"
431 - "{{ immich_config_dir }}"
432 - "{{ immich_config_dir }}/postgres"
433 - "{{ immich_config_dir }}/redis"
434 - "{{ immich_config_dir }}/library"
435 - "{{ immich_config_dir }}/cache"
436 - "{{ immich_config_dir }}/model-cache"
437 - "{{ immich_config_dir }}/postgres-init"
438 - "{{ forgejo_config_dir }}"
439 - "{{ forgejo_config_dir }}/forgejo-runner-data"
440 - "{{ forgejo_config_dir }}/forgejo-ansible-runner-data"
441 - "{{ web_tools_config_dir }}"
442 - "{{ tandoor_config_dir }}"
443 - "{{ tandoor_data_dir }}/db"
444 - "{{ tandoor_data_dir }}/media"
445 - "{{ tandoor_data_dir }}/static"
446 - "{{ ghost_config_dir }}/config"
447 - "{{ ghost_config_dir }}/content"
448 - "{{ ghost_config_dir }}/mysql"
449
450# NFS mount directories
451runner_nfs_directories:
452 - "{{ runner_nfs_mount_dir }}"
453 - "{{ runner_nfs_mount_dir }}/frigate"
454 - "{{ runner_nfs_mount_dir }}/immich"
455 - "{{ runner_nfs_mount_dir }}/forgejo"
456 - "{{ runner_nfs_mount_dir }}/harbor"
457 - "{{ runner_nfs_mount_dir }}/cvat"
458
459# ==============================================================================
460# PERFORMANCE SETTINGS
461# ==============================================================================
462
463# Network performance tuning for NFS
464runner_performance_tuning_enabled: true
465runner_sysctl_settings:
466 # Extreme performance network buffers for Ryzen 7 + 32GB RAM
467 net.core.rmem_max: 268435456 # 256MB socket receive buffer
468 net.core.wmem_max: 268435456 # 256MB socket send buffer
469 net.core.rmem_default: 33554432 # 32MB default receive buffer
470 net.core.wmem_default: 33554432 # 32MB default send buffer
471 net.ipv4.tcp_rmem: "4096 131072 268435456" # TCP receive: 4KB min, 128KB default, 256MB max
472 net.ipv4.tcp_wmem: "4096 131072 268435456" # TCP send: 4KB min, 128KB default, 256MB max
473 net.core.netdev_max_backlog: 30000 # Handle high connection burst (32 connections)
474 net.ipv4.tcp_congestion_control: "bbr" # BBR congestion control
475 net.ipv4.tcp_window_scaling: 1 # Enable TCP window scaling
476 net.ipv4.tcp_timestamps: 1 # Enable TCP timestamps for RTT calculation
477 net.ipv4.tcp_sack: 1 # Enable selective acknowledgments
478 # NFS client cache tuning for 32GB RAM
479 vm.dirty_background_ratio: 3 # Start writeback at 3% (more aggressive)
480 vm.dirty_ratio: 8 # Force writeback at 8% (more aggressive)
481 vm.vfs_cache_pressure: 25 # Keep even more file cache (25% vs 50%)
482 vm.min_free_kbytes: 131072 # Keep 128MB free for network buffers
483
484# Harbor Configuration (external deployment)
485harbor_enabled: true
486harbor_config_dir: "/docker/harbor"
487harbor_version: "2.13.2"
488harbor_hostname: "{{ vault_runner.harbor_hostname | default('registry.local') }}"
489harbor_http_port: 8080
490harbor_registry_port: 5000
491harbor_admin_password: "{{ vault_runner.harbor_admin_password | default('changeme') }}"
492harbor_db_password: "{{ vault_runner.harbor_db_password | default('changeme') }}"
493harbor_data_volume: "{{ runner_nfs_mount_dir }}/harbor"
494
495# Docker resource limits
496default_memory_limit: "1g"
497default_cpu_limit: "1"
498
499# Health check configuration
500health_check_interval: "30s"
501health_check_timeout: "30s"
502health_check_retries: 5
503health_check_start_period: "60s"
504
505# ==============================================================================
506# SERVICE HEALTH ENDPOINTS
507# ==============================================================================
508service_endpoints:
509 ollama: "http://localhost:{{ llm_stack_ollama_port }}/api/tags"
510 openwebui: "http://localhost:{{ llm_stack_openwebui_port }}/api/health"
511 litellm: "http://localhost:{{ llm_stack_litellm_port }}/"
512 frigate: "http://localhost:{{ frigate_port }}/api/config"
513 immich: "http://localhost:{{ immich_server_port }}/api/server-info/ping"
514 forgejo: "http://localhost:{{ forgejo_http_port }}/api/v1/version"
515 stirling_pdf: "http://localhost:{{ web_tools_stirling_port }}/api/v1/info/status"
516 convertx: "http://localhost:{{ web_tools_convertx_port }}/"
517 cyberchef: "http://localhost:{{ web_tools_cyberchef_port }}/"
518 it_tools: "http://localhost:{{ web_tools_it_tools_port }}/"
519 tandoor: "http://localhost:{{ tandoor_port }}/accounts/login/"
520 ghost: "http://localhost:{{ ghost_port }}/ghost/api/admin/site/"
521
522# ==============================================================================
523# LOGGING CONFIGURATION
524# ==============================================================================
525logging_driver: "json-file"
526logging_max_size: "10m"
527logging_max_file: "3"
528
529# Service-specific logging levels (unified LLM stack uses llm_stack_* variables)
530# ollama_log_level: "info" # Now uses llm_stack_ollama_log_level
531# openwebui_log_level: "info" # Now uses llm_stack_openwebui_log_level
532# litellm_log_level: "info" # Now uses llm_stack_litellm_log_level
533frigate_log_level: "info"
534immich_log_level: "log"
535forgejo_log_level: "Info"
536ghost_logging: "info"
537
538