Move services.json into ansible
This commit is contained in:
		
							parent
							
								
									6548019090
								
							
						
					
					
						commit
						3fed27b42f
					
				
					 11 changed files with 188 additions and 153 deletions
				
			
		
							
								
								
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -2,6 +2,7 @@ | ||||||
| 
 | 
 | ||||||
| types-dnscontrol.d.ts | types-dnscontrol.d.ts | ||||||
| dns/hosts.json | dns/hosts.json | ||||||
|  | dns/services.json | ||||||
| 
 | 
 | ||||||
| secrets.auto.tfvars | secrets.auto.tfvars | ||||||
| .terraform | .terraform | ||||||
|  |  | ||||||
							
								
								
									
										24
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										24
									
								
								Makefile
									
										
									
									
									
								
							|  | @ -3,27 +3,33 @@ SHELL := /bin/bash | ||||||
| include .env | include .env | ||||||
| export
 | export
 | ||||||
| 
 | 
 | ||||||
| DNS_OUTPUT = "dns/hosts.json" | PWD := $(shell pwd) | ||||||
| SERVICES_OUTPUT = "inventory/group_vars/all/opentofu.yaml" |  | ||||||
| 
 | 
 | ||||||
| $(DNS_OUTPUT): | .FORCE: | ||||||
|  | 
 | ||||||
|  | ./dns/hosts.json: .FORCE | ||||||
| 	tofu output --json \
 | 	tofu output --json \
 | ||||||
| 		| jq 'with_entries(.value |= .value).hosts' \
 | 		| jq 'with_entries(.value |= .value).hosts' \
 | ||||||
| 		> $(DNS_OUTPUT) | 		> ./dns/hosts.json | ||||||
| 
 | 
 | ||||||
| $(SERVICES_OUTPUT): | ./dns/services.json: ./inventory/group_vars/all/all_services.yml | ||||||
|  | 	ansible-playbook \
 | ||||||
|  | 		-e services_json_file=$(PWD)/dns/services.json \
 | ||||||
|  | 		playbooks/create_services_for_dnscontrol.yml | ||||||
|  | 
 | ||||||
|  | ./inventory/group_vars/all/opentofu.yaml: .FORCE | ||||||
| 	tofu output --json \
 | 	tofu output --json \
 | ||||||
| 		| yq -y '{opentofu: with_entries(.value |= .value)}' \
 | 		| yq -y '{opentofu: with_entries(.value |= .value)}' \
 | ||||||
| 		> $(SERVICES_OUTPUT) | 		> ./inventory/group_vars/all/opentofu.yaml | ||||||
| 
 | 
 | ||||||
| outputs: $(DNS_OUTPUT) $(SERVICES_OUTPUT) | outputs: ./dns/hosts.json ./dns/services.json ./inventory/group_vars/all/opentofu.yaml | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| ./types-dnscontrol.d.ts: | ./types-dnscontrol.d.ts: | ||||||
| 	dnscontrol write-types | 	dnscontrol write-types | ||||||
| 
 | 
 | ||||||
| dns: $(DNS_OUTPUT) ./types-dnscontrol.d.ts | dns: ./types-dnscontrol.d.ts ./dns/hosts.json ./dns/services.json | ||||||
| 	dnscontrol push | 	dnscontrol push | ||||||
| 
 | 
 | ||||||
| dns-check: $(DNS_OUTPUT) ./types-dnscontrol.d.ts | dns-check: ./types-dnscontrol.d.ts ./dns/hosts.json ./dns/services.json | ||||||
| 	dnscontrol check-creds ovh | 	dnscontrol check-creds ovh | ||||||
|  |  | ||||||
|  | @ -1,89 +0,0 @@ | ||||||
| { |  | ||||||
| 	"catch-all-serguzim.me": { |  | ||||||
| 		"target": "*", |  | ||||||
| 		"domain": "serguzim.me", |  | ||||||
| 		"host": "node002" |  | ||||||
| 	}, |  | ||||||
| 	"acme_dns": { |  | ||||||
| 		"target": "acme", |  | ||||||
| 		"domain": "serguzim.me", |  | ||||||
| 		"host": "node003" |  | ||||||
| 	}, |  | ||||||
| 	"authentik": { |  | ||||||
| 		"target": "auth", |  | ||||||
| 		"domain": "serguzim.me", |  | ||||||
| 		"host": "node002" |  | ||||||
| 	}, |  | ||||||
| 	"openfaas": { |  | ||||||
| 		"target": "faas", |  | ||||||
| 		"domain": "serguzim.me", |  | ||||||
| 		"host": "node002" |  | ||||||
| 	}, |  | ||||||
| 	"mailcow": { |  | ||||||
| 		"target": "mail", |  | ||||||
| 		"domain": "serguzim.me", |  | ||||||
| 		"host": "node003" |  | ||||||
| 	}, |  | ||||||
| 	"synapse": { |  | ||||||
| 		"target": "matrix", |  | ||||||
| 		"domain": "serguzim.me", |  | ||||||
| 		"host": "node002" |  | ||||||
| 	}, |  | ||||||
| 	"linkwarden": { |  | ||||||
| 		"target": "bookmarks", |  | ||||||
| 		"domain": "serguzim.me", |  | ||||||
| 		"host": "node003" |  | ||||||
| 	}, |  | ||||||
| 	"minio": { |  | ||||||
| 		"target": "s3", |  | ||||||
| 		"domain": "serguzim.me", |  | ||||||
| 		"host": "node002" |  | ||||||
| 	}, |  | ||||||
| 	"minio-console": { |  | ||||||
| 		"target": "console.s3", |  | ||||||
| 		"domain": "serguzim.me", |  | ||||||
| 		"alias": "minio" |  | ||||||
| 	}, |  | ||||||
| 	"umami": { |  | ||||||
| 		"target": "analytics", |  | ||||||
| 		"domain": "serguzim.me", |  | ||||||
| 		"host": "node003" |  | ||||||
| 	}, |  | ||||||
| 	"webpage-serguzim.me": { |  | ||||||
| 		"target": "@", |  | ||||||
| 		"domain": "serguzim.me", |  | ||||||
| 		"alias": "openfaas" |  | ||||||
| 	}, |  | ||||||
| 	"wiki_js": { |  | ||||||
| 		"target": "wiki", |  | ||||||
| 		"domain": "serguzim.me", |  | ||||||
| 		"host": "node003" |  | ||||||
| 	}, |  | ||||||
| 
 |  | ||||||
| 	"synapse_msrg.cc": { |  | ||||||
| 		"target": "matrix", |  | ||||||
| 		"domain": "msrg.cc", |  | ||||||
| 		"alias": "synapse" |  | ||||||
| 	}, |  | ||||||
| 	"shlink": { |  | ||||||
| 		"target": "@", |  | ||||||
| 		"domain": "msrg.cc", |  | ||||||
| 		"host": "node002" |  | ||||||
| 	}, |  | ||||||
| 	"shlink-msvg.cc": { |  | ||||||
| 		"target": "@", |  | ||||||
| 		"domain": "msvg.cc", |  | ||||||
| 		"alias": "shlink" |  | ||||||
| 	}, |  | ||||||
| 
 |  | ||||||
| 	"reitanlage_oranienburg": { |  | ||||||
| 		"target": "@", |  | ||||||
| 		"domain": "reitanlage-oranienburg.de", |  | ||||||
| 		"host": "node002" |  | ||||||
| 	}, |  | ||||||
| 	"reitanlage_oranienburg-www": { |  | ||||||
| 		"target": "www", |  | ||||||
| 		"domain": "reitanlage-oranienburg.de", |  | ||||||
| 		"alias": "reitanlage_oranienburg" |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  | @ -1,58 +1,178 @@ | ||||||
| all_services: | all_services: | ||||||
|   - name: acme_dns |   - name: acme_dns | ||||||
|  |     host: node003 | ||||||
|  |     dns: | ||||||
|  |       - domain: serguzim.me | ||||||
|  |         target: acme | ||||||
|   - name: authentik |   - name: authentik | ||||||
|  |     host: node002 | ||||||
|  |     dns: | ||||||
|  |       - domain: serguzim.me | ||||||
|  |         target: auth | ||||||
|   - name: extra_services |   - name: extra_services | ||||||
|  |     host: node002 | ||||||
|  |     dns: | ||||||
|  |       - domain: serguzim.me | ||||||
|  |         target: "*" | ||||||
|   - name: faas |   - name: faas | ||||||
|  |     host: node002 | ||||||
|  |     dns: | ||||||
|  |       - domain: serguzim.me | ||||||
|  |         target: faas | ||||||
|  |       - domain: serguzim.me | ||||||
|  |         target: "@" | ||||||
|  |         name: webpage-serguzim | ||||||
|  |         alias: faas | ||||||
|   - name: forgejo |   - name: forgejo | ||||||
|  |     host: node002 | ||||||
|  |     dns: | ||||||
|  |       - domain: serguzim.me | ||||||
|  |         target: forgejo | ||||||
|     volumes_backup: |     volumes_backup: | ||||||
|       - forgejo_data |       - forgejo_data | ||||||
|   - name: forgejo_runner |   - name: forgejo_runner | ||||||
|  |     host: node002 | ||||||
|   - name: healthcheck |   - name: healthcheck | ||||||
|  |     host: node002 | ||||||
|   - name: homebox |   - name: homebox | ||||||
|  |     host: node002 | ||||||
|  |     dns: | ||||||
|  |       - domain: serguzim.me | ||||||
|  |         target: inventory | ||||||
|     volumes_backup: |     volumes_backup: | ||||||
|       - homebox_data |       - homebox_data | ||||||
|   - name: immich |   - name: immich | ||||||
|  |     host: node002 | ||||||
|  |     dns: | ||||||
|  |       - domain: serguzim.me | ||||||
|  |         target: gallery | ||||||
|     volumes_backup: |     volumes_backup: | ||||||
|       - immich_upload |       - immich_upload | ||||||
|   - name: influxdb |   - name: influxdb | ||||||
|  |     host: node002 | ||||||
|  |     dns: | ||||||
|  |       - domain: serguzim.me | ||||||
|  |         target: tick | ||||||
|     volumes_backup: |     volumes_backup: | ||||||
|       - influxdb_data |       - influxdb_data | ||||||
|   - name: jellyfin |   - name: jellyfin | ||||||
|  |     host: node002 | ||||||
|  |     dns: | ||||||
|  |       - domain: serguzim.me | ||||||
|  |         target: media | ||||||
|     volumes_backup: |     volumes_backup: | ||||||
|       - jellyfin_config |       - jellyfin_config | ||||||
|       #- jellyfin_media # TODO |       #- jellyfin_media # TODO | ||||||
|   - name: linkwarden |   - name: linkwarden | ||||||
|  |     host: node003 | ||||||
|  |     dns: | ||||||
|  |       - domain: serguzim.me | ||||||
|  |         target: bookmarks | ||||||
|   - name: mailcow |   - name: mailcow | ||||||
|  |     host: node003 | ||||||
|  |     dns: | ||||||
|  |       - domain: serguzim.me | ||||||
|  |         target: mail | ||||||
|   - name: minio |   - name: minio | ||||||
|  |     host: node002 | ||||||
|  |     dns: | ||||||
|  |       - domain: serguzim.me | ||||||
|  |         target: s3 | ||||||
|  |       - domain: serguzim.me | ||||||
|  |         target: console.s3 | ||||||
|  |         name: minio-console | ||||||
|  |         alias: minio | ||||||
|     volumes_backup: |     volumes_backup: | ||||||
|       - minio_data |       - minio_data | ||||||
|   - name: ntfy |   - name: ntfy | ||||||
|  |     host: node002 | ||||||
|  |     dns: | ||||||
|  |       - domain: serguzim.me | ||||||
|  |         target: push | ||||||
|     volumes_backup: |     volumes_backup: | ||||||
|       - ntfy_data |       - ntfy_data | ||||||
|   - name: reitanlage_oranienburg |   - name: reitanlage_oranienburg | ||||||
|  |     host: node002 | ||||||
|  |     dns: | ||||||
|  |       - domain: reitanlage-oranienburg.de | ||||||
|  |         target: "@" | ||||||
|  |       - domain: reitanlage-oranienburg.de | ||||||
|  |         target: www | ||||||
|  |         name: reitanlage_oranienburg-www | ||||||
|  |         alias: reitanlage_oranienburg | ||||||
|     volumes_backup: |     volumes_backup: | ||||||
|       - reitanlage-oranienburg_data |       - reitanlage-oranienburg_data | ||||||
|   - name: shlink |   - name: shlink | ||||||
|  |     host: node002 | ||||||
|  |     dns: | ||||||
|  |       - domain: msrg.cc | ||||||
|  |         target: "@" | ||||||
|  |       - domain: msvg.cc | ||||||
|  |         target: "@" | ||||||
|  |         name: shlink-msvg | ||||||
|  |         alias: shlink | ||||||
|   - name: synapse |   - name: synapse | ||||||
|  |     host: node002 | ||||||
|  |     dns: | ||||||
|  |       - domain: serguzim.me | ||||||
|  |         target: matrix | ||||||
|  |       - domain: msrg.cc | ||||||
|  |         target: matrix | ||||||
|  |         name: synapse_msrg | ||||||
|  |         alias: synapse | ||||||
|     volumes_backup: |     volumes_backup: | ||||||
|       - synapse_media_store |       - synapse_media_store | ||||||
|     ports: |     ports: | ||||||
|       - 8448:8448 |       - 8448:8448 | ||||||
|   - name: tandoor |   - name: tandoor | ||||||
|  |     host: node002 | ||||||
|  |     dns: | ||||||
|  |       - domain: serguzim.me | ||||||
|  |         target: recipes | ||||||
|     volumes_backup: |     volumes_backup: | ||||||
|       - tandoor_mediafiles |       - tandoor_mediafiles | ||||||
|   - name: teamspeak_fallback |   - name: teamspeak_fallback | ||||||
|  |     host: node002 | ||||||
|     volumes_backup: |     volumes_backup: | ||||||
|       - teamspeak-fallback-data |       - teamspeak-fallback-data | ||||||
|   - name: telegraf |   - name: telegraf | ||||||
|  |     host: node002 | ||||||
|   - name: tinytinyrss |   - name: tinytinyrss | ||||||
|  |     host: node002 | ||||||
|  |     dns: | ||||||
|  |       - domain: serguzim.me | ||||||
|  |         target: rss | ||||||
|   - name: umami |   - name: umami | ||||||
|  |     host: node003 | ||||||
|  |     dns: | ||||||
|  |       - domain: serguzim.me | ||||||
|  |         target: analytics | ||||||
|   - name: uptime_kuma |   - name: uptime_kuma | ||||||
|  |     host: node002 | ||||||
|  |     dns: | ||||||
|  |       - domain: serguzim.me | ||||||
|  |         target: status | ||||||
|     volumes_backup: |     volumes_backup: | ||||||
|       - uptime-kuma_data |       - uptime-kuma_data | ||||||
|   - name: vikunja |   - name: vikunja | ||||||
|  |     host: node002 | ||||||
|  |     dns: | ||||||
|  |       - domain: serguzim.me | ||||||
|  |         target: todo | ||||||
|     volumes_backup: |     volumes_backup: | ||||||
|       - vikunja_data |       - vikunja_data | ||||||
|   - name: webhook |   - name: webhook | ||||||
|  |     host: node002 | ||||||
|  |     dns: | ||||||
|  |       - domain: serguzim.me | ||||||
|  |         target: hook | ||||||
|   - name: wiki_js |   - name: wiki_js | ||||||
|  |     host: node003 | ||||||
|  |     dns: | ||||||
|  |       - domain: serguzim.me | ||||||
|  |         target: wiki | ||||||
|   - name: woodpecker |   - name: woodpecker | ||||||
|  |     host: node002 | ||||||
|  |     dns: | ||||||
|  |       - domain: serguzim.me | ||||||
|  |         target: ci | ||||||
|  |  | ||||||
|  | @ -19,8 +19,6 @@ all: | ||||||
|       host_backup: |       host_backup: | ||||||
|         hc_uid: "{{ vault_node001.backup.hc_uid }}" |         hc_uid: "{{ vault_node001.backup.hc_uid }}" | ||||||
|         uptime_kuma_token: "{{ vault_node001.backup.uptime_kuma_token }}" |         uptime_kuma_token: "{{ vault_node001.backup.uptime_kuma_token }}" | ||||||
|         volumes: |  | ||||||
|           - minecraft-2_data |  | ||||||
| 
 | 
 | ||||||
|     node002: |     node002: | ||||||
|       ansible_host: node002.vpn.serguzim.net |       ansible_host: node002.vpn.serguzim.net | ||||||
|  | @ -33,32 +31,6 @@ all: | ||||||
|       host_backup: |       host_backup: | ||||||
|         hc_uid: "{{ vault_node002.backup.hc_uid }}" |         hc_uid: "{{ vault_node002.backup.hc_uid }}" | ||||||
|         uptime_kuma_token: "{{ vault_node002.backup.uptime_kuma_token }}" |         uptime_kuma_token: "{{ vault_node002.backup.uptime_kuma_token }}" | ||||||
|         volumes: |  | ||||||
|       host_services: |  | ||||||
|         - authentik |  | ||||||
|         - extra_services |  | ||||||
|         - faas |  | ||||||
|         - forgejo |  | ||||||
|         - forgejo_runner |  | ||||||
|         - healthcheck |  | ||||||
|         - homebox |  | ||||||
|         - immich |  | ||||||
|         - influxdb |  | ||||||
|         - jellyfin |  | ||||||
|         - minio |  | ||||||
|         - ntfy |  | ||||||
|         - reitanlage_oranienburg |  | ||||||
|         - shlink |  | ||||||
|         - synapse |  | ||||||
|         - tandoor |  | ||||||
|         - teamspeak_fallback |  | ||||||
|         - telegraf |  | ||||||
|         - tinytinyrss |  | ||||||
|         - uptime_kuma |  | ||||||
|         - vikunja |  | ||||||
|         - watchtower |  | ||||||
|         - webhook |  | ||||||
|         - woodpecker |  | ||||||
| 
 | 
 | ||||||
|     node003: |     node003: | ||||||
|       ansible_host: node003.vpn.serguzim.net |       ansible_host: node003.vpn.serguzim.net | ||||||
|  | @ -71,10 +43,3 @@ all: | ||||||
|       host_backup: |       host_backup: | ||||||
|         hc_uid: "{{ vault_node003.backup.hc_uid }}" |         hc_uid: "{{ vault_node003.backup.hc_uid }}" | ||||||
|         uptime_kuma_token: "{{ vault_node003.backup.uptime_kuma_token }}" |         uptime_kuma_token: "{{ vault_node003.backup.uptime_kuma_token }}" | ||||||
|         volumes: [] |  | ||||||
|       host_services: |  | ||||||
|         - acme_dns |  | ||||||
|         - linkwarden |  | ||||||
|         - mailcow |  | ||||||
|         - umami |  | ||||||
|         - wiki_js |  | ||||||
|  |  | ||||||
							
								
								
									
										11
									
								
								playbooks/create_services_for_dnscontrol.yml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								playbooks/create_services_for_dnscontrol.yml
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | ||||||
|  | --- | ||||||
|  | - name: Create services for dnscontrol | ||||||
|  |   hosts: localhost | ||||||
|  |   tasks: | ||||||
|  |     - name: Create the services json file | ||||||
|  |       ansible.builtin.template: | ||||||
|  |         src: "json.j2" | ||||||
|  |         dest: "{{ services_json_file }}" | ||||||
|  |         mode: "0644" | ||||||
|  |       vars: | ||||||
|  |         json: "{{ all_services | services_to_dnscontrol() }}" | ||||||
|  | @ -1,17 +0,0 @@ | ||||||
| class FilterModule(object): |  | ||||||
|     def filters(self): |  | ||||||
|         return { |  | ||||||
|             'my_service_attributes': self.my_service_attributes, |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|     def my_service_attributes(self, services, my_services, attribute="name"): |  | ||||||
|         result = [] |  | ||||||
|         for service in services: |  | ||||||
|             if service["name"] in my_services: |  | ||||||
|                 if attribute in service: |  | ||||||
|                     if type(service[attribute]) == list: |  | ||||||
|                         result.extend(service[attribute]) |  | ||||||
|                     else: |  | ||||||
|                         result.append(service[attribute]) |  | ||||||
| 
 |  | ||||||
|         return result |  | ||||||
							
								
								
									
										38
									
								
								playbooks/filter_plugins/service_filters.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								playbooks/filter_plugins/service_filters.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,38 @@ | ||||||
|  | class FilterModule(object): | ||||||
|  |     def filters(self): | ||||||
|  |         return { | ||||||
|  |             'my_service_attributes': self.my_service_attributes, | ||||||
|  |             'services_to_dnscontrol': self.services_to_dnscontrol, | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     def my_service_attributes(self, services, host, attribute="name"): | ||||||
|  |         result = [] | ||||||
|  |         for service in services: | ||||||
|  |             if service["host"] != host: | ||||||
|  |                 continue | ||||||
|  |             if not attribute in service: | ||||||
|  |                 continue | ||||||
|  | 
 | ||||||
|  |             if type(service[attribute]) == list: | ||||||
|  |                 result.extend(service[attribute]) | ||||||
|  |             else: | ||||||
|  |                 result.append(service[attribute]) | ||||||
|  | 
 | ||||||
|  |         return result | ||||||
|  | 
 | ||||||
|  |     def services_to_dnscontrol(self, services): | ||||||
|  |         result = {} | ||||||
|  |         for service in services: | ||||||
|  |             for dns in service.get("dns", []): | ||||||
|  |                 name = dns.get("name", service["name"]) | ||||||
|  |                 result[name] = { | ||||||
|  |                     "target": dns["target"], | ||||||
|  |                     "domain": dns["domain"], | ||||||
|  |                 } | ||||||
|  |                 | ||||||
|  |                 if "alias" in dns: | ||||||
|  |                     result[name]["alias"] = dns["alias"] | ||||||
|  |                 else: | ||||||
|  |                     result[name]["host"] = service["host"] | ||||||
|  | 
 | ||||||
|  |         return result | ||||||
|  | @ -23,6 +23,6 @@ | ||||||
|         apply: |         apply: | ||||||
|           tags: "{{ services_item }}" |           tags: "{{ services_item }}" | ||||||
|       tags: always |       tags: always | ||||||
|       loop: "{{ all_services | my_service_attributes(host_services) }}" |       loop: "{{ all_services | my_service_attributes(inventory_hostname) }}" | ||||||
|       loop_control: |       loop_control: | ||||||
|         loop_var: services_item |         loop_var: services_item | ||||||
|  |  | ||||||
|  | @ -5,7 +5,7 @@ backup_image: "{{ (container_registry.public, 'services/backup') | path_join }}" | ||||||
| backup_svc: | backup_svc: | ||||||
|   name: backup |   name: backup | ||||||
| 
 | 
 | ||||||
| backup_volumes_list: "{{ all_services | my_service_attributes(host_services, 'volumes_backup') }}" | backup_volumes_list: "{{ all_services | my_service_attributes(inventory_hostname, 'volumes_backup') }}" | ||||||
| backup_volumes_service: "{{ backup_volumes_list | map_backup_volumes_service }}" | backup_volumes_service: "{{ backup_volumes_list | map_backup_volumes_service }}" | ||||||
| 
 | 
 | ||||||
| backup_env: | backup_env: | ||||||
|  |  | ||||||
|  | @ -9,7 +9,7 @@ caddy_ports_default: | ||||||
|   - 443:443 |   - 443:443 | ||||||
|   - 443:443/udp |   - 443:443/udp | ||||||
|   - "{{ host_vpn.ip }}:2019:2019" |   - "{{ host_vpn.ip }}:2019:2019" | ||||||
| caddy_ports_extra: "{{ all_services | my_service_attributes(host_services, 'ports') }}" | caddy_ports_extra: "{{ all_services | my_service_attributes(inventory_hostname, 'ports') }}" | ||||||
| caddy_ports: "{{ caddy_ports_default | union(caddy_ports_extra) }}" | caddy_ports: "{{ caddy_ports_default | union(caddy_ports_extra) }}" | ||||||
| 
 | 
 | ||||||
| caddy_svc: | caddy_svc: | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue