Remove dups
This commit is contained in:
@@ -1,20 +0,0 @@
|
|||||||
---
|
|
||||||
- name: "Activate Checkmk changes"
|
|
||||||
hosts: localhost
|
|
||||||
gather_facts: false
|
|
||||||
vars_files:
|
|
||||||
- secrets.yaml
|
|
||||||
vars:
|
|
||||||
server_url: "http://192.168.2.4:5000"
|
|
||||||
site: "cmk"
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- name: "Start activation on a specific site"
|
|
||||||
checkmk.general.activation:
|
|
||||||
server_url: "{{ server_url }}"
|
|
||||||
site: "{{ site }}"
|
|
||||||
automation_user: "{{ automation_user }}"
|
|
||||||
automation_secret: "{{ automation_secret }}"
|
|
||||||
force_foreign_changes: 'true'
|
|
||||||
sites:
|
|
||||||
- "{{ site }}"
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Install Checkmk agent on all hosts
|
|
||||||
hosts: all
|
|
||||||
become: true
|
|
||||||
roles:
|
|
||||||
- checkmk.general.agent
|
|
||||||
vars:
|
|
||||||
checkmk_agent_version: "2.4.0p15"
|
|
||||||
checkmk_agent_server: << checkmk_server >>
|
|
||||||
checkmk_agent_server_protocol: << checkmk_protocol >>
|
|
||||||
checkmk_agent_site: << checkmk_site >>
|
|
||||||
checkmk_agent_auto_activate: << checkmk_auto_activate >>
|
|
||||||
checkmk_agent_tls: << checkmk_tls >>
|
|
||||||
checkmk_agent_user: << checkmk_user >>
|
|
||||||
checkmk_agent_pass: << checkmk_pass >>
|
|
||||||
checkmk_agent_host_name: << checkmk_host >>
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "checkmk-install-agent",
|
|
||||||
"kind": "ansible",
|
|
||||||
"metadata": {
|
|
||||||
"name": "Install Checkmk Agent",
|
|
||||||
"description": "Installs and registers the Checkmk monitoring agent on target hosts using the checkmk.general.agent Ansible role.",
|
|
||||||
"tags": [],
|
|
||||||
"icon": {
|
|
||||||
"provider": "selfhst",
|
|
||||||
"id": "checkmk"
|
|
||||||
},
|
|
||||||
"draft": false,
|
|
||||||
"version": {
|
|
||||||
"name": "2.4.0",
|
|
||||||
"source_dep_name": "manual/checkmk-install-agent"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"title": "Checkmk Configuration",
|
|
||||||
"name": "checkmk",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "checkmk_server",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Checkmk Server",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "checkmk_protocol",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Protocol",
|
|
||||||
"required": true,
|
|
||||||
"default": "https",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "https"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "checkmk_site",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Checkmk Site",
|
|
||||||
"required": true,
|
|
||||||
"default": "cmk",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "cmk"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "checkmk_auto_activate",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Auto Activate Agent",
|
|
||||||
"required": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "checkmk_tls",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "TLS",
|
|
||||||
"required": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "checkmk_user",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Checkmk Automation User",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "checkmk_pass",
|
|
||||||
"type": "secret",
|
|
||||||
"title": "Automation Password",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "checkmk_host",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Checkmk Host Name",
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Manage Checkmk host
|
|
||||||
hosts: all
|
|
||||||
gather_facts: false
|
|
||||||
tasks:
|
|
||||||
- name: "Create or update host in Checkmk"
|
|
||||||
checkmk.general.host:
|
|
||||||
server_url: "<< checkmk_protocol >>://<< checkmk_server >>"
|
|
||||||
site: << checkmk_site >>
|
|
||||||
automation_user: << checkmk_user >>
|
|
||||||
automation_secret: << checkmk_pass >>
|
|
||||||
name: << host_name >>
|
|
||||||
attributes:
|
|
||||||
ipaddress: << host_ip >>
|
|
||||||
folder: << host_folder >>
|
|
||||||
state: "present"
|
|
||||||
delegate_to: localhost
|
|
||||||
run_once: true
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "checkmk-manage-host",
|
|
||||||
"kind": "ansible",
|
|
||||||
"metadata": {
|
|
||||||
"name": "Manage Checkmk Host",
|
|
||||||
"description": "Manages host entries in Checkmk monitoring using the checkmk.general.host Ansible module. Creates or updates host configuration in your Checkmk instance.",
|
|
||||||
"tags": [],
|
|
||||||
"icon": {
|
|
||||||
"provider": "selfhst",
|
|
||||||
"id": "checkmk"
|
|
||||||
},
|
|
||||||
"draft": false,
|
|
||||||
"version": {
|
|
||||||
"name": "2.4.0",
|
|
||||||
"source_dep_name": "manual/checkmk-manage-host"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"title": "Checkmk Configuration",
|
|
||||||
"name": "checkmk",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "checkmk_server",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Checkmk Server",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "checkmk_protocol",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Protocol",
|
|
||||||
"required": true,
|
|
||||||
"default": "https",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "https"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "checkmk_site",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Checkmk Site",
|
|
||||||
"required": true,
|
|
||||||
"default": "cmk",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "cmk"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "checkmk_user",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Checkmk Automation User",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "checkmk_pass",
|
|
||||||
"type": "secret",
|
|
||||||
"title": "Automation Password",
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Host Configuration",
|
|
||||||
"name": "host",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "host_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Host Name",
|
|
||||||
"required": true,
|
|
||||||
"description": "Hostname to add to Checkmk"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "host_ip",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Host IP",
|
|
||||||
"required": true,
|
|
||||||
"description": "IP address of the host"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "host_folder",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Folder Path",
|
|
||||||
"required": true,
|
|
||||||
"default": "/",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
# to run: ansible-playbook -i ./inventory.ini install-agent.yaml --ask-become-pass
|
|
||||||
---
|
|
||||||
- name: "Install Checkmk agent on all hosts"
|
|
||||||
hosts: all
|
|
||||||
become: yes
|
|
||||||
roles:
|
|
||||||
- checkmk.general.agent
|
|
||||||
vars:
|
|
||||||
checkmk_agent_version: "2.3.0p7"
|
|
||||||
#checkmk_agent_server: "192.168.2.4:5000"
|
|
||||||
checkmk_agent_server: "checkmk.mikemcfetridge.com"
|
|
||||||
checkmk_agent_server_protocol: https
|
|
||||||
checkmk_agent_site: "cmk"
|
|
||||||
checkmk_agent_auto_activate: true
|
|
||||||
checkmk_agent_tls: "true" # NOTE: Register Agent to enable TLS
|
|
||||||
checkmk_agent_user: "{{ automation_user }}"
|
|
||||||
checkmk_agent_pass: "{{ automation_secret }}"
|
|
||||||
checkmk_agent_host_name: "{{ ansible_hostname }}" # NOTE: Required to replace FQDN with hostname only
|
|
||||||
vars_files:
|
|
||||||
- secrets.yaml
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
[servers]
|
|
||||||
192.168.2.1
|
|
||||||
192.168.2.2
|
|
||||||
192.168.2.3
|
|
||||||
192.168.2.4
|
|
||||||
192.168.2.5
|
|
||||||
192.168.2.6
|
|
||||||
192.168.2.7
|
|
||||||
192.168.2.8
|
|
||||||
192.168.2.9
|
|
||||||
192.168.2.10
|
|
||||||
192.168.2.11
|
|
||||||
192.168.2.12
|
|
||||||
192.168.2.13
|
|
||||||
192.168.2.14
|
|
||||||
192.168.2.16
|
|
||||||
192.168.2.17
|
|
||||||
192.168.2.18
|
|
||||||
192.168.2.19
|
|
||||||
192.168.2.20
|
|
||||||
192.168.2.22
|
|
||||||
192.168.2.23
|
|
||||||
192.168.2.24
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
[servers]
|
|
||||||
ansible-server.home.mikemcfetridge.com
|
|
||||||
arrsserver.home.mikemcfetridge.com
|
|
||||||
beszel-server.home.mikemcfetridge.com
|
|
||||||
checkmk.home.mikemcfetridge.com
|
|
||||||
dockerapps.home.mikemcfetridge.com
|
|
||||||
gitea-server.home.mikemcfetridge.com
|
|
||||||
glance-server.home.mikemcfetridge.com
|
|
||||||
immich-wallabag.home.mikemcfetridge.com
|
|
||||||
linkwarden.home.mikemcfetridge.com
|
|
||||||
netbird-1.home.mikemcfetridge.com
|
|
||||||
netbird-2.home.mikemcfetridge.com
|
|
||||||
npm-server.home.mikemcfetridge.com
|
|
||||||
pihole-server.home.mikemcfetridge.com
|
|
||||||
pve.home.mikemcfetridge.com
|
|
||||||
pve2.home.mikemcfetridge.com
|
|
||||||
retrogaming-server.home.mikemcfetridge.com
|
|
||||||
searxng-server.home.mikemcfetridge.com
|
|
||||||
technitiumdns-server.home.mikemcfetridge.com
|
|
||||||
vaultwarden-server.home.mikemcfetridge.com
|
|
||||||
wireguard-server.home.mikemcfetridge.com
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
---
|
|
||||||
- name: "Manage Checkmk rules"
|
|
||||||
hosts: localhost
|
|
||||||
gather_facts: false
|
|
||||||
vars_files:
|
|
||||||
- secrets.yaml
|
|
||||||
vars:
|
|
||||||
server_url: "http://192.168.2.4:5000"
|
|
||||||
site: "cmk"
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- name: Get a rule with a particular rule id
|
|
||||||
ansible.builtin.debug:
|
|
||||||
msg: "Rule: {{ extensions | to_nice_yaml }}"
|
|
||||||
vars:
|
|
||||||
extensions: "{{
|
|
||||||
lookup('checkmk.general.rule',
|
|
||||||
rule_id='checkmk-rule-id',
|
|
||||||
server_url=server_url,
|
|
||||||
site=site,
|
|
||||||
automation_user=automation_user,
|
|
||||||
automation_secret=automation_secret,
|
|
||||||
validate_certs=False
|
|
||||||
)
|
|
||||||
}}"
|
|
||||||
@@ -1,286 +0,0 @@
|
|||||||
---
|
|
||||||
- name: "Manage Checkmk hosts"
|
|
||||||
hosts: localhost
|
|
||||||
gather_facts: false
|
|
||||||
vars_files:
|
|
||||||
- secrets.yaml
|
|
||||||
vars:
|
|
||||||
server_url: "http://192.168.2.4:5000"
|
|
||||||
site: "cmk"
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
|
|
||||||
- name: "Create host - PVE01"
|
|
||||||
checkmk.general.host:
|
|
||||||
server_url: "{{ server_url }}"
|
|
||||||
site: "{{ site }}"
|
|
||||||
automation_user: "{{ automation_user }}"
|
|
||||||
automation_secret: "{{ automation_secret }}"
|
|
||||||
name: "pve01"
|
|
||||||
attributes:
|
|
||||||
ipaddress: "192.168.2.1"
|
|
||||||
folder: "/"
|
|
||||||
state: "present"
|
|
||||||
|
|
||||||
- name: "Create host - PVE02"
|
|
||||||
checkmk.general.host:
|
|
||||||
server_url: "{{ server_url }}"
|
|
||||||
site: "{{ site }}"
|
|
||||||
automation_user: "{{ automation_user }}"
|
|
||||||
automation_secret: "{{ automation_secret }}"
|
|
||||||
name: "pve02"
|
|
||||||
attributes:
|
|
||||||
ipaddress: "192.168.2.2"
|
|
||||||
folder: "/"
|
|
||||||
state: "present"
|
|
||||||
|
|
||||||
- name: "Create host - beszel"
|
|
||||||
checkmk.general.host:
|
|
||||||
server_url: "{{ server_url }}"
|
|
||||||
site: "{{ site }}"
|
|
||||||
automation_user: "{{ automation_user }}"
|
|
||||||
automation_secret: "{{ automation_secret }}"
|
|
||||||
name: "Beszel"
|
|
||||||
attributes:
|
|
||||||
ipaddress: "192.168.2.3"
|
|
||||||
folder: "/"
|
|
||||||
state: "present"
|
|
||||||
|
|
||||||
- name: "Create host - Checkmk"
|
|
||||||
checkmk.general.host:
|
|
||||||
server_url: "{{ server_url }}"
|
|
||||||
site: "{{ site }}"
|
|
||||||
automation_user: "{{ automation_user }}"
|
|
||||||
automation_secret: "{{ automation_secret }}"
|
|
||||||
name: "Checkmk"
|
|
||||||
attributes:
|
|
||||||
ipaddress: "192.168.2.4"
|
|
||||||
folder: "/"
|
|
||||||
state: "present"
|
|
||||||
|
|
||||||
- name: "Create host - komodo"
|
|
||||||
checkmk.general.host:
|
|
||||||
server_url: "{{ server_url }}"
|
|
||||||
site: "{{ site }}"
|
|
||||||
automation_user: "{{ automation_user }}"
|
|
||||||
automation_secret: "{{ automation_secret }}"
|
|
||||||
name: "komodo"
|
|
||||||
attributes:
|
|
||||||
ipaddress: "192.168.2.5"
|
|
||||||
folder: "/"
|
|
||||||
state: "present"
|
|
||||||
|
|
||||||
- name: "Create host - Datacenter"
|
|
||||||
checkmk.general.host:
|
|
||||||
server_url: "{{ server_url }}"
|
|
||||||
site: "{{ site }}"
|
|
||||||
automation_user: "{{ automation_user }}"
|
|
||||||
automation_secret: "{{ automation_secret }}"
|
|
||||||
name: "Datacenter"
|
|
||||||
attributes:
|
|
||||||
ipaddress: "192.168.2.6"
|
|
||||||
folder: "/"
|
|
||||||
state: "present"
|
|
||||||
|
|
||||||
- name: "Create host - DockerApps"
|
|
||||||
checkmk.general.host:
|
|
||||||
server_url: "{{ server_url }}"
|
|
||||||
site: "{{ site }}"
|
|
||||||
automation_user: "{{ automation_user }}"
|
|
||||||
automation_secret: "{{ automation_secret }}"
|
|
||||||
name: "DockerApps"
|
|
||||||
attributes:
|
|
||||||
ipaddress: "192.168.2.7"
|
|
||||||
folder: "/"
|
|
||||||
state: "present"
|
|
||||||
|
|
||||||
|
|
||||||
- name: "Create host - PIHOLE"
|
|
||||||
checkmk.general.host:
|
|
||||||
server_url: "{{ server_url }}"
|
|
||||||
site: "{{ site }}"
|
|
||||||
automation_user: "{{ automation_user }}"
|
|
||||||
automation_secret: "{{ automation_secret }}"
|
|
||||||
name: "PiHole"
|
|
||||||
attributes:
|
|
||||||
ipaddress: "192.168.2.8"
|
|
||||||
folder: "/"
|
|
||||||
state: "present"
|
|
||||||
|
|
||||||
- name: "Create host - TECHNITIUMDNS"
|
|
||||||
checkmk.general.host:
|
|
||||||
server_url: "{{ server_url }}"
|
|
||||||
site: "{{ site }}"
|
|
||||||
automation_user: "{{ automation_user }}"
|
|
||||||
automation_secret: "{{ automation_secret }}"
|
|
||||||
name: "TechnitiumDNS"
|
|
||||||
attributes:
|
|
||||||
ipaddress: "192.168.2.9"
|
|
||||||
folder: "/"
|
|
||||||
state: "present"
|
|
||||||
|
|
||||||
- name: "Create host - Wireguard"
|
|
||||||
checkmk.general.host:
|
|
||||||
server_url: "{{ server_url }}"
|
|
||||||
site: "{{ site }}"
|
|
||||||
automation_user: "{{ automation_user }}"
|
|
||||||
automation_secret: "{{ automation_secret }}"
|
|
||||||
name: "Wireguard"
|
|
||||||
attributes:
|
|
||||||
ipaddress: "192.168.2.10"
|
|
||||||
folder: "/"
|
|
||||||
state: "present"
|
|
||||||
|
|
||||||
- name: "Create host - Ansible"
|
|
||||||
checkmk.general.host:
|
|
||||||
server_url: "{{ server_url }}"
|
|
||||||
site: "{{ site }}"
|
|
||||||
automation_user: "{{ automation_user }}"
|
|
||||||
automation_secret: "{{ automation_secret }}"
|
|
||||||
name: "Ansible"
|
|
||||||
attributes:
|
|
||||||
ipaddress: "192.168.2.11"
|
|
||||||
folder: "/"
|
|
||||||
state: "present"
|
|
||||||
|
|
||||||
- name: "Create host - LinkWarden"
|
|
||||||
checkmk.general.host:
|
|
||||||
server_url: "{{ server_url }}"
|
|
||||||
site: "{{ site }}"
|
|
||||||
automation_user: "{{ automation_user }}"
|
|
||||||
automation_secret: "{{ automation_secret }}"
|
|
||||||
name: "LinkWarden"
|
|
||||||
attributes:
|
|
||||||
ipaddress: "192.168.2.12"
|
|
||||||
folder: "/"
|
|
||||||
state: "present"
|
|
||||||
|
|
||||||
- name: "Create host - Immich"
|
|
||||||
checkmk.general.host:
|
|
||||||
server_url: "{{ server_url }}"
|
|
||||||
site: "{{ site }}"
|
|
||||||
automation_user: "{{ automation_user }}"
|
|
||||||
automation_secret: "{{ automation_secret }}"
|
|
||||||
name: "Immich"
|
|
||||||
attributes:
|
|
||||||
ipaddress: "192.168.2.13"
|
|
||||||
folder: "/"
|
|
||||||
state: "present"
|
|
||||||
|
|
||||||
- name: "Create host - RetroGaming"
|
|
||||||
checkmk.general.host:
|
|
||||||
server_url: "{{ server_url }}"
|
|
||||||
site: "{{ site }}"
|
|
||||||
automation_user: "{{ automation_user }}"
|
|
||||||
automation_secret: "{{ automation_secret }}"
|
|
||||||
name: "RetroGaming"
|
|
||||||
attributes:
|
|
||||||
ipaddress: "192.168.2.14"
|
|
||||||
folder: "/"
|
|
||||||
state: "present"
|
|
||||||
|
|
||||||
- name: "Create host - MediaServer"
|
|
||||||
checkmk.general.host:
|
|
||||||
server_url: "{{ server_url }}"
|
|
||||||
site: "{{ site }}"
|
|
||||||
automation_user: "{{ automation_user }}"
|
|
||||||
automation_secret: "{{ automation_secret }}"
|
|
||||||
name: "MediaServer"
|
|
||||||
attributes:
|
|
||||||
ipaddress: "192.168.2.16"
|
|
||||||
folder: "/"
|
|
||||||
state: "present"
|
|
||||||
|
|
||||||
- name: "Create host - NetBird1"
|
|
||||||
checkmk.general.host:
|
|
||||||
server_url: "{{ server_url }}"
|
|
||||||
site: "{{ site }}"
|
|
||||||
automation_user: "{{ automation_user }}"
|
|
||||||
automation_secret: "{{ automation_secret }}"
|
|
||||||
name: "NetBird1"
|
|
||||||
attributes:
|
|
||||||
ipaddress: "192.168.2.17"
|
|
||||||
folder: "/"
|
|
||||||
state: "present"
|
|
||||||
|
|
||||||
- name: "Create host - NetBird2"
|
|
||||||
checkmk.general.host:
|
|
||||||
server_url: "{{ server_url }}"
|
|
||||||
site: "{{ site }}"
|
|
||||||
automation_user: "{{ automation_user }}"
|
|
||||||
automation_secret: "{{ automation_secret }}"
|
|
||||||
name: "NetBird2"
|
|
||||||
attributes:
|
|
||||||
ipaddress: "192.168.2.18"
|
|
||||||
folder: "/"
|
|
||||||
state: "present"
|
|
||||||
|
|
||||||
- name: "Create host - VaultWarden"
|
|
||||||
checkmk.general.host:
|
|
||||||
server_url: "{{ server_url }}"
|
|
||||||
site: "{{ site }}"
|
|
||||||
automation_user: "{{ automation_user }}"
|
|
||||||
automation_secret: "{{ automation_secret }}"
|
|
||||||
name: "VaultWarden"
|
|
||||||
attributes:
|
|
||||||
ipaddress: "192.168.2.19"
|
|
||||||
folder: "/"
|
|
||||||
state: "present"
|
|
||||||
|
|
||||||
- name: "Create host - Glance"
|
|
||||||
checkmk.general.host:
|
|
||||||
server_url: "{{ server_url }}"
|
|
||||||
site: "{{ site }}"
|
|
||||||
automation_user: "{{ automation_user }}"
|
|
||||||
automation_secret: "{{ automation_secret }}"
|
|
||||||
name: "Glance"
|
|
||||||
attributes:
|
|
||||||
ipaddress: "192.168.2.20"
|
|
||||||
folder: "/"
|
|
||||||
state: "present"
|
|
||||||
|
|
||||||
- name: "Create host - NPM"
|
|
||||||
checkmk.general.host:
|
|
||||||
server_url: "{{ server_url }}"
|
|
||||||
site: "{{ site }}"
|
|
||||||
automation_user: "{{ automation_user }}"
|
|
||||||
automation_secret: "{{ automation_secret }}"
|
|
||||||
name: "Npm"
|
|
||||||
attributes:
|
|
||||||
ipaddress: "192.168.2.22"
|
|
||||||
folder: "/"
|
|
||||||
state: "present"
|
|
||||||
|
|
||||||
- name: "Create host - Searxng"
|
|
||||||
checkmk.general.host:
|
|
||||||
server_url: "{{ server_url }}"
|
|
||||||
site: "{{ site }}"
|
|
||||||
automation_user: "{{ automation_user }}"
|
|
||||||
automation_secret: "{{ automation_secret }}"
|
|
||||||
name: "Searxng"
|
|
||||||
attributes:
|
|
||||||
ipaddress: "192.168.2.23"
|
|
||||||
folder: "/"
|
|
||||||
state: "present"
|
|
||||||
|
|
||||||
- name: "Create host - Gitea"
|
|
||||||
checkmk.general.host:
|
|
||||||
server_url: "{{ server_url }}"
|
|
||||||
site: "{{ site }}"
|
|
||||||
automation_user: "{{ automation_user }}"
|
|
||||||
automation_secret: "{{ automation_secret }}"
|
|
||||||
name: "Gitea"
|
|
||||||
attributes:
|
|
||||||
ipaddress: "192.168.2.24"
|
|
||||||
folder: "/"
|
|
||||||
state: "present"
|
|
||||||
|
|
||||||
- name: "Start activation on a specific site"
|
|
||||||
checkmk.general.activation:
|
|
||||||
server_url: "{{ server_url }}"
|
|
||||||
site: "{{ site }}"
|
|
||||||
automation_user: "{{ automation_user }}"
|
|
||||||
automation_secret: "{{ automation_secret }}"
|
|
||||||
force_foreign_changes: 'true'
|
|
||||||
sites:
|
|
||||||
- "{{ site }}"
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
---
|
|
||||||
- name: "Manage Checkmk rules"
|
|
||||||
hosts: localhost
|
|
||||||
gather_facts: false
|
|
||||||
vars_files:
|
|
||||||
- secrets.yaml
|
|
||||||
vars:
|
|
||||||
server_url: "checkmk.home.arpa"
|
|
||||||
site: "cmk"
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- name: Create DNS Check Rule
|
|
||||||
checkmk.general.rule:
|
|
||||||
server_url: "{{ server_url }}"
|
|
||||||
site: "{{ site }}"
|
|
||||||
automation_user: "{{ automation_user }}"
|
|
||||||
automation_secret: "{{ automation_secret }}"
|
|
||||||
ruleset: "active_checks:dns"
|
|
||||||
rule:
|
|
||||||
properties: {
|
|
||||||
"comment": "Ansible managed",
|
|
||||||
"description": "DNS DNS Monitoring",
|
|
||||||
"disabled": false,
|
|
||||||
}
|
|
||||||
conditions: {
|
|
||||||
"host_label_groups": [],
|
|
||||||
"host_name": {
|
|
||||||
"match_on": [
|
|
||||||
"your-dns-container-host"
|
|
||||||
],
|
|
||||||
"operator": "one_of"
|
|
||||||
},
|
|
||||||
"host_tags": [],
|
|
||||||
"service_label_groups": []
|
|
||||||
}
|
|
||||||
"value_raw": {
|
|
||||||
"hostname": "hostname-to-query",
|
|
||||||
"server": "dns-server-ip",
|
|
||||||
"expected_addresses_list": [
|
|
||||||
"expected-ip-address"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
location:
|
|
||||||
folder: "/"
|
|
||||||
position: "top"
|
|
||||||
state: "present"
|
|
||||||
|
|
||||||
- name: Create NVME Temperature override rule
|
|
||||||
checkmk.general.rule:
|
|
||||||
server_url: "{{ server_url }}"
|
|
||||||
site: "{{ site }}"
|
|
||||||
automation_user: "{{ automation_user }}"
|
|
||||||
automation_secret: "{{ automation_secret }}"
|
|
||||||
ruleset: "checkgroup_parameters:temperature"
|
|
||||||
rule:
|
|
||||||
conditions:
|
|
||||||
host_label_groups: []
|
|
||||||
host_tags: []
|
|
||||||
service_description:
|
|
||||||
match_on:
|
|
||||||
- "DRIVE MODEL NAME*"
|
|
||||||
operator: "one_of"
|
|
||||||
service_label_groups: []
|
|
||||||
location:
|
|
||||||
folder: "/"
|
|
||||||
position: "top"
|
|
||||||
properties:
|
|
||||||
description: "NVME Temperature override"
|
|
||||||
disabled: false
|
|
||||||
value_raw: "{'levels': (60.0, 80.0)}"
|
|
||||||
state: present
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
---
|
|
||||||
automation_user: "ansible"
|
|
||||||
automation_secret: "Px40If4VUvvA35"
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Enable Docker TLS
|
|
||||||
hosts: all
|
|
||||||
become: true
|
|
||||||
vars:
|
|
||||||
certs_path: "<< certs_path >>"
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- name: Check if docker certs are existing
|
|
||||||
ansible.builtin.stat:
|
|
||||||
path: {{ certs_path }}
|
|
||||||
register: certs_dir
|
|
||||||
|
|
||||||
- name: Fail if docker certs are not existing
|
|
||||||
ansible.builtin.fail:
|
|
||||||
msg: "Docker certificates are not existing in /root/docker-certs."
|
|
||||||
when: not certs_dir.stat.exists
|
|
||||||
|
|
||||||
- name: Get machine's primary internal ip address from eth0 interface
|
|
||||||
ansible.builtin.setup:
|
|
||||||
register: ip_address
|
|
||||||
|
|
||||||
- name: Set machine's primary internal ip address
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
ip_address: {{ ip_address.ansible_facts.ansible_default_ipv4.address }}
|
|
||||||
|
|
||||||
- name: Check if ip_address is a valid ip address
|
|
||||||
ansible.builtin.assert:
|
|
||||||
that:
|
|
||||||
- ip_address is match("^(?:[0-9]{1,3}\\.){3}[0-9]{1,3}$")
|
|
||||||
fail_msg: "ip_address is not a valid ip address."
|
|
||||||
success_msg: "ip_address is a valid ip address."
|
|
||||||
|
|
||||||
- name: Change docker daemon to use certs
|
|
||||||
ansible.builtin.lineinfile:
|
|
||||||
path: /lib/systemd/system/docker.service
|
|
||||||
line: >
|
|
||||||
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
|
|
||||||
-H tcp://{{ ip_address }}:2376 --tlsverify --tlscacert={{ certs_path }}/ca.pem
|
|
||||||
--tlscert={{ certs_path }}/server-cert.pem --tlskey={{ certs_path }}/server-key.pem
|
|
||||||
regexp: '^ExecStart='
|
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: Reload systemd daemon
|
|
||||||
ansible.builtin.systemd:
|
|
||||||
daemon_reload: true
|
|
||||||
|
|
||||||
- name: Restart docker daemon
|
|
||||||
ansible.builtin.systemd:
|
|
||||||
name: docker
|
|
||||||
state: restarted
|
|
||||||
enabled: true
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "docker-certs-enable",
|
|
||||||
"kind": "ansible",
|
|
||||||
"metadata": {
|
|
||||||
"name": "Enable Docker TLS",
|
|
||||||
"description": "Enables TLS on the Docker daemon using existing certificates. Configures Docker for secure remote API access over an encrypted connection.",
|
|
||||||
"tags": [],
|
|
||||||
"icon": {
|
|
||||||
"provider": "simple-icons",
|
|
||||||
"id": "docker"
|
|
||||||
},
|
|
||||||
"draft": true,
|
|
||||||
"version": {
|
|
||||||
"name": "1.0.0",
|
|
||||||
"source_dep_name": "manual/docker-certs-enable"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"title": "Certificate Configuration",
|
|
||||||
"name": "certificates",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "certs_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Certs Path",
|
|
||||||
"required": false,
|
|
||||||
"default": "/root/docker-certs",
|
|
||||||
"description": "Path where certificates are stored",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/root/docker-certs"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Generate Docker TLS certificates
|
|
||||||
hosts: all
|
|
||||||
become: true
|
|
||||||
vars:
|
|
||||||
certs_path: "<< certs_path >>"
|
|
||||||
cert_validity_days: << cert_validity_days >>
|
|
||||||
cn_domain: "<< cn_domain >>"
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- name: Check if docker certs are existing
|
|
||||||
ansible.builtin.stat:
|
|
||||||
path: {{ certs_path }}
|
|
||||||
register: certs_dir
|
|
||||||
|
|
||||||
- name: Create docker certs directory (if needed)
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: {{ certs_path }}
|
|
||||||
state: directory
|
|
||||||
mode: '0700'
|
|
||||||
when: not certs_dir.stat.exists
|
|
||||||
|
|
||||||
- name: Check if docker certs directory is empty
|
|
||||||
ansible.builtin.command: ls -A {{ certs_path }}
|
|
||||||
register: certs_list
|
|
||||||
when: certs_dir.stat.exists
|
|
||||||
changed_when: false
|
|
||||||
ignore_errors: true
|
|
||||||
|
|
||||||
- name: Fail if docker certs already exist
|
|
||||||
ansible.builtin.fail:
|
|
||||||
msg: "Docker certificates already exist in /root/docker-certs."
|
|
||||||
when: certs_list.stdout | default('') != ''
|
|
||||||
|
|
||||||
- name: Get machine's primary internal ip address from eth0 interface
|
|
||||||
ansible.builtin.setup:
|
|
||||||
register: ip_address
|
|
||||||
|
|
||||||
- name: Set machine's primary internal ip address
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
ip_address: {{ ip_address.ansible_facts.ansible_default_ipv4.address }}
|
|
||||||
|
|
||||||
- name: Check if ip_address is a valid ip address
|
|
||||||
ansible.builtin.assert:
|
|
||||||
that:
|
|
||||||
- ip_address is match("^(?:[0-9]{1,3}\\.){3}[0-9]{1,3}$")
|
|
||||||
fail_msg: "ip_address is not a valid ip address."
|
|
||||||
success_msg: "ip_address is a valid ip address."
|
|
||||||
|
|
||||||
- name: Generate CA private key
|
|
||||||
ansible.builtin.command:
|
|
||||||
cmd: >
|
|
||||||
openssl genrsa -out {{ certs_path }}/ca-key.pem 4096
|
|
||||||
args:
|
|
||||||
creates: {{ certs_path }}/ca-key.pem
|
|
||||||
|
|
||||||
- name: Generate CA certificate
|
|
||||||
ansible.builtin.command:
|
|
||||||
cmd: >
|
|
||||||
openssl req -sha256 -new -x509
|
|
||||||
-subj "/CN={{ cn_domain }}"
|
|
||||||
-days {{ cert_validity_days }}
|
|
||||||
-key {{ certs_path }}/ca-key.pem
|
|
||||||
-out {{ certs_path }}/ca.pem
|
|
||||||
args:
|
|
||||||
creates: {{ certs_path }}/ca.pem
|
|
||||||
|
|
||||||
- name: Generate server private key
|
|
||||||
ansible.builtin.command:
|
|
||||||
cmd: >
|
|
||||||
openssl genrsa -out {{ certs_path }}/server-key.pem 4096
|
|
||||||
creates: {{ certs_path }}/server-key.pem
|
|
||||||
|
|
||||||
- name: Generate server certificate signing request
|
|
||||||
ansible.builtin.command:
|
|
||||||
cmd: >
|
|
||||||
openssl req -sha256 -new
|
|
||||||
-subj "/CN={{ inventory_hostname }}"
|
|
||||||
-key {{ certs_path }}/server-key.pem
|
|
||||||
-out {{ certs_path }}/server.csr
|
|
||||||
creates: {{ certs_path }}/server.csr
|
|
||||||
|
|
||||||
- name: Generate server certificate extension file
|
|
||||||
ansible.builtin.shell: |
|
|
||||||
echo "subjectAltName = DNS:{{ inventory_hostname }},IP:{{ ip_address }},IP:127.0.0.1" >> {{ certs_path }}/extfile.cnf
|
|
||||||
echo "extendedKeyUsage = serverAuth" >> {{ certs_path }}/extfile.cnf
|
|
||||||
args:
|
|
||||||
creates: {{ certs_path }}/extfile.cnf
|
|
||||||
|
|
||||||
- name: Generate server certificate
|
|
||||||
ansible.builtin.command:
|
|
||||||
cmd: >
|
|
||||||
openssl x509 -req -days {{ cert_validity_days }} -sha256
|
|
||||||
-in {{ certs_path }}/server.csr
|
|
||||||
-CA {{ certs_path }}/ca.pem
|
|
||||||
-CAkey {{ certs_path }}/ca-key.pem
|
|
||||||
-CAcreateserial -out {{ certs_path }}/server-cert.pem
|
|
||||||
-extfile {{ certs_path }}/extfile.cnf
|
|
||||||
creates: {{ certs_path }}/server-cert.pem
|
|
||||||
|
|
||||||
- name: Generate client private key
|
|
||||||
ansible.builtin.command:
|
|
||||||
cmd: >
|
|
||||||
openssl genrsa -out {{ certs_path }}/key.pem 4096
|
|
||||||
creates: {{ certs_path }}/key.pem
|
|
||||||
|
|
||||||
- name: Generate client certificate signing request
|
|
||||||
ansible.builtin.command:
|
|
||||||
cmd: >
|
|
||||||
openssl req -sha256 -new
|
|
||||||
-subj "/CN=client"
|
|
||||||
-key {{ certs_path }}/key.pem
|
|
||||||
-out {{ certs_path }}/client.csr
|
|
||||||
creates: {{ certs_path }}/client.csr
|
|
||||||
|
|
||||||
- name: Generate client certificate extension file
|
|
||||||
ansible.builtin.shell: |
|
|
||||||
echo "extendedKeyUsage = clientAuth" >> {{ certs_path }}/client-extfile.cnf
|
|
||||||
args:
|
|
||||||
creates: {{ certs_path }}/client-extfile.cnf
|
|
||||||
|
|
||||||
- name: Generate client certificate
|
|
||||||
ansible.builtin.command:
|
|
||||||
cmd: >
|
|
||||||
openssl x509 -req -days {{ cert_validity_days }}
|
|
||||||
-sha256 -in {{ certs_path }}/client.csr
|
|
||||||
-CA {{ certs_path }}/ca.pem
|
|
||||||
-CAkey {{ certs_path }}/ca-key.pem
|
|
||||||
-CAcreateserial -out {{ certs_path }}/cert.pem
|
|
||||||
-extfile {{ certs_path }}/client-extfile.cnf
|
|
||||||
creates: {{ certs_path }}/cert.pem
|
|
||||||
|
|
||||||
- name: Remove client certificate signing request
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: {{ certs_path }}/server.csr
|
|
||||||
state: absent
|
|
||||||
|
|
||||||
- name: Remove client certificate signing request
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: {{ certs_path }}/client.csr
|
|
||||||
state: absent
|
|
||||||
|
|
||||||
- name: Remove server certificate extension file
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: {{ certs_path }}/extfile.cnf
|
|
||||||
state: absent
|
|
||||||
|
|
||||||
- name: Remove client certificate extension file
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: {{ certs_path }}/client-extfile.cnf
|
|
||||||
state: absent
|
|
||||||
|
|
||||||
- name: Set permissions for docker certs
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: {{ certs_path }}
|
|
||||||
mode: '0700'
|
|
||||||
recurse: true
|
|
||||||
follow: true
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "docker-certs",
|
|
||||||
"kind": "ansible",
|
|
||||||
"metadata": {
|
|
||||||
"name": "Generate Docker TLS Certificates",
|
|
||||||
"description": "Generates TLS certificates for the Docker daemon, including CA, server, and client certificates. Used to secure Docker remote API access.",
|
|
||||||
"tags": [],
|
|
||||||
"icon": {
|
|
||||||
"provider": "simple-icons",
|
|
||||||
"id": "docker"
|
|
||||||
},
|
|
||||||
"draft": true,
|
|
||||||
"version": {
|
|
||||||
"name": "1.0.0",
|
|
||||||
"source_dep_name": "manual/docker-certs"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"title": "Certificate Configuration",
|
|
||||||
"name": "certificates",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "certs_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Certs Path",
|
|
||||||
"required": false,
|
|
||||||
"default": "/root/docker-certs",
|
|
||||||
"description": "Path where certificates will be stored",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/root/docker-certs"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "cert_validity_days",
|
|
||||||
"type": "int",
|
|
||||||
"title": "Validity Days",
|
|
||||||
"required": false,
|
|
||||||
"default": 3630,
|
|
||||||
"description": "Certificate validity period in days",
|
|
||||||
"config": {
|
|
||||||
"slider": true,
|
|
||||||
"min": 30,
|
|
||||||
"max": 3650,
|
|
||||||
"step": 30,
|
|
||||||
"placeholder": "3650",
|
|
||||||
"unit": "days"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "cn_domain",
|
|
||||||
"type": "str",
|
|
||||||
"title": "CA Common Name",
|
|
||||||
"required": false,
|
|
||||||
"description": "Common Name (CN) for the CA certificate",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "home.arpa.tld"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Docker prune safe
|
|
||||||
hosts: all
|
|
||||||
become: true
|
|
||||||
gather_facts: false
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- name: Prune Docker resources with safe defaults
|
|
||||||
community.docker.docker_prune:
|
|
||||||
containers: << prune_stopped_containers | default(false) >>
|
|
||||||
images: true
|
|
||||||
images_filters:
|
|
||||||
dangling: << not (prune_include_unused_tagged_images | default(false)) >>
|
|
||||||
networks: << prune_unused_networks | default(false) >>
|
|
||||||
volumes: << prune_unused_volumes | default(false) >>
|
|
||||||
builder_cache: << prune_builder_cache | default(false) >>
|
|
||||||
builder_cache_keep_storage: "<< prune_keep_storage_mb | default(1024) >>M"
|
|
||||||
timeout: 300
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
collections:
|
|
||||||
- name: community.docker
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "docker-cleanup",
|
|
||||||
"kind": "ansible",
|
|
||||||
"metadata": {
|
|
||||||
"name": "Docker Cleanup",
|
|
||||||
"description": "Safely prunes Docker resources on target hosts. Only removes resources that are explicitly enabled in the configuration, keeping a conservative default.",
|
|
||||||
"tags": [
|
|
||||||
"docker",
|
|
||||||
"cleanup",
|
|
||||||
"prune",
|
|
||||||
"maintenance"
|
|
||||||
],
|
|
||||||
"icon": {
|
|
||||||
"provider": "mdi",
|
|
||||||
"id": "broom",
|
|
||||||
"color": "fuchsia"
|
|
||||||
},
|
|
||||||
"draft": false,
|
|
||||||
"version": {
|
|
||||||
"name": "1",
|
|
||||||
"source_dep_name": "manual/docker-cleanup"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"title": "Prune Options",
|
|
||||||
"name": "prune",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "prune_include_unused_tagged_images",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Tagged Images",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "prune_stopped_containers",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Prune Stopped Containers",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "prune_unused_volumes",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Prune Unused Volumes",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "prune_unused_networks",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Prune Unused Networks",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "prune_builder_cache",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Prune Builder Cache",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "prune_keep_storage_mb",
|
|
||||||
"type": "int",
|
|
||||||
"title": "Keep Storage",
|
|
||||||
"required": false,
|
|
||||||
"default": 1024,
|
|
||||||
"description": "Minimum amount of cache/storage to keep when pruning (where supported)",
|
|
||||||
"config": {
|
|
||||||
"slider": true,
|
|
||||||
"min": 256,
|
|
||||||
"max": 102400,
|
|
||||||
"step": 256,
|
|
||||||
"placeholder": "1024",
|
|
||||||
"unit": "MB"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Docker disk usage report
|
|
||||||
hosts: all
|
|
||||||
become: true
|
|
||||||
gather_facts: false
|
|
||||||
|
|
||||||
vars:
|
|
||||||
report_root: "/opt/docker-reports"
|
|
||||||
report_timestamp: "{{ lookup('pipe', 'date +%Y%m%d-%H%M%S') }}"
|
|
||||||
report_file_name: "docker_disk_usage_<< inventory_hostname >>_<< report_timestamp >>.txt"
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- name: Ensure report root exists
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: "<< report_root >>"
|
|
||||||
state: directory
|
|
||||||
mode: "0750"
|
|
||||||
|
|
||||||
- name: Collect docker system df summary
|
|
||||||
ansible.builtin.command: docker system df
|
|
||||||
register: docker_df_summary
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Collect docker system df verbose report
|
|
||||||
ansible.builtin.command: docker system df -v
|
|
||||||
register: docker_df_verbose
|
|
||||||
changed_when: false
|
|
||||||
when: include_verbose_report | default(false)
|
|
||||||
|
|
||||||
- name: Build report body
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
docker_disk_usage_report_body: |
|
|
||||||
Host: << inventory_hostname >>
|
|
||||||
Timestamp: {{ lookup('pipe', 'date -u +%Y-%m-%dT%H:%M:%SZ') }}
|
|
||||||
|
|
||||||
Docker system df:
|
|
||||||
<< docker_df_summary.stdout >>
|
|
||||||
<%- if include_verbose_report | default(false) %>
|
|
||||||
|
|
||||||
Docker system df -v:
|
|
||||||
<< docker_df_verbose.stdout >>
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
- name: Save local disk usage report
|
|
||||||
ansible.builtin.copy:
|
|
||||||
dest: "<< report_root >>/<< report_file_name >>"
|
|
||||||
content: "<< docker_disk_usage_report_body >>"
|
|
||||||
mode: "0640"
|
|
||||||
|
|
||||||
- name: Build Discord report content
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
discord_disk_report_content: |
|
|
||||||
<< discord_message_prefix | default('Docker Disk Usage Report') >>
|
|
||||||
```text
|
|
||||||
<< docker_disk_usage_report_body | truncate(1700, true, '...') >>
|
|
||||||
```
|
|
||||||
when:
|
|
||||||
- discord_enabled | default(false)
|
|
||||||
- (discord_webhook_url | default('')) | length > 0
|
|
||||||
|
|
||||||
- name: Send disk usage report to Discord webhook
|
|
||||||
ansible.builtin.uri:
|
|
||||||
url: "<< discord_webhook_url | default('') >>"
|
|
||||||
method: POST
|
|
||||||
body_format: json
|
|
||||||
body:
|
|
||||||
username: "<< discord_username | default('Docker Reporter') >>"
|
|
||||||
content: "<< discord_disk_report_content >>"
|
|
||||||
status_code: 204
|
|
||||||
when:
|
|
||||||
- discord_enabled | default(false)
|
|
||||||
- (discord_webhook_url | default('')) | length > 0
|
|
||||||
@@ -1,148 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "docker-disk-usage-report",
|
|
||||||
"kind": "ansible",
|
|
||||||
"metadata": {
|
|
||||||
"name": "Docker Disk Usage Report",
|
|
||||||
"description": "Generates a Docker disk usage report on target hosts and optionally sends a summary to Discord via webhook.",
|
|
||||||
"tags": [
|
|
||||||
"docker",
|
|
||||||
"report",
|
|
||||||
"disk",
|
|
||||||
"monitoring"
|
|
||||||
],
|
|
||||||
"icon": {
|
|
||||||
"provider": "mdi",
|
|
||||||
"id": "chart-box",
|
|
||||||
"color": "blue"
|
|
||||||
},
|
|
||||||
"draft": true,
|
|
||||||
"version": {
|
|
||||||
"name": "1",
|
|
||||||
"source_dep_name": "manual/docker-disk-usage-report"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"title": "Report",
|
|
||||||
"name": "report",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "include_verbose_report",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Verbose Report",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"description": "Include docker system df -v output in local report"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Discord Webhook",
|
|
||||||
"name": "discord",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "discord_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Discord",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"description": "Send a short report to Discord webhook"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "discord_webhook_url",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Discord Webhook URL",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "discord_username",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Discord Username",
|
|
||||||
"required": false,
|
|
||||||
"default": "Docker Reporter",
|
|
||||||
"description": "Sender name for webhook message",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "Docker Reporter"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "discord_message_prefix",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Discord Message Prefix",
|
|
||||||
"required": false,
|
|
||||||
"default": "Docker Disk Usage Report",
|
|
||||||
"description": "Prefix line sent before report content",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "Docker Disk Usage Report"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Internal",
|
|
||||||
"name": "internal",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "docker_df_verbose",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Docker DF Verbose",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "report_file_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Report File Name",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "report_root",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Report Root",
|
|
||||||
"required": false,
|
|
||||||
"default": "/reports",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/reports"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "docker_disk_usage_report_body",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Report Body",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "discord_disk_report_content",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Discord Report",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "inventory_hostname",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Inventory Hostname",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "report_timestamp",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Report Timestamp",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "docker_df_summary",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Docker DF Summary",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Docker healthcheck audit
|
|
||||||
hosts: all
|
|
||||||
become: true
|
|
||||||
gather_facts: false
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- name: Collect Docker containers
|
|
||||||
community.docker.docker_host_info:
|
|
||||||
containers: true
|
|
||||||
register: docker_host_info
|
|
||||||
|
|
||||||
- name: Build list of containers missing healthcheck
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
containers_missing_healthcheck: "{{ (containers_missing_healthcheck | default([])) + [item.Names[0] | default(item.Id)] }}"
|
|
||||||
when:
|
|
||||||
- item.Config is defined
|
|
||||||
- item.Config.Healthcheck is not defined
|
|
||||||
loop: "{{ docker_host_info.containers | default([]) }}"
|
|
||||||
|
|
||||||
- name: Ensure missing-healthcheck list exists
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
containers_missing_healthcheck: []
|
|
||||||
when: containers_missing_healthcheck is not defined
|
|
||||||
|
|
||||||
- name: Build audit report
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
docker_healthcheck_audit_report:
|
|
||||||
checked_containers: "{{ docker_host_info.containers | default([]) | length }}"
|
|
||||||
missing_healthcheck_count: "{{ containers_missing_healthcheck | length }}"
|
|
||||||
missing_healthcheck_containers: "{{ containers_missing_healthcheck }}"
|
|
||||||
|
|
||||||
- name: Save healthcheck audit report
|
|
||||||
ansible.builtin.copy:
|
|
||||||
dest: "<< audit_report_path | default('/tmp/docker-healthcheck-audit.json') >>"
|
|
||||||
content: "{{ docker_healthcheck_audit_report | to_nice_json }}"
|
|
||||||
mode: "0640"
|
|
||||||
when: audit_save_report | default(true)
|
|
||||||
|
|
||||||
- name: Print audit summary
|
|
||||||
ansible.builtin.debug:
|
|
||||||
msg: >-
|
|
||||||
Checked {{ docker_healthcheck_audit_report.checked_containers }} containers,
|
|
||||||
found {{ docker_healthcheck_audit_report.missing_healthcheck_count }} without healthcheck.
|
|
||||||
|
|
||||||
- name: Fail when missing healthchecks are found
|
|
||||||
ansible.builtin.fail:
|
|
||||||
msg: "Containers missing healthcheck: {{ containers_missing_healthcheck | join(', ') }}"
|
|
||||||
when:
|
|
||||||
- audit_fail_on_missing | default(false)
|
|
||||||
- containers_missing_healthcheck | length > 0
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
collections:
|
|
||||||
- name: community.docker
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "docker-healthcheck-audit",
|
|
||||||
"kind": "ansible",
|
|
||||||
"metadata": {
|
|
||||||
"name": "Docker Healthcheck Audit",
|
|
||||||
"description": "Audits Docker containers for missing healthchecks and optionally fails the playbook when violations are found. Can save a JSON audit report to the target host.",
|
|
||||||
"tags": [
|
|
||||||
"docker",
|
|
||||||
"audit",
|
|
||||||
"healthcheck",
|
|
||||||
"compliance"
|
|
||||||
],
|
|
||||||
"icon": {
|
|
||||||
"provider": "mdi",
|
|
||||||
"id": "stethoscope",
|
|
||||||
"color": "blue"
|
|
||||||
},
|
|
||||||
"draft": false,
|
|
||||||
"version": {
|
|
||||||
"name": "1",
|
|
||||||
"source_dep_name": "manual/docker-healthcheck-audit"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"title": "Audit",
|
|
||||||
"name": "audit",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "audit_fail_on_missing",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Fail Missing Checks",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"description": "Fail the play if one or more containers are missing a healthcheck"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "audit_save_report",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Save JSON Report",
|
|
||||||
"required": false,
|
|
||||||
"default": true,
|
|
||||||
"description": "Save audit report to a JSON file on the target host"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "audit_report_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Audit Report Path",
|
|
||||||
"required": false,
|
|
||||||
"default": "/tmp/docker-healthcheck-audit.json",
|
|
||||||
"description": "Path to store the generated JSON report",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/tmp/docker-healthcheck-audit.json"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Internal",
|
|
||||||
"name": "internal",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "containers_missing_healthcheck",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Containers Missing Healthcheck",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "docker_healthcheck_audit_report",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Healthcheck Audit Report",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "docker_host_info",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Docker Host Info",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Install Docker on Ubuntu
|
|
||||||
hosts: all
|
|
||||||
become: true
|
|
||||||
gather_facts: true
|
|
||||||
|
|
||||||
vars:
|
|
||||||
docker_apt_arch_map:
|
|
||||||
x86_64: amd64
|
|
||||||
aarch64: arm64
|
|
||||||
armv7l: armhf
|
|
||||||
ppc64le: ppc64el
|
|
||||||
s390x: s390x
|
|
||||||
docker_apt_arch: "{{ docker_apt_arch_map[ansible_architecture] | default('amd64') }}"
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- name: Remove conflicting packages
|
|
||||||
ansible.builtin.apt:
|
|
||||||
name:
|
|
||||||
- docker.io
|
|
||||||
- docker-compose
|
|
||||||
- docker-compose-v2
|
|
||||||
- docker-doc
|
|
||||||
- podman-docker
|
|
||||||
- containerd
|
|
||||||
- runc
|
|
||||||
state: absent
|
|
||||||
|
|
||||||
- name: Install prerequisite packages
|
|
||||||
ansible.builtin.apt:
|
|
||||||
name:
|
|
||||||
- ca-certificates
|
|
||||||
- curl
|
|
||||||
update_cache: true
|
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: Create apt keyrings directory
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: /etc/apt/keyrings
|
|
||||||
state: directory
|
|
||||||
mode: "0755"
|
|
||||||
|
|
||||||
- name: Download Docker GPG key
|
|
||||||
ansible.builtin.get_url:
|
|
||||||
url: https://download.docker.com/linux/ubuntu/gpg
|
|
||||||
dest: /etc/apt/keyrings/docker.asc
|
|
||||||
mode: "0644"
|
|
||||||
force: true
|
|
||||||
|
|
||||||
- name: Add Docker apt repository list file
|
|
||||||
ansible.builtin.copy:
|
|
||||||
dest: /etc/apt/sources.list.d/docker.list
|
|
||||||
mode: "0644"
|
|
||||||
content: |
|
|
||||||
deb [arch={{ docker_apt_arch }} signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable
|
|
||||||
|
|
||||||
- name: Install Docker Engine packages
|
|
||||||
ansible.builtin.apt:
|
|
||||||
name:
|
|
||||||
- docker-ce
|
|
||||||
- docker-ce-cli
|
|
||||||
- containerd.io
|
|
||||||
- docker-buildx-plugin
|
|
||||||
- docker-compose-plugin
|
|
||||||
update_cache: true
|
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: Ensure Docker service is enabled and started
|
|
||||||
ansible.builtin.systemd:
|
|
||||||
name: docker
|
|
||||||
enabled: true
|
|
||||||
state: started
|
|
||||||
|
|
||||||
<%- if add_user_to_docker == true %>
|
|
||||||
- name: Add user to docker group
|
|
||||||
ansible.builtin.user:
|
|
||||||
name: "<< user >>"
|
|
||||||
groups: docker
|
|
||||||
append: true
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
- name: Verify Docker CLI is available
|
|
||||||
ansible.builtin.command: docker --version
|
|
||||||
changed_when: false
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "docker-install-ubuntu",
|
|
||||||
"kind": "ansible",
|
|
||||||
"metadata": {
|
|
||||||
"name": "Install Docker on Ubuntu",
|
|
||||||
"description": "Installs Docker Engine on Ubuntu systems using the official Docker APT repository.",
|
|
||||||
"tags": [],
|
|
||||||
"icon": {
|
|
||||||
"provider": "simple-icons",
|
|
||||||
"id": "docker",
|
|
||||||
"color": "blue"
|
|
||||||
},
|
|
||||||
"draft": false,
|
|
||||||
"version": {
|
|
||||||
"name": "1",
|
|
||||||
"source_dep_name": "manual/docker-install-ubuntu"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"title": "User Access",
|
|
||||||
"name": "postinstall",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "add_user_to_docker",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Docker Group",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"description": "Add a user to the docker group"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "user",
|
|
||||||
"type": "str",
|
|
||||||
"title": "User",
|
|
||||||
"required": false,
|
|
||||||
"default": "",
|
|
||||||
"description": "Username to add to docker group",
|
|
||||||
"needs": [
|
|
||||||
"add_user_to_docker=true"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Docker mysql backup
|
|
||||||
hosts: all
|
|
||||||
become: true
|
|
||||||
gather_facts: false
|
|
||||||
|
|
||||||
vars:
|
|
||||||
backup_root: "/opt/docker-db-backups/mysql"
|
|
||||||
backup_timestamp: "{{ lookup('pipe', 'date +%Y%m%d-%H%M%S') }}"
|
|
||||||
backup_file_name: "backup_mysql_<< container_name >>_<< backup_timestamp >>.sql.gz"
|
|
||||||
backup_file_path: "<< backup_root >>/<< backup_file_name >>"
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- name: Ensure backup root exists
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: "<< backup_root >>"
|
|
||||||
state: directory
|
|
||||||
mode: "0750"
|
|
||||||
|
|
||||||
- name: Get container information
|
|
||||||
community.docker.docker_container_info:
|
|
||||||
name: "<< container_name >>"
|
|
||||||
register: container_info
|
|
||||||
|
|
||||||
- name: Fail if container does not exist
|
|
||||||
ansible.builtin.fail:
|
|
||||||
msg: "Container '<< container_name >>' does not exist"
|
|
||||||
when: not container_info.exists
|
|
||||||
|
|
||||||
- name: Run backup and validation
|
|
||||||
block:
|
|
||||||
- name: Dump all databases with password
|
|
||||||
ansible.builtin.shell: |
|
|
||||||
set -euo pipefail
|
|
||||||
docker exec -e MYSQL_PWD=<< mysql_password | quote >> "<< container_name >>" \
|
|
||||||
mysqldump --single-transaction --routines --events --triggers \
|
|
||||||
--all-databases -u "<< mysql_user | default('root') >>" \
|
|
||||||
| gzip > "<< backup_file_path >>"
|
|
||||||
args:
|
|
||||||
executable: /bin/bash
|
|
||||||
changed_when: true
|
|
||||||
when:
|
|
||||||
- mysql_database | default('all') == 'all'
|
|
||||||
- (mysql_password | default('')) | length > 0
|
|
||||||
|
|
||||||
- name: Dump all databases without password
|
|
||||||
ansible.builtin.shell: |
|
|
||||||
set -euo pipefail
|
|
||||||
docker exec "<< container_name >>" \
|
|
||||||
mysqldump --single-transaction --routines --events --triggers \
|
|
||||||
--all-databases -u "<< mysql_user | default('root') >>" \
|
|
||||||
| gzip > "<< backup_file_path >>"
|
|
||||||
args:
|
|
||||||
executable: /bin/bash
|
|
||||||
changed_when: true
|
|
||||||
when:
|
|
||||||
- mysql_database | default('all') == 'all'
|
|
||||||
- (mysql_password | default('')) | length == 0
|
|
||||||
|
|
||||||
- name: Dump selected database with password
|
|
||||||
ansible.builtin.shell: |
|
|
||||||
set -euo pipefail
|
|
||||||
docker exec -e MYSQL_PWD=<< mysql_password | quote >> "<< container_name >>" \
|
|
||||||
mysqldump --single-transaction --routines --events --triggers \
|
|
||||||
-u "<< mysql_user | default('root') >>" "<< mysql_database >>" \
|
|
||||||
| gzip > "<< backup_file_path >>"
|
|
||||||
args:
|
|
||||||
executable: /bin/bash
|
|
||||||
changed_when: true
|
|
||||||
when:
|
|
||||||
- mysql_database | default('all') != 'all'
|
|
||||||
- (mysql_password | default('')) | length > 0
|
|
||||||
|
|
||||||
- name: Dump selected database without password
|
|
||||||
ansible.builtin.shell: |
|
|
||||||
set -euo pipefail
|
|
||||||
docker exec "<< container_name >>" \
|
|
||||||
mysqldump --single-transaction --routines --events --triggers \
|
|
||||||
-u "<< mysql_user | default('root') >>" "<< mysql_database >>" \
|
|
||||||
| gzip > "<< backup_file_path >>"
|
|
||||||
args:
|
|
||||||
executable: /bin/bash
|
|
||||||
changed_when: true
|
|
||||||
when:
|
|
||||||
- mysql_database | default('all') != 'all'
|
|
||||||
- (mysql_password | default('')) | length == 0
|
|
||||||
|
|
||||||
- name: Validate backup file exists
|
|
||||||
ansible.builtin.stat:
|
|
||||||
path: "<< backup_file_path >>"
|
|
||||||
register: backup_archive_stat
|
|
||||||
|
|
||||||
- name: Fail if backup file is missing or empty
|
|
||||||
ansible.builtin.fail:
|
|
||||||
msg: "Backup file missing or empty: << backup_file_path >>"
|
|
||||||
when:
|
|
||||||
- not (backup_archive_stat.stat.exists | default(false))
|
|
||||||
or (backup_archive_stat.stat.size | default(0) | int) == 0
|
|
||||||
|
|
||||||
- name: Validate gzip archive integrity
|
|
||||||
ansible.builtin.command: gzip -t "<< backup_file_path >>"
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Validate mysql dump signature
|
|
||||||
ansible.builtin.shell: |
|
|
||||||
set -euo pipefail
|
|
||||||
gzip -dc "<< backup_file_path >>" \
|
|
||||||
| head -n 50 \
|
|
||||||
| grep -Eq 'MySQL dump'
|
|
||||||
args:
|
|
||||||
executable: /bin/bash
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Remove old mysql backup archives
|
|
||||||
ansible.builtin.find:
|
|
||||||
paths: "<< backup_root >>"
|
|
||||||
patterns: "backup_mysql_<< container_name >>_*.sql.gz"
|
|
||||||
age: "<< backup_retention_days | default(14) >>d"
|
|
||||||
recurse: true
|
|
||||||
register: old_backups
|
|
||||||
|
|
||||||
- name: Delete old mysql backup archives
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: "<< item.path >>"
|
|
||||||
state: absent
|
|
||||||
loop: "<< old_backups.files >>"
|
|
||||||
|
|
||||||
- name: Mark backup status success
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
backup_status: "success"
|
|
||||||
backup_status_message: "Backup and validation succeeded"
|
|
||||||
rescue:
|
|
||||||
- name: Mark backup status failed
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
backup_status: "failed"
|
|
||||||
backup_status_message: "<< ansible_failed_result.msg | default('Backup or validation failed') >>"
|
|
||||||
always:
|
|
||||||
- name: Send mysql backup status to Discord
|
|
||||||
ansible.builtin.uri:
|
|
||||||
url: "<< discord_webhook | default('') >>"
|
|
||||||
method: POST
|
|
||||||
body_format: json
|
|
||||||
body:
|
|
||||||
content: |
|
|
||||||
MySQL Backup << backup_status | default('failed') | upper >>
|
|
||||||
Host: << inventory_hostname >>
|
|
||||||
Container: << container_name >>
|
|
||||||
File: << backup_file_path >>
|
|
||||||
Message: << backup_status_message | default('n/a') >>
|
|
||||||
status_code: 204
|
|
||||||
when:
|
|
||||||
- send_discord_notification | default(false)
|
|
||||||
- (discord_webhook | default('')) | length > 0
|
|
||||||
|
|
||||||
- name: Fail play if backup failed
|
|
||||||
ansible.builtin.fail:
|
|
||||||
msg: "<< backup_status_message | default('Backup failed') >>"
|
|
||||||
when: backup_status | default('failed') == 'failed'
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
collections:
|
|
||||||
- name: community.docker
|
|
||||||
@@ -1,186 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "docker-mysql-backup",
|
|
||||||
"kind": "ansible",
|
|
||||||
"metadata": {
|
|
||||||
"name": "Docker MySQL Backup",
|
|
||||||
"description": "Connects to a named MySQL container and creates compressed SQL dumps with configurable retention. Supports optional Discord notifications on success or failure.",
|
|
||||||
"tags": [
|
|
||||||
"docker",
|
|
||||||
"backup",
|
|
||||||
"mysql",
|
|
||||||
"database"
|
|
||||||
],
|
|
||||||
"icon": {
|
|
||||||
"provider": "simple-icons",
|
|
||||||
"id": "mysql",
|
|
||||||
"color": "emerald"
|
|
||||||
},
|
|
||||||
"draft": true,
|
|
||||||
"version": {
|
|
||||||
"name": "1",
|
|
||||||
"source_dep_name": "manual/docker-mysql-backup"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"title": "Backup",
|
|
||||||
"name": "backup",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "container_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Container Name",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "mysql_user",
|
|
||||||
"type": "str",
|
|
||||||
"title": "MySQL User",
|
|
||||||
"required": false,
|
|
||||||
"default": "root",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "root"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "mysql_password",
|
|
||||||
"type": "str",
|
|
||||||
"title": "MySQL Password",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "mysql_database",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Database Name",
|
|
||||||
"required": false,
|
|
||||||
"default": "all",
|
|
||||||
"description": "Database to dump, or 'all' for all databases",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "all"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "backup_retention_days",
|
|
||||||
"type": "int",
|
|
||||||
"title": "Retention Days",
|
|
||||||
"required": false,
|
|
||||||
"default": 14,
|
|
||||||
"description": "Delete backup archives older than this many days",
|
|
||||||
"config": {
|
|
||||||
"slider": true,
|
|
||||||
"min": 1,
|
|
||||||
"max": 365,
|
|
||||||
"step": 1,
|
|
||||||
"placeholder": "14",
|
|
||||||
"unit": "days"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Notification",
|
|
||||||
"name": "notification",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "send_discord_notification",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Send Discord Notification",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"description": "Send success/failure status to Discord webhook"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "discord_webhook",
|
|
||||||
"type": "secret",
|
|
||||||
"title": "Discord Webhook",
|
|
||||||
"required": false,
|
|
||||||
"default": "",
|
|
||||||
"description": "Discord webhook URL for notifications"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Internal",
|
|
||||||
"name": "internal",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "backup_file_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Backup File Name",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "backup_root",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Backup Root",
|
|
||||||
"required": false,
|
|
||||||
"default": "/backups/mysql",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/backups/mysql"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ansible_failed_result",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Failed Result",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "backup_timestamp",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Backup Timestamp",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "old_backups",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Old Backups",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "backup_status",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Backup Status",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "inventory_hostname",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Inventory Hostname",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "backup_file_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Backup File Path",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "item",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Loop Item",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "backup_status_message",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Backup Status Message",
|
|
||||||
"required": false,
|
|
||||||
"default": "",
|
|
||||||
"config": {
|
|
||||||
"textarea": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Docker orphan detection
|
|
||||||
hosts: all
|
|
||||||
become: true
|
|
||||||
gather_facts: false
|
|
||||||
|
|
||||||
vars:
|
|
||||||
report_root: "/opt/docker-reports"
|
|
||||||
report_timestamp: "{{ lookup('pipe', 'date +%Y%m%d-%H%M%S') }}"
|
|
||||||
report_file_name: "docker_orphan_detection_<< inventory_hostname >>_<< report_timestamp >>.txt"
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- name: Ensure report root exists
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: "<< report_root >>"
|
|
||||||
state: directory
|
|
||||||
mode: "0750"
|
|
||||||
|
|
||||||
- name: List exited containers
|
|
||||||
ansible.builtin.command: docker ps -a --filter status=exited --format "{{.Names}}"
|
|
||||||
register: orphan_exited_containers
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: List dead containers
|
|
||||||
ansible.builtin.command: docker ps -a --filter status=dead --format "{{.Names}}"
|
|
||||||
register: orphan_dead_containers
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: List dangling images
|
|
||||||
ansible.builtin.command: docker images -f dangling=true -q
|
|
||||||
register: orphan_dangling_images
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: List dangling volumes
|
|
||||||
ansible.builtin.command: docker volume ls -qf dangling=true
|
|
||||||
register: orphan_dangling_volumes
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: List dangling networks
|
|
||||||
ansible.builtin.command: docker network ls -qf dangling=true
|
|
||||||
register: orphan_dangling_networks
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Build orphan report body
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
docker_orphan_report_body: |
|
|
||||||
Host: << inventory_hostname >>
|
|
||||||
Timestamp: {{ lookup('pipe', 'date -u +%Y-%m-%dT%H:%M:%SZ') }}
|
|
||||||
|
|
||||||
Exited containers (<< orphan_exited_containers.stdout_lines | length >>):
|
|
||||||
<< (orphan_exited_containers.stdout_lines | default([])) | join('\n') if (orphan_exited_containers.stdout_lines | length > 0) else 'none' >>
|
|
||||||
|
|
||||||
Dead containers (<< orphan_dead_containers.stdout_lines | length >>):
|
|
||||||
<< (orphan_dead_containers.stdout_lines | default([])) | join('\n') if (orphan_dead_containers.stdout_lines | length > 0) else 'none' >>
|
|
||||||
|
|
||||||
Dangling images (<< orphan_dangling_images.stdout_lines | length >>):
|
|
||||||
<< (orphan_dangling_images.stdout_lines | default([])) | join('\n') if (orphan_dangling_images.stdout_lines | length > 0) else 'none' >>
|
|
||||||
|
|
||||||
Dangling volumes (<< orphan_dangling_volumes.stdout_lines | length >>):
|
|
||||||
<< (orphan_dangling_volumes.stdout_lines | default([])) | join('\n') if (orphan_dangling_volumes.stdout_lines | length > 0) else 'none' >>
|
|
||||||
|
|
||||||
Dangling networks (<< orphan_dangling_networks.stdout_lines | length >>):
|
|
||||||
<< (orphan_dangling_networks.stdout_lines | default([])) | join('\n') if (orphan_dangling_networks.stdout_lines | length > 0) else 'none' >>
|
|
||||||
|
|
||||||
- name: Save local orphan detection report
|
|
||||||
ansible.builtin.copy:
|
|
||||||
dest: "<< report_root >>/<< report_file_name >>"
|
|
||||||
content: "<< docker_orphan_report_body >>"
|
|
||||||
mode: "0640"
|
|
||||||
|
|
||||||
- name: Build Discord report content
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
discord_orphan_report_content: |
|
|
||||||
<< discord_message_prefix | default('Docker Orphan Detection Report') >>
|
|
||||||
```text
|
|
||||||
<< docker_orphan_report_body | truncate(1700, true, '...') >>
|
|
||||||
```
|
|
||||||
when:
|
|
||||||
- discord_enabled | default(false)
|
|
||||||
- (discord_webhook_url | default('')) | length > 0
|
|
||||||
|
|
||||||
- name: Send orphan report to Discord webhook
|
|
||||||
ansible.builtin.uri:
|
|
||||||
url: "<< discord_webhook_url | default('') >>"
|
|
||||||
method: POST
|
|
||||||
body_format: json
|
|
||||||
body:
|
|
||||||
username: "<< discord_username | default('Docker Reporter') >>"
|
|
||||||
content: "<< discord_orphan_report_content >>"
|
|
||||||
status_code: 204
|
|
||||||
when:
|
|
||||||
- discord_enabled | default(false)
|
|
||||||
- (discord_webhook_url | default('')) | length > 0
|
|
||||||
@@ -1,155 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "docker-orphan-detection",
|
|
||||||
"kind": "ansible",
|
|
||||||
"metadata": {
|
|
||||||
"name": "Docker Orphan Detection",
|
|
||||||
"description": "Detects orphaned Docker resources (dead/exited containers, dangling images, volumes, and networks) and optionally sends a report to Discord via webhook.",
|
|
||||||
"tags": [
|
|
||||||
"docker",
|
|
||||||
"audit",
|
|
||||||
"orphan",
|
|
||||||
"report"
|
|
||||||
],
|
|
||||||
"icon": {
|
|
||||||
"provider": "mdi",
|
|
||||||
"id": "magnify",
|
|
||||||
"color": "fuchsia"
|
|
||||||
},
|
|
||||||
"draft": true,
|
|
||||||
"version": {
|
|
||||||
"name": "1",
|
|
||||||
"source_dep_name": "manual/docker-orphan-detection"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"title": "Discord Webhook",
|
|
||||||
"name": "discord",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "discord_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Discord",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"description": "Send orphan detection summary to Discord webhook"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "discord_webhook_url",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Discord Webhook URL",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "discord_username",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Discord Username",
|
|
||||||
"required": false,
|
|
||||||
"default": "Docker Reporter",
|
|
||||||
"description": "Sender name for webhook message",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "Docker Reporter"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "discord_message_prefix",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Discord Message Prefix",
|
|
||||||
"required": false,
|
|
||||||
"default": "Docker Orphan Detection Report",
|
|
||||||
"description": "Prefix line sent before report content",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "Docker Orphan Detection Report"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Internal",
|
|
||||||
"name": "internal",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "report_root",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Report Root",
|
|
||||||
"required": false,
|
|
||||||
"default": "/reports",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/reports"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "orphan_dead_containers",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Orphan Dead Containers",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "orphan_dangling_images",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Orphan Dangling Images",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "orphan_dangling_volumes",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Orphan Dangling Volumes",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "docker_orphan_report_body",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Orphan Report Body",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "report_timestamp",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Report Timestamp",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "orphan_exited_containers",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Orphan Exited Containers",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "orphan_dangling_networks",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Orphan Dangling Networks",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "report_file_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Report File Name",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "discord_orphan_report_content",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Orphan Report",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "inventory_hostname",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Inventory Hostname",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,156 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Docker postgres backup
|
|
||||||
hosts: all
|
|
||||||
become: true
|
|
||||||
gather_facts: false
|
|
||||||
|
|
||||||
vars:
|
|
||||||
backup_root: "/opt/docker-db-backups/postgres"
|
|
||||||
backup_timestamp: "{{ lookup('pipe', 'date +%Y%m%d-%H%M%S') }}"
|
|
||||||
backup_file_name: "backup_postgres_<< container_name >>_<< backup_timestamp >>.sql.gz"
|
|
||||||
backup_file_path: "<< backup_root >>/<< backup_file_name >>"
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- name: Ensure backup root exists
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: "<< backup_root >>"
|
|
||||||
state: directory
|
|
||||||
mode: "0750"
|
|
||||||
|
|
||||||
- name: Get container information
|
|
||||||
community.docker.docker_container_info:
|
|
||||||
name: "<< container_name >>"
|
|
||||||
register: container_info
|
|
||||||
|
|
||||||
- name: Fail if container does not exist
|
|
||||||
ansible.builtin.fail:
|
|
||||||
msg: "Container '<< container_name >>' does not exist"
|
|
||||||
when: not container_info.exists
|
|
||||||
|
|
||||||
- name: Run backup and validation
|
|
||||||
block:
|
|
||||||
- name: Dump all databases with password
|
|
||||||
ansible.builtin.shell: |
|
|
||||||
set -euo pipefail
|
|
||||||
docker exec -e PGPASSWORD=<< postgres_password | quote >> "<< container_name >>" \
|
|
||||||
pg_dumpall -U "<< postgres_user | default('postgres') >>" \
|
|
||||||
| gzip > "<< backup_file_path >>"
|
|
||||||
args:
|
|
||||||
executable: /bin/bash
|
|
||||||
changed_when: true
|
|
||||||
when:
|
|
||||||
- postgres_database | default('all') == 'all'
|
|
||||||
- (postgres_password | default('')) | length > 0
|
|
||||||
|
|
||||||
- name: Dump all databases without password
|
|
||||||
ansible.builtin.shell: |
|
|
||||||
set -euo pipefail
|
|
||||||
docker exec "<< container_name >>" \
|
|
||||||
pg_dumpall -U "<< postgres_user | default('postgres') >>" \
|
|
||||||
| gzip > "<< backup_file_path >>"
|
|
||||||
args:
|
|
||||||
executable: /bin/bash
|
|
||||||
changed_when: true
|
|
||||||
when:
|
|
||||||
- postgres_database | default('all') == 'all'
|
|
||||||
- (postgres_password | default('')) | length == 0
|
|
||||||
|
|
||||||
- name: Dump selected database with password
|
|
||||||
ansible.builtin.shell: |
|
|
||||||
set -euo pipefail
|
|
||||||
docker exec -e PGPASSWORD=<< postgres_password | quote >> "<< container_name >>" \
|
|
||||||
pg_dump -U "<< postgres_user | default('postgres') >>" \
|
|
||||||
"<< postgres_database >>" \
|
|
||||||
| gzip > "<< backup_file_path >>"
|
|
||||||
args:
|
|
||||||
executable: /bin/bash
|
|
||||||
changed_when: true
|
|
||||||
when:
|
|
||||||
- postgres_database | default('all') != 'all'
|
|
||||||
- (postgres_password | default('')) | length > 0
|
|
||||||
|
|
||||||
- name: Dump selected database without password
|
|
||||||
ansible.builtin.shell: |
|
|
||||||
set -euo pipefail
|
|
||||||
docker exec "<< container_name >>" \
|
|
||||||
pg_dump -U "<< postgres_user | default('postgres') >>" \
|
|
||||||
"<< postgres_database >>" \
|
|
||||||
| gzip > "<< backup_file_path >>"
|
|
||||||
args:
|
|
||||||
executable: /bin/bash
|
|
||||||
changed_when: true
|
|
||||||
when:
|
|
||||||
- postgres_database | default('all') != 'all'
|
|
||||||
- (postgres_password | default('')) | length == 0
|
|
||||||
|
|
||||||
- name: Validate backup file exists
|
|
||||||
ansible.builtin.stat:
|
|
||||||
path: "<< backup_file_path >>"
|
|
||||||
register: backup_archive_stat
|
|
||||||
|
|
||||||
- name: Fail if backup file is missing or empty
|
|
||||||
ansible.builtin.fail:
|
|
||||||
msg: "Backup file missing or empty: << backup_file_path >>"
|
|
||||||
when:
|
|
||||||
- not (backup_archive_stat.stat.exists | default(false))
|
|
||||||
or (backup_archive_stat.stat.size | default(0) | int) == 0
|
|
||||||
|
|
||||||
- name: Validate gzip archive integrity
|
|
||||||
ansible.builtin.command: gzip -t "<< backup_file_path >>"
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Validate postgres dump signature
|
|
||||||
ansible.builtin.shell: |
|
|
||||||
set -euo pipefail
|
|
||||||
gzip -dc "<< backup_file_path >>" \
|
|
||||||
| head -n 50 \
|
|
||||||
| grep -Eq 'PostgreSQL database dump'
|
|
||||||
args:
|
|
||||||
executable: /bin/bash
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Remove old postgres backup archives
|
|
||||||
ansible.builtin.find:
|
|
||||||
paths: "<< backup_root >>"
|
|
||||||
patterns: "backup_postgres_<< container_name >>_*.sql.gz"
|
|
||||||
age: "<< backup_retention_days | default(14) >>d"
|
|
||||||
recurse: true
|
|
||||||
register: old_backups
|
|
||||||
|
|
||||||
- name: Delete old postgres backup archives
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: "<< item.path >>"
|
|
||||||
state: absent
|
|
||||||
loop: "<< old_backups.files >>"
|
|
||||||
|
|
||||||
- name: Mark backup status success
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
backup_status: "success"
|
|
||||||
backup_status_message: "Backup and validation succeeded"
|
|
||||||
rescue:
|
|
||||||
- name: Mark backup status failed
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
backup_status: "failed"
|
|
||||||
backup_status_message: "<< ansible_failed_result.msg | default('Backup or validation failed') >>"
|
|
||||||
always:
|
|
||||||
- name: Send postgres backup status to Discord
|
|
||||||
ansible.builtin.uri:
|
|
||||||
url: "<< discord_webhook | default('') >>"
|
|
||||||
method: POST
|
|
||||||
body_format: json
|
|
||||||
body:
|
|
||||||
content: |
|
|
||||||
PostgreSQL Backup << backup_status | default('failed') | upper >>
|
|
||||||
Host: << inventory_hostname >>
|
|
||||||
Container: << container_name >>
|
|
||||||
File: << backup_file_path >>
|
|
||||||
Message: << backup_status_message | default('n/a') >>
|
|
||||||
status_code: 204
|
|
||||||
when:
|
|
||||||
- send_discord_notification | default(false)
|
|
||||||
- (discord_webhook | default('')) | length > 0
|
|
||||||
|
|
||||||
- name: Fail play if backup failed
|
|
||||||
ansible.builtin.fail:
|
|
||||||
msg: "<< backup_status_message | default('Backup failed') >>"
|
|
||||||
when: backup_status | default('failed') == 'failed'
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
collections:
|
|
||||||
- name: community.docker
|
|
||||||
@@ -1,187 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "docker-postgres-backup",
|
|
||||||
"kind": "ansible",
|
|
||||||
"metadata": {
|
|
||||||
"name": "Docker Postgres Backup",
|
|
||||||
"description": "Connects to a named PostgreSQL container and creates compressed SQL dumps with configurable retention. Supports optional Discord notifications on success or failure.",
|
|
||||||
"tags": [
|
|
||||||
"docker",
|
|
||||||
"backup",
|
|
||||||
"postgres",
|
|
||||||
"database"
|
|
||||||
],
|
|
||||||
"icon": {
|
|
||||||
"provider": "simple-icons",
|
|
||||||
"id": "postgresql",
|
|
||||||
"color": "emerald"
|
|
||||||
},
|
|
||||||
"draft": true,
|
|
||||||
"version": {
|
|
||||||
"name": "1",
|
|
||||||
"source_dep_name": "manual/docker-postgres-backup"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"title": "Backup",
|
|
||||||
"name": "backup",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "container_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Container Name",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "postgres_user",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Postgres User",
|
|
||||||
"required": false,
|
|
||||||
"default": "postgres",
|
|
||||||
"description": "Database user for pg_dump/pg_dumpall",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "postgres"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "postgres_password",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Postgres Password",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "postgres_database",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Database Name",
|
|
||||||
"required": false,
|
|
||||||
"default": "all",
|
|
||||||
"description": "Database to dump, or 'all' for all databases",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "all"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "backup_retention_days",
|
|
||||||
"type": "int",
|
|
||||||
"title": "Retention Days",
|
|
||||||
"required": false,
|
|
||||||
"default": 14,
|
|
||||||
"description": "Delete backup archives older than this many days",
|
|
||||||
"config": {
|
|
||||||
"slider": true,
|
|
||||||
"min": 1,
|
|
||||||
"max": 365,
|
|
||||||
"step": 1,
|
|
||||||
"placeholder": "14",
|
|
||||||
"unit": "days"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Notification",
|
|
||||||
"name": "notification",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "send_discord_notification",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Send Discord Notification",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"description": "Send success/failure status to Discord webhook"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "discord_webhook",
|
|
||||||
"type": "secret",
|
|
||||||
"title": "Discord Webhook",
|
|
||||||
"required": false,
|
|
||||||
"default": "",
|
|
||||||
"description": "Discord webhook URL for notifications"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Internal",
|
|
||||||
"name": "internal",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "backup_status",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Backup Status",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "inventory_hostname",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Inventory Hostname",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "backup_timestamp",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Backup Timestamp",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "item",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Loop Item",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "backup_file_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Backup File Path",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "old_backups",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Old Backups",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "backup_root",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Backup Root",
|
|
||||||
"required": false,
|
|
||||||
"default": "/backups/postgres",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/backups/postgres"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "backup_file_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Backup File Name",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ansible_failed_result",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Failed Result",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "backup_status_message",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Backup Status Message",
|
|
||||||
"required": false,
|
|
||||||
"default": "",
|
|
||||||
"config": {
|
|
||||||
"textarea": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Docker volume backup
|
|
||||||
hosts: all
|
|
||||||
become: true
|
|
||||||
gather_facts: false
|
|
||||||
|
|
||||||
vars:
|
|
||||||
backup_root: "/opt/docker-volume-backups"
|
|
||||||
backup_timestamp: "{{ lookup('pipe', 'date +%Y%m%d-%H%M%S') }}"
|
|
||||||
backup_archive_name: "backup_<< container_name >>_{{ backup_timestamp }}.tar.gz"
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- name: Ensure backup root exists
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: "{{ backup_root }}"
|
|
||||||
state: directory
|
|
||||||
mode: "0750"
|
|
||||||
|
|
||||||
- name: Get container information
|
|
||||||
community.docker.docker_container_info:
|
|
||||||
name: "<< container_name >>"
|
|
||||||
register: container_info
|
|
||||||
|
|
||||||
- name: Fail if container does not exist
|
|
||||||
ansible.builtin.fail:
|
|
||||||
msg: "Container '<< container_name >>' does not exist"
|
|
||||||
when: not container_info.exists
|
|
||||||
|
|
||||||
- name: Record container running state
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
container_was_running: "{{ (container_info.container.State.Status | default('')) == 'running' }}"
|
|
||||||
|
|
||||||
- name: Stop container for consistent backup
|
|
||||||
community.docker.docker_container:
|
|
||||||
name: "<< container_name >>"
|
|
||||||
state: stopped
|
|
||||||
when:
|
|
||||||
- stop_containers_during_backup | default(false)
|
|
||||||
- container_was_running
|
|
||||||
|
|
||||||
- name: Back up container path using all attached volumes
|
|
||||||
ansible.builtin.shell: |
|
|
||||||
set -eu
|
|
||||||
docker run --rm \
|
|
||||||
--volumes-from "<< container_name >>" \
|
|
||||||
-v "{{ backup_root }}":/backup \
|
|
||||||
busybox sh -c '
|
|
||||||
test -e "<< backup_container_path >>"
|
|
||||||
tar -czf "/backup/{{ backup_archive_name }}" \
|
|
||||||
-C / "<< backup_container_path | regex_replace('^/', '') >>"
|
|
||||||
'
|
|
||||||
args:
|
|
||||||
executable: /bin/sh
|
|
||||||
changed_when: true
|
|
||||||
|
|
||||||
- name: Start container after backup
|
|
||||||
community.docker.docker_container:
|
|
||||||
name: "<< container_name >>"
|
|
||||||
state: started
|
|
||||||
when:
|
|
||||||
- stop_containers_during_backup | default(false)
|
|
||||||
- container_was_running
|
|
||||||
|
|
||||||
- name: Remove old backup archives
|
|
||||||
ansible.builtin.find:
|
|
||||||
paths: "{{ backup_root }}"
|
|
||||||
patterns: "backup_<< container_name >>_*.tar.gz"
|
|
||||||
age: "<< backup_retention_days | default(14) >>d"
|
|
||||||
recurse: true
|
|
||||||
register: old_backups
|
|
||||||
|
|
||||||
- name: Delete old backup archives
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: "{{ item.path }}"
|
|
||||||
state: absent
|
|
||||||
loop: "{{ old_backups.files }}"
|
|
||||||
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
collections:
|
|
||||||
- name: community.docker
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "docker-volume-backup",
|
|
||||||
"kind": "ansible",
|
|
||||||
"metadata": {
|
|
||||||
"name": "Docker Volume Backup",
|
|
||||||
"description": "Backs up data from a Docker container path by auto-attaching all container volumes into a temporary backup container. Creates timestamped tar.gz archives with configurable retention.",
|
|
||||||
"tags": [
|
|
||||||
"docker",
|
|
||||||
"backup",
|
|
||||||
"volume",
|
|
||||||
"container"
|
|
||||||
],
|
|
||||||
"icon": {
|
|
||||||
"provider": "mdi",
|
|
||||||
"id": "harddisk",
|
|
||||||
"color": "emerald"
|
|
||||||
},
|
|
||||||
"draft": true,
|
|
||||||
"version": {
|
|
||||||
"name": "1",
|
|
||||||
"source_dep_name": "manual/docker-volume-backup"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"title": "Backup",
|
|
||||||
"name": "backup",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "container_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Container Name",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "backup_retention_days",
|
|
||||||
"type": "int",
|
|
||||||
"title": "Retention Days",
|
|
||||||
"required": false,
|
|
||||||
"default": 14,
|
|
||||||
"description": "Delete backup archives older than this many days",
|
|
||||||
"config": {
|
|
||||||
"slider": true,
|
|
||||||
"min": 1,
|
|
||||||
"max": 365,
|
|
||||||
"step": 1,
|
|
||||||
"placeholder": "14",
|
|
||||||
"unit": "days"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "backup_container_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Backup Path",
|
|
||||||
"required": true,
|
|
||||||
"description": "Path inside the container that should be archived"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "stop_containers_during_backup",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Stop Backup",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"description": "If enabled, stop the container before backup and start it again afterwards if it was running"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Internal",
|
|
||||||
"name": "internal",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "backup_timestamp",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Backup Timestamp",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "backup_root",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Backup Root",
|
|
||||||
"required": false,
|
|
||||||
"default": "/backups",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/backups"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "backup_archive_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Backup Archive Name",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "item",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Loop Item",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "old_backups",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Old Backups",
|
|
||||||
"required": false,
|
|
||||||
"default": ""
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,404 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Configure K3s post-install platform services - Fetch kubeconfig
|
|
||||||
hosts: all
|
|
||||||
gather_facts: false
|
|
||||||
become: true
|
|
||||||
<%- if secrets_file %>
|
|
||||||
vars_files:
|
|
||||||
- << secrets_file >>
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
vars:
|
|
||||||
kubeconfig_path: "<< kubeconfig_local_path >>"
|
|
||||||
kubeconfig_server_target: "<< kubeconfig_server_endpoint >>"
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- name: Validate that the kubeconfig source host exists in inventory
|
|
||||||
ansible.builtin.assert:
|
|
||||||
that:
|
|
||||||
- "'<< kubeconfig_source_host | default('k3s-server-01') >>' in hostvars"
|
|
||||||
fail_msg: "Inventory host '<< kubeconfig_source_host | default('k3s-server-01') >>' was not found."
|
|
||||||
run_once: true
|
|
||||||
|
|
||||||
- name: Read kubeconfig from the primary K3s server
|
|
||||||
ansible.builtin.slurp:
|
|
||||||
src: "<< kubeconfig_source_path | default('/etc/rancher/k3s/k3s.yaml') >>"
|
|
||||||
delegate_to: "<< kubeconfig_source_host | default('k3s-server-01') >>"
|
|
||||||
register: k3s_source_kubeconfig
|
|
||||||
when: fetch_kubeconfig | default(true)
|
|
||||||
run_once: true
|
|
||||||
|
|
||||||
- name: Ensure local kubeconfig directory exists
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: "{{ kubeconfig_path | dirname }}"
|
|
||||||
state: directory
|
|
||||||
mode: "0700"
|
|
||||||
delegate_to: localhost
|
|
||||||
run_once: true
|
|
||||||
when: fetch_kubeconfig | default(true)
|
|
||||||
|
|
||||||
- name: Write kubeconfig to the control machine
|
|
||||||
ansible.builtin.copy:
|
|
||||||
dest: "{{ kubeconfig_path }}"
|
|
||||||
mode: "0600"
|
|
||||||
content: "{{ (k3s_source_kubeconfig.content | b64decode) | regex_replace('https://127\\.0\\.0\\.1:6443', 'https://' ~ kubeconfig_server_target ~ ':6443') }}"
|
|
||||||
delegate_to: localhost
|
|
||||||
run_once: true
|
|
||||||
when: fetch_kubeconfig | default(true)
|
|
||||||
|
|
||||||
- name: Configure K3s post-install platform services - Prepare Longhorn prerequisites
|
|
||||||
hosts: all
|
|
||||||
gather_facts: false
|
|
||||||
become: true
|
|
||||||
<%- if secrets_file %>
|
|
||||||
vars_files:
|
|
||||||
- << secrets_file >>
|
|
||||||
<%- endif %>
|
|
||||||
vars:
|
|
||||||
longhorn_target_hosts: "{{ query('inventory_hostnames', '<< longhorn_node_hosts >>') }}"
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- name: Validate Longhorn target host pattern
|
|
||||||
ansible.builtin.assert:
|
|
||||||
that:
|
|
||||||
- longhorn_target_hosts | length > 0
|
|
||||||
fail_msg: "No inventory hosts matched '<< longhorn_node_hosts >>'."
|
|
||||||
when: longhorn_prerequisites_enabled | default(false)
|
|
||||||
run_once: true
|
|
||||||
|
|
||||||
- name: Install Longhorn prerequisite packages
|
|
||||||
ansible.builtin.apt:
|
|
||||||
name:
|
|
||||||
- open-iscsi
|
|
||||||
- nfs-common
|
|
||||||
- cryptsetup
|
|
||||||
- util-linux
|
|
||||||
state: present
|
|
||||||
update_cache: true
|
|
||||||
when:
|
|
||||||
- longhorn_prerequisites_enabled | default(false)
|
|
||||||
- inventory_hostname in longhorn_target_hosts
|
|
||||||
|
|
||||||
- name: Ensure iscsid service is enabled and running
|
|
||||||
ansible.builtin.service:
|
|
||||||
name: iscsid
|
|
||||||
state: started
|
|
||||||
enabled: true
|
|
||||||
when:
|
|
||||||
- longhorn_prerequisites_enabled | default(false)
|
|
||||||
- inventory_hostname in longhorn_target_hosts
|
|
||||||
|
|
||||||
- name: Ensure open-iscsi service is enabled and running when present
|
|
||||||
ansible.builtin.service:
|
|
||||||
name: open-iscsi
|
|
||||||
state: started
|
|
||||||
enabled: true
|
|
||||||
failed_when: false
|
|
||||||
when:
|
|
||||||
- longhorn_prerequisites_enabled | default(false)
|
|
||||||
- inventory_hostname in longhorn_target_hosts
|
|
||||||
|
|
||||||
- name: Persist dm_crypt kernel module for Longhorn
|
|
||||||
ansible.builtin.copy:
|
|
||||||
dest: /etc/modules-load.d/longhorn.conf
|
|
||||||
mode: "0644"
|
|
||||||
content: |
|
|
||||||
dm_crypt
|
|
||||||
when:
|
|
||||||
- longhorn_prerequisites_enabled | default(false)
|
|
||||||
- inventory_hostname in longhorn_target_hosts
|
|
||||||
|
|
||||||
- name: Load dm_crypt kernel module immediately
|
|
||||||
community.general.modprobe:
|
|
||||||
name: dm_crypt
|
|
||||||
state: present
|
|
||||||
when:
|
|
||||||
- longhorn_prerequisites_enabled | default(false)
|
|
||||||
- inventory_hostname in longhorn_target_hosts
|
|
||||||
|
|
||||||
- name: Disable multipathd when the environment does not use multipath storage
|
|
||||||
ansible.builtin.service:
|
|
||||||
name: multipathd
|
|
||||||
state: stopped
|
|
||||||
enabled: false
|
|
||||||
failed_when: false
|
|
||||||
when:
|
|
||||||
- longhorn_prerequisites_enabled | default(false)
|
|
||||||
- longhorn_disable_multipathd | default(false)
|
|
||||||
- inventory_hostname in longhorn_target_hosts
|
|
||||||
|
|
||||||
- name: Configure K3s post-install platform services - Configure cluster add-ons
|
|
||||||
hosts: all
|
|
||||||
gather_facts: false
|
|
||||||
<%- if secrets_file %>
|
|
||||||
vars_files:
|
|
||||||
- << secrets_file >>
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
vars:
|
|
||||||
kubeconfig_path: "<< kubeconfig_local_path >>"
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- block:
|
|
||||||
- name: Ensure the kubeconfig file exists before applying cluster resources
|
|
||||||
ansible.builtin.stat:
|
|
||||||
path: "{{ kubeconfig_path }}"
|
|
||||||
register: kubeconfig_stat
|
|
||||||
|
|
||||||
- name: Fail when the kubeconfig file is missing
|
|
||||||
ansible.builtin.fail:
|
|
||||||
msg: "Kubeconfig not found at {{ kubeconfig_path }}. Enable fetch_kubeconfig or provide an existing kubeconfig path."
|
|
||||||
when: not (kubeconfig_stat.stat.exists | default(false))
|
|
||||||
|
|
||||||
- name: Verify Helm is available on the control machine when required
|
|
||||||
ansible.builtin.command:
|
|
||||||
cmd: helm version --short
|
|
||||||
changed_when: false
|
|
||||||
when: (cert_manager_install_enabled | default(false)) or (metrics_server_install_enabled | default(false)) or (longhorn_install_enabled | default(false))
|
|
||||||
|
|
||||||
- name: Validate ACME email when ClusterIssuer creation is enabled
|
|
||||||
ansible.builtin.assert:
|
|
||||||
that:
|
|
||||||
- (cert_manager_acme_email | default('')) | length > 0
|
|
||||||
fail_msg: "cert_manager_acme_email must be set when cert_manager_clusterissuer_enabled=true."
|
|
||||||
when: cert_manager_clusterissuer_enabled | default(false)
|
|
||||||
|
|
||||||
- name: Build namespace list for enabled platform components
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
managed_namespaces: >-
|
|
||||||
{{
|
|
||||||
(
|
|
||||||
(extra_namespaces_yaml | default('[]') | from_yaml)
|
|
||||||
+ ([cert_manager_namespace | default('cert-manager')] if cert_manager_install_enabled | default(false) or cert_manager_create_cloudflare_secret | default(false) or cert_manager_clusterissuer_enabled | default(false) else [])
|
|
||||||
+ ([longhorn_namespace | default('longhorn-system')] if longhorn_install_enabled | default(false) else [])
|
|
||||||
+ ([traefik_dashboard_namespace | default('traefik')] if traefik_dashboard_exposure_enabled | default(false) else [])
|
|
||||||
) | unique
|
|
||||||
}}
|
|
||||||
when: ensure_namespaces | default(true)
|
|
||||||
|
|
||||||
- name: Ensure selected namespaces exist
|
|
||||||
kubernetes.core.k8s:
|
|
||||||
kubeconfig: "{{ kubeconfig_path }}"
|
|
||||||
state: present
|
|
||||||
definition:
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Namespace
|
|
||||||
metadata:
|
|
||||||
name: "{{ item }}"
|
|
||||||
loop: "{{ managed_namespaces | default([]) }}"
|
|
||||||
loop_control:
|
|
||||||
label: "{{ item }}"
|
|
||||||
when:
|
|
||||||
- ensure_namespaces | default(true)
|
|
||||||
- item | length > 0
|
|
||||||
|
|
||||||
- name: Add cert-manager Helm repository
|
|
||||||
kubernetes.core.helm_repository:
|
|
||||||
name: jetstack
|
|
||||||
repo_url: https://charts.jetstack.io
|
|
||||||
when: cert_manager_install_enabled | default(false)
|
|
||||||
|
|
||||||
- name: Install cert-manager
|
|
||||||
kubernetes.core.helm:
|
|
||||||
kubeconfig: "{{ kubeconfig_path }}"
|
|
||||||
name: cert-manager
|
|
||||||
chart_ref: jetstack/cert-manager
|
|
||||||
chart_version: "<< cert_manager_chart_version | default('1.18.2') >>"
|
|
||||||
release_namespace: "<< cert_manager_namespace | default('cert-manager') >>"
|
|
||||||
create_namespace: true
|
|
||||||
wait: true
|
|
||||||
values:
|
|
||||||
crds:
|
|
||||||
enabled: true
|
|
||||||
when: cert_manager_install_enabled | default(false)
|
|
||||||
|
|
||||||
- name: Create Cloudflare API token secret placeholder for cert-manager
|
|
||||||
kubernetes.core.k8s:
|
|
||||||
kubeconfig: "{{ kubeconfig_path }}"
|
|
||||||
state: present
|
|
||||||
definition:
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Secret
|
|
||||||
metadata:
|
|
||||||
name: "<< cert_manager_cloudflare_secret_name | default('cloudflare-api-token-secret') >>"
|
|
||||||
namespace: "<< cert_manager_namespace | default('cert-manager') >>"
|
|
||||||
type: Opaque
|
|
||||||
stringData:
|
|
||||||
<< cert_manager_cloudflare_secret_key | default('api-token') >>: "<< cert_manager_cloudflare_api_token | default('replace-me-with-your-cloudflare-api-token') >>"
|
|
||||||
when: cert_manager_create_cloudflare_secret | default(false)
|
|
||||||
|
|
||||||
- name: Create cert-manager ClusterIssuer
|
|
||||||
kubernetes.core.k8s:
|
|
||||||
kubeconfig: "{{ kubeconfig_path }}"
|
|
||||||
state: present
|
|
||||||
definition:
|
|
||||||
apiVersion: cert-manager.io/v1
|
|
||||||
kind: ClusterIssuer
|
|
||||||
metadata:
|
|
||||||
name: "<< cert_manager_clusterissuer_name | default('letsencrypt-production') >>"
|
|
||||||
spec:
|
|
||||||
acme:
|
|
||||||
email: "<< cert_manager_acme_email >>"
|
|
||||||
server: "<< cert_manager_acme_server | default('https://acme-v02.api.letsencrypt.org/directory') >>"
|
|
||||||
privateKeySecretRef:
|
|
||||||
name: "<< cert_manager_clusterissuer_name | default('letsencrypt-production') >>-account-key"
|
|
||||||
solvers:
|
|
||||||
- dns01:
|
|
||||||
cloudflare:
|
|
||||||
apiTokenSecretRef:
|
|
||||||
name: "<< cert_manager_cloudflare_secret_name | default('cloudflare-api-token-secret') >>"
|
|
||||||
key: "<< cert_manager_cloudflare_secret_key | default('api-token') >>"
|
|
||||||
when: cert_manager_clusterissuer_enabled | default(false)
|
|
||||||
|
|
||||||
- name: Add metrics-server Helm repository
|
|
||||||
kubernetes.core.helm_repository:
|
|
||||||
name: metrics-server
|
|
||||||
repo_url: https://kubernetes-sigs.github.io/metrics-server/
|
|
||||||
when: metrics_server_install_enabled | default(false)
|
|
||||||
|
|
||||||
- name: Install metrics-server
|
|
||||||
kubernetes.core.helm:
|
|
||||||
kubeconfig: "{{ kubeconfig_path }}"
|
|
||||||
name: metrics-server
|
|
||||||
chart_ref: metrics-server/metrics-server
|
|
||||||
chart_version: "<< metrics_server_chart_version | default('3.13.0') >>"
|
|
||||||
release_namespace: "<< metrics_server_namespace | default('kube-system') >>"
|
|
||||||
create_namespace: true
|
|
||||||
wait: true
|
|
||||||
<%- if metrics_server_kubelet_insecure_tls %>
|
|
||||||
values:
|
|
||||||
args:
|
|
||||||
- --kubelet-insecure-tls
|
|
||||||
<%- endif %>
|
|
||||||
when: metrics_server_install_enabled | default(false)
|
|
||||||
|
|
||||||
- name: Add Longhorn Helm repository
|
|
||||||
kubernetes.core.helm_repository:
|
|
||||||
name: longhorn
|
|
||||||
repo_url: https://charts.longhorn.io
|
|
||||||
when: longhorn_install_enabled | default(false)
|
|
||||||
|
|
||||||
- name: Install Longhorn
|
|
||||||
kubernetes.core.helm:
|
|
||||||
kubeconfig: "{{ kubeconfig_path }}"
|
|
||||||
name: longhorn
|
|
||||||
chart_ref: longhorn/longhorn
|
|
||||||
chart_version: "<< longhorn_chart_version | default('1.9.1') >>"
|
|
||||||
release_namespace: "<< longhorn_namespace | default('longhorn-system') >>"
|
|
||||||
create_namespace: true
|
|
||||||
wait: true
|
|
||||||
values:
|
|
||||||
defaultSettings:
|
|
||||||
defaultDataPath: "<< longhorn_default_data_path | default('/var/lib/longhorn') >>"
|
|
||||||
when: longhorn_install_enabled | default(false)
|
|
||||||
|
|
||||||
- name: Expose Traefik dashboard through an IngressRoute
|
|
||||||
kubernetes.core.k8s:
|
|
||||||
kubeconfig: "{{ kubeconfig_path }}"
|
|
||||||
state: present
|
|
||||||
definition:
|
|
||||||
apiVersion: traefik.io/v1alpha1
|
|
||||||
kind: IngressRoute
|
|
||||||
metadata:
|
|
||||||
name: traefik-dashboard
|
|
||||||
namespace: "<< traefik_dashboard_namespace | default('traefik') >>"
|
|
||||||
spec:
|
|
||||||
entryPoints:
|
|
||||||
- "<< traefik_dashboard_entrypoint | default('websecure') >>"
|
|
||||||
routes:
|
|
||||||
- match: "Host(`<< traefik_dashboard_host | default('traefik.example.internal') >>`)"
|
|
||||||
kind: Rule
|
|
||||||
<%- if traefik_dashboard_middleware_name %>
|
|
||||||
middlewares:
|
|
||||||
- name: "<< traefik_dashboard_middleware_name >>"
|
|
||||||
namespace: "<< traefik_dashboard_middleware_namespace | default('traefik') >>"
|
|
||||||
<%- endif %>
|
|
||||||
services:
|
|
||||||
- kind: TraefikService
|
|
||||||
name: api@internal
|
|
||||||
<%- if traefik_dashboard_tls_enabled %>
|
|
||||||
tls:
|
|
||||||
secretName: "<< traefik_dashboard_tls_secret_name | default('traefik-dashboard-tls') >>"
|
|
||||||
<%- endif %>
|
|
||||||
when: traefik_dashboard_exposure_enabled | default(false)
|
|
||||||
|
|
||||||
- name: Read kube-proxy ConfigMap before strictARP patch
|
|
||||||
kubernetes.core.k8s_info:
|
|
||||||
kubeconfig: "{{ kubeconfig_path }}"
|
|
||||||
api_version: v1
|
|
||||||
kind: ConfigMap
|
|
||||||
namespace: kube-system
|
|
||||||
name: kube-proxy
|
|
||||||
register: kube_proxy_configmap
|
|
||||||
when: kube_proxy_strict_arp_enabled | default(false)
|
|
||||||
|
|
||||||
- name: Build kube-proxy configuration with strictARP enabled
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
kube_proxy_rendered_config: >-
|
|
||||||
{{
|
|
||||||
(kube_proxy_configmap.resources[0].data['config.conf'] | from_yaml)
|
|
||||||
| combine(
|
|
||||||
{
|
|
||||||
'ipvs': (
|
|
||||||
(kube_proxy_configmap.resources[0].data['config.conf'] | from_yaml).ipvs
|
|
||||||
| default({})
|
|
||||||
| combine({'strictARP': true})
|
|
||||||
)
|
|
||||||
},
|
|
||||||
recursive=True
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
when:
|
|
||||||
- kube_proxy_strict_arp_enabled | default(false)
|
|
||||||
- kube_proxy_configmap.resources | length > 0
|
|
||||||
|
|
||||||
- name: Patch kube-proxy ConfigMap with strictARP enabled
|
|
||||||
kubernetes.core.k8s:
|
|
||||||
kubeconfig: "{{ kubeconfig_path }}"
|
|
||||||
state: present
|
|
||||||
merge_type:
|
|
||||||
- merge
|
|
||||||
definition:
|
|
||||||
apiVersion: v1
|
|
||||||
kind: ConfigMap
|
|
||||||
metadata:
|
|
||||||
name: kube-proxy
|
|
||||||
namespace: kube-system
|
|
||||||
data:
|
|
||||||
config.conf: "{{ kube_proxy_rendered_config | to_nice_yaml(indent=2) }}"
|
|
||||||
when:
|
|
||||||
- kube_proxy_strict_arp_enabled | default(false)
|
|
||||||
- kube_proxy_configmap.resources | length > 0
|
|
||||||
|
|
||||||
- name: Read kube-proxy daemonset for restart
|
|
||||||
kubernetes.core.k8s_info:
|
|
||||||
kubeconfig: "{{ kubeconfig_path }}"
|
|
||||||
api_version: apps/v1
|
|
||||||
kind: DaemonSet
|
|
||||||
namespace: kube-system
|
|
||||||
name: kube-proxy
|
|
||||||
register: kube_proxy_daemonset
|
|
||||||
when: kube_proxy_strict_arp_enabled | default(false)
|
|
||||||
|
|
||||||
- name: Restart kube-proxy daemonset after strictARP change
|
|
||||||
kubernetes.core.k8s:
|
|
||||||
kubeconfig: "{{ kubeconfig_path }}"
|
|
||||||
state: present
|
|
||||||
merge_type:
|
|
||||||
- merge
|
|
||||||
definition:
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: DaemonSet
|
|
||||||
metadata:
|
|
||||||
name: kube-proxy
|
|
||||||
namespace: kube-system
|
|
||||||
spec:
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
annotations:
|
|
||||||
homelab.boilerplates.io/restarted-at: "{{ lookup('pipe', 'date -u +%Y-%m-%dT%H:%M:%SZ') }}"
|
|
||||||
when:
|
|
||||||
- kube_proxy_strict_arp_enabled | default(false)
|
|
||||||
- kube_proxy_daemonset.resources | length > 0
|
|
||||||
delegate_to: localhost
|
|
||||||
run_once: true
|
|
||||||
@@ -1,527 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "k3s-postinstall",
|
|
||||||
"kind": "ansible",
|
|
||||||
"metadata": {
|
|
||||||
"name": "K3s Post-Install Platform Setup",
|
|
||||||
"description": "Configures common post-install building blocks for a fresh K3s cluster. Supports kubeconfig retrieval, namespace management, Traefik dashboard exposure, cert-manager bootstrap, metrics-server, Longhorn preparation, and optional kube-system tuning.",
|
|
||||||
"tags": [
|
|
||||||
"kubernetes",
|
|
||||||
"k3s",
|
|
||||||
"postinstall",
|
|
||||||
"helm",
|
|
||||||
"homelab"
|
|
||||||
],
|
|
||||||
"icon": {
|
|
||||||
"provider": "simple-icons",
|
|
||||||
"id": "kubernetes"
|
|
||||||
},
|
|
||||||
"draft": false,
|
|
||||||
"version": {
|
|
||||||
"name": "1.0.0",
|
|
||||||
"source_dep_name": "manual/k3s-postinstall"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"title": "Execution",
|
|
||||||
"name": "execution",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "secrets_file",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Secrets File",
|
|
||||||
"required": false,
|
|
||||||
"default": "",
|
|
||||||
"description": "Optional vars file to load before running the playbook."
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Kubeconfig",
|
|
||||||
"name": "kubeconfig",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "fetch_kubeconfig",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Fetch Kubeconfig",
|
|
||||||
"required": false,
|
|
||||||
"default": true,
|
|
||||||
"description": "Fetch the admin kubeconfig from the first K3s server before applying cluster resources"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "kubeconfig_source_host",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Source Host",
|
|
||||||
"required": false,
|
|
||||||
"default": "k3s-server-01",
|
|
||||||
"description": "Inventory host that stores the K3s admin kubeconfig",
|
|
||||||
"needs": [
|
|
||||||
"fetch_kubeconfig=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "k3s-server-01"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "kubeconfig_source_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Source Path",
|
|
||||||
"required": false,
|
|
||||||
"default": "/etc/rancher/k3s/k3s.yaml",
|
|
||||||
"description": "Path to the kubeconfig file on the K3s server",
|
|
||||||
"needs": [
|
|
||||||
"fetch_kubeconfig=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/etc/rancher/k3s/k3s.yaml"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "kubeconfig_server_endpoint",
|
|
||||||
"type": "str",
|
|
||||||
"title": "API Endpoint",
|
|
||||||
"required": false,
|
|
||||||
"default": "{{ hostvars['k3s-server-01'].ansible_host | default('k3s-server-01') }}",
|
|
||||||
"description": "Host or IP that should replace 127.0.0.1 in the fetched kubeconfig",
|
|
||||||
"needs": [
|
|
||||||
"fetch_kubeconfig=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "192.168.1.10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "kubeconfig_local_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Local Kubeconfig",
|
|
||||||
"required": false,
|
|
||||||
"default": "{{ lookup('env', 'HOME') }}/.kube/k3s.yaml",
|
|
||||||
"description": "Local kubeconfig path used by the control machine for all cluster operations",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "{{ lookup('env', 'HOME') }}/.kube/k3s.yaml"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Namespaces",
|
|
||||||
"name": "namespaces",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "ensure_namespaces",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Manage Namespaces",
|
|
||||||
"required": false,
|
|
||||||
"default": true,
|
|
||||||
"description": "Ensure common namespaces exist before installing platform add-ons"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "extra_namespaces_yaml",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Extra Namespaces",
|
|
||||||
"required": false,
|
|
||||||
"default": "[]",
|
|
||||||
"description": "YAML list of extra namespaces to create",
|
|
||||||
"needs": [
|
|
||||||
"ensure_namespaces=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"textarea": true,
|
|
||||||
"placeholder": "- apps\n- monitoring"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Traefik",
|
|
||||||
"name": "traefik",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "traefik_dashboard_exposure_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Expose Dashboard",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"description": "Create a Traefik IngressRoute that exposes the internal Traefik dashboard"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_dashboard_namespace",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Namespace",
|
|
||||||
"required": false,
|
|
||||||
"default": "traefik",
|
|
||||||
"description": "Namespace where the Traefik release is installed",
|
|
||||||
"needs": [
|
|
||||||
"traefik_dashboard_exposure_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "traefik"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_dashboard_host",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Dashboard Host",
|
|
||||||
"required": false,
|
|
||||||
"default": "traefik.example.internal",
|
|
||||||
"description": "FQDN used to expose the Traefik dashboard",
|
|
||||||
"needs": [
|
|
||||||
"traefik_dashboard_exposure_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "traefik.example.internal"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_dashboard_entrypoint",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Entrypoint",
|
|
||||||
"required": false,
|
|
||||||
"default": "websecure",
|
|
||||||
"description": "Traefik entrypoint for the dashboard route",
|
|
||||||
"needs": [
|
|
||||||
"traefik_dashboard_exposure_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "websecure"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_dashboard_tls_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "TLS",
|
|
||||||
"required": false,
|
|
||||||
"default": true,
|
|
||||||
"needs": [
|
|
||||||
"traefik_dashboard_exposure_enabled=true"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_dashboard_tls_secret_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "TLS Secret",
|
|
||||||
"required": false,
|
|
||||||
"default": "traefik-dashboard-tls",
|
|
||||||
"description": "TLS secret used by the dashboard route when TLS is enabled",
|
|
||||||
"needs": [
|
|
||||||
"traefik_dashboard_exposure_enabled=true",
|
|
||||||
"traefik_dashboard_tls_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "traefik-dashboard-tls"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_dashboard_middleware_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Middleware",
|
|
||||||
"required": false,
|
|
||||||
"default": "",
|
|
||||||
"description": "Optional Traefik middleware name attached to the dashboard route",
|
|
||||||
"needs": [
|
|
||||||
"traefik_dashboard_exposure_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "traefik-dashboard-auth"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_dashboard_middleware_namespace",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Middleware NS",
|
|
||||||
"required": false,
|
|
||||||
"default": "traefik",
|
|
||||||
"needs": [
|
|
||||||
"traefik_dashboard_exposure_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "traefik"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Cert-Manager",
|
|
||||||
"name": "cert-manager",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "cert_manager_install_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Install cert-manager",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "cert_manager_chart_version",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Chart Version",
|
|
||||||
"required": false,
|
|
||||||
"default": "1.18.2",
|
|
||||||
"needs": [
|
|
||||||
"cert_manager_install_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "1.18.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "cert_manager_namespace",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Namespace",
|
|
||||||
"required": false,
|
|
||||||
"default": "cert-manager",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "cert-manager"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "cert_manager_create_cloudflare_secret",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Cloudflare Secret",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"description": "Create a placeholder secret for a Cloudflare DNS API token"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "cert_manager_cloudflare_secret_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Secret Name",
|
|
||||||
"required": false,
|
|
||||||
"default": "cloudflare-api-token-secret",
|
|
||||||
"description": "Secret name for the Cloudflare DNS API token",
|
|
||||||
"needs": [
|
|
||||||
"cert_manager_create_cloudflare_secret=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "cloudflare-api-token-secret"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "cert_manager_cloudflare_secret_key",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Secret Key",
|
|
||||||
"required": false,
|
|
||||||
"default": "api-token",
|
|
||||||
"description": "Secret key that stores the Cloudflare API token",
|
|
||||||
"needs": [
|
|
||||||
"cert_manager_create_cloudflare_secret=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "api-token"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "cert_manager_cloudflare_api_token",
|
|
||||||
"type": "secret",
|
|
||||||
"title": "Cloudflare Token",
|
|
||||||
"required": false,
|
|
||||||
"default": "",
|
|
||||||
"description": "Optional Cloudflare API token value used to populate the placeholder secret",
|
|
||||||
"needs": [
|
|
||||||
"cert_manager_create_cloudflare_secret=true"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "cert_manager_clusterissuer_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "ClusterIssuer",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"description": "Create a production Let's Encrypt ClusterIssuer that uses Cloudflare DNS-01"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "cert_manager_clusterissuer_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "ClusterIssuer Name",
|
|
||||||
"required": false,
|
|
||||||
"default": "letsencrypt-production",
|
|
||||||
"needs": [
|
|
||||||
"cert_manager_clusterissuer_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "letsencrypt-production"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "cert_manager_acme_email",
|
|
||||||
"type": "str",
|
|
||||||
"title": "ACME Email",
|
|
||||||
"required": false,
|
|
||||||
"default": "",
|
|
||||||
"description": "Email address used for ACME registration",
|
|
||||||
"needs": [
|
|
||||||
"cert_manager_clusterissuer_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "me@example.com"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "cert_manager_acme_server",
|
|
||||||
"type": "str",
|
|
||||||
"title": "ACME Server",
|
|
||||||
"required": false,
|
|
||||||
"default": "https://acme-v02.api.letsencrypt.org/directory",
|
|
||||||
"description": "ACME directory URL used by the ClusterIssuer",
|
|
||||||
"needs": [
|
|
||||||
"cert_manager_clusterissuer_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "https://acme-v02.api.letsencrypt.org/directory"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Metrics Server",
|
|
||||||
"name": "metrics-server",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "metrics_server_install_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Install Metrics Server",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "metrics_server_chart_version",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Chart Version",
|
|
||||||
"required": false,
|
|
||||||
"default": "3.13.0",
|
|
||||||
"needs": [
|
|
||||||
"metrics_server_install_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "3.13.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "metrics_server_namespace",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Namespace",
|
|
||||||
"required": false,
|
|
||||||
"default": "kube-system",
|
|
||||||
"needs": [
|
|
||||||
"metrics_server_install_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "kube-system"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "metrics_server_kubelet_insecure_tls",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Insecure TLS",
|
|
||||||
"required": false,
|
|
||||||
"default": true,
|
|
||||||
"description": "Add --kubelet-insecure-tls for clusters that use self-signed kubelet certificates",
|
|
||||||
"needs": [
|
|
||||||
"metrics_server_install_enabled=true"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Longhorn",
|
|
||||||
"name": "longhorn",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "longhorn_prerequisites_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Prepare Nodes",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"description": "Install host packages and kernel module configuration needed by Longhorn"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "longhorn_node_hosts",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Node Hosts",
|
|
||||||
"required": false,
|
|
||||||
"default": "k3s_cluster",
|
|
||||||
"description": "Inventory host pattern for the nodes that should be prepared for Longhorn",
|
|
||||||
"needs": [
|
|
||||||
"longhorn_prerequisites_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "k3s_cluster"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "longhorn_disable_multipathd",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Disable multipathd",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"description": "Stop and disable multipathd if your nodes do not use multipath storage",
|
|
||||||
"needs": [
|
|
||||||
"longhorn_prerequisites_enabled=true"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "longhorn_install_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Install Longhorn",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"description": "Install Longhorn with Helm after prerequisites are in place"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "longhorn_chart_version",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Chart Version",
|
|
||||||
"required": false,
|
|
||||||
"default": "1.9.1",
|
|
||||||
"needs": [
|
|
||||||
"longhorn_install_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "1.9.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "longhorn_namespace",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Namespace",
|
|
||||||
"required": false,
|
|
||||||
"default": "longhorn-system",
|
|
||||||
"needs": [
|
|
||||||
"longhorn_install_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "longhorn-system"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "longhorn_default_data_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Data Path",
|
|
||||||
"required": false,
|
|
||||||
"default": "/var/lib/longhorn",
|
|
||||||
"description": "Default host path used by Longhorn for replica data",
|
|
||||||
"needs": [
|
|
||||||
"longhorn_install_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/var/lib/longhorn"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Kube-System",
|
|
||||||
"name": "kube-system",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "kube_proxy_strict_arp_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Enable strictARP",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"description": "Patch the kube-proxy ConfigMap and restart the daemonset with strictARP enabled"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,200 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Bootstrap K3s cluster with k3sup
|
|
||||||
hosts: all
|
|
||||||
gather_facts: false
|
|
||||||
<%- if secrets_file %>
|
|
||||||
vars_files:
|
|
||||||
- << secrets_file >>
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
vars:
|
|
||||||
k3s_server_target: "{{ hostvars['<< k3s_server_host >>'].ansible_host | default('<< k3s_server_host >>') }}"
|
|
||||||
<%- if kubeconfig_destination_mode == 'remote' %>
|
|
||||||
k3s_generated_kubeconfig_path: "/tmp/<< k3s_context_name | default('homelab-k3s') >>-kubeconfig"
|
|
||||||
<%- else %>
|
|
||||||
k3s_generated_kubeconfig_path: "<< local_kubeconfig_path >>"
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- name: Gather control machine facts
|
|
||||||
ansible.builtin.setup:
|
|
||||||
delegate_to: localhost
|
|
||||||
run_once: true
|
|
||||||
register: localhost_facts
|
|
||||||
|
|
||||||
- name: Validate that the first server host exists in inventory
|
|
||||||
ansible.builtin.assert:
|
|
||||||
that:
|
|
||||||
- "'<< k3s_server_host >>' in hostvars"
|
|
||||||
fail_msg: "Inventory host '<< k3s_server_host >>' was not found."
|
|
||||||
run_once: true
|
|
||||||
|
|
||||||
- name: Resolve k3sup release asset
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
k3sup_release_asset: >-
|
|
||||||
{%- if localhost_facts.ansible_facts.ansible_system == 'Linux' and localhost_facts.ansible_facts.ansible_architecture in ['x86_64', 'amd64'] -%}
|
|
||||||
k3sup
|
|
||||||
{%- elif localhost_facts.ansible_facts.ansible_system == 'Linux' and localhost_facts.ansible_facts.ansible_architecture in ['aarch64', 'arm64'] -%}
|
|
||||||
k3sup-arm64
|
|
||||||
{%- elif localhost_facts.ansible_facts.ansible_system == 'Linux' and localhost_facts.ansible_facts.ansible_architecture in ['armv7l', 'armv6l'] -%}
|
|
||||||
k3sup-arm
|
|
||||||
{%- elif localhost_facts.ansible_facts.ansible_system == 'Darwin' and localhost_facts.ansible_facts.ansible_architecture in ['x86_64', 'amd64'] -%}
|
|
||||||
k3sup-darwin
|
|
||||||
{%- elif localhost_facts.ansible_facts.ansible_system == 'Darwin' and localhost_facts.ansible_facts.ansible_architecture in ['arm64', 'aarch64'] -%}
|
|
||||||
k3sup-darwin-arm64
|
|
||||||
{%- else -%}
|
|
||||||
unsupported
|
|
||||||
{%- endif -%}
|
|
||||||
when: install_k3sup_binary | default(false)
|
|
||||||
run_once: true
|
|
||||||
|
|
||||||
- name: Fail when k3sup binary installation is not supported for this control machine
|
|
||||||
ansible.builtin.fail:
|
|
||||||
msg: "Automatic k3sup installation is not supported for {{ localhost_facts.ansible_facts.ansible_system }}/{{ localhost_facts.ansible_facts.ansible_architecture }}. Set install_k3sup_binary=false and install k3sup manually."
|
|
||||||
when:
|
|
||||||
- install_k3sup_binary | default(false)
|
|
||||||
- k3sup_release_asset == "unsupported"
|
|
||||||
run_once: true
|
|
||||||
|
|
||||||
- name: Ensure local directory for k3sup exists
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: "{{ '<< k3sup_install_path >>' | dirname }}"
|
|
||||||
state: directory
|
|
||||||
mode: "0755"
|
|
||||||
delegate_to: localhost
|
|
||||||
become: true
|
|
||||||
when: install_k3sup_binary | default(false)
|
|
||||||
run_once: true
|
|
||||||
|
|
||||||
- name: Install k3sup binary on the control machine
|
|
||||||
ansible.builtin.get_url:
|
|
||||||
url: "https://github.com/alexellis/k3sup/releases/download/<< k3sup_version >>/{{ k3sup_release_asset }}"
|
|
||||||
dest: "<< k3sup_install_path >>"
|
|
||||||
mode: "0755"
|
|
||||||
delegate_to: localhost
|
|
||||||
become: true
|
|
||||||
when: install_k3sup_binary | default(false)
|
|
||||||
run_once: true
|
|
||||||
|
|
||||||
- name: Verify k3sup is available
|
|
||||||
ansible.builtin.command:
|
|
||||||
cmd: "<< k3sup_install_path >> version"
|
|
||||||
changed_when: false
|
|
||||||
delegate_to: localhost
|
|
||||||
run_once: true
|
|
||||||
|
|
||||||
- name: Ensure local kubeconfig directory exists when using local destination mode
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: "{{ k3s_generated_kubeconfig_path | dirname }}"
|
|
||||||
state: directory
|
|
||||||
mode: "0700"
|
|
||||||
delegate_to: localhost
|
|
||||||
when: "<< kubeconfig_destination_mode >>" == "local"
|
|
||||||
run_once: true
|
|
||||||
|
|
||||||
- name: Check whether K3s is already present on the first server
|
|
||||||
ansible.builtin.stat:
|
|
||||||
path: /etc/rancher/k3s/k3s.yaml
|
|
||||||
delegate_to: "<< k3s_server_host >>"
|
|
||||||
register: k3s_server_install_state
|
|
||||||
run_once: true
|
|
||||||
|
|
||||||
- name: Bootstrap the first K3s server with k3sup
|
|
||||||
ansible.builtin.command:
|
|
||||||
cmd: >-
|
|
||||||
<< k3sup_install_path >> install
|
|
||||||
--ip {{ k3s_server_target }}
|
|
||||||
--user << k3s_server_user | default('ubuntu') >>
|
|
||||||
--ssh-port << k3s_server_ssh_port | default(22) >>
|
|
||||||
--local-path {{ k3s_generated_kubeconfig_path }}
|
|
||||||
--merge=false
|
|
||||||
--context << k3s_context_name | default('homelab-k3s') >>
|
|
||||||
<%- if k3sup_use_sudo %>
|
|
||||||
--sudo
|
|
||||||
<%- endif %>
|
|
||||||
<%- if k3s_server_ssh_key_path %>
|
|
||||||
--ssh-key << k3s_server_ssh_key_path | quote >>
|
|
||||||
<%- endif %>
|
|
||||||
<%- if extra_server_args %>
|
|
||||||
--k3s-extra-args << extra_server_args | quote >>
|
|
||||||
<%- endif %>
|
|
||||||
delegate_to: localhost
|
|
||||||
when:
|
|
||||||
- bootstrap_control_plane | default(true)
|
|
||||||
- not (k3s_server_install_state.stat.exists | default(false))
|
|
||||||
run_once: true
|
|
||||||
|
|
||||||
- name: Resolve inventory hosts for K3s agents
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
k3s_agent_inventory_hosts: "{{ query('inventory_hostnames', '<< k3s_agent_hosts_pattern >>') }}"
|
|
||||||
when: join_agent_nodes | default(true)
|
|
||||||
run_once: true
|
|
||||||
|
|
||||||
- name: Fail when agent join is enabled but no hosts match the inventory pattern
|
|
||||||
ansible.builtin.assert:
|
|
||||||
that:
|
|
||||||
- k3s_agent_inventory_hosts | length > 0
|
|
||||||
fail_msg: "No inventory hosts matched '<< k3s_agent_hosts_pattern >>'."
|
|
||||||
when: join_agent_nodes | default(true)
|
|
||||||
run_once: true
|
|
||||||
|
|
||||||
- name: Check whether K3s agent is already present on each node
|
|
||||||
ansible.builtin.stat:
|
|
||||||
path: /etc/systemd/system/k3s-agent.service
|
|
||||||
delegate_to: "{{ item }}"
|
|
||||||
loop: "{{ k3s_agent_inventory_hosts | default([]) }}"
|
|
||||||
loop_control:
|
|
||||||
label: "{{ item }}"
|
|
||||||
register: k3s_agent_install_state
|
|
||||||
when: join_agent_nodes | default(true)
|
|
||||||
run_once: true
|
|
||||||
|
|
||||||
- name: Join agent nodes to the K3s cluster with k3sup
|
|
||||||
ansible.builtin.command:
|
|
||||||
cmd: >-
|
|
||||||
<< k3sup_install_path >> join
|
|
||||||
--ip {{ hostvars[item.item].ansible_host | default(item.item) }}
|
|
||||||
--server-ip {{ k3s_server_target }}
|
|
||||||
--user << k3s_agent_user | default('ubuntu') >>
|
|
||||||
--server-user << k3s_server_user | default('ubuntu') >>
|
|
||||||
--ssh-port << k3s_agent_ssh_port | default(22) >>
|
|
||||||
--server-ssh-port << k3s_server_ssh_port | default(22) >>
|
|
||||||
<%- if k3sup_use_sudo %>
|
|
||||||
--sudo
|
|
||||||
<%- endif %>
|
|
||||||
<%- if k3s_server_ssh_key_path %>
|
|
||||||
--ssh-key << k3s_server_ssh_key_path | quote >>
|
|
||||||
<%- endif %>
|
|
||||||
<%- if extra_agent_args %>
|
|
||||||
--k3s-extra-args << extra_agent_args | quote >>
|
|
||||||
<%- endif %>
|
|
||||||
delegate_to: localhost
|
|
||||||
loop: "{{ k3s_agent_install_state.results | default([]) }}"
|
|
||||||
loop_control:
|
|
||||||
label: "{{ item.item }}"
|
|
||||||
when:
|
|
||||||
- join_agent_nodes | default(true)
|
|
||||||
- not (item.stat.exists | default(false))
|
|
||||||
run_once: true
|
|
||||||
|
|
||||||
- name: Ensure remote kubeconfig directory exists
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: "{{ '<< kubeconfig_remote_path >>' | dirname }}"
|
|
||||||
state: directory
|
|
||||||
mode: "0700"
|
|
||||||
delegate_to: "<< kubeconfig_remote_host | default('localhost') >>"
|
|
||||||
become: << kubeconfig_remote_become | default(false) >>
|
|
||||||
when: "<< kubeconfig_destination_mode >>" == "remote"
|
|
||||||
run_once: true
|
|
||||||
|
|
||||||
- name: Copy kubeconfig to the remote destination host
|
|
||||||
ansible.builtin.copy:
|
|
||||||
src: "{{ k3s_generated_kubeconfig_path }}"
|
|
||||||
dest: "<< kubeconfig_remote_path >>"
|
|
||||||
owner: "<< kubeconfig_remote_owner | default('ubuntu') >>"
|
|
||||||
group: "<< kubeconfig_remote_group | default('ubuntu') >>"
|
|
||||||
mode: "<< kubeconfig_remote_mode | default('0600') >>"
|
|
||||||
delegate_to: "<< kubeconfig_remote_host | default('localhost') >>"
|
|
||||||
become: << kubeconfig_remote_become | default(false) >>
|
|
||||||
when: "<< kubeconfig_destination_mode >>" == "remote"
|
|
||||||
run_once: true
|
|
||||||
@@ -1,353 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "k3sup-k3s-cluster",
|
|
||||||
"kind": "ansible",
|
|
||||||
"metadata": {
|
|
||||||
"name": "Bootstrap K3s Cluster with k3sup",
|
|
||||||
"description": "Bootstraps a K3s cluster from the Ansible control machine by using k3sup over SSH. Supports first-server install, optional agent joins, and local or remote kubeconfig placement.",
|
|
||||||
"tags": [
|
|
||||||
"kubernetes",
|
|
||||||
"k3s",
|
|
||||||
"k3sup",
|
|
||||||
"bootstrap"
|
|
||||||
],
|
|
||||||
"icon": {
|
|
||||||
"provider": "simple-icons",
|
|
||||||
"id": "kubernetes"
|
|
||||||
},
|
|
||||||
"draft": true,
|
|
||||||
"version": {
|
|
||||||
"name": "1.0.0",
|
|
||||||
"source_dep_name": "manual/k3sup-k3s-cluster"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"title": "Execution",
|
|
||||||
"name": "execution",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "secrets_file",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Secrets File",
|
|
||||||
"required": false,
|
|
||||||
"default": "",
|
|
||||||
"description": "Optional vars file to load before running the playbook."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "install_k3sup_binary",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Install k3sup",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"description": "Download and install the k3sup binary on the Ansible control machine before bootstrapping"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "k3sup_version",
|
|
||||||
"type": "str",
|
|
||||||
"title": "k3sup Version",
|
|
||||||
"required": false,
|
|
||||||
"default": "0.13.15",
|
|
||||||
"description": "Version of k3sup to install when binary installation is enabled",
|
|
||||||
"needs": [
|
|
||||||
"install_k3sup_binary=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "0.13.15"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "k3sup_install_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "k3sup Path",
|
|
||||||
"required": false,
|
|
||||||
"default": "/usr/local/bin/k3sup",
|
|
||||||
"description": "Local filesystem path for the k3sup binary",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/usr/local/bin/k3sup"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Control Plane",
|
|
||||||
"name": "control-plane",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "bootstrap_control_plane",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Bootstrap Server",
|
|
||||||
"required": false,
|
|
||||||
"default": true,
|
|
||||||
"description": "Run k3sup install against the first K3s server"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "k3s_server_host",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Server Host",
|
|
||||||
"required": true,
|
|
||||||
"default": "k3s-server-01",
|
|
||||||
"description": "Inventory host name for the first K3s server",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "k3s-server-01"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "k3s_server_user",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Server SSH User",
|
|
||||||
"required": false,
|
|
||||||
"default": "ubuntu",
|
|
||||||
"description": "SSH user used by k3sup for the first server",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "ubuntu"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "k3s_server_ssh_port",
|
|
||||||
"type": "int",
|
|
||||||
"title": "Server SSH Port",
|
|
||||||
"required": false,
|
|
||||||
"default": 22,
|
|
||||||
"description": "SSH port used for the first server",
|
|
||||||
"config": {
|
|
||||||
"slider": true,
|
|
||||||
"min": 1,
|
|
||||||
"max": 65535,
|
|
||||||
"step": 1,
|
|
||||||
"placeholder": "22"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "k3s_server_ssh_key_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "SSH Key Path",
|
|
||||||
"required": false,
|
|
||||||
"default": "",
|
|
||||||
"description": "Optional private SSH key path for k3sup",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "~/.ssh/id_ed25519"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "k3s_context_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Cluster Context",
|
|
||||||
"required": false,
|
|
||||||
"default": "homelab-k3s",
|
|
||||||
"description": "kubectl context name written into the generated kubeconfig",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "homelab-k3s"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "k3sup_use_sudo",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Use sudo",
|
|
||||||
"required": false,
|
|
||||||
"default": true,
|
|
||||||
"description": "Run k3sup remote operations with sudo on the target hosts"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "extra_server_args",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Server Args",
|
|
||||||
"required": false,
|
|
||||||
"default": "--write-kubeconfig-mode 644 --disable servicelb",
|
|
||||||
"description": "Optional extra K3s server arguments passed through k3sup",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "--write-kubeconfig-mode 644 --disable servicelb"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Agents",
|
|
||||||
"name": "agents",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "join_agent_nodes",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Join Agents",
|
|
||||||
"required": false,
|
|
||||||
"default": true,
|
|
||||||
"description": "Join matching inventory hosts to the cluster as K3s agents"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "k3s_agent_hosts_pattern",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Agent Hosts",
|
|
||||||
"required": false,
|
|
||||||
"default": "k3s_agents",
|
|
||||||
"description": "Inventory host pattern used to discover K3s agent nodes",
|
|
||||||
"needs": [
|
|
||||||
"join_agent_nodes=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "k3s_agents"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "k3s_agent_user",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Agent SSH User",
|
|
||||||
"required": false,
|
|
||||||
"default": "ubuntu",
|
|
||||||
"description": "SSH user used by k3sup for agent nodes",
|
|
||||||
"needs": [
|
|
||||||
"join_agent_nodes=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "ubuntu"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "k3s_agent_ssh_port",
|
|
||||||
"type": "int",
|
|
||||||
"title": "Agent SSH Port",
|
|
||||||
"required": false,
|
|
||||||
"default": 22,
|
|
||||||
"description": "SSH port used for agent nodes",
|
|
||||||
"needs": [
|
|
||||||
"join_agent_nodes=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"slider": true,
|
|
||||||
"min": 1,
|
|
||||||
"max": 65535,
|
|
||||||
"step": 1,
|
|
||||||
"placeholder": "22"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "extra_agent_args",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Agent Args",
|
|
||||||
"required": false,
|
|
||||||
"default": "",
|
|
||||||
"description": "Optional extra K3s agent arguments passed through k3sup",
|
|
||||||
"needs": [
|
|
||||||
"join_agent_nodes=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "--node-label role=worker"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Kubeconfig",
|
|
||||||
"name": "kubeconfig",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "kubeconfig_destination_mode",
|
|
||||||
"type": "enum",
|
|
||||||
"title": "Destination Mode",
|
|
||||||
"required": false,
|
|
||||||
"default": "local",
|
|
||||||
"description": "Store the generated kubeconfig locally on the control machine or copy it to another managed host",
|
|
||||||
"config": {
|
|
||||||
"options": [
|
|
||||||
"local",
|
|
||||||
"remote"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "local_kubeconfig_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Local Kubeconfig",
|
|
||||||
"required": false,
|
|
||||||
"default": "{{ lookup('env', 'HOME') }}/.kube/config",
|
|
||||||
"description": "Local kubeconfig path used when destination mode is local",
|
|
||||||
"needs": [
|
|
||||||
"kubeconfig_destination_mode=local"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "{{ lookup('env', 'HOME') }}/.kube/config"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "kubeconfig_remote_host",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Remote Host",
|
|
||||||
"required": false,
|
|
||||||
"default": "localhost",
|
|
||||||
"description": "Managed inventory host that should receive the kubeconfig copy",
|
|
||||||
"needs": [
|
|
||||||
"kubeconfig_destination_mode=remote"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "bastion-01"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "kubeconfig_remote_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Remote Kubeconfig",
|
|
||||||
"required": false,
|
|
||||||
"default": "/home/ubuntu/.kube/config",
|
|
||||||
"description": "Destination path on the remote host for the kubeconfig file",
|
|
||||||
"needs": [
|
|
||||||
"kubeconfig_destination_mode=remote"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/home/ubuntu/.kube/config"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "kubeconfig_remote_owner",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Remote Owner",
|
|
||||||
"required": false,
|
|
||||||
"default": "ubuntu",
|
|
||||||
"description": "Owner for the remote kubeconfig file",
|
|
||||||
"needs": [
|
|
||||||
"kubeconfig_destination_mode=remote"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "ubuntu"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "kubeconfig_remote_group",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Remote Group",
|
|
||||||
"required": false,
|
|
||||||
"default": "ubuntu",
|
|
||||||
"description": "Group for the remote kubeconfig file",
|
|
||||||
"needs": [
|
|
||||||
"kubeconfig_destination_mode=remote"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "ubuntu"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "kubeconfig_remote_mode",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Remote Mode",
|
|
||||||
"required": false,
|
|
||||||
"default": "0600",
|
|
||||||
"description": "Filesystem mode for the remote kubeconfig file",
|
|
||||||
"needs": [
|
|
||||||
"kubeconfig_destination_mode=remote"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "0600"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "kubeconfig_remote_become",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Remote Become",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"description": "Use become when creating directories or copying the remote kubeconfig",
|
|
||||||
"needs": [
|
|
||||||
"kubeconfig_destination_mode=remote"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Add SSH authorized keys
|
|
||||||
hosts: all
|
|
||||||
become: true
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- name: Install SSH public key
|
|
||||||
ansible.posix.authorized_key:
|
|
||||||
user: "<< target_user >>"
|
|
||||||
state: present
|
|
||||||
key: "<< ssh_public_key >>"
|
|
||||||
manage_dir: true
|
|
||||||
|
|
||||||
<%- if configure_passwordless_sudo %>
|
|
||||||
- name: Enable passwordless sudo for the sudo group
|
|
||||||
ansible.builtin.copy:
|
|
||||||
dest: /etc/sudoers.d/90-sudo-nopasswd
|
|
||||||
content: |
|
|
||||||
%sudo ALL=(ALL:ALL) NOPASSWD: ALL
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: "0440"
|
|
||||||
validate: /usr/sbin/visudo -cf %s
|
|
||||||
<%- endif %>
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "ubuntu-add-sshkey",
|
|
||||||
"kind": "ansible",
|
|
||||||
"metadata": {
|
|
||||||
"name": "Add SSH Key and Configure Sudoers",
|
|
||||||
"description": "Installs a single SSH public key for a target user on the workload-selected hosts and can enable passwordless sudo for the Ubuntu sudo group.",
|
|
||||||
"tags": [],
|
|
||||||
"icon": {
|
|
||||||
"provider": "simple-icons",
|
|
||||||
"id": "ansible"
|
|
||||||
},
|
|
||||||
"draft": false,
|
|
||||||
"version": {
|
|
||||||
"name": "1.0.0",
|
|
||||||
"source_dep_name": "manual/ubuntu-add-sshkey"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"title": "Access",
|
|
||||||
"name": "access",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "target_user",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Target User",
|
|
||||||
"required": false,
|
|
||||||
"default": "ubuntu",
|
|
||||||
"description": "Linux user account that should receive the authorized SSH keys.",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "ubuntu"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ssh_public_key",
|
|
||||||
"type": "str",
|
|
||||||
"title": "SSH Public Key",
|
|
||||||
"required": true,
|
|
||||||
"description": "SSH public key to add to the target user's authorized_keys file.",
|
|
||||||
"config": {
|
|
||||||
"textarea": true,
|
|
||||||
"placeholder": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBExampleKey user@laptop"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "configure_passwordless_sudo",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Passwordless Sudo",
|
|
||||||
"required": false,
|
|
||||||
"default": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Install curated Ubuntu packages
|
|
||||||
hosts: all
|
|
||||||
become: true
|
|
||||||
gather_facts: true
|
|
||||||
|
|
||||||
vars:
|
|
||||||
ubuntu_package_matrix:
|
|
||||||
- name: python3-venv
|
|
||||||
enabled: << install_python3_venv >>
|
|
||||||
- name: python3-pip
|
|
||||||
enabled: << install_python3_pip >>
|
|
||||||
- name: python3-apt
|
|
||||||
enabled: << install_python3_apt >>
|
|
||||||
- name: curl
|
|
||||||
enabled: << install_curl >>
|
|
||||||
- name: wget
|
|
||||||
enabled: << install_wget >>
|
|
||||||
- name: git
|
|
||||||
enabled: << install_git >>
|
|
||||||
- name: jq
|
|
||||||
enabled: << install_jq >>
|
|
||||||
- name: rsync
|
|
||||||
enabled: << install_rsync >>
|
|
||||||
- name: unzip
|
|
||||||
enabled: << install_unzip >>
|
|
||||||
- name: ca-certificates
|
|
||||||
enabled: << install_ca_certificates >>
|
|
||||||
- name: gnupg
|
|
||||||
enabled: << install_gnupg >>
|
|
||||||
- name: lsb-release
|
|
||||||
enabled: << install_lsb_release >>
|
|
||||||
- name: prometheus-node-exporter
|
|
||||||
enabled: << install_prometheus_node_exporter >>
|
|
||||||
- name: nfs-common
|
|
||||||
enabled: << install_nfs_common >>
|
|
||||||
- name: qemu-guest-agent
|
|
||||||
enabled: << install_qemu_guest_agent >>
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- name: Validate Ubuntu APT target
|
|
||||||
ansible.builtin.assert:
|
|
||||||
that:
|
|
||||||
- ansible_facts['distribution'] == 'Ubuntu'
|
|
||||||
- ansible_facts['pkg_mgr'] == 'apt'
|
|
||||||
fail_msg: "This playbook only supports Ubuntu hosts that use APT."
|
|
||||||
|
|
||||||
- name: Build selected package list
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
ubuntu_selected_packages: "{{ ubuntu_package_matrix | selectattr('enabled') | map(attribute='name') | list }}"
|
|
||||||
|
|
||||||
- name: Refresh APT package index
|
|
||||||
ansible.builtin.command:
|
|
||||||
cmd: apt-get update
|
|
||||||
environment:
|
|
||||||
DEBIAN_FRONTEND: noninteractive
|
|
||||||
register: ubuntu_packages_apt_update
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Install selected Ubuntu packages
|
|
||||||
ansible.builtin.apt:
|
|
||||||
name: "{{ ubuntu_selected_packages }}"
|
|
||||||
state: present
|
|
||||||
update_cache: false
|
|
||||||
when: ubuntu_selected_packages | length > 0
|
|
||||||
|
|
||||||
- name: Enable and start Prometheus node exporter
|
|
||||||
ansible.builtin.service:
|
|
||||||
name: prometheus-node-exporter
|
|
||||||
state: started
|
|
||||||
enabled: true
|
|
||||||
when: << install_prometheus_node_exporter >>
|
|
||||||
|
|
||||||
- name: Enable and start QEMU guest agent
|
|
||||||
ansible.builtin.service:
|
|
||||||
name: qemu-guest-agent
|
|
||||||
state: started
|
|
||||||
enabled: true
|
|
||||||
when: << install_qemu_guest_agent >>
|
|
||||||
|
|
||||||
- name: Show selected package summary
|
|
||||||
ansible.builtin.debug:
|
|
||||||
msg:
|
|
||||||
- "Host: {{ inventory_hostname }}"
|
|
||||||
- "Selected packages: {{ ubuntu_selected_packages | join(', ') if (ubuntu_selected_packages | length > 0) else 'none' }}"
|
|
||||||
@@ -1,157 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "ubuntu-packages",
|
|
||||||
"kind": "ansible",
|
|
||||||
"metadata": {
|
|
||||||
"name": "Install Ubuntu Packages",
|
|
||||||
"description": "Installs a curated set of useful Ubuntu packages with per-package switches for scripting, package management, monitoring, NFS, and VM guest integration.",
|
|
||||||
"tags": [
|
|
||||||
"ubuntu",
|
|
||||||
"apt",
|
|
||||||
"packages",
|
|
||||||
"ansible"
|
|
||||||
],
|
|
||||||
"icon": {
|
|
||||||
"provider": "simple-icons",
|
|
||||||
"id": "ansible"
|
|
||||||
},
|
|
||||||
"draft": false,
|
|
||||||
"version": {
|
|
||||||
"name": "1.0.0",
|
|
||||||
"source_dep_name": "manual/ubuntu-packages"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"title": "Base Packages",
|
|
||||||
"name": "base_packages",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "install_python3_venv",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "python3-venv",
|
|
||||||
"required": false,
|
|
||||||
"default": true,
|
|
||||||
"description": "Install Python virtual environment support."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "install_python3_pip",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "python3-pip",
|
|
||||||
"required": false,
|
|
||||||
"default": true,
|
|
||||||
"description": "Install pip for Python 3."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "install_python3_apt",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "python3-apt",
|
|
||||||
"required": false,
|
|
||||||
"default": true,
|
|
||||||
"description": "Install Python bindings for APT."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "install_curl",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "curl",
|
|
||||||
"required": false,
|
|
||||||
"default": true,
|
|
||||||
"description": "Install curl for HTTP requests and downloads."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "install_wget",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "wget",
|
|
||||||
"required": false,
|
|
||||||
"default": true,
|
|
||||||
"description": "Install wget for scripted downloads."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "install_git",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "git",
|
|
||||||
"required": false,
|
|
||||||
"default": true,
|
|
||||||
"description": "Install Git for source control and repository operations."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "install_jq",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "jq",
|
|
||||||
"required": false,
|
|
||||||
"default": true,
|
|
||||||
"description": "Install jq for JSON parsing in shell scripts."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "install_rsync",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "rsync",
|
|
||||||
"required": false,
|
|
||||||
"default": true,
|
|
||||||
"description": "Install rsync for file synchronization and copy jobs."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "install_unzip",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "unzip",
|
|
||||||
"required": false,
|
|
||||||
"default": true,
|
|
||||||
"description": "Install unzip for archive extraction."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "install_ca_certificates",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "ca-certificates",
|
|
||||||
"required": false,
|
|
||||||
"default": true,
|
|
||||||
"description": "Install CA certificates for HTTPS trust."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "install_gnupg",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "gnupg",
|
|
||||||
"required": false,
|
|
||||||
"default": true,
|
|
||||||
"description": "Install GnuPG for repository keys and signing workflows."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "install_lsb_release",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "lsb-release",
|
|
||||||
"required": false,
|
|
||||||
"default": true,
|
|
||||||
"description": "Install lsb-release for distro detection in scripts."
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Optional Packages",
|
|
||||||
"name": "optional_packages",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "install_prometheus_node_exporter",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "prometheus-node-exporter",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"description": "Install Prometheus node exporter and enable its service."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "install_nfs_common",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "nfs-common",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"description": "Install NFS client utilities."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "install_qemu_guest_agent",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "qemu-guest-agent",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"description": "Install the QEMU guest agent and enable its service."
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Install Ubuntu VM core packages
|
|
||||||
hosts: all
|
|
||||||
become: true
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- name: Install packages
|
|
||||||
ansible.builtin.apt:
|
|
||||||
name:
|
|
||||||
- prometheus-node-exporter
|
|
||||||
- nfs-common
|
|
||||||
- qemu-guest-agent
|
|
||||||
update_cache: true
|
|
||||||
|
|
||||||
- name: Start guest qemu-guest-agent
|
|
||||||
ansible.builtin.service:
|
|
||||||
name: qemu-guest-agent
|
|
||||||
state: started
|
|
||||||
enabled: true
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "ubuntu-vm-core",
|
|
||||||
"kind": "ansible",
|
|
||||||
"metadata": {
|
|
||||||
"name": "Install Ubuntu VM Core Packages",
|
|
||||||
"description": "Installs essential packages for Ubuntu virtual machines, including Prometheus node exporter, NFS client utilities, and QEMU guest agent.",
|
|
||||||
"tags": [],
|
|
||||||
"icon": {
|
|
||||||
"provider": "simple-icons",
|
|
||||||
"id": "ansible"
|
|
||||||
},
|
|
||||||
"draft": false,
|
|
||||||
"version": {
|
|
||||||
"name": "1.0.0",
|
|
||||||
"source_dep_name": "manual/ubuntu-vm-core"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": []
|
|
||||||
}
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
---
|
|
||||||
services:
|
|
||||||
<< service_name >>:
|
|
||||||
image: docker.io/adguard/adguardhome:v0.107.74
|
|
||||||
restart: << restart_policy >>
|
|
||||||
<%- if network_mode == 'host' %>
|
|
||||||
network_mode: host
|
|
||||||
<%- elif network_mode == 'bridge' or network_mode == 'macvlan' or traefik_enabled %>
|
|
||||||
networks:
|
|
||||||
<%- if traefik_enabled %>
|
|
||||||
<< traefik_network >>:
|
|
||||||
<%- endif %>
|
|
||||||
<%- if network_mode == 'macvlan' %>
|
|
||||||
<< network_name >>:
|
|
||||||
ipv4_address: << network_macvlan_ipv4_address >>
|
|
||||||
<%- elif network_mode == 'bridge' %>
|
|
||||||
<< network_name >>:
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
<%- if not network_mode or network_mode == 'bridge' or traefik_enabled %>
|
|
||||||
ports:
|
|
||||||
<%- if not traefik_enabled %>
|
|
||||||
- "<< ports_http >>:80/tcp"
|
|
||||||
- "<< ports_https >>:443/tcp"
|
|
||||||
<%- endif %>
|
|
||||||
<%- if initial_setup %>
|
|
||||||
- "<< ports_initial >>:3000/tcp"
|
|
||||||
<%- endif %>
|
|
||||||
- "<< ports_https >>:443/udp"
|
|
||||||
- "<< ports_dns >>:53/tcp"
|
|
||||||
- "<< ports_dns >>:53/udp"
|
|
||||||
- "<< ports_tls >>:853/tcp"
|
|
||||||
- "<< ports_dnscrypt >>:5443/tcp"
|
|
||||||
- "<< ports_dnscrypt >>:5443/udp"
|
|
||||||
<%- endif %>
|
|
||||||
volumes:
|
|
||||||
<%- if volume_mode == 'mount' %>
|
|
||||||
- << volume_mount_path >>/work:/opt/adguardhome/work:rw
|
|
||||||
- << volume_mount_path >>/conf:/opt/adguardhome/conf:rw
|
|
||||||
<%- else %>
|
|
||||||
- << service_name >>_work:/opt/adguardhome/work
|
|
||||||
- << service_name >>_conf:/opt/adguardhome/conf
|
|
||||||
<%- endif %>
|
|
||||||
cap_add:
|
|
||||||
- NET_ADMIN
|
|
||||||
- NET_BIND_SERVICE
|
|
||||||
- NET_RAW
|
|
||||||
<%- if traefik_enabled %>
|
|
||||||
labels:
|
|
||||||
- traefik.enable=true
|
|
||||||
- traefik.docker.network=<< traefik_network >>
|
|
||||||
- traefik.http.services.<< service_name >>_web.loadBalancer.server.port=80
|
|
||||||
- traefik.http.routers.<< service_name >>_web_http.service=<< service_name >>_web
|
|
||||||
- traefik.http.routers.<< service_name >>_web_http.rule=Host(`<< traefik_host >>.<< traefik_domain >>`)
|
|
||||||
- traefik.http.routers.<< service_name >>_web_http.entrypoints=<< traefik_entrypoint >>
|
|
||||||
<%- if traefik_tls_enabled %>
|
|
||||||
- traefik.http.routers.<< service_name >>_web_https.service=<< service_name >>_web
|
|
||||||
- traefik.http.routers.<< service_name >>_web_https.rule=Host(`<< traefik_host >>.<< traefik_domain >>`)
|
|
||||||
- traefik.http.routers.<< service_name >>_web_https.entrypoints=<< traefik_tls_entrypoint >>
|
|
||||||
- traefik.http.routers.<< service_name >>_web_https.tls=true
|
|
||||||
- traefik.http.routers.<< service_name >>_web_https.tls.certresolver=<< traefik_tls_certresolver >>
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
<%- if network_mode == 'bridge' or network_mode == 'macvlan' or traefik_enabled %>
|
|
||||||
networks:
|
|
||||||
<%- if network_mode == 'bridge' or network_mode == 'macvlan'%>
|
|
||||||
<< network_name >>:
|
|
||||||
<%- if network_external %>
|
|
||||||
external: true
|
|
||||||
<%- else %>
|
|
||||||
<%- if network_mode == 'macvlan' %>
|
|
||||||
driver: macvlan
|
|
||||||
driver_opts:
|
|
||||||
parent: << network_macvlan_parent_interface >>
|
|
||||||
ipam:
|
|
||||||
config:
|
|
||||||
- subnet: << network_macvlan_subnet >>
|
|
||||||
gateway: << network_macvlan_gateway >>
|
|
||||||
name: << network_name >>
|
|
||||||
<%- else %>
|
|
||||||
driver: bridge
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
<%- if traefik_enabled %>
|
|
||||||
<< traefik_network >>:
|
|
||||||
external: true
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
<%- if volume_mode == 'local' %>
|
|
||||||
volumes:
|
|
||||||
<< service_name >>_work:
|
|
||||||
driver: local
|
|
||||||
<< service_name >>_conf:
|
|
||||||
driver: local
|
|
||||||
<%- elif volume_mode == 'nfs' %>
|
|
||||||
volumes:
|
|
||||||
<< service_name >>_work:
|
|
||||||
driver: local
|
|
||||||
driver_opts:
|
|
||||||
type: nfs
|
|
||||||
o: addr=<< volume_nfs_server >>,nfsvers=4,<< volume_nfs_options >>
|
|
||||||
device: ":<< volume_nfs_path >>/work"
|
|
||||||
<< service_name >>_conf:
|
|
||||||
driver: local
|
|
||||||
driver_opts:
|
|
||||||
type: nfs
|
|
||||||
o: addr=<< volume_nfs_server >>,nfsvers=4,<< volume_nfs_options >>
|
|
||||||
device: ":<< volume_nfs_path >>/conf"
|
|
||||||
<%- endif %>
|
|
||||||
@@ -1,373 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "adguardhome",
|
|
||||||
"kind": "compose",
|
|
||||||
"metadata": {
|
|
||||||
"name": "AdGuard Home",
|
|
||||||
"description": "Network-wide DNS-based ad and tracker blocker. AdGuard Home operates as a DNS server that blocks tracking domains, with support for DNS-over-HTTPS, DNS-over-TLS, DNS-over-QUIC, parental controls, and safe browsing filters.",
|
|
||||||
"tags": [
|
|
||||||
"traefik",
|
|
||||||
"network",
|
|
||||||
"volume"
|
|
||||||
],
|
|
||||||
"icon": {
|
|
||||||
"provider": "selfhst",
|
|
||||||
"id": "adguard-home"
|
|
||||||
},
|
|
||||||
"draft": false,
|
|
||||||
"version": {
|
|
||||||
"name": "v0.107.74",
|
|
||||||
"source_dep_name": "docker.io/adguard/adguardhome",
|
|
||||||
"source_dep_version": "v0.107.74"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"title": "General",
|
|
||||||
"name": "general",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "service_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Service Name",
|
|
||||||
"required": false,
|
|
||||||
"default": "adguardhome",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "adguardhome"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "restart_policy",
|
|
||||||
"type": "enum",
|
|
||||||
"title": "Restart Policy",
|
|
||||||
"required": true,
|
|
||||||
"default": "unless-stopped",
|
|
||||||
"config": {
|
|
||||||
"options": [
|
|
||||||
"unless-stopped",
|
|
||||||
"always",
|
|
||||||
"on-failure",
|
|
||||||
"no"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "initial_setup",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Initial Setup",
|
|
||||||
"required": false,
|
|
||||||
"default": true,
|
|
||||||
"description": "Enable initial setup wizard on port 3000 (only used without Traefik)"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Network",
|
|
||||||
"name": "network",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "network_mode",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Network Mode",
|
|
||||||
"required": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "network_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Network Name",
|
|
||||||
"required": false,
|
|
||||||
"default": "adguardhome_network",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "adguardhome_network"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "network_macvlan_ipv4_address",
|
|
||||||
"type": "str",
|
|
||||||
"title": "IPv4 Address",
|
|
||||||
"required": true,
|
|
||||||
"default": "IP_ADDRESS",
|
|
||||||
"needs": [
|
|
||||||
"network_mode=macvlan"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "IP_ADDRESS"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "network_macvlan_parent_interface",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Parent Interface",
|
|
||||||
"required": true,
|
|
||||||
"default": "eth0",
|
|
||||||
"needs": [
|
|
||||||
"network_mode=macvlan"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "eth0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "network_macvlan_subnet",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Subnet",
|
|
||||||
"required": true,
|
|
||||||
"default": "IP_RANGE",
|
|
||||||
"needs": [
|
|
||||||
"network_mode=macvlan"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "IP_RANGE"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "network_macvlan_gateway",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Gateway",
|
|
||||||
"required": true,
|
|
||||||
"default": "GATEWAY",
|
|
||||||
"needs": [
|
|
||||||
"network_mode=macvlan"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "GATEWAY"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "network_external",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "External Network",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Ports",
|
|
||||||
"name": "ports",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "ports_http",
|
|
||||||
"type": "str",
|
|
||||||
"title": "HTTP Port",
|
|
||||||
"required": false,
|
|
||||||
"default": 80,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "80"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ports_https",
|
|
||||||
"type": "str",
|
|
||||||
"title": "HTTPS Port",
|
|
||||||
"required": false,
|
|
||||||
"default": 443,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "443"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ports_dns",
|
|
||||||
"type": "int",
|
|
||||||
"title": "DNS Port",
|
|
||||||
"required": true,
|
|
||||||
"default": 53,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "53"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ports_initial",
|
|
||||||
"type": "int",
|
|
||||||
"title": "Initial Setup Port",
|
|
||||||
"required": false,
|
|
||||||
"default": 3000,
|
|
||||||
"description": "Initial setup wizard port (only when Traefik is disabled)",
|
|
||||||
"needs": [
|
|
||||||
"traefik_enabled=false",
|
|
||||||
"initial_setup=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "3000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ports_tls",
|
|
||||||
"type": "int",
|
|
||||||
"title": "DoT Port",
|
|
||||||
"required": true,
|
|
||||||
"default": 853,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "853"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ports_dnscrypt",
|
|
||||||
"type": "int",
|
|
||||||
"title": "DNSCrypt Port",
|
|
||||||
"required": true,
|
|
||||||
"default": 5443,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "5443"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Traefik",
|
|
||||||
"name": "traefik",
|
|
||||||
"toggle": "traefik_enabled",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "traefik_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Traefik",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_host",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Host",
|
|
||||||
"required": true,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "adguardhome"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_domain",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Domain",
|
|
||||||
"required": true,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "home.arpa"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_entrypoint",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Entrypoint",
|
|
||||||
"required": true,
|
|
||||||
"default": "web",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "web"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_network",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Network",
|
|
||||||
"required": true,
|
|
||||||
"default": "traefik",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "traefik"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_tls_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "TLS",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_tls_entrypoint",
|
|
||||||
"type": "str",
|
|
||||||
"title": "TLS Entrypoint",
|
|
||||||
"required": true,
|
|
||||||
"default": "websecure",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "websecure"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"traefik_tls_enabled=true"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_tls_certresolver",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Cert Resolver",
|
|
||||||
"required": true,
|
|
||||||
"default": "cloudflare",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "cloudflare"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"traefik_tls_enabled=true"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Volume",
|
|
||||||
"name": "volume",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "volume_mode",
|
|
||||||
"type": "enum",
|
|
||||||
"title": "Volume Mode",
|
|
||||||
"required": true,
|
|
||||||
"default": "local",
|
|
||||||
"config": {
|
|
||||||
"options": [
|
|
||||||
"local",
|
|
||||||
"mount",
|
|
||||||
"nfs"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "volume_mount_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Volume Mount Path",
|
|
||||||
"required": true,
|
|
||||||
"default": "/data",
|
|
||||||
"needs": [
|
|
||||||
"volume_mode=mount"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/data"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "volume_nfs_server",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Volume Nfs Server",
|
|
||||||
"required": true,
|
|
||||||
"default": "NFS_SERVER",
|
|
||||||
"needs": [
|
|
||||||
"volume_mode=nfs"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "NFS_SERVER"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "volume_nfs_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Volume Nfs Path",
|
|
||||||
"required": true,
|
|
||||||
"default": "/export",
|
|
||||||
"needs": [
|
|
||||||
"volume_mode=nfs"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/export"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "volume_nfs_options",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Volume Nfs Options",
|
|
||||||
"required": true,
|
|
||||||
"default": "rw,nolock,soft",
|
|
||||||
"needs": [
|
|
||||||
"volume_mode=nfs"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "rw,nolock,soft"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
services:
|
|
||||||
<< service_name >>:
|
|
||||||
image: docker.io/grafana/alloy:v1.16.0
|
|
||||||
restart: << restart_policy >>
|
|
||||||
<%- if container_hostname %>
|
|
||||||
hostname: << container_hostname >>
|
|
||||||
<%- endif %>
|
|
||||||
<%- if traefik_enabled %>
|
|
||||||
networks:
|
|
||||||
<< traefik_network >>:
|
|
||||||
<%- endif %>
|
|
||||||
command:
|
|
||||||
- run
|
|
||||||
- /etc/alloy/alloy.d/
|
|
||||||
- --server.http.listen-addr=127.0.0.1:12345
|
|
||||||
<%- if not traefik_enabled %>
|
|
||||||
ports:
|
|
||||||
- "<< ports_webui >>:12345"
|
|
||||||
<%- endif %>
|
|
||||||
volumes:
|
|
||||||
- << service_name >>_data:/alloy/data
|
|
||||||
- ./config:/etc/alloy/alloy.d/:ro
|
|
||||||
<%- if logs_enabled or metrics_enabled %>
|
|
||||||
- /:/rootfs:ro
|
|
||||||
- /sys:/sys:ro
|
|
||||||
<%- endif %>
|
|
||||||
<%- if logs_enabled and logs_system %>
|
|
||||||
- /run:/run:ro
|
|
||||||
- /var/log:/var/log:ro
|
|
||||||
<%- endif %>
|
|
||||||
<%- if (logs_enabled and logs_docker) or (metrics_enabled and metrics_docker) %>
|
|
||||||
- /var/lib/docker/:/var/lib/docker/:ro
|
|
||||||
<%- endif %>
|
|
||||||
<%- if metrics_enabled and metrics_system %>
|
|
||||||
- /run/udev/data:/run/udev/data:ro
|
|
||||||
<%- endif %>
|
|
||||||
<%- if traefik_enabled %>
|
|
||||||
labels:
|
|
||||||
- traefik.enable=true
|
|
||||||
- traefik.docker.network=<< traefik_network >>
|
|
||||||
- traefik.http.services.<< service_name >>-web.loadBalancer.server.port=12345
|
|
||||||
- traefik.http.routers.<< service_name >>-http.service=<< service_name >>-web
|
|
||||||
- traefik.http.routers.<< service_name >>-http.rule=Host(`<< traefik_host >>.<< traefik_domain >>`)
|
|
||||||
- traefik.http.routers.<< service_name >>-http.entrypoints=<< traefik_entrypoint >>
|
|
||||||
<%- if traefik_tls_enabled %>
|
|
||||||
- traefik.http.routers.<< service_name >>-https.service=<< service_name >>-web
|
|
||||||
- traefik.http.routers.<< service_name >>-https.rule=Host(`<< traefik_host >>.<< traefik_domain >>`)
|
|
||||||
- traefik.http.routers.<< service_name >>-https.entrypoints=<< traefik_tls_entrypoint >>
|
|
||||||
- traefik.http.routers.<< service_name >>-https.tls=true
|
|
||||||
- traefik.http.routers.<< service_name >>-https.tls.certresolver=<< traefik_tls_certresolver >>
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
<%- if traefik_enabled %>
|
|
||||||
networks:
|
|
||||||
<< traefik_network >>:
|
|
||||||
external: true
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
<< service_name >>_data:
|
|
||||||
driver: local
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
logging {
|
|
||||||
level = "info"
|
|
||||||
format = "logfmt"
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
<%- if logs_enabled and logs_docker %>
|
|
||||||
discovery.docker "dockerlogs" {
|
|
||||||
host = "unix:///var/run/docker.sock"
|
|
||||||
}
|
|
||||||
|
|
||||||
discovery.relabel "dockerlogs" {
|
|
||||||
targets = []
|
|
||||||
|
|
||||||
rule {
|
|
||||||
source_labels = ["__meta_docker_container_name"]
|
|
||||||
regex = "/(.*)"
|
|
||||||
target_label = "service_name"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loki.source.docker "default" {
|
|
||||||
host = "unix:///var/run/docker.sock"
|
|
||||||
targets = discovery.docker.dockerlogs.targets
|
|
||||||
labels = {"platform" = "docker"}
|
|
||||||
relabel_rules = discovery.relabel.dockerlogs.rules
|
|
||||||
forward_to = [loki.write.default.receiver]
|
|
||||||
}
|
|
||||||
<%- endif %>
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
<%- if logs_enabled and logs_system %>
|
|
||||||
loki.source.journal "journal" {
|
|
||||||
max_age = "24h0m0s"
|
|
||||||
relabel_rules = discovery.relabel.journal.rules
|
|
||||||
forward_to = [loki.write.default.receiver]
|
|
||||||
labels = {component = string.format("%s-journal", constants.hostname)}
|
|
||||||
// NOTE: This is important to fix https://github.com/grafana/alloy/issues/924
|
|
||||||
path = "/var/log/journal"
|
|
||||||
}
|
|
||||||
|
|
||||||
local.file_match "system" {
|
|
||||||
path_targets = [{
|
|
||||||
__address__ = "localhost",
|
|
||||||
__path__ = "/var/log/{syslog,messages,*.log}",
|
|
||||||
instance = constants.hostname,
|
|
||||||
job = string.format("%s-logs", constants.hostname),
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
|
|
||||||
discovery.relabel "journal" {
|
|
||||||
targets = []
|
|
||||||
rule {
|
|
||||||
source_labels = ["__journal__systemd_unit"]
|
|
||||||
target_label = "unit"
|
|
||||||
}
|
|
||||||
rule {
|
|
||||||
source_labels = ["__journal__boot_id"]
|
|
||||||
target_label = "boot_id"
|
|
||||||
}
|
|
||||||
rule {
|
|
||||||
source_labels = ["__journal__transport"]
|
|
||||||
target_label = "transport"
|
|
||||||
}
|
|
||||||
rule {
|
|
||||||
source_labels = ["__journal_priority_keyword"]
|
|
||||||
target_label = "level"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loki.source.file "system" {
|
|
||||||
targets = local.file_match.system.targets
|
|
||||||
forward_to = [loki.write.default.receiver]
|
|
||||||
}
|
|
||||||
<%- endif %>
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
<%- if metrics_enabled and metrics_docker %>
|
|
||||||
prometheus.exporter.cadvisor "dockermetrics" {
|
|
||||||
docker_host = "unix:///var/run/docker.sock"
|
|
||||||
storage_duration = "5m"
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Relabel component to drop container_spec metrics that often have NaN values */
|
|
||||||
prometheus.relabel "docker_filter" {
|
|
||||||
forward_to = [prometheus.remote_write.default.receiver]
|
|
||||||
|
|
||||||
rule {
|
|
||||||
source_labels = ["__name__"]
|
|
||||||
regex = "container_spec_(cpu_period|cpu_quota|cpu_shares|memory_limit_bytes|memory_swap_limit_bytes|memory_reservation_limit_bytes)"
|
|
||||||
action = "drop"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
prometheus.scrape "dockermetrics" {
|
|
||||||
targets = prometheus.exporter.cadvisor.dockermetrics.targets
|
|
||||||
forward_to = [prometheus.relabel.docker_filter.receiver]
|
|
||||||
scrape_interval = "10s"
|
|
||||||
}
|
|
||||||
<%- endif %>
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
<%- if metrics_enabled and metrics_system %>
|
|
||||||
discovery.relabel "metrics" {
|
|
||||||
targets = prometheus.exporter.unix.metrics.targets
|
|
||||||
rule {
|
|
||||||
target_label = "instance"
|
|
||||||
replacement = constants.hostname
|
|
||||||
}
|
|
||||||
rule {
|
|
||||||
target_label = "job"
|
|
||||||
replacement = string.format("%s-metrics", constants.hostname)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
prometheus.exporter.unix "metrics" {
|
|
||||||
disable_collectors = ["ipvs", "btrfs", "infiniband", "xfs", "zfs"]
|
|
||||||
enable_collectors = ["meminfo"]
|
|
||||||
rootfs_path = "/rootfs"
|
|
||||||
filesystem {
|
|
||||||
fs_types_exclude = "^(autofs|binfmt_misc|bpf|cgroup2?|configfs|debugfs|devpts|devtmpfs|tmpfs|fusectl|hugetlbfs|iso9660|mqueue|nsfs|overlay|proc|procfs|pstore|rpc_pipefs|securityfs|selinuxfs|squashfs|sysfs|tracefs)$"
|
|
||||||
mount_points_exclude = "^/(dev|proc|run/credentials/.+|sys|var/lib/docker/.+)($|/)"
|
|
||||||
mount_timeout = "5s"
|
|
||||||
}
|
|
||||||
netclass {
|
|
||||||
ignored_devices = "^(veth.*|cali.*|[a-f0-9]{15})$"
|
|
||||||
}
|
|
||||||
netdev {
|
|
||||||
device_exclude = "^(veth.*|cali.*|[a-f0-9]{15})$"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
prometheus.scrape "metrics" {
|
|
||||||
scrape_interval = "15s"
|
|
||||||
targets = discovery.relabel.metrics.output
|
|
||||||
forward_to = [prometheus.remote_write.default.receiver]
|
|
||||||
}
|
|
||||||
<%- endif %>
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
<%- if logs_enabled %>
|
|
||||||
loki.write "default" {
|
|
||||||
endpoint {
|
|
||||||
url = "<< logs_loki_url >>"
|
|
||||||
|
|
||||||
// Batching configuration to reduce request volume and prevent rate limiting
|
|
||||||
batch_wait = "5s" // Wait up to 5 seconds before sending
|
|
||||||
batch_size = "1MiB" // Send when batch reaches 1MB (1048576 bytes)
|
|
||||||
}
|
|
||||||
external_labels = {}
|
|
||||||
}
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
<%- if metrics_enabled %>
|
|
||||||
prometheus.remote_write "default" {
|
|
||||||
endpoint {
|
|
||||||
url = "<< metrics_prometheus_url >>"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
<%- endif %>
|
|
||||||
@@ -1,239 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "alloy",
|
|
||||||
"kind": "compose",
|
|
||||||
"metadata": {
|
|
||||||
"name": "Grafana Alloy",
|
|
||||||
"description": "OpenTelemetry collector by Grafana that collects, processes, and exports metrics and logs to various backends like Prometheus and Loki.",
|
|
||||||
"tags": [
|
|
||||||
"traefik"
|
|
||||||
],
|
|
||||||
"icon": {
|
|
||||||
"provider": "selfhst",
|
|
||||||
"id": "grafana-alloy"
|
|
||||||
},
|
|
||||||
"draft": false,
|
|
||||||
"version": {
|
|
||||||
"name": "v1.16.0",
|
|
||||||
"source_dep_name": "docker.io/grafana/alloy",
|
|
||||||
"source_dep_version": "v1.16.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"title": "General",
|
|
||||||
"name": "general",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "service_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Service Name",
|
|
||||||
"required": false,
|
|
||||||
"default": "alloy",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "alloy"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "container_hostname",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Hostname",
|
|
||||||
"required": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "restart_policy",
|
|
||||||
"type": "enum",
|
|
||||||
"title": "Container restart policy",
|
|
||||||
"required": true,
|
|
||||||
"default": "unless-stopped",
|
|
||||||
"config": {
|
|
||||||
"options": [
|
|
||||||
"unless-stopped",
|
|
||||||
"always",
|
|
||||||
"on-failure",
|
|
||||||
"no"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Log Collection",
|
|
||||||
"toggle": "logs_enabled",
|
|
||||||
"name": "logs",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "logs_docker",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Docker Logs",
|
|
||||||
"required": false,
|
|
||||||
"default": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "logs_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Logs",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "logs_loki_url",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Loki URL",
|
|
||||||
"required": true,
|
|
||||||
"default": "http://loki:3100/loki/api/v1/push",
|
|
||||||
"description": "Loki endpoint URL for sending logs",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "http://loki:3100/loki/api/v1/push"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "logs_system",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "System Logs",
|
|
||||||
"required": false,
|
|
||||||
"default": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Metrics Collection",
|
|
||||||
"toggle": "metrics_enabled",
|
|
||||||
"name": "metrics",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "metrics_docker",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Docker Metrics",
|
|
||||||
"required": false,
|
|
||||||
"default": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "metrics_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Metrics",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "metrics_prometheus_url",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Prometheus URL",
|
|
||||||
"required": true,
|
|
||||||
"default": "http://prometheus:9090/api/v1/write",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "http://prometheus:9090/api/v1/write"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "metrics_system",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "System Metrics",
|
|
||||||
"required": false,
|
|
||||||
"default": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Ports",
|
|
||||||
"name": "ports",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "ports_webui",
|
|
||||||
"type": "int",
|
|
||||||
"title": "Web UI Port",
|
|
||||||
"required": false,
|
|
||||||
"default": 12345,
|
|
||||||
"description": "Port for Alloy web UI",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "12345"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Traefik",
|
|
||||||
"name": "traefik",
|
|
||||||
"toggle": "traefik_enabled",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "traefik_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Traefik",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_host",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Host",
|
|
||||||
"required": true,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "alloy"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_domain",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Domain",
|
|
||||||
"required": true,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "home.arpa"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_entrypoint",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Entrypoint",
|
|
||||||
"required": true,
|
|
||||||
"default": "web",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "web"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_network",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Traefik network name",
|
|
||||||
"required": true,
|
|
||||||
"default": "traefik",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "traefik"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_tls_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "TLS",
|
|
||||||
"required": false,
|
|
||||||
"default": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_tls_entrypoint",
|
|
||||||
"type": "str",
|
|
||||||
"title": "TLS Entrypoint",
|
|
||||||
"required": true,
|
|
||||||
"default": "websecure",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "websecure"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"traefik_tls_enabled=true"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_tls_certresolver",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Cert Resolver",
|
|
||||||
"required": true,
|
|
||||||
"default": "cloudflare",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "cloudflare"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"traefik_tls_enabled=true"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
# Arcane agent token generated by Arcane when creating a remote environment.
|
|
||||||
ARCANE_AGENT_TOKEN='<< agent_token >>'
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
---
|
|
||||||
services:
|
|
||||||
<< service_name if service_name is string and service_name and (service_name | lower) not in ['true', 'false'] else 'arcane-agent' >>:
|
|
||||||
image: ghcr.io/getarcaneapp/agent:v2.1.0
|
|
||||||
restart: << restart_policy >>
|
|
||||||
<%- if container_name is string and container_name and (container_name | lower) not in ['true', 'false'] %>
|
|
||||||
container_name: << container_name >>
|
|
||||||
<%- endif %>
|
|
||||||
environment:
|
|
||||||
<%- if connection_mode == 'direct' %>
|
|
||||||
AGENT_MODE: "true"
|
|
||||||
<%- elif connection_mode == 'edge' %>
|
|
||||||
EDGE_AGENT: "true"
|
|
||||||
<%- endif %>
|
|
||||||
EDGE_TRANSPORT: "<< edge_transport >>"
|
|
||||||
AGENT_TOKEN: "${ARCANE_AGENT_TOKEN}"
|
|
||||||
MANAGER_API_URL: "<< manager_api_url >>"
|
|
||||||
TZ: "<< container_timezone >>"
|
|
||||||
volumes:
|
|
||||||
- << docker_socket_path >>:/var/run/docker.sock
|
|
||||||
<%- if volume_mode == 'mount' and volume_mount_path %>
|
|
||||||
- << volume_mount_path >>:/app/data
|
|
||||||
<%- else %>
|
|
||||||
- << service_name if service_name is string and service_name and (service_name | lower) not in ['true', 'false'] else 'arcane-agent' >>-data:/app/data
|
|
||||||
<%- endif %>
|
|
||||||
<%- if project_mount_path %>
|
|
||||||
- << project_mount_path >>:/app/data/projects
|
|
||||||
<%- endif %>
|
|
||||||
<%- if connection_mode == 'direct' %>
|
|
||||||
ports:
|
|
||||||
- "<< ports_agent >>:3553"
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
<%- if volume_mode == 'local' or (volume_mode == 'mount' and not volume_mount_path) %>
|
|
||||||
volumes:
|
|
||||||
<< service_name if service_name is string and service_name and (service_name | lower) not in ['true', 'false'] else 'arcane-agent' >>-data:
|
|
||||||
driver: local
|
|
||||||
<%- elif volume_mode == 'nfs' %>
|
|
||||||
volumes:
|
|
||||||
<< service_name if service_name is string and service_name and (service_name | lower) not in ['true', 'false'] else 'arcane-agent' >>-data:
|
|
||||||
driver: local
|
|
||||||
driver_opts:
|
|
||||||
type: nfs
|
|
||||||
o: addr=<< volume_nfs_server >>,nfsvers=4,<< volume_nfs_options >>
|
|
||||||
device: ":<< volume_nfs_path >>"
|
|
||||||
<%- endif %>
|
|
||||||
@@ -1,247 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "arcane-agent",
|
|
||||||
"kind": "compose",
|
|
||||||
"metadata": {
|
|
||||||
"name": "Arcane Agent",
|
|
||||||
"description": "Remote Docker host agent for Arcane manager environments, supporting direct inbound and edge outbound connection modes.",
|
|
||||||
"tags": [
|
|
||||||
"docker",
|
|
||||||
"management",
|
|
||||||
"agent"
|
|
||||||
],
|
|
||||||
"icon": {
|
|
||||||
"provider": "selfhst",
|
|
||||||
"id": "arcane",
|
|
||||||
"color": "violet"
|
|
||||||
},
|
|
||||||
"draft": false,
|
|
||||||
"version": {
|
|
||||||
"name": "v2.1.0",
|
|
||||||
"source_dep_name": "ghcr.io/getarcaneapp/agent",
|
|
||||||
"source_dep_version": "v2.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"title": "General",
|
|
||||||
"name": "general",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "service_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Service Name",
|
|
||||||
"required": false,
|
|
||||||
"description": "Name of the Docker Compose service. Leave empty to omit/fall back to Arcane defaults.",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "arcane-agent"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "container_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Container Name",
|
|
||||||
"required": false,
|
|
||||||
"description": "Name to use for the container. Leave empty to omit/fall back to Arcane defaults.",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "arcane-agent"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "container_timezone",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Container Timezone",
|
|
||||||
"required": false,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "Europe/Berlin"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "restart_policy",
|
|
||||||
"type": "enum",
|
|
||||||
"title": "Restart Policy",
|
|
||||||
"required": true,
|
|
||||||
"default": "unless-stopped",
|
|
||||||
"config": {
|
|
||||||
"options": [
|
|
||||||
"unless-stopped",
|
|
||||||
"always",
|
|
||||||
"on-failure",
|
|
||||||
"no"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "docker_socket_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Docker Socket Path",
|
|
||||||
"required": true,
|
|
||||||
"default": "/var/run/docker.sock",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/var/run/docker.sock"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Advanced",
|
|
||||||
"name": "advanced",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "project_mount_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Project Mount Path",
|
|
||||||
"required": false,
|
|
||||||
"description": "Optional host path mounted to /app/data/projects for agent-visible project/Compose stack storage. Leave empty to skip this mount.",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/path/to/projects"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Agent Connection",
|
|
||||||
"name": "connection",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "connection_mode",
|
|
||||||
"type": "enum",
|
|
||||||
"title": "Connection Mode",
|
|
||||||
"required": false,
|
|
||||||
"default": "direct",
|
|
||||||
"description": "Direct exposes TCP 3553 for the manager to connect inbound. Edge connects outbound from the agent to the manager.",
|
|
||||||
"config": {
|
|
||||||
"options": [
|
|
||||||
"direct",
|
|
||||||
"edge"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "edge_transport",
|
|
||||||
"type": "enum",
|
|
||||||
"title": "Transport Mode",
|
|
||||||
"required": false,
|
|
||||||
"default": "poll",
|
|
||||||
"description": "Arcane agent transport. Official generated snippets default to poll; auto keeps a live tunnel when possible.",
|
|
||||||
"config": {
|
|
||||||
"options": [
|
|
||||||
"poll",
|
|
||||||
"auto"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "manager_api_url",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Manager API URL",
|
|
||||||
"required": true,
|
|
||||||
"default": "http://arcane:3552",
|
|
||||||
"description": "Arcane manager API URL reachable from the agent.",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "https://arcane.example.com"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "agent_token",
|
|
||||||
"type": "secret",
|
|
||||||
"title": "Agent Token",
|
|
||||||
"required": true,
|
|
||||||
"description": "Agent token generated by Arcane when creating the remote environment."
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Storage",
|
|
||||||
"name": "storage",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "volume_mode",
|
|
||||||
"type": "enum",
|
|
||||||
"title": "Volume Mode",
|
|
||||||
"required": false,
|
|
||||||
"default": "local",
|
|
||||||
"config": {
|
|
||||||
"options": [
|
|
||||||
"local",
|
|
||||||
"mount",
|
|
||||||
"nfs"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "volume_mount_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Data Mount Path",
|
|
||||||
"required": false,
|
|
||||||
"default": "",
|
|
||||||
"description": "Host path for agent data when using mount mode.",
|
|
||||||
"needs": [
|
|
||||||
"volume_mode=mount"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/opt/arcane-agent/data"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "volume_nfs_server",
|
|
||||||
"type": "str",
|
|
||||||
"title": "NFS Server",
|
|
||||||
"required": false,
|
|
||||||
"default": "",
|
|
||||||
"needs": [
|
|
||||||
"volume_mode=nfs"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "nas.home.arpa"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "volume_nfs_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "NFS Path",
|
|
||||||
"required": false,
|
|
||||||
"default": "",
|
|
||||||
"description": "NFS export path for Arcane agent data.",
|
|
||||||
"needs": [
|
|
||||||
"volume_mode=nfs"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/export/app"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "volume_nfs_options",
|
|
||||||
"type": "str",
|
|
||||||
"title": "NFS Options",
|
|
||||||
"required": false,
|
|
||||||
"default": "rw",
|
|
||||||
"needs": [
|
|
||||||
"volume_mode=nfs"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "rw"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Ports",
|
|
||||||
"name": "ports",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "ports_agent",
|
|
||||||
"type": "int",
|
|
||||||
"title": "Agent Port",
|
|
||||||
"required": false,
|
|
||||||
"default": 3553,
|
|
||||||
"needs": [
|
|
||||||
"connection_mode=direct"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "3553"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
# Arcane manager secrets
|
|
||||||
# ENCRYPTION_KEY must be 32 bytes. For a hex value, use: openssl rand -hex 32
|
|
||||||
ARCANE_ENCRYPTION_KEY='<< encryption_key >>'
|
|
||||||
ARCANE_JWT_SECRET='<< jwt_secret >>'
|
|
||||||
<%- if oidc_enabled %>
|
|
||||||
ARCANE_OIDC_CLIENT_SECRET='<< oidc_client_secret >>'
|
|
||||||
<%- endif %>
|
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
---
|
|
||||||
services:
|
|
||||||
<< service_name if service_name is string and service_name and (service_name | lower) not in ['true', 'false'] else 'arcane' >>:
|
|
||||||
image: ghcr.io/getarcaneapp/manager:v2.1.0
|
|
||||||
restart: << restart_policy >>
|
|
||||||
<%- if container_name is string and container_name and (container_name | lower) not in ['true', 'false'] %>
|
|
||||||
container_name: << container_name >>
|
|
||||||
<%- endif %>
|
|
||||||
environment:
|
|
||||||
APP_URL: "<< app_url >>"
|
|
||||||
<%- if puid %>
|
|
||||||
PUID: "<< puid >>"
|
|
||||||
<%- endif %>
|
|
||||||
<%- if pgid %>
|
|
||||||
PGID: "<< pgid >>"
|
|
||||||
<%- endif %>
|
|
||||||
ENCRYPTION_KEY: "${ARCANE_ENCRYPTION_KEY}"
|
|
||||||
JWT_SECRET: "${ARCANE_JWT_SECRET}"
|
|
||||||
TZ: "<< container_timezone >>"
|
|
||||||
<%- if analytics_enabled %>
|
|
||||||
ANALYTICS_DISABLED: "false"
|
|
||||||
<%- endif %>
|
|
||||||
<%- if oidc_enabled %>
|
|
||||||
OIDC_ENABLED: "true"
|
|
||||||
OIDC_CLIENT_ID: "<< oidc_client_id >>"
|
|
||||||
OIDC_CLIENT_SECRET: "${ARCANE_OIDC_CLIENT_SECRET}"
|
|
||||||
OIDC_ISSUER_URL: "<< oidc_issuer_url >>"
|
|
||||||
<%- if oidc_provider_name %>
|
|
||||||
OIDC_PROVIDER_NAME: "<< oidc_provider_name >>"
|
|
||||||
<%- endif %>
|
|
||||||
<%- if oidc_scopes %>
|
|
||||||
OIDC_SCOPES: "<< oidc_scopes >>"
|
|
||||||
<%- endif %>
|
|
||||||
<%- if oidc_groups_claim %>
|
|
||||||
OIDC_GROUPS_CLAIM: "<< oidc_groups_claim >>"
|
|
||||||
<%- endif %>
|
|
||||||
<%- if oidc_role_mappings %>
|
|
||||||
OIDC_ROLE_MAPPINGS: '<< oidc_role_mappings >>'
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
volumes:
|
|
||||||
- << docker_socket_path >>:/var/run/docker.sock
|
|
||||||
<%- if volume_mode == 'mount' and volume_mount_path %>
|
|
||||||
- << volume_mount_path >>:/app/data
|
|
||||||
<%- else %>
|
|
||||||
- << service_name if service_name is string and service_name and (service_name | lower) not in ['true', 'false'] else 'arcane' >>-data:/app/data
|
|
||||||
<%- endif %>
|
|
||||||
<%- if project_mount_path %>
|
|
||||||
- << project_mount_path >>:/app/data/projects
|
|
||||||
<%- endif %>
|
|
||||||
<%- if builds_mount_path %>
|
|
||||||
- << builds_mount_path >>:/builds
|
|
||||||
<%- endif %>
|
|
||||||
<%- if backups_mount_path %>
|
|
||||||
- << backups_mount_path >>:/backups
|
|
||||||
<%- endif %>
|
|
||||||
<%- if traefik_enabled %>
|
|
||||||
networks:
|
|
||||||
- << traefik_network >>
|
|
||||||
<%- endif %>
|
|
||||||
<%- if not traefik_enabled %>
|
|
||||||
ports:
|
|
||||||
- "<< ports_http >>:3552"
|
|
||||||
<%- endif %>
|
|
||||||
<%- if traefik_enabled %>
|
|
||||||
labels:
|
|
||||||
- traefik.enable=true
|
|
||||||
- traefik.docker.network=<< traefik_network >>
|
|
||||||
- traefik.http.services.<< service_name if service_name is string and service_name and (service_name | lower) not in ['true', 'false'] else 'arcane' >>-web.loadBalancer.server.port=3552
|
|
||||||
- traefik.http.routers.<< service_name if service_name is string and service_name and (service_name | lower) not in ['true', 'false'] else 'arcane' >>-http.service=<< service_name if service_name is string and service_name and (service_name | lower) not in ['true', 'false'] else 'arcane' >>-web
|
|
||||||
- traefik.http.routers.<< service_name if service_name is string and service_name and (service_name | lower) not in ['true', 'false'] else 'arcane' >>-http.rule=Host(`<< traefik_host >>.<< traefik_domain >>`)
|
|
||||||
- traefik.http.routers.<< service_name if service_name is string and service_name and (service_name | lower) not in ['true', 'false'] else 'arcane' >>-http.entrypoints=<< traefik_entrypoint >>
|
|
||||||
<%- if traefik_tls_enabled %>
|
|
||||||
- traefik.http.routers.<< service_name if service_name is string and service_name and (service_name | lower) not in ['true', 'false'] else 'arcane' >>-https.service=<< service_name if service_name is string and service_name and (service_name | lower) not in ['true', 'false'] else 'arcane' >>-web
|
|
||||||
- traefik.http.routers.<< service_name if service_name is string and service_name and (service_name | lower) not in ['true', 'false'] else 'arcane' >>-https.rule=Host(`<< traefik_host >>.<< traefik_domain >>`)
|
|
||||||
- traefik.http.routers.<< service_name if service_name is string and service_name and (service_name | lower) not in ['true', 'false'] else 'arcane' >>-https.entrypoints=<< traefik_tls_entrypoint >>
|
|
||||||
- traefik.http.routers.<< service_name if service_name is string and service_name and (service_name | lower) not in ['true', 'false'] else 'arcane' >>-https.tls=true
|
|
||||||
- traefik.http.routers.<< service_name if service_name is string and service_name and (service_name | lower) not in ['true', 'false'] else 'arcane' >>-https.tls.certresolver=<< traefik_tls_certresolver >>
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
<%- if volume_mode == 'local' or (volume_mode == 'mount' and not volume_mount_path) %>
|
|
||||||
volumes:
|
|
||||||
<< service_name if service_name is string and service_name and (service_name | lower) not in ['true', 'false'] else 'arcane' >>-data:
|
|
||||||
driver: local
|
|
||||||
<%- elif volume_mode == 'nfs' %>
|
|
||||||
volumes:
|
|
||||||
<< service_name if service_name is string and service_name and (service_name | lower) not in ['true', 'false'] else 'arcane' >>-data:
|
|
||||||
driver: local
|
|
||||||
driver_opts:
|
|
||||||
type: nfs
|
|
||||||
o: addr=<< volume_nfs_server >>,nfsvers=4,<< volume_nfs_options >>
|
|
||||||
device: ":<< volume_nfs_path >>"
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
<%- if traefik_enabled %>
|
|
||||||
networks:
|
|
||||||
<< traefik_network >>:
|
|
||||||
external: true
|
|
||||||
<%- endif %>
|
|
||||||
@@ -1,451 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "arcane",
|
|
||||||
"kind": "compose",
|
|
||||||
"metadata": {
|
|
||||||
"name": "Arcane",
|
|
||||||
"description": "Modern self-hosted Docker management UI for containers, images, volumes, networks, Docker Compose projects, and remote environments.",
|
|
||||||
"tags": [
|
|
||||||
"docker",
|
|
||||||
"management",
|
|
||||||
"traefik"
|
|
||||||
],
|
|
||||||
"icon": {
|
|
||||||
"provider": "selfhst",
|
|
||||||
"id": "arcane",
|
|
||||||
"color": "violet"
|
|
||||||
},
|
|
||||||
"draft": false,
|
|
||||||
"version": {
|
|
||||||
"name": "v2.1.0",
|
|
||||||
"source_dep_name": "ghcr.io/getarcaneapp/manager",
|
|
||||||
"source_dep_version": "v2.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"title": "General",
|
|
||||||
"name": "general",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "service_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Service Name",
|
|
||||||
"required": false,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "arcane"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "container_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Container Name",
|
|
||||||
"required": false,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "arcane"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "app_url",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Application URL",
|
|
||||||
"required": true,
|
|
||||||
"default": "http://localhost:3552",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "https://arcane.example.com"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "container_timezone",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Container Timezone",
|
|
||||||
"required": false,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "Europe/Berlin"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "restart_policy",
|
|
||||||
"type": "enum",
|
|
||||||
"title": "Restart Policy",
|
|
||||||
"required": true,
|
|
||||||
"default": "unless-stopped",
|
|
||||||
"config": {
|
|
||||||
"options": [
|
|
||||||
"unless-stopped",
|
|
||||||
"always",
|
|
||||||
"on-failure",
|
|
||||||
"no"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "puid",
|
|
||||||
"type": "int",
|
|
||||||
"title": "PUID",
|
|
||||||
"required": false,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "1000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "pgid",
|
|
||||||
"type": "int",
|
|
||||||
"title": "PGID",
|
|
||||||
"required": false,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "1000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "docker_socket_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Docker Socket Path",
|
|
||||||
"required": true,
|
|
||||||
"default": "/var/run/docker.sock",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/var/run/docker.sock"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "analytics_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Enable Analytics",
|
|
||||||
"required": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Advanced",
|
|
||||||
"name": "advanced",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "project_mount_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Project Mount Path",
|
|
||||||
"required": false,
|
|
||||||
"description": "Optional host path mounted to /app/data/projects for Arcane project/Compose stack storage. Leave empty to skip this mount.",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/path/to/projects"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "builds_mount_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Builds Mount Path",
|
|
||||||
"required": false,
|
|
||||||
"description": "Optional host path mounted to /builds for Arcane build workspace files. Leave empty to skip this mount.",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/path/to/builds"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "backups_mount_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Backups Mount Path",
|
|
||||||
"required": false,
|
|
||||||
"description": "Optional host path mounted to /backups for Arcane volume backups. Leave empty to skip this mount.",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/path/to/backups"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Secrets",
|
|
||||||
"name": "secrets",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "encryption_key",
|
|
||||||
"type": "secret",
|
|
||||||
"title": "Encryption Key",
|
|
||||||
"required": true,
|
|
||||||
"description": "Arcane ENCRYPTION_KEY. It must be 32 bytes; a 64-character hex value from `openssl rand -hex 32` is recommended.",
|
|
||||||
"config": {
|
|
||||||
"autogenerated": {
|
|
||||||
"length": 64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "jwt_secret",
|
|
||||||
"type": "secret",
|
|
||||||
"title": "JWT Secret",
|
|
||||||
"required": true,
|
|
||||||
"config": {
|
|
||||||
"autogenerated": {
|
|
||||||
"length": 64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Storage",
|
|
||||||
"name": "storage",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "volume_mode",
|
|
||||||
"type": "enum",
|
|
||||||
"title": "Volume Mode",
|
|
||||||
"required": false,
|
|
||||||
"default": "local",
|
|
||||||
"config": {
|
|
||||||
"options": [
|
|
||||||
"local",
|
|
||||||
"mount",
|
|
||||||
"nfs"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "volume_mount_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Data Mount Path",
|
|
||||||
"required": false,
|
|
||||||
"default": "",
|
|
||||||
"needs": [
|
|
||||||
"volume_mode=mount"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/opt/arcane/data"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "volume_nfs_server",
|
|
||||||
"type": "str",
|
|
||||||
"title": "NFS Server",
|
|
||||||
"required": false,
|
|
||||||
"default": "",
|
|
||||||
"needs": [
|
|
||||||
"volume_mode=nfs"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "nas.home.arpa"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "volume_nfs_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "NFS Path",
|
|
||||||
"required": false,
|
|
||||||
"default": "",
|
|
||||||
"needs": [
|
|
||||||
"volume_mode=nfs"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/export/app"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "volume_nfs_options",
|
|
||||||
"type": "str",
|
|
||||||
"title": "NFS Options",
|
|
||||||
"required": false,
|
|
||||||
"default": "rw",
|
|
||||||
"needs": [
|
|
||||||
"volume_mode=nfs"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "rw"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Traefik",
|
|
||||||
"name": "traefik",
|
|
||||||
"toggle": "traefik_enabled",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "traefik_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Traefik",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_host",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Host",
|
|
||||||
"required": true,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "arcane"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_domain",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Domain",
|
|
||||||
"required": true,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "home.arpa"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_entrypoint",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Entrypoint",
|
|
||||||
"required": true,
|
|
||||||
"default": "web",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "web"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_network",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Network",
|
|
||||||
"required": true,
|
|
||||||
"default": "traefik",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "traefik"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_tls_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "TLS",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_tls_entrypoint",
|
|
||||||
"type": "str",
|
|
||||||
"title": "TLS Entrypoint",
|
|
||||||
"required": true,
|
|
||||||
"default": "websecure",
|
|
||||||
"needs": [
|
|
||||||
"traefik_tls_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "websecure"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_tls_certresolver",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Cert Resolver",
|
|
||||||
"required": true,
|
|
||||||
"default": "cloudflare",
|
|
||||||
"needs": [
|
|
||||||
"traefik_tls_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "cloudflare"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Ports",
|
|
||||||
"name": "ports",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "ports_http",
|
|
||||||
"type": "int",
|
|
||||||
"title": "HTTP Port",
|
|
||||||
"required": false,
|
|
||||||
"default": 3552,
|
|
||||||
"needs": [
|
|
||||||
"traefik_enabled=false"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "3552"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "OIDC Single Sign-On",
|
|
||||||
"name": "oidc",
|
|
||||||
"toggle": "oidc_enabled",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "oidc_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "OIDC",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "oidc_client_id",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Client ID",
|
|
||||||
"required": true,
|
|
||||||
"needs": [
|
|
||||||
"oidc_enabled=true"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "oidc_client_secret",
|
|
||||||
"type": "secret",
|
|
||||||
"title": "Client Secret",
|
|
||||||
"required": true,
|
|
||||||
"needs": [
|
|
||||||
"oidc_enabled=true"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "oidc_issuer_url",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Issuer URL",
|
|
||||||
"required": true,
|
|
||||||
"description": "Issuer URL of your OIDC provider. Arcane's docs recommend no trailing slash.",
|
|
||||||
"needs": [
|
|
||||||
"oidc_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "https://auth.example.com/application/o/arcane"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "oidc_provider_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Provider Name",
|
|
||||||
"required": false,
|
|
||||||
"needs": [
|
|
||||||
"oidc_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "My Identity Provider"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "oidc_scopes",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Scopes",
|
|
||||||
"required": false,
|
|
||||||
"description": "Optional OIDC scopes to request. Arcane defaults to openid email profile if unset; include your groups scope when using group mappings.",
|
|
||||||
"needs": [
|
|
||||||
"oidc_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "openid email profile groups"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "oidc_groups_claim",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Groups Claim",
|
|
||||||
"required": false,
|
|
||||||
"needs": [
|
|
||||||
"oidc_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "groups"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "oidc_role_mappings",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Role Mappings",
|
|
||||||
"required": false,
|
|
||||||
"description": "Optional JSON array for OIDC group-to-role mappings, for example [{\"claimValue\":\"docker-admins\",\"roleId\":\"role_admin\"}].",
|
|
||||||
"needs": [
|
|
||||||
"oidc_enabled=true"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
AUTHENTIK_SECRET_KEY='<< authentik_secret_key >>'
|
|
||||||
DATABASE_USER='<< database_user >>'
|
|
||||||
DATABASE_PASSWORD='<< database_password >>'
|
|
||||||
<%- if email_enabled %>
|
|
||||||
EMAIL_USERNAME='<< email_username >>'
|
|
||||||
EMAIL_PASSWORD='<< email_password >>'
|
|
||||||
<%- endif %>
|
|
||||||
<%- if authentik_admin_password %>
|
|
||||||
AUTHENTIK_BOOTSTRAP_PASSWORD='<< authentik_admin_password >>'
|
|
||||||
<%- endif %>
|
|
||||||
@@ -1,210 +0,0 @@
|
|||||||
---
|
|
||||||
services:
|
|
||||||
<< service_name >>:
|
|
||||||
image: ghcr.io/goauthentik/server:2026.2.2
|
|
||||||
restart: << restart_policy >>
|
|
||||||
command: server
|
|
||||||
environment:
|
|
||||||
- AUTHENTIK_SECRET_KEY=${AUTHENTIK_SECRET_KEY}
|
|
||||||
- AUTHENTIK_ERROR_REPORTING__ENABLED=<< authentik_error_reporting | lower >>
|
|
||||||
<%- if database_external %>
|
|
||||||
- AUTHENTIK_POSTGRESQL__HOST=<< database_host >>
|
|
||||||
- AUTHENTIK_POSTGRESQL__PORT=<< database_port >>
|
|
||||||
<%- else %>
|
|
||||||
- AUTHENTIK_POSTGRESQL__HOST=<< service_name >>_postgres
|
|
||||||
- AUTHENTIK_POSTGRESQL__PORT=5432
|
|
||||||
<%- endif %>
|
|
||||||
- AUTHENTIK_POSTGRESQL__USER=${DATABASE_USER}
|
|
||||||
- AUTHENTIK_POSTGRESQL__NAME=<< database_name >>
|
|
||||||
- AUTHENTIK_POSTGRESQL__PASSWORD=${DATABASE_PASSWORD}
|
|
||||||
<%- if email_enabled %>
|
|
||||||
- AUTHENTIK_EMAIL__HOST=<< email_host >>
|
|
||||||
- AUTHENTIK_EMAIL__PORT=<< email_port >>
|
|
||||||
- AUTHENTIK_EMAIL__FROM=<< email_from >>
|
|
||||||
- AUTHENTIK_EMAIL__USERNAME=${EMAIL_USERNAME}
|
|
||||||
- AUTHENTIK_EMAIL__PASSWORD=${EMAIL_PASSWORD}
|
|
||||||
<%- if email_encryption == "ssl" %>
|
|
||||||
- AUTHENTIK_EMAIL__USE_SSL=True
|
|
||||||
<%- elif email_encryption == "starttls" %>
|
|
||||||
- AUTHENTIK_EMAIL__USE_TLS=True
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
networks:
|
|
||||||
<%- if traefik_enabled %>
|
|
||||||
- << traefik_network >>
|
|
||||||
<%- endif %>
|
|
||||||
- << service_name >>_backend
|
|
||||||
<%- if not traefik_enabled %>
|
|
||||||
ports:
|
|
||||||
- "<< ports_http >>:9000"
|
|
||||||
- "<< ports_https >>:9443"
|
|
||||||
<%- endif %>
|
|
||||||
volumes:
|
|
||||||
<%- if volume_mode == 'mount' %>
|
|
||||||
- << volume_mount_path >>/data:/data
|
|
||||||
- << volume_mount_path >>/templates:/templates
|
|
||||||
<%- elif volume_mode == 'local' or volume_mode == 'nfs' %>
|
|
||||||
- << service_name >>_data:/data
|
|
||||||
- << service_name >>_templates:/templates
|
|
||||||
<%- endif %>
|
|
||||||
<%- if traefik_enabled %>
|
|
||||||
labels:
|
|
||||||
- traefik.enable=true
|
|
||||||
- traefik.docker.network=<< traefik_network >>
|
|
||||||
- traefik.http.services.<< service_name >>_web.loadBalancer.server.port=9000
|
|
||||||
- traefik.http.routers.<< service_name >>_http.service=<< service_name >>_web
|
|
||||||
- traefik.http.routers.<< service_name >>_http.rule=Host(`<< traefik_host >>.<< traefik_domain >>`)
|
|
||||||
- traefik.http.routers.<< service_name >>_http.entrypoints=<< traefik_entrypoint >>
|
|
||||||
- "traefik.http.middlewares.authentik.forwardauth.address=\
|
|
||||||
http://<< service_name >>:9000/outpost.goauthentik.io/auth/traefik"
|
|
||||||
- "traefik.http.middlewares.authentik.forwardauth.trustForwardHeader=true"
|
|
||||||
- "traefik.http.middlewares.authentik.forwardauth.authResponseHeaders=\
|
|
||||||
X-authentik-username,\
|
|
||||||
X-authentik-groups,\
|
|
||||||
X-authentik-entitlements,\
|
|
||||||
X-authentik-email,\
|
|
||||||
X-authentik-name,\
|
|
||||||
X-authentik-uid,\
|
|
||||||
X-authentik-jwt,\
|
|
||||||
X-authentik-meta-jwks,\
|
|
||||||
X-authentik-meta-outpost,\
|
|
||||||
X-authentik-meta-provider,\
|
|
||||||
X-authentik-meta-app,\
|
|
||||||
X-authentik-meta-version"
|
|
||||||
<%- if traefik_tls_enabled %>
|
|
||||||
- traefik.http.routers.<< service_name >>_https.service=<< service_name >>_web
|
|
||||||
- traefik.http.routers.<< service_name >>_https.rule=Host(`<< traefik_host >>.<< traefik_domain >>`)
|
|
||||||
- traefik.http.routers.<< service_name >>_https.entrypoints=<< traefik_tls_entrypoint >>
|
|
||||||
- traefik.http.routers.<< service_name >>_https.tls=true
|
|
||||||
- traefik.http.routers.<< service_name >>_https.tls.certresolver=<< traefik_tls_certresolver >>
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
<%- if not database_external %>
|
|
||||||
depends_on:
|
|
||||||
- << service_name >>_postgres
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
<< service_name >>_worker:
|
|
||||||
image: ghcr.io/goauthentik/server:2026.2.2
|
|
||||||
restart: << restart_policy >>
|
|
||||||
command: worker
|
|
||||||
environment:
|
|
||||||
- AUTHENTIK_SECRET_KEY=${AUTHENTIK_SECRET_KEY}
|
|
||||||
- AUTHENTIK_ERROR_REPORTING__ENABLED=<< authentik_error_reporting | lower >>
|
|
||||||
<%- if database_external %>
|
|
||||||
- AUTHENTIK_POSTGRESQL__HOST=<< database_host >>
|
|
||||||
- AUTHENTIK_POSTGRESQL__PORT=<< database_port >>
|
|
||||||
<%- else %>
|
|
||||||
- AUTHENTIK_POSTGRESQL__HOST=<< service_name >>_postgres
|
|
||||||
- AUTHENTIK_POSTGRESQL__PORT=5432
|
|
||||||
<%- endif %>
|
|
||||||
- AUTHENTIK_POSTGRESQL__USER=${DATABASE_USER}
|
|
||||||
- AUTHENTIK_POSTGRESQL__NAME=<< database_name >>
|
|
||||||
- AUTHENTIK_POSTGRESQL__PASSWORD=${DATABASE_PASSWORD}
|
|
||||||
<%- if email_enabled %>
|
|
||||||
- AUTHENTIK_EMAIL__HOST=<< email_host >>
|
|
||||||
- AUTHENTIK_EMAIL__PORT=<< email_port >>
|
|
||||||
- AUTHENTIK_EMAIL__FROM=<< email_from >>
|
|
||||||
- AUTHENTIK_EMAIL__USERNAME=${EMAIL_USERNAME}
|
|
||||||
- AUTHENTIK_EMAIL__PASSWORD=${EMAIL_PASSWORD}
|
|
||||||
<%- if email_encryption == "ssl" %>
|
|
||||||
- AUTHENTIK_EMAIL__USE_SSL=True
|
|
||||||
<%- elif email_encryption == "starttls" %>
|
|
||||||
- AUTHENTIK_EMAIL__USE_TLS=True
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
<%- if authentik_admin_password %>
|
|
||||||
- AUTHENTIK_BOOTSTRAP_PASSWORD=${AUTHENTIK_BOOTSTRAP_PASSWORD}
|
|
||||||
<%- endif %>
|
|
||||||
user: root
|
|
||||||
networks:
|
|
||||||
- << service_name >>_backend
|
|
||||||
volumes:
|
|
||||||
- /run/docker.sock:/run/docker.sock
|
|
||||||
<%- if volume_mode == 'mount' %>
|
|
||||||
- << volume_mount_path >>/data:/data
|
|
||||||
- << volume_mount_path >>/certs:/certs
|
|
||||||
- << volume_mount_path >>/templates:/templates
|
|
||||||
<%- elif volume_mode == 'local' or volume_mode == 'nfs' %>
|
|
||||||
- << service_name >>_data:/data
|
|
||||||
- << service_name >>_certs:/certs
|
|
||||||
- << service_name >>_templates:/templates
|
|
||||||
<%- endif %>
|
|
||||||
<%- if not database_external %>
|
|
||||||
depends_on:
|
|
||||||
- << service_name >>_postgres
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
<%- if not database_external %>
|
|
||||||
<< service_name >>_postgres:
|
|
||||||
image: docker.io/library/postgres:17.9
|
|
||||||
restart: << restart_policy >>
|
|
||||||
environment:
|
|
||||||
- POSTGRES_USER=${DATABASE_USER}
|
|
||||||
- POSTGRES_PASSWORD=${DATABASE_PASSWORD}
|
|
||||||
- POSTGRES_DB=<< database_name >>
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD-SHELL", "pg_isready -U << database_user >>"]
|
|
||||||
start_period: 30s
|
|
||||||
interval: 10s
|
|
||||||
timeout: 10s
|
|
||||||
retries: 5
|
|
||||||
networks:
|
|
||||||
- << service_name >>_backend
|
|
||||||
volumes:
|
|
||||||
<%- if volume_mode == 'mount' %>
|
|
||||||
- << volume_mount_path >>/postgres:/var/lib/postgresql/data
|
|
||||||
<%- elif volume_mode == 'local' or volume_mode == 'nfs' %>
|
|
||||||
- << service_name >>_postgres:/var/lib/postgresql/data
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
networks:
|
|
||||||
<< service_name >>_backend:
|
|
||||||
driver: bridge
|
|
||||||
<%- if traefik_enabled %>
|
|
||||||
<< traefik_network >>:
|
|
||||||
external: true
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
<%- if volume_mode == 'local' %>
|
|
||||||
volumes:
|
|
||||||
<%- if not database_external %>
|
|
||||||
<< service_name >>_postgres:
|
|
||||||
driver: local
|
|
||||||
<%- endif %>
|
|
||||||
<< service_name >>_data:
|
|
||||||
driver: local
|
|
||||||
<< service_name >>_certs:
|
|
||||||
driver: local
|
|
||||||
<< service_name >>_templates:
|
|
||||||
driver: local
|
|
||||||
<%- elif volume_mode == 'nfs' %>
|
|
||||||
volumes:
|
|
||||||
<%- if not database_external %>
|
|
||||||
<< service_name >>_postgres:
|
|
||||||
driver: local
|
|
||||||
driver_opts:
|
|
||||||
type: nfs
|
|
||||||
o: addr=<< volume_nfs_server >>,nfsvers=4,<< volume_nfs_options >>
|
|
||||||
device: ":<< volume_nfs_path >>/postgres"
|
|
||||||
<%- endif %>
|
|
||||||
<< service_name >>_data:
|
|
||||||
driver: local
|
|
||||||
driver_opts:
|
|
||||||
type: nfs
|
|
||||||
o: addr=<< volume_nfs_server >>,nfsvers=4,<< volume_nfs_options >>
|
|
||||||
device: ":<< volume_nfs_path >>/data"
|
|
||||||
<< service_name >>_certs:
|
|
||||||
driver: local
|
|
||||||
driver_opts:
|
|
||||||
type: nfs
|
|
||||||
o: addr=<< volume_nfs_server >>,nfsvers=4,<< volume_nfs_options >>
|
|
||||||
device: ":<< volume_nfs_path >>/certs"
|
|
||||||
<< service_name >>_templates:
|
|
||||||
driver: local
|
|
||||||
driver_opts:
|
|
||||||
type: nfs
|
|
||||||
o: addr=<< volume_nfs_server >>,nfsvers=4,<< volume_nfs_options >>
|
|
||||||
device: ":<< volume_nfs_path >>/templates"
|
|
||||||
<%- endif %>
|
|
||||||
@@ -1,402 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "authentik-compose",
|
|
||||||
"kind": "compose",
|
|
||||||
"metadata": {
|
|
||||||
"name": "Authentik",
|
|
||||||
"description": "Open-source Identity Provider (IdP) that supports OAuth2, SAML, LDAP, and SCIM for single sign-on and user authentication across your applications.",
|
|
||||||
"tags": [
|
|
||||||
"traefik",
|
|
||||||
"volume"
|
|
||||||
],
|
|
||||||
"icon": {
|
|
||||||
"provider": "selfhst",
|
|
||||||
"id": "authentik",
|
|
||||||
"color": "default"
|
|
||||||
},
|
|
||||||
"draft": false,
|
|
||||||
"version": {
|
|
||||||
"name": "2026.2.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"name": "general",
|
|
||||||
"title": "General",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "service_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Service Name",
|
|
||||||
"required": false,
|
|
||||||
"default": "authentik",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "authentik"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "restart_policy",
|
|
||||||
"type": "enum",
|
|
||||||
"title": "Restart Policy",
|
|
||||||
"required": true,
|
|
||||||
"default": "unless-stopped",
|
|
||||||
"config": {
|
|
||||||
"options": [
|
|
||||||
"unless-stopped",
|
|
||||||
"always",
|
|
||||||
"on-failure",
|
|
||||||
"no"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "database",
|
|
||||||
"title": "Database",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "database_password",
|
|
||||||
"type": "secret",
|
|
||||||
"title": "Database password",
|
|
||||||
"required": true,
|
|
||||||
"config": {
|
|
||||||
"autogenerated": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "database_user",
|
|
||||||
"type": "str",
|
|
||||||
"title": "The database user",
|
|
||||||
"required": false,
|
|
||||||
"default": "authentik",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "authentik"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "database_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "The database name",
|
|
||||||
"required": false,
|
|
||||||
"default": "authentik",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "authentik"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "database_external",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "External Database",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "database_host",
|
|
||||||
"type": "str",
|
|
||||||
"title": "External database host",
|
|
||||||
"required": false,
|
|
||||||
"default": "",
|
|
||||||
"needs": [
|
|
||||||
"database_external=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "postgres.home.arpa"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "database_port",
|
|
||||||
"type": "int",
|
|
||||||
"title": "External database port",
|
|
||||||
"required": false,
|
|
||||||
"default": 5432,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "5432"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"database_external=true"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ports",
|
|
||||||
"title": "Ports",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "ports_http",
|
|
||||||
"type": "str",
|
|
||||||
"title": "HTTP Port",
|
|
||||||
"required": false,
|
|
||||||
"default": 8000,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "8000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ports_https",
|
|
||||||
"type": "str",
|
|
||||||
"title": "HTTPS Port",
|
|
||||||
"required": false,
|
|
||||||
"default": 8443,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "8443"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik",
|
|
||||||
"title": "Traefik",
|
|
||||||
"toggle": "traefik_enabled",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "traefik_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Traefik",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_host",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Host",
|
|
||||||
"required": true,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "authentik"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_domain",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Domain",
|
|
||||||
"required": true,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "home.arpa"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_entrypoint",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Entrypoint",
|
|
||||||
"required": true,
|
|
||||||
"default": "web",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "web"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_network",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Network",
|
|
||||||
"required": true,
|
|
||||||
"default": "traefik",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "traefik"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_tls_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "TLS",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_tls_entrypoint",
|
|
||||||
"type": "str",
|
|
||||||
"title": "TLS Entrypoint",
|
|
||||||
"required": true,
|
|
||||||
"default": "websecure",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "websecure"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"traefik_tls_enabled=true"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_tls_certresolver",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Cert Resolver",
|
|
||||||
"required": true,
|
|
||||||
"default": "cloudflare",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "cloudflare"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"traefik_tls_enabled=true"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "authentik",
|
|
||||||
"title": "Authentik",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "authentik_secret_key",
|
|
||||||
"type": "secret",
|
|
||||||
"title": "Secret Key",
|
|
||||||
"required": true,
|
|
||||||
"config": {
|
|
||||||
"autogenerated": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "authentik_admin_password",
|
|
||||||
"type": "secret",
|
|
||||||
"title": "Admin Password",
|
|
||||||
"required": false,
|
|
||||||
"config": {
|
|
||||||
"autogenerated": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "authentik_error_reporting",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Error Reporting",
|
|
||||||
"required": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "volume",
|
|
||||||
"title": "Volume",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "volume_mode",
|
|
||||||
"type": "enum",
|
|
||||||
"title": "Volume Mode",
|
|
||||||
"required": true,
|
|
||||||
"default": "local",
|
|
||||||
"config": {
|
|
||||||
"options": [
|
|
||||||
"local",
|
|
||||||
"mount",
|
|
||||||
"nfs"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "volume_mount_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Volume Mount Path",
|
|
||||||
"required": true,
|
|
||||||
"default": "/data",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/data"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"volume_mode=mount"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "volume_nfs_server",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Volume Nfs Server",
|
|
||||||
"required": true,
|
|
||||||
"default": "NFS_SERVER",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "NFS_SERVER"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"volume_mode=nfs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "volume_nfs_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Volume Nfs Path",
|
|
||||||
"required": true,
|
|
||||||
"default": "/export",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/export"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"volume_mode=nfs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "volume_nfs_options",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Volume Nfs Options",
|
|
||||||
"required": true,
|
|
||||||
"default": "rw,nolock,soft",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "rw,nolock,soft"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"volume_mode=nfs"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "email",
|
|
||||||
"title": "Email",
|
|
||||||
"toggle": "email_enabled",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "email_host",
|
|
||||||
"type": "str",
|
|
||||||
"title": "SMTP server hostname",
|
|
||||||
"required": true,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "smtp.home.arpa"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "email_port",
|
|
||||||
"type": "int",
|
|
||||||
"title": "SMTP server port",
|
|
||||||
"required": true,
|
|
||||||
"default": 25,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "25"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "email_username",
|
|
||||||
"type": "str",
|
|
||||||
"title": "SMTP username",
|
|
||||||
"required": true,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "user@example.com"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "email_password",
|
|
||||||
"type": "secret",
|
|
||||||
"title": "SMTP password",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "email_from",
|
|
||||||
"type": "str",
|
|
||||||
"title": "From email address",
|
|
||||||
"required": true,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "noreply@example.com"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "email_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Email",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "email_encryption",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Encryption",
|
|
||||||
"required": false,
|
|
||||||
"default": "tls",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "tls"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
services:
|
|
||||||
<< service_name >>:
|
|
||||||
image: docker.io/ubuntu/bind9:9.20-24.10_edge
|
|
||||||
restart: << restart_policy >>
|
|
||||||
<%- if container_hostname %>
|
|
||||||
hostname: << container_hostname >>
|
|
||||||
<%- endif %>
|
|
||||||
environment:
|
|
||||||
- TZ=<< container_timezone >>
|
|
||||||
- BIND9_USER=bind
|
|
||||||
<%- if network_mode == 'host' %>
|
|
||||||
network_mode: host
|
|
||||||
<%- elif network_mode == 'bridge' or network_mode == 'macvlan' %>
|
|
||||||
networks:
|
|
||||||
<%- if network_mode == 'macvlan' %>
|
|
||||||
<< network_name >>:
|
|
||||||
ipv4_address: << network_macvlan_ipv4_address >>
|
|
||||||
<%- elif network_mode == 'bridge' %>
|
|
||||||
<< network_name >>:
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
<%- if network_mode == '' or network_mode == 'bridge' %>
|
|
||||||
ports:
|
|
||||||
- "53:53/tcp"
|
|
||||||
- "53:53/udp"
|
|
||||||
<%- endif %>
|
|
||||||
volumes:
|
|
||||||
<%- if volume_mode == 'mount' %>
|
|
||||||
- << volume_mount_path >>/config:/etc/bind:rw
|
|
||||||
- << volume_mount_path >>/zones:/var/lib/bind:rw
|
|
||||||
- << volume_mount_path >>/cache:/var/cache/bind:rw
|
|
||||||
<%- else %>
|
|
||||||
- << service_name >>_config:/etc/bind
|
|
||||||
- << service_name >>_zones:/var/lib/bind
|
|
||||||
- << service_name >>_cache:/var/cache/bind
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
<%- if network_mode == 'bridge' or network_mode == 'macvlan' %>
|
|
||||||
networks:
|
|
||||||
<< network_name >>:
|
|
||||||
<%- if network_external %>
|
|
||||||
external: true
|
|
||||||
<%- else %>
|
|
||||||
<%- if network_mode == 'macvlan' %>
|
|
||||||
driver: macvlan
|
|
||||||
driver_opts:
|
|
||||||
parent: << network_macvlan_parent_interface >>
|
|
||||||
ipam:
|
|
||||||
config:
|
|
||||||
- subnet: << network_macvlan_subnet >>
|
|
||||||
gateway: << network_macvlan_gateway >>
|
|
||||||
name: << network_name >>
|
|
||||||
<%- elif network_mode == 'bridge' %>
|
|
||||||
driver: bridge
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
<%- if volume_mode == 'local' %>
|
|
||||||
volumes:
|
|
||||||
<< service_name >>_config:
|
|
||||||
driver: local
|
|
||||||
<< service_name >>_zones:
|
|
||||||
driver: local
|
|
||||||
<< service_name >>_cache:
|
|
||||||
driver: local
|
|
||||||
<%- elif volume_mode == 'nfs' %>
|
|
||||||
volumes:
|
|
||||||
<< service_name >>_config:
|
|
||||||
driver: local
|
|
||||||
driver_opts:
|
|
||||||
type: nfs
|
|
||||||
o: addr=<< volume_nfs_server >>,<< volume_nfs_options >>
|
|
||||||
device: ":<< volume_nfs_path >>/config"
|
|
||||||
<< service_name >>_zones:
|
|
||||||
driver: local
|
|
||||||
driver_opts:
|
|
||||||
type: nfs
|
|
||||||
o: addr=<< volume_nfs_server >>,<< volume_nfs_options >>
|
|
||||||
device: ":<< volume_nfs_path >>/zones"
|
|
||||||
<< service_name >>_cache:
|
|
||||||
driver: local
|
|
||||||
driver_opts:
|
|
||||||
type: nfs
|
|
||||||
o: addr=<< volume_nfs_server >>,<< volume_nfs_options >>
|
|
||||||
device: ":<< volume_nfs_path >>/cache"
|
|
||||||
<%- endif %>
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
// BIND9 Main Configuration File
|
|
||||||
// Documentation: https://bind9.readthedocs.io/
|
|
||||||
|
|
||||||
<%- if tsig_enabled %>
|
|
||||||
include "/etc/bind/tsig.key";
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
acl "trusted" {
|
|
||||||
127.0.0.1;
|
|
||||||
::1;
|
|
||||||
10.0.0.0/8;
|
|
||||||
172.16.0.0/12;
|
|
||||||
192.168.0.0/16;
|
|
||||||
};
|
|
||||||
|
|
||||||
options {
|
|
||||||
directory "/var/cache/bind";
|
|
||||||
|
|
||||||
// DNS forwarders for recursive queries
|
|
||||||
forwarders {
|
|
||||||
1.1.1.1;
|
|
||||||
8.8.8.8;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Allow recursion from trusted networks only
|
|
||||||
allow-recursion { trusted; };
|
|
||||||
|
|
||||||
// Allow queries from any (adjust as needed)
|
|
||||||
allow-query { any; };
|
|
||||||
|
|
||||||
// Disable zone transfers by default (enable per-zone with TSIG)
|
|
||||||
allow-transfer { none; };
|
|
||||||
|
|
||||||
// DNSSEC validation
|
|
||||||
dnssec-validation auto;
|
|
||||||
|
|
||||||
// Listen on all interfaces
|
|
||||||
listen-on { any; };
|
|
||||||
listen-on-v6 { any; };
|
|
||||||
|
|
||||||
// Disable query logging (enable for debugging)
|
|
||||||
// querylog yes;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Local zones
|
|
||||||
zone "localhost" {
|
|
||||||
type master;
|
|
||||||
file "/etc/bind/db.local";
|
|
||||||
};
|
|
||||||
|
|
||||||
zone "127.in-addr.arpa" {
|
|
||||||
type master;
|
|
||||||
file "/etc/bind/db.127";
|
|
||||||
};
|
|
||||||
|
|
||||||
zone "0.in-addr.arpa" {
|
|
||||||
type master;
|
|
||||||
file "/etc/bind/db.0";
|
|
||||||
};
|
|
||||||
|
|
||||||
zone "255.in-addr.arpa" {
|
|
||||||
type master;
|
|
||||||
file "/etc/bind/db.255";
|
|
||||||
};
|
|
||||||
|
|
||||||
// Include your custom zones
|
|
||||||
include "/etc/bind/named.conf.zones";
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
zone "<< domain_name >>" {
|
|
||||||
type master;
|
|
||||||
file "/var/lib/bind/db.primary.zone";
|
|
||||||
|
|
||||||
<%- if tsig_enabled %>
|
|
||||||
allow-transfer { key "tsig-transfer-key"; };
|
|
||||||
allow-update { key "tsig-transfer-key"; };
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
<%- if dnssec_enabled %>
|
|
||||||
dnssec-policy default;
|
|
||||||
inline-signing yes;
|
|
||||||
<%- endif %>
|
|
||||||
};
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
<%- if tsig_enabled %>
|
|
||||||
key "tsig-transfer-key" {
|
|
||||||
algorithm hmac-sha256;
|
|
||||||
secret "<< tsig_key_secret >>";
|
|
||||||
};
|
|
||||||
<%- endif %>
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
$TTL 86400
|
|
||||||
@ IN SOA ns1.<< domain_name >>. admin.<< domain_name >>. (
|
|
||||||
2026010101 ; serial
|
|
||||||
3600 ; refresh
|
|
||||||
900 ; retry
|
|
||||||
604800 ; expire
|
|
||||||
86400 ; minimum
|
|
||||||
)
|
|
||||||
|
|
||||||
@ IN NS ns1.<< domain_name >>.
|
|
||||||
ns1 IN A 127.0.0.1
|
|
||||||
@@ -1,262 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "bind9",
|
|
||||||
"kind": "compose",
|
|
||||||
"metadata": {
|
|
||||||
"name": "BIND9",
|
|
||||||
"description": "The most widely used authoritative and recursive DNS server. This template includes example zones, TSIG authentication for secure zone transfers, and DNSSEC support.",
|
|
||||||
"tags": [
|
|
||||||
"network",
|
|
||||||
"volume"
|
|
||||||
],
|
|
||||||
"icon": {
|
|
||||||
"provider": "selfhst",
|
|
||||||
"id": "bind-9"
|
|
||||||
},
|
|
||||||
"draft": false,
|
|
||||||
"version": {
|
|
||||||
"name": "9.20-24.10_edge",
|
|
||||||
"source_dep_name": "docker.io/ubuntu/bind9",
|
|
||||||
"source_dep_version": "9.20-24.10_edge"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"title": "dns_security",
|
|
||||||
"name": "dns-security",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "dnssec_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "DNSSEC",
|
|
||||||
"required": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "dns_zone",
|
|
||||||
"name": "dns-zone",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "domain_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Primary domain name",
|
|
||||||
"required": false,
|
|
||||||
"default": "home.arpa",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "home.arpa"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "tsig_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "TSIG",
|
|
||||||
"required": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "tsig_key_secret",
|
|
||||||
"type": "secret",
|
|
||||||
"title": "TSIG key secret",
|
|
||||||
"required": false,
|
|
||||||
"needs": [
|
|
||||||
"tsig_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"autogenerated": {
|
|
||||||
"kind": "base64",
|
|
||||||
"bytes": 32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Volume",
|
|
||||||
"name": "volume",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "volume_mode",
|
|
||||||
"type": "enum",
|
|
||||||
"title": "Volume Mode",
|
|
||||||
"required": true,
|
|
||||||
"default": "local",
|
|
||||||
"config": {
|
|
||||||
"options": [
|
|
||||||
"local",
|
|
||||||
"mount",
|
|
||||||
"nfs"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "volume_mount_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Volume Mount Path",
|
|
||||||
"required": true,
|
|
||||||
"default": "/data",
|
|
||||||
"needs": [
|
|
||||||
"volume_mode=mount"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/data"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "volume_nfs_server",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Volume Nfs Server",
|
|
||||||
"required": true,
|
|
||||||
"default": "NFS_SERVER",
|
|
||||||
"needs": [
|
|
||||||
"volume_mode=nfs"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "NFS_SERVER"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "volume_nfs_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Volume Nfs Path",
|
|
||||||
"required": true,
|
|
||||||
"default": "/export",
|
|
||||||
"needs": [
|
|
||||||
"volume_mode=nfs"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/export"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "volume_nfs_options",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Volume Nfs Options",
|
|
||||||
"required": true,
|
|
||||||
"default": "rw,nolock,soft",
|
|
||||||
"needs": [
|
|
||||||
"volume_mode=nfs"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "rw,nolock,soft"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "General",
|
|
||||||
"name": "general",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "service_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Service Name",
|
|
||||||
"required": false,
|
|
||||||
"default": "bind9",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "bind9"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "container_hostname",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Container Hostname",
|
|
||||||
"required": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "container_timezone",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Container Timezone",
|
|
||||||
"required": false,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "Europe/Berlin"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "restart_policy",
|
|
||||||
"type": "enum",
|
|
||||||
"title": "Restart Policy",
|
|
||||||
"required": true,
|
|
||||||
"default": "unless-stopped",
|
|
||||||
"config": {
|
|
||||||
"options": [
|
|
||||||
"unless-stopped",
|
|
||||||
"always",
|
|
||||||
"on-failure",
|
|
||||||
"no"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "network_mode",
|
|
||||||
"type": "enum",
|
|
||||||
"title": "Network mode",
|
|
||||||
"required": false,
|
|
||||||
"default": "bridge",
|
|
||||||
"config": {
|
|
||||||
"options": [
|
|
||||||
"bridge",
|
|
||||||
"macvlan",
|
|
||||||
"host"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "network_external",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "External Network",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "network_macvlan_parent_interface",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Parent Interface",
|
|
||||||
"required": false,
|
|
||||||
"default": "",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "eth0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "network_macvlan_gateway",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Gateway",
|
|
||||||
"required": false,
|
|
||||||
"default": "",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "10.20.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "network_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Network Name",
|
|
||||||
"required": false,
|
|
||||||
"default": "bind9_network",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "bind9_network"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "network_macvlan_subnet",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Subnet",
|
|
||||||
"required": false,
|
|
||||||
"default": "",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "10.20.0.0/16"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "network_macvlan_ipv4_address",
|
|
||||||
"type": "str",
|
|
||||||
"title": "IPv4 Address",
|
|
||||||
"required": false,
|
|
||||||
"default": "",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "10.20.1.50"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
<%- if tls_enabled and tls_email %>
|
|
||||||
{
|
|
||||||
email << tls_email >>
|
|
||||||
}
|
|
||||||
|
|
||||||
<%- endif %>
|
|
||||||
import /etc/caddy/config/*.caddy
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
services:
|
|
||||||
<< service_name >>:
|
|
||||||
image: docker.io/library/caddy:2.11.2-alpine
|
|
||||||
restart: << restart_policy >>
|
|
||||||
<%- if container_timezone %>
|
|
||||||
environment:
|
|
||||||
- TZ=<< container_timezone >>
|
|
||||||
<%- endif %>
|
|
||||||
ports:
|
|
||||||
- "<< ports_http >>:80"
|
|
||||||
- "<< ports_https >>:443"
|
|
||||||
- "<< ports_https >>:443/udp"
|
|
||||||
volumes:
|
|
||||||
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
|
||||||
- ./config:/etc/caddy/config:ro
|
|
||||||
<%- if webserver_enabled %>
|
|
||||||
<%- if webserver_content_type == 'mount' %>
|
|
||||||
- << webserver_content_mount_path >>:/srv:ro
|
|
||||||
<%- elif webserver_content_type == 'nfs' %>
|
|
||||||
- caddy_site:/srv:ro
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
- caddy_data:/data
|
|
||||||
- caddy_config:/config
|
|
||||||
networks:
|
|
||||||
- << docker_network >>
|
|
||||||
|
|
||||||
networks:
|
|
||||||
<< docker_network >>:
|
|
||||||
<%- if docker_network_external %>
|
|
||||||
external: true
|
|
||||||
<%- else %>
|
|
||||||
driver: bridge
|
|
||||||
name: << docker_network >>
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
<%- if webserver_enabled and webserver_content_type == 'nfs' %>
|
|
||||||
caddy_site:
|
|
||||||
driver: local
|
|
||||||
driver_opts:
|
|
||||||
type: nfs
|
|
||||||
o: addr=<< webserver_content_nfs_server >>,nfsvers=4,<< webserver_content_nfs_options >>
|
|
||||||
device: ":<< webserver_content_nfs_path >>"
|
|
||||||
<%- endif %>
|
|
||||||
caddy_data:
|
|
||||||
caddy_config:
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
<%- if webserver_enabled %>
|
|
||||||
<< webserver_domain >> {
|
|
||||||
root * /srv
|
|
||||||
file_server
|
|
||||||
<%- if webserver_custom_config_content %>
|
|
||||||
<%- for line in webserver_custom_config_content.split('\n') %>
|
|
||||||
<< line >>
|
|
||||||
<%- endfor %>
|
|
||||||
<%- endif %>
|
|
||||||
}
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
<%- if reverse_proxy_enabled %>
|
|
||||||
<< reverse_proxy_domain >> {
|
|
||||||
<%- if reverse_proxy_custom_config_content %>
|
|
||||||
reverse_proxy << reverse_proxy_upstream >> {
|
|
||||||
<%- for line in reverse_proxy_custom_config_content.split('\n') %>
|
|
||||||
<< line >>
|
|
||||||
<%- endfor %>
|
|
||||||
}
|
|
||||||
<%- else %>
|
|
||||||
reverse_proxy << reverse_proxy_upstream >>
|
|
||||||
<%- endif %>
|
|
||||||
}
|
|
||||||
<%- endif %>
|
|
||||||
@@ -1,319 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "caddy",
|
|
||||||
"kind": "compose",
|
|
||||||
"metadata": {
|
|
||||||
"name": "Caddy",
|
|
||||||
"description": "Modern web server and reverse proxy with automatic HTTPS, modular Caddyfile config, and simple presets for static sites or upstream proxying.",
|
|
||||||
"tags": [
|
|
||||||
"reverse-proxy",
|
|
||||||
"web-server",
|
|
||||||
"tls"
|
|
||||||
],
|
|
||||||
"icon": {
|
|
||||||
"provider": "selfhst",
|
|
||||||
"id": "caddy",
|
|
||||||
"color": "emerald"
|
|
||||||
},
|
|
||||||
"draft": false,
|
|
||||||
"version": {
|
|
||||||
"name": "2.11.2-alpine",
|
|
||||||
"source_dep_name": "docker.io/library/caddy",
|
|
||||||
"source_dep_version": "2.11.2-alpine"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"name": "general",
|
|
||||||
"title": "General",
|
|
||||||
"description": "Basic container naming and lifecycle settings.",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "service_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Service Name",
|
|
||||||
"required": false,
|
|
||||||
"default": "caddy",
|
|
||||||
"description": "Compose service name for the Caddy container.",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "caddy"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "restart_policy",
|
|
||||||
"type": "enum",
|
|
||||||
"title": "Restart Policy",
|
|
||||||
"required": true,
|
|
||||||
"default": "unless-stopped",
|
|
||||||
"description": "Restart policy applied to the container.",
|
|
||||||
"config": {
|
|
||||||
"options": [
|
|
||||||
"unless-stopped",
|
|
||||||
"always",
|
|
||||||
"on-failure",
|
|
||||||
"no"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "container_timezone",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Container Timezone",
|
|
||||||
"required": false,
|
|
||||||
"description": "Optional timezone passed through as the `TZ` environment variable.",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "UTC"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "network",
|
|
||||||
"title": "Network",
|
|
||||||
"description": "Port publishing and Docker network attachment.",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "ports_http",
|
|
||||||
"type": "int",
|
|
||||||
"title": "HTTP Port",
|
|
||||||
"required": true,
|
|
||||||
"default": 80,
|
|
||||||
"description": "Host port published for HTTP traffic on container port 80.",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "80"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ports_https",
|
|
||||||
"type": "int",
|
|
||||||
"title": "HTTPS Port",
|
|
||||||
"required": true,
|
|
||||||
"default": 443,
|
|
||||||
"description": "Host port published for HTTPS traffic on container port 443.",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "443"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "docker_network",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Docker Network",
|
|
||||||
"required": true,
|
|
||||||
"default": "caddy",
|
|
||||||
"description": "Docker network that Caddy should join.",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "caddy"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "docker_network_external",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "External Network",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "tls",
|
|
||||||
"title": "TLS",
|
|
||||||
"description": "Optional global ACME metadata for Caddy.",
|
|
||||||
"toggle": "tls_enabled",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "tls_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "TLS Settings",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "tls_email",
|
|
||||||
"type": "str",
|
|
||||||
"title": "ACME Email",
|
|
||||||
"required": false,
|
|
||||||
"description": "Email address used for ACME account registration.",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "admin@example.com"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"tls_enabled=true"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "webserver",
|
|
||||||
"title": "Webserver",
|
|
||||||
"description": "Optional generated static site config that serves files from `/srv`.",
|
|
||||||
"toggle": "webserver_enabled",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "webserver_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Static Webserver",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"description": "Render a basic static site config into `config/webserver.caddy`."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "webserver_domain",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Site Address",
|
|
||||||
"required": true,
|
|
||||||
"description": "Hostname or site address used by the generated static site config.",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "example.com"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"webserver_enabled=true"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "webserver_content_type",
|
|
||||||
"type": "enum",
|
|
||||||
"title": "Site Content",
|
|
||||||
"required": true,
|
|
||||||
"default": "mount",
|
|
||||||
"description": "Storage mode used for static site content mounted into `/srv`.",
|
|
||||||
"config": {
|
|
||||||
"options": [
|
|
||||||
"mount",
|
|
||||||
"nfs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"webserver_enabled=true"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "webserver_content_mount_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Bind Mount Path",
|
|
||||||
"required": true,
|
|
||||||
"default": "./data",
|
|
||||||
"description": "Host path used when site content is mounted directly from the filesystem.",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "./data"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"webserver_enabled=true",
|
|
||||||
"webserver_content_type=mount"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "webserver_content_nfs_server",
|
|
||||||
"type": "str",
|
|
||||||
"title": "NFS Server",
|
|
||||||
"required": true,
|
|
||||||
"default": "192.0.2.1",
|
|
||||||
"description": "Hostname or IP address of the NFS server that stores site content.",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "192.0.2.1"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"webserver_enabled=true",
|
|
||||||
"webserver_content_type=nfs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "webserver_content_nfs_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "NFS Export Path",
|
|
||||||
"required": true,
|
|
||||||
"default": "/path/to/export",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/path/to/export"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"webserver_enabled=true",
|
|
||||||
"webserver_content_type=nfs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "webserver_content_nfs_options",
|
|
||||||
"type": "str",
|
|
||||||
"title": "NFS Mount Options",
|
|
||||||
"required": true,
|
|
||||||
"default": "rw,nolock,soft",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "rw,nolock,soft"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"webserver_enabled=true",
|
|
||||||
"webserver_content_type=nfs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "webserver_custom_config_content",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Custom Config Content",
|
|
||||||
"required": false,
|
|
||||||
"description": "Optional additional Caddyfile directives inserted into the generated webserver site block when not empty.",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "encode zstd gzip",
|
|
||||||
"textarea": true
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"webserver_enabled=true"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "reverse-proxy",
|
|
||||||
"title": "Reverse Proxy",
|
|
||||||
"description": "Optional generated reverse proxy config for forwarding requests to an upstream service.",
|
|
||||||
"toggle": "reverse_proxy_enabled",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "reverse_proxy_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Reverse Proxy",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"description": "Append a reverse proxy site block to `config/webserver.caddy`."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "reverse_proxy_domain",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Site Address",
|
|
||||||
"required": true,
|
|
||||||
"description": "Hostname or site address used by the generated reverse proxy config.",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "app.example.com"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"reverse_proxy_enabled=true"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "reverse_proxy_upstream",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Upstream",
|
|
||||||
"required": true,
|
|
||||||
"description": "Upstream target used by the generated reverse proxy config, for example `app:3000`.",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "app:3000"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"reverse_proxy_enabled=true"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "reverse_proxy_custom_config_content",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Custom Config Content",
|
|
||||||
"required": false,
|
|
||||||
"description": "Optional additional `reverse_proxy` subdirectives inserted into the generated reverse proxy block when not empty.",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "header_up X-Forwarded-Proto https",
|
|
||||||
"textarea": true
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"reverse_proxy_enabled=true"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
# Checkmk credentials
|
|
||||||
CMK_PASSWORD=<< cmk_password >>
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
---
|
|
||||||
services:
|
|
||||||
<< service_name >>:
|
|
||||||
image: checkmk/check-mk-community:2.5.0-latest
|
|
||||||
restart: << restart_policy >>
|
|
||||||
environment:
|
|
||||||
<%- if container_timezone %>
|
|
||||||
- TZ=<< container_timezone >>
|
|
||||||
<%- endif %>
|
|
||||||
- CMK_PASSWORD=${CMK_PASSWORD}
|
|
||||||
- CMK_SITE_ID=<< cmk_site_id >>
|
|
||||||
tmpfs:
|
|
||||||
- /opt/omd/sites/<< cmk_site_id >>/tmp:uid=<< user_uid >>,gid=<< user_gid >>
|
|
||||||
volumes:
|
|
||||||
<%- if not container_timezone %>
|
|
||||||
- /etc/localtime:/etc/localtime:ro
|
|
||||||
<%- endif %>
|
|
||||||
- << service_name >>_data:/omd/sites:rw
|
|
||||||
<%- if traefik_enabled %>
|
|
||||||
networks:
|
|
||||||
<< traefik_network >>:
|
|
||||||
<%- endif %>
|
|
||||||
ports:
|
|
||||||
<%- if not traefik_enabled %>
|
|
||||||
- "<< ports_http >>:5000"
|
|
||||||
<%- endif %>
|
|
||||||
- "<< ports_agent >>:8000"
|
|
||||||
- "<< ports_snmp >>:162/udp"
|
|
||||||
<%- if traefik_enabled %>
|
|
||||||
labels:
|
|
||||||
- traefik.enable=true
|
|
||||||
- traefik.docker.network=<< traefik_network >>
|
|
||||||
- traefik.http.services.<< service_name >>-web.loadBalancer.server.port=5000
|
|
||||||
- traefik.http.services.<< service_name >>-web.loadBalancer.server.scheme=http
|
|
||||||
- traefik.http.routers.<< service_name >>-http.service=<< service_name >>-web
|
|
||||||
- traefik.http.routers.<< service_name >>-http.rule=Host(`<< traefik_host >>.<< traefik_domain >>`)
|
|
||||||
- traefik.http.routers.<< service_name >>-http.entrypoints=<< traefik_entrypoint >>
|
|
||||||
<%- if traefik_tls_enabled %>
|
|
||||||
- traefik.http.routers.<< service_name >>-https.service=<< service_name >>-web
|
|
||||||
- traefik.http.routers.<< service_name >>-https.rule=Host(`<< traefik_host >>.<< traefik_domain >>`)
|
|
||||||
- traefik.http.routers.<< service_name >>-https.entrypoints=<< traefik_tls_entrypoint >>
|
|
||||||
- traefik.http.routers.<< service_name >>-https.tls=true
|
|
||||||
- traefik.http.routers.<< service_name >>-https.tls.certresolver=<< traefik_tls_certresolver >>
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
<< service_name >>_data:
|
|
||||||
driver: local
|
|
||||||
|
|
||||||
<%- if traefik_enabled %>
|
|
||||||
networks:
|
|
||||||
<< traefik_network >>:
|
|
||||||
external: true
|
|
||||||
<%- endif %>
|
|
||||||
@@ -1,225 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "checkmk",
|
|
||||||
"kind": "compose",
|
|
||||||
"metadata": {
|
|
||||||
"name": "Checkmk",
|
|
||||||
"description": "Comprehensive IT monitoring solution for infrastructure, applications, and services. Provides real-time health and performance insights with server, network, cloud, and application monitoring.",
|
|
||||||
"tags": [
|
|
||||||
"traefik"
|
|
||||||
],
|
|
||||||
"icon": {
|
|
||||||
"provider": "selfhst",
|
|
||||||
"id": "checkmk"
|
|
||||||
},
|
|
||||||
"draft": false,
|
|
||||||
"version": {
|
|
||||||
"name": "2.5.0-latest",
|
|
||||||
"source_dep_name": "checkmk/check-mk-community",
|
|
||||||
"source_dep_version": "2.5.0-latest"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"title": "General",
|
|
||||||
"name": "general",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "service_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Service Name",
|
|
||||||
"required": false,
|
|
||||||
"default": "checkmk",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "checkmk"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "container_timezone",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Container Timezone",
|
|
||||||
"required": false,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "Europe/Berlin"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "user_uid",
|
|
||||||
"type": "int",
|
|
||||||
"title": "User Uid",
|
|
||||||
"required": false,
|
|
||||||
"default": 1000,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "1000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "user_gid",
|
|
||||||
"type": "int",
|
|
||||||
"title": "User Gid",
|
|
||||||
"required": false,
|
|
||||||
"default": 1000,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "1000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "restart_policy",
|
|
||||||
"type": "enum",
|
|
||||||
"title": "Restart Policy",
|
|
||||||
"required": true,
|
|
||||||
"default": "unless-stopped",
|
|
||||||
"config": {
|
|
||||||
"options": [
|
|
||||||
"unless-stopped",
|
|
||||||
"always",
|
|
||||||
"on-failure",
|
|
||||||
"no"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "cmk_password",
|
|
||||||
"type": "secret",
|
|
||||||
"title": "CheckMK admin password",
|
|
||||||
"required": true,
|
|
||||||
"config": {
|
|
||||||
"autogenerated": {
|
|
||||||
"length": 32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "cmk_site_id",
|
|
||||||
"type": "str",
|
|
||||||
"title": "CheckMK site ID",
|
|
||||||
"required": true,
|
|
||||||
"default": "cmk",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "cmk"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Traefik",
|
|
||||||
"name": "traefik",
|
|
||||||
"toggle": "traefik_enabled",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "traefik_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Traefik",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_host",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Host",
|
|
||||||
"required": true,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "checkmk"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_domain",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Domain",
|
|
||||||
"required": true,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "home.arpa"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_entrypoint",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Entrypoint",
|
|
||||||
"required": true,
|
|
||||||
"default": "web",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "web"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_network",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Network",
|
|
||||||
"required": true,
|
|
||||||
"default": "traefik",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "traefik"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_tls_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "TLS",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_tls_entrypoint",
|
|
||||||
"type": "str",
|
|
||||||
"title": "TLS Entrypoint",
|
|
||||||
"required": true,
|
|
||||||
"default": "websecure",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "websecure"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"traefik_tls_enabled=true"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_tls_certresolver",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Cert Resolver",
|
|
||||||
"required": true,
|
|
||||||
"default": "cloudflare",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "cloudflare"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"traefik_tls_enabled=true"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Ports",
|
|
||||||
"name": "ports",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "ports_http",
|
|
||||||
"type": "int",
|
|
||||||
"title": "HTTP Port",
|
|
||||||
"required": false,
|
|
||||||
"default": 5000,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "5000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ports_agent",
|
|
||||||
"type": "int",
|
|
||||||
"title": "Agent port",
|
|
||||||
"required": true,
|
|
||||||
"default": 8000,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "8000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ports_snmp",
|
|
||||||
"type": "int",
|
|
||||||
"title": "SNMP trap port",
|
|
||||||
"required": true,
|
|
||||||
"default": 162,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "162"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
# Cloudflared credentials
|
|
||||||
TUNNEL_TOKEN=<< tunnel_token >>
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
services:
|
|
||||||
<< service_name >>:
|
|
||||||
image: cloudflare/cloudflared:2026.3.0
|
|
||||||
container_name: << container_name >>
|
|
||||||
environment:
|
|
||||||
- TUNNEL_TOKEN=${TUNNEL_TOKEN}
|
|
||||||
command: << tunnel_run_command >>
|
|
||||||
networks:
|
|
||||||
- << network_name >>
|
|
||||||
restart: << restart_policy >>
|
|
||||||
|
|
||||||
networks:
|
|
||||||
<< network_name >>:
|
|
||||||
<%- if network_external %>
|
|
||||||
external: true
|
|
||||||
<%- else %>
|
|
||||||
driver: bridge
|
|
||||||
<%- endif %>
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "cloudflared",
|
|
||||||
"kind": "compose",
|
|
||||||
"metadata": {
|
|
||||||
"name": "Cloudflared",
|
|
||||||
"description": "Runs a Cloudflare Tunnel connector in Docker Compose so private services can be published through Cloudflare Zero Trust.",
|
|
||||||
"tags": [],
|
|
||||||
"icon": {
|
|
||||||
"provider": "selfhst",
|
|
||||||
"id": "cloudflare-zero-trust"
|
|
||||||
},
|
|
||||||
"draft": false,
|
|
||||||
"version": {
|
|
||||||
"name": "2026.3.0",
|
|
||||||
"source_dep_name": "cloudflare/cloudflared",
|
|
||||||
"source_dep_version": "2026.3.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"title": "General",
|
|
||||||
"name": "general",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "service_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Compose service name",
|
|
||||||
"required": false,
|
|
||||||
"default": "cloudflared",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "cloudflared"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "container_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Container name",
|
|
||||||
"required": false,
|
|
||||||
"default": "cloudflared",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "cloudflared"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "restart_policy",
|
|
||||||
"type": "enum",
|
|
||||||
"title": "Container restart policy",
|
|
||||||
"required": true,
|
|
||||||
"default": "unless-stopped",
|
|
||||||
"config": {
|
|
||||||
"options": [
|
|
||||||
"unless-stopped",
|
|
||||||
"always",
|
|
||||||
"on-failure",
|
|
||||||
"no"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "tunnel_run_command",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Command",
|
|
||||||
"required": false,
|
|
||||||
"default": "tunnel --no-autoupdate run",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "tunnel --no-autoupdate run"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "tunnel_token",
|
|
||||||
"type": "secret",
|
|
||||||
"title": "Tunnel Token",
|
|
||||||
"required": true,
|
|
||||||
"description": "Cloudflare tunnel token used by the connector."
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Network",
|
|
||||||
"name": "network",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "network_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Network Name",
|
|
||||||
"required": true,
|
|
||||||
"default": "proxy",
|
|
||||||
"description": "Docker network name for the tunnel container",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "proxy"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "network_external",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "External Network",
|
|
||||||
"required": false,
|
|
||||||
"default": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
# CrowdSec enrollment and bouncer placeholders
|
|
||||||
<%- if console_enrollment_enabled %>
|
|
||||||
ENROLL_KEY=<< console_enrollment_key >>
|
|
||||||
<%- endif %>
|
|
||||||
<%- if bouncer_traefik_key %>
|
|
||||||
BOUNCER_KEY_TRAEFIK=<< bouncer_traefik_key >>
|
|
||||||
<%- endif %>
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
services:
|
|
||||||
<< service_name >>:
|
|
||||||
image: crowdsecurity/crowdsec:<< image_tag >>
|
|
||||||
container_name: << container_name >>
|
|
||||||
environment:
|
|
||||||
- TZ=<< container_timezone >>
|
|
||||||
- COLLECTIONS=<< collections_core >><%- if collections_extra %> << collections_extra >><%- endif %><%- if appsec_enabled %> crowdsecurity/appsec-virtual-patching crowdsecurity/appsec-generic-rules<%- endif %>
|
|
||||||
<%- if docker_logs_enabled %>
|
|
||||||
- GID=<< docker_group_id >>
|
|
||||||
<%- endif %>
|
|
||||||
<%- if console_enrollment_enabled %>
|
|
||||||
- ENROLL_KEY=${ENROLL_KEY}
|
|
||||||
- ENROLL_INSTANCE_NAME=<< console_enrollment_name >>
|
|
||||||
<%- if console_enrollment_tags %>
|
|
||||||
- ENROLL_TAGS=<< console_enrollment_tags >>
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
<%- if bouncer_traefik_key %>
|
|
||||||
- BOUNCER_KEY_TRAEFIK=${BOUNCER_KEY_TRAEFIK}
|
|
||||||
<%- endif %>
|
|
||||||
volumes:
|
|
||||||
- ./config/acquis.yaml:/etc/crowdsec/acquis.yaml:ro
|
|
||||||
- ./config/acquis.d:/etc/crowdsec/acquis.d:ro
|
|
||||||
- crowdsec_data:/var/lib/crowdsec/data
|
|
||||||
- /var/log:/var/log-host:ro
|
|
||||||
<%- if docker_logs_enabled %>
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
|
||||||
<%- endif %>
|
|
||||||
<%- if traefik_accesslog_enabled %>
|
|
||||||
- << traefik_accesslog_mount_path >>:/var/log/traefik:ro
|
|
||||||
<%- endif %>
|
|
||||||
<%- if lapi_expose_enabled or (appsec_enabled and appsec_expose_enabled) %>
|
|
||||||
ports:
|
|
||||||
<%- if lapi_expose_enabled %>
|
|
||||||
- "<< lapi_bind_address >>:<< lapi_port >>:8080"
|
|
||||||
<%- endif %>
|
|
||||||
<%- if appsec_enabled and appsec_expose_enabled %>
|
|
||||||
- "<< appsec_bind_address >>:<< appsec_port >>:7422"
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
restart: << restart_policy >>
|
|
||||||
networks:
|
|
||||||
- crowdsec
|
|
||||||
<%- if traefik_network_enabled %>
|
|
||||||
- << traefik_network >>
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
networks:
|
|
||||||
crowdsec:
|
|
||||||
driver: bridge
|
|
||||||
<%- if traefik_network_enabled %>
|
|
||||||
<< traefik_network >>:
|
|
||||||
<%- if traefik_network_external %>
|
|
||||||
external: true
|
|
||||||
<%- else %>
|
|
||||||
driver: bridge
|
|
||||||
name: << traefik_network >>
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
crowdsec_data:
|
|
||||||
driver: local
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<%- if appsec_enabled %>
|
|
||||||
source: appsec
|
|
||||||
listen_addr: 0.0.0.0:7422
|
|
||||||
path: << appsec_path >>
|
|
||||||
appsec_config: crowdsecurity/appsec-default
|
|
||||||
labels:
|
|
||||||
type: appsec
|
|
||||||
name: << appsec_name >>
|
|
||||||
<%- endif %>
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
<%- if host_logs_enabled %>
|
|
||||||
filenames:
|
|
||||||
- /var/log-host/auth.log
|
|
||||||
- /var/log-host/syslog
|
|
||||||
labels:
|
|
||||||
type: syslog
|
|
||||||
<%- endif %>
|
|
||||||
<%- if host_logs_enabled and (docker_logs_enabled or traefik_accesslog_enabled) %>
|
|
||||||
---
|
|
||||||
<%- endif %>
|
|
||||||
<%- if docker_logs_enabled %>
|
|
||||||
source: docker
|
|
||||||
container_name_regexp:
|
|
||||||
- << docker_container_name_regexp >>
|
|
||||||
labels:
|
|
||||||
type: << docker_log_type >>
|
|
||||||
<%- endif %>
|
|
||||||
<%- if docker_logs_enabled and traefik_accesslog_enabled %>
|
|
||||||
---
|
|
||||||
<%- endif %>
|
|
||||||
<%- if traefik_accesslog_enabled %>
|
|
||||||
filenames:
|
|
||||||
- /var/log/traefik/<< traefik_accesslog_filename >>
|
|
||||||
labels:
|
|
||||||
type: traefik
|
|
||||||
<%- endif %>
|
|
||||||
@@ -1,451 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "crowdsec",
|
|
||||||
"kind": "compose",
|
|
||||||
"metadata": {
|
|
||||||
"name": "CrowdSec",
|
|
||||||
"description": "Standalone CrowdSec Security Engine deployment for a single Docker host, with host and reverse-proxy log acquisition, optional AppSec exposure, and console or bouncer enrollment placeholders.",
|
|
||||||
"tags": [
|
|
||||||
"security",
|
|
||||||
"logging",
|
|
||||||
"traefik"
|
|
||||||
],
|
|
||||||
"icon": {
|
|
||||||
"provider": "selfhst",
|
|
||||||
"id": "crowdsec"
|
|
||||||
},
|
|
||||||
"draft": true,
|
|
||||||
"version": {
|
|
||||||
"name": "v1.7.6",
|
|
||||||
"source_dep_name": "manual/crowdsec"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"title": "General",
|
|
||||||
"name": "general",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "service_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Service Name",
|
|
||||||
"required": false,
|
|
||||||
"default": "crowdsec",
|
|
||||||
"description": "Compose service name for CrowdSec.",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "crowdsec"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "container_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Container Name",
|
|
||||||
"required": false,
|
|
||||||
"default": "crowdsec",
|
|
||||||
"description": "Container name for CrowdSec.",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "crowdsec"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "image_tag",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Image Tag",
|
|
||||||
"required": true,
|
|
||||||
"default": "v1.7.6",
|
|
||||||
"description": "CrowdSec image tag to deploy.",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "v1.7.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "container_timezone",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Container Timezone",
|
|
||||||
"required": true,
|
|
||||||
"default": "UTC",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "UTC"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "restart_policy",
|
|
||||||
"type": "enum",
|
|
||||||
"title": "Restart Policy",
|
|
||||||
"required": true,
|
|
||||||
"default": "unless-stopped",
|
|
||||||
"config": {
|
|
||||||
"options": [
|
|
||||||
"unless-stopped",
|
|
||||||
"always",
|
|
||||||
"on-failure",
|
|
||||||
"no"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Collections",
|
|
||||||
"name": "collections",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "collections_core",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Core Collections",
|
|
||||||
"required": true,
|
|
||||||
"default": "crowdsecurity/linux crowdsecurity/sshd",
|
|
||||||
"description": "Space-separated base collections to install on startup.",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "crowdsecurity/linux crowdsecurity/sshd"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "collections_extra",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Extra Collections",
|
|
||||||
"required": false,
|
|
||||||
"default": "crowdsecurity/traefik",
|
|
||||||
"description": "Additional space-separated collections to install, for example a reverse-proxy parser.",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "crowdsecurity/traefik"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Acquisition",
|
|
||||||
"name": "acquisition",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "host_logs_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Host Logs",
|
|
||||||
"required": false,
|
|
||||||
"default": true,
|
|
||||||
"description": "Ingest host auth and syslog files from `/var/log`."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "docker_logs_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Docker Logs",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"description": "Read logs from a matching Docker container through the Docker socket."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "docker_group_id",
|
|
||||||
"type": "int",
|
|
||||||
"title": "Docker Group ID",
|
|
||||||
"required": true,
|
|
||||||
"default": 998,
|
|
||||||
"description": "Host Docker group ID so the container can access the socket.",
|
|
||||||
"needs": [
|
|
||||||
"docker_logs_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "998"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "docker_container_name_regexp",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Docker Container Regex",
|
|
||||||
"required": true,
|
|
||||||
"default": ".*traefik.*",
|
|
||||||
"description": "Regular expression used to match the Docker container whose logs should be parsed.",
|
|
||||||
"needs": [
|
|
||||||
"docker_logs_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": ".*traefik.*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "docker_log_type",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Docker Log Type",
|
|
||||||
"required": true,
|
|
||||||
"default": "traefik",
|
|
||||||
"description": "Parser type label for the Docker datasource.",
|
|
||||||
"needs": [
|
|
||||||
"docker_logs_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "traefik"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Traefik",
|
|
||||||
"name": "traefik",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "traefik_network_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Shared Traefik Network",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"description": "Attach CrowdSec to an existing Docker network shared with Traefik or other bouncers."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_network",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Traefik Network",
|
|
||||||
"required": true,
|
|
||||||
"default": "traefik",
|
|
||||||
"description": "Docker network shared with Traefik or other remediation components.",
|
|
||||||
"needs": [
|
|
||||||
"traefik_network_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "traefik"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_network_external",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "External Network",
|
|
||||||
"required": false,
|
|
||||||
"default": true,
|
|
||||||
"needs": [
|
|
||||||
"traefik_network_enabled=true"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_accesslog_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Traefik Access Log",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"description": "Read Traefik access logs from a mounted host path."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_accesslog_mount_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Traefik Log Path",
|
|
||||||
"required": true,
|
|
||||||
"default": "/var/log/traefik",
|
|
||||||
"description": "Host directory containing Traefik access logs.",
|
|
||||||
"needs": [
|
|
||||||
"traefik_accesslog_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/var/log/traefik"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_accesslog_filename",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Traefik Log File",
|
|
||||||
"required": true,
|
|
||||||
"default": "access.log",
|
|
||||||
"description": "Filename of the Traefik access log inside the mounted directory.",
|
|
||||||
"needs": [
|
|
||||||
"traefik_accesslog_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "access.log"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Local API",
|
|
||||||
"toggle": "lapi_expose_enabled",
|
|
||||||
"name": "lapi",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "lapi_expose_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Expose Local API",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"description": "Publish CrowdSec Local API on the host."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "lapi_bind_address",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Local API Bind Address",
|
|
||||||
"required": true,
|
|
||||||
"default": "127.0.0.1",
|
|
||||||
"description": "Host address used for the Local API port binding.",
|
|
||||||
"needs": [
|
|
||||||
"lapi_expose_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "127.0.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "lapi_port",
|
|
||||||
"type": "int",
|
|
||||||
"title": "Local API Port",
|
|
||||||
"required": true,
|
|
||||||
"default": 8080,
|
|
||||||
"description": "Host port used for the Local API binding.",
|
|
||||||
"needs": [
|
|
||||||
"lapi_expose_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "8080"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "AppSec",
|
|
||||||
"toggle": "appsec_enabled",
|
|
||||||
"name": "appsec",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "appsec_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Enable AppSec",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "appsec_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "AppSec Name",
|
|
||||||
"required": true,
|
|
||||||
"default": "traefik-appsec",
|
|
||||||
"description": "Friendly name for the AppSec component.",
|
|
||||||
"needs": [
|
|
||||||
"appsec_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "traefik-appsec"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "appsec_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "AppSec Path",
|
|
||||||
"required": true,
|
|
||||||
"default": "/",
|
|
||||||
"description": "Request path handled by the AppSec listener.",
|
|
||||||
"needs": [
|
|
||||||
"appsec_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "appsec_expose_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Expose AppSec",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"description": "Publish the AppSec listener on the host.",
|
|
||||||
"needs": [
|
|
||||||
"appsec_enabled=true"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "appsec_bind_address",
|
|
||||||
"type": "str",
|
|
||||||
"title": "AppSec Bind Address",
|
|
||||||
"required": true,
|
|
||||||
"default": "127.0.0.1",
|
|
||||||
"description": "Host address used for the AppSec port binding.",
|
|
||||||
"needs": [
|
|
||||||
"appsec_enabled=true",
|
|
||||||
"appsec_expose_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "127.0.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "appsec_port",
|
|
||||||
"type": "int",
|
|
||||||
"title": "AppSec Port",
|
|
||||||
"required": true,
|
|
||||||
"default": 7422,
|
|
||||||
"description": "Host port used for the AppSec port binding.",
|
|
||||||
"needs": [
|
|
||||||
"appsec_enabled=true",
|
|
||||||
"appsec_expose_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "7422"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Console Enrollment",
|
|
||||||
"toggle": "console_enrollment_enabled",
|
|
||||||
"name": "console",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "console_enrollment_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Console Enrollment",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"description": "Enroll this CrowdSec instance into CrowdSec Console."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "console_enrollment_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Instance Name",
|
|
||||||
"required": true,
|
|
||||||
"default": "crowdsec-homelab",
|
|
||||||
"description": "Human-readable name shown in CrowdSec Console.",
|
|
||||||
"needs": [
|
|
||||||
"console_enrollment_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "crowdsec-homelab"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "console_enrollment_tags",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Enrollment Tags",
|
|
||||||
"required": false,
|
|
||||||
"default": "homelab,edge",
|
|
||||||
"description": "Comma-separated tags assigned during console enrollment.",
|
|
||||||
"needs": [
|
|
||||||
"console_enrollment_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "homelab,edge"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "console_enrollment_key",
|
|
||||||
"type": "secret",
|
|
||||||
"title": "Enrollment Key",
|
|
||||||
"required": true,
|
|
||||||
"description": "Enrollment key generated by CrowdSec Console.",
|
|
||||||
"needs": [
|
|
||||||
"console_enrollment_enabled=true"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Bouncers",
|
|
||||||
"name": "bouncers",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "bouncer_traefik_key",
|
|
||||||
"type": "secret",
|
|
||||||
"title": "Traefik Bouncer Key",
|
|
||||||
"required": false,
|
|
||||||
"description": "Optional seed key for a Traefik bouncer or plugin.",
|
|
||||||
"config": {
|
|
||||||
"autogenerated": {
|
|
||||||
"length": 32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
---
|
|
||||||
services:
|
|
||||||
<< service_name >>:
|
|
||||||
image: docker.io/louislam/dockge:1.5.0
|
|
||||||
restart: << restart_policy >>
|
|
||||||
environment:
|
|
||||||
- TZ=<< container_timezone >>
|
|
||||||
- DOCKGE_STACKS_DIR=<< stacks_path >>
|
|
||||||
volumes:
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
|
||||||
- << service_name >>_data:/app/data
|
|
||||||
- << stacks_path >>:<< stacks_path >>
|
|
||||||
<%- if traefik_enabled %>
|
|
||||||
networks:
|
|
||||||
- << traefik_network >>
|
|
||||||
<%- endif %>
|
|
||||||
<%- if not traefik_enabled %>
|
|
||||||
ports:
|
|
||||||
- "<< ports_http >>:5001"
|
|
||||||
<%- endif %>
|
|
||||||
<%- if traefik_enabled %>
|
|
||||||
labels:
|
|
||||||
- traefik.enable=true
|
|
||||||
- traefik.docker.network=<< traefik_network >>
|
|
||||||
- traefik.http.services.<< service_name >>-web.loadBalancer.server.port=5001
|
|
||||||
- traefik.http.routers.<< service_name >>-http.service=<< service_name >>-web
|
|
||||||
- traefik.http.routers.<< service_name >>-http.rule=Host(`<< traefik_host >>.<< traefik_domain >>`)
|
|
||||||
- traefik.http.routers.<< service_name >>-http.entrypoints=<< traefik_entrypoint >>
|
|
||||||
<%- if traefik_tls_enabled %>
|
|
||||||
- traefik.http.routers.<< service_name >>-https.service=<< service_name >>-web
|
|
||||||
- traefik.http.routers.<< service_name >>-https.rule=Host(`<< traefik_host >>.<< traefik_domain >>`)
|
|
||||||
- traefik.http.routers.<< service_name >>-https.entrypoints=<< traefik_tls_entrypoint >>
|
|
||||||
- traefik.http.routers.<< service_name >>-https.tls=true
|
|
||||||
- traefik.http.routers.<< service_name >>-https.tls.certresolver=<< traefik_tls_certresolver >>
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
<< service_name >>_data:
|
|
||||||
driver: local
|
|
||||||
|
|
||||||
<%- if traefik_enabled %>
|
|
||||||
networks:
|
|
||||||
<< traefik_network >>:
|
|
||||||
external: true
|
|
||||||
<%- endif %>
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "dockge",
|
|
||||||
"kind": "compose",
|
|
||||||
"metadata": {
|
|
||||||
"name": "Dockge",
|
|
||||||
"description": "Web-based Docker Compose stack manager with a clean UI for creating, editing, starting, and stopping compose stacks directly from the browser.",
|
|
||||||
"tags": [
|
|
||||||
"traefik"
|
|
||||||
],
|
|
||||||
"icon": {
|
|
||||||
"provider": "selfhst",
|
|
||||||
"id": "dockge"
|
|
||||||
},
|
|
||||||
"draft": false,
|
|
||||||
"version": {
|
|
||||||
"name": "1.5.0",
|
|
||||||
"source_dep_name": "docker.io/louislam/dockge",
|
|
||||||
"source_dep_version": "1.5.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"title": "General",
|
|
||||||
"name": "general",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "service_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Service Name",
|
|
||||||
"required": false,
|
|
||||||
"default": "dockge",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "dockge"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "container_timezone",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Container Timezone",
|
|
||||||
"required": false,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "Europe/Berlin"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "restart_policy",
|
|
||||||
"type": "enum",
|
|
||||||
"title": "Restart Policy",
|
|
||||||
"required": true,
|
|
||||||
"default": "unless-stopped",
|
|
||||||
"config": {
|
|
||||||
"options": [
|
|
||||||
"unless-stopped",
|
|
||||||
"always",
|
|
||||||
"on-failure",
|
|
||||||
"no"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "stacks_path",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Docker Compose Path",
|
|
||||||
"required": true,
|
|
||||||
"default": "/stacks",
|
|
||||||
"description": "Path used for Docker Compose.",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "/stacks"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Traefik",
|
|
||||||
"name": "traefik",
|
|
||||||
"toggle": "traefik_enabled",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "traefik_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Traefik",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_host",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Host",
|
|
||||||
"required": true,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "dockge"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_domain",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Domain",
|
|
||||||
"required": true,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "home.arpa"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_entrypoint",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Entrypoint",
|
|
||||||
"required": true,
|
|
||||||
"default": "web",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "web"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_network",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Network",
|
|
||||||
"required": true,
|
|
||||||
"default": "traefik",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "traefik"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_tls_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "TLS",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_tls_entrypoint",
|
|
||||||
"type": "str",
|
|
||||||
"title": "TLS Entrypoint",
|
|
||||||
"required": true,
|
|
||||||
"default": "websecure",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "websecure"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"traefik_tls_enabled=true"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_tls_certresolver",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Cert Resolver",
|
|
||||||
"required": true,
|
|
||||||
"default": "cloudflare",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "cloudflare"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"traefik_tls_enabled=true"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Ports",
|
|
||||||
"name": "ports",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "ports_http",
|
|
||||||
"type": "str",
|
|
||||||
"title": "HTTP Port",
|
|
||||||
"required": false,
|
|
||||||
"default": 5001,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "5001"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
# Dockhand credentials
|
|
||||||
<%- if database_type == 'postgres' %>
|
|
||||||
DATABASE_PASSWORD=<< database_password >>
|
|
||||||
<%- endif %>
|
|
||||||
<%- if encryption_key %>
|
|
||||||
ENCRYPTION_KEY=<< encryption_key >>
|
|
||||||
<%- endif %>
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
services:
|
|
||||||
<< service_name >>:
|
|
||||||
image: docker.io/fnsys/dockhand:v1.0.27
|
|
||||||
restart: << restart_policy >>
|
|
||||||
<%- if database_type == 'postgres' or disable_local_login or encryption_key or puid or pgid %>
|
|
||||||
environment:
|
|
||||||
<%- if database_type == 'postgres' %>
|
|
||||||
- DATABASE_URL=postgres://<< database_user >>:${DATABASE_PASSWORD}@<< database_host >>:<< database_port >>/<< database_name >>
|
|
||||||
<%- endif %>
|
|
||||||
<%- if encryption_key %>
|
|
||||||
- ENCRYPTION_KEY=${ENCRYPTION_KEY}
|
|
||||||
<%- endif %>
|
|
||||||
<%- if puid %>
|
|
||||||
- PUID=<< puid >>
|
|
||||||
<%- endif %>
|
|
||||||
<%- if pgid %>
|
|
||||||
- PGID=<< pgid >>
|
|
||||||
<%- endif %>
|
|
||||||
<%- if disable_local_login %>
|
|
||||||
- DISABLE_LOCAL_LOGIN=<< disable_local_login | lower >>
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
volumes:
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
|
||||||
- dockhand_data:/app/data
|
|
||||||
<%- if traefik_enabled %>
|
|
||||||
networks:
|
|
||||||
- << traefik_network >>
|
|
||||||
<%- endif %>
|
|
||||||
<%- if not traefik_enabled %>
|
|
||||||
ports:
|
|
||||||
- "<< ports_http >>:3000"
|
|
||||||
<%- endif %>
|
|
||||||
<%- if traefik_enabled %>
|
|
||||||
labels:
|
|
||||||
- traefik.enable=true
|
|
||||||
- traefik.docker.network=<< traefik_network >>
|
|
||||||
- traefik.http.services.<< service_name >>-web.loadBalancer.server.port=3000
|
|
||||||
- traefik.http.routers.<< service_name >>-http.service=<< service_name >>-web
|
|
||||||
- traefik.http.routers.<< service_name >>-http.rule=Host(`<< traefik_host >>.<< traefik_domain >>`)
|
|
||||||
- traefik.http.routers.<< service_name >>-http.entrypoints=<< traefik_entrypoint >>
|
|
||||||
<%- if traefik_tls_enabled %>
|
|
||||||
- traefik.http.routers.<< service_name >>-https.service=<< service_name >>-web
|
|
||||||
- traefik.http.routers.<< service_name >>-https.rule=Host(`<< traefik_host >>.<< traefik_domain >>`)
|
|
||||||
- traefik.http.routers.<< service_name >>-https.entrypoints=<< traefik_tls_entrypoint >>
|
|
||||||
- traefik.http.routers.<< service_name >>-https.tls=true
|
|
||||||
- traefik.http.routers.<< service_name >>-https.tls.certresolver=<< traefik_tls_certresolver >>
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
dockhand_data:
|
|
||||||
driver: local
|
|
||||||
|
|
||||||
<%- if traefik_enabled %>
|
|
||||||
networks:
|
|
||||||
<< traefik_network >>:
|
|
||||||
external: true
|
|
||||||
<%- endif %>
|
|
||||||
@@ -1,290 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "dockhand",
|
|
||||||
"kind": "compose",
|
|
||||||
"metadata": {
|
|
||||||
"name": "Dockhand",
|
|
||||||
"description": "Modern Docker management UI with Compose stack support, Git-based stack deployments, and optional OIDC authentication.",
|
|
||||||
"tags": [
|
|
||||||
"traefik",
|
|
||||||
"postgresql",
|
|
||||||
"sqlite"
|
|
||||||
],
|
|
||||||
"icon": {
|
|
||||||
"provider": "selfhst",
|
|
||||||
"id": "dockhand"
|
|
||||||
},
|
|
||||||
"draft": false,
|
|
||||||
"version": {
|
|
||||||
"name": "v1.0.27",
|
|
||||||
"source_dep_name": "docker.io/fnsys/dockhand",
|
|
||||||
"source_dep_version": "v1.0.27"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"title": "General",
|
|
||||||
"name": "general",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "service_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Service Name",
|
|
||||||
"required": false,
|
|
||||||
"default": "dockhand",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "dockhand"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "restart_policy",
|
|
||||||
"type": "enum",
|
|
||||||
"title": "Restart Policy",
|
|
||||||
"required": true,
|
|
||||||
"default": "unless-stopped",
|
|
||||||
"config": {
|
|
||||||
"options": [
|
|
||||||
"unless-stopped",
|
|
||||||
"always",
|
|
||||||
"on-failure",
|
|
||||||
"no"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "encryption_key",
|
|
||||||
"type": "secret",
|
|
||||||
"title": "Encryption Key",
|
|
||||||
"required": false,
|
|
||||||
"description": "Base64-encoded 32-byte AES-256 key used for credential encryption.",
|
|
||||||
"config": {
|
|
||||||
"autogenerated": {
|
|
||||||
"kind": "base64",
|
|
||||||
"bytes": 32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "puid",
|
|
||||||
"type": "int",
|
|
||||||
"title": "PUID",
|
|
||||||
"required": false,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "1000"
|
|
||||||
},
|
|
||||||
"description": "Optional user ID for Dockhand. On Linux check with `id -u`."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "pgid",
|
|
||||||
"type": "int",
|
|
||||||
"title": "PGID",
|
|
||||||
"required": false,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "1000"
|
|
||||||
},
|
|
||||||
"description": "Optional group ID for Dockhand. On Linux check with `id -g`."
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Ports",
|
|
||||||
"name": "ports",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "ports_http",
|
|
||||||
"type": "int",
|
|
||||||
"title": "HTTP Port",
|
|
||||||
"required": true,
|
|
||||||
"default": 3000,
|
|
||||||
"needs": [
|
|
||||||
"traefik_enabled=false"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "3000"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Traefik",
|
|
||||||
"name": "traefik",
|
|
||||||
"toggle": "traefik_enabled",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "traefik_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Traefik",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_host",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Host",
|
|
||||||
"required": true,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "dockhand"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_domain",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Domain",
|
|
||||||
"required": true,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "home.arpa"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_entrypoint",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Entrypoint",
|
|
||||||
"required": true,
|
|
||||||
"default": "web",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "web"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_network",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Network",
|
|
||||||
"required": true,
|
|
||||||
"default": "traefik",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "traefik"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_tls_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "TLS",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_tls_entrypoint",
|
|
||||||
"type": "str",
|
|
||||||
"title": "TLS Entrypoint",
|
|
||||||
"required": true,
|
|
||||||
"default": "websecure",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "websecure"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"traefik_tls_enabled=true"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_tls_certresolver",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Cert Resolver",
|
|
||||||
"required": true,
|
|
||||||
"default": "cloudflare",
|
|
||||||
"needs": [
|
|
||||||
"traefik_tls_enabled=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "cloudflare"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Database",
|
|
||||||
"name": "database",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "database_type",
|
|
||||||
"type": "enum",
|
|
||||||
"title": "Database Type",
|
|
||||||
"required": false,
|
|
||||||
"default": "sqlite",
|
|
||||||
"config": {
|
|
||||||
"options": [
|
|
||||||
"sqlite",
|
|
||||||
"postgres"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "database_host",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Database Host",
|
|
||||||
"required": true,
|
|
||||||
"needs": [
|
|
||||||
"database_type=postgres"
|
|
||||||
],
|
|
||||||
"default": "postgres",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "postgres"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "database_port",
|
|
||||||
"type": "int",
|
|
||||||
"title": "Database Port",
|
|
||||||
"required": true,
|
|
||||||
"needs": [
|
|
||||||
"database_type=postgres"
|
|
||||||
],
|
|
||||||
"default": 5432,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "5432"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "database_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Database Name",
|
|
||||||
"required": true,
|
|
||||||
"needs": [
|
|
||||||
"database_type=postgres"
|
|
||||||
],
|
|
||||||
"default": "dockhand",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "dockhand"
|
|
||||||
},
|
|
||||||
"description": "Database name used for PostgreSQL."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "database_user",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Database User",
|
|
||||||
"required": true,
|
|
||||||
"needs": [
|
|
||||||
"database_type=postgres"
|
|
||||||
],
|
|
||||||
"default": "dockhand",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "dockhand"
|
|
||||||
},
|
|
||||||
"description": "Username used for PostgreSQL."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "database_password",
|
|
||||||
"type": "secret",
|
|
||||||
"title": "Database Password",
|
|
||||||
"required": true,
|
|
||||||
"needs": [
|
|
||||||
"database_type=postgres"
|
|
||||||
],
|
|
||||||
"description": "Password used for PostgreSQL."
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Authentication",
|
|
||||||
"name": "authentication",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "disable_local_login",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Disable Local Login",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"description": "when SSO correctly setup, not recommended as first deployment"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
# Forgejo database credentials
|
|
||||||
<%- if database_type != 'sqlite' %>
|
|
||||||
DATABASE_USER=<< database_user >>
|
|
||||||
DATABASE_PASSWORD=<< database_password >>
|
|
||||||
<%- endif %>
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
services:
|
|
||||||
<< service_name >>:
|
|
||||||
image: codeberg.org/forgejo/forgejo:15.0.2
|
|
||||||
restart: << restart_policy >>
|
|
||||||
environment:
|
|
||||||
- USER_UID=<< user_uid >>
|
|
||||||
- USER_GID=<< user_gid >>
|
|
||||||
<%- if database_type != 'sqlite' %>
|
|
||||||
- FORGEJO__database__DB_TYPE=<< database_type >>
|
|
||||||
<%- if database_external %>
|
|
||||||
- FORGEJO__database__HOST=<< database_host >>
|
|
||||||
<%- else %>
|
|
||||||
- FORGEJO__database__HOST=<< service_name >>_db
|
|
||||||
<%- endif %>
|
|
||||||
- FORGEJO__database__NAME=<< database_name >>
|
|
||||||
- FORGEJO__database__USER=${DATABASE_USER}
|
|
||||||
- FORGEJO__database__PASSWD=${DATABASE_PASSWORD}
|
|
||||||
<%- endif %>
|
|
||||||
- FORGEJO__server__SSH_PORT=<< ports_ssh >>
|
|
||||||
<%- if not traefik_enabled %>
|
|
||||||
- FORGEJO__server__ROOT_URL=<< forgejo_url >>
|
|
||||||
<%- else %>
|
|
||||||
- FORGEJO__server__ROOT_URL=https://<< traefik_host >>.<< traefik_domain >>
|
|
||||||
<%- endif %>
|
|
||||||
<%- if not database_external and (database_type == "postgres" or database_type == "mysql") or traefik_enabled %>
|
|
||||||
networks:
|
|
||||||
<%- if not database_external and database_type != 'sqlite' %>
|
|
||||||
- << service_name >>_backend
|
|
||||||
<%- endif %>
|
|
||||||
<%- if traefik_enabled %>
|
|
||||||
- << traefik_network >>
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
ports:
|
|
||||||
<%- if not traefik_enabled %>
|
|
||||||
- "<< ports_http >>:3000"
|
|
||||||
<%- endif %>
|
|
||||||
- "<< ports_ssh >>:22"
|
|
||||||
volumes:
|
|
||||||
- << service_name >>_data:/data
|
|
||||||
- /etc/timezone:/etc/timezone:ro
|
|
||||||
- /etc/localtime:/etc/localtime:ro
|
|
||||||
<%- if traefik_enabled %>
|
|
||||||
labels:
|
|
||||||
- traefik.enable=true
|
|
||||||
- traefik.docker.network=<< traefik_network >>
|
|
||||||
- traefik.http.services.<< service_name >>_web.loadBalancer.server.port=3000
|
|
||||||
- traefik.http.routers.<< service_name >>_http.service=<< service_name >>_web
|
|
||||||
- traefik.http.routers.<< service_name >>_http.rule=Host(`<< traefik_host >>.<< traefik_domain >>`)
|
|
||||||
- traefik.http.routers.<< service_name >>_http.entrypoints=<< traefik_entrypoint >>
|
|
||||||
<%- if traefik_tls_enabled %>
|
|
||||||
- traefik.http.routers.<< service_name >>_https.service=<< service_name >>_web
|
|
||||||
- traefik.http.routers.<< service_name >>_https.rule=Host(`<< traefik_host >>.<< traefik_domain >>`)
|
|
||||||
- traefik.http.routers.<< service_name >>_https.entrypoints=<< traefik_tls_entrypoint >>
|
|
||||||
- traefik.http.routers.<< service_name >>_https.tls=true
|
|
||||||
- traefik.http.routers.<< service_name >>_https.tls.certresolver=<< traefik_tls_certresolver >>
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
<%- if not database_external and database_type != 'sqlite' %>
|
|
||||||
depends_on:
|
|
||||||
- << service_name >>_db
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
<%- if not database_external and database_type == "postgres" %>
|
|
||||||
<< service_name >>_db:
|
|
||||||
image: docker.io/library/postgres:18
|
|
||||||
restart: << restart_policy >>
|
|
||||||
environment:
|
|
||||||
- TZ=<< container_timezone >>
|
|
||||||
- POSTGRES_USER=${DATABASE_USER}
|
|
||||||
- POSTGRES_PASSWORD=${DATABASE_PASSWORD}
|
|
||||||
- POSTGRES_DB=<< database_name >>
|
|
||||||
networks:
|
|
||||||
- << service_name >>_backend
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD-SHELL", "pg_isready -U << database_user >>"]
|
|
||||||
start_period: 30s
|
|
||||||
interval: 10s
|
|
||||||
timeout: 10s
|
|
||||||
retries: 5
|
|
||||||
volumes:
|
|
||||||
- << service_name >>_db:/var/lib/postgresql/data
|
|
||||||
<%- elif not database_external and database_type == "mysql" %>
|
|
||||||
<< service_name >>_db:
|
|
||||||
image: docker.io/library/mysql:8.1
|
|
||||||
restart: << restart_policy >>
|
|
||||||
environment:
|
|
||||||
- MYSQL_USER=${DATABASE_USER}
|
|
||||||
- MYSQL_PASSWORD=${DATABASE_PASSWORD}
|
|
||||||
- MYSQL_DATABASE=<< database_name >>
|
|
||||||
- MYSQL_ROOT_PASSWORD=${DATABASE_PASSWORD}
|
|
||||||
networks:
|
|
||||||
- << service_name >>_backend
|
|
||||||
volumes:
|
|
||||||
- << service_name >>_db:/var/lib/mysql
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
<< service_name >>_data:
|
|
||||||
driver: local
|
|
||||||
<%- if not database_external %>
|
|
||||||
<%- if database_type == "postgres" or database_type == "mysql" %>
|
|
||||||
<< service_name >>_db:
|
|
||||||
driver: local
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
<%- if not database_external and (database_type == "postgres" or database_type == "mysql") or traefik_enabled %>
|
|
||||||
networks:
|
|
||||||
<%- if not database_external %>
|
|
||||||
<< service_name >>_backend:
|
|
||||||
driver: bridge
|
|
||||||
<%- endif %>
|
|
||||||
<%- if traefik_enabled %>
|
|
||||||
<< traefik_network >>:
|
|
||||||
external: true
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
@@ -1,290 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "forgejo",
|
|
||||||
"kind": "compose",
|
|
||||||
"metadata": {
|
|
||||||
"name": "Forgejo",
|
|
||||||
"description": "Self-hosted lightweight software forge for Git repository hosting, code review, issue tracking, package publishing, and team collaboration.",
|
|
||||||
"tags": [
|
|
||||||
"traefik"
|
|
||||||
],
|
|
||||||
"icon": {
|
|
||||||
"provider": "selfhst",
|
|
||||||
"id": "forgejo"
|
|
||||||
},
|
|
||||||
"draft": false,
|
|
||||||
"version": {
|
|
||||||
"name": "15.0.2",
|
|
||||||
"source_dep_name": "codeberg.org/forgejo/forgejo",
|
|
||||||
"source_dep_version": "15.0.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"title": "General",
|
|
||||||
"name": "general",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "service_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Service Name",
|
|
||||||
"required": false,
|
|
||||||
"default": "forgejo",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "forgejo"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "container_timezone",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Container Timezone",
|
|
||||||
"required": false,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "Europe/Berlin"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "user_uid",
|
|
||||||
"type": "int",
|
|
||||||
"title": "User Uid",
|
|
||||||
"required": false,
|
|
||||||
"default": 1000,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "1000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "user_gid",
|
|
||||||
"type": "int",
|
|
||||||
"title": "User Gid",
|
|
||||||
"required": false,
|
|
||||||
"default": 1000,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "1000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "restart_policy",
|
|
||||||
"type": "enum",
|
|
||||||
"title": "Restart Policy",
|
|
||||||
"required": true,
|
|
||||||
"default": "unless-stopped",
|
|
||||||
"config": {
|
|
||||||
"options": [
|
|
||||||
"unless-stopped",
|
|
||||||
"always",
|
|
||||||
"on-failure",
|
|
||||||
"no"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "forgejo_url",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Public URL",
|
|
||||||
"required": false,
|
|
||||||
"default": "https://forgejo.home.arpa",
|
|
||||||
"needs": [
|
|
||||||
"traefik_enabled=false"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "https://forgejo.home.arpa"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Database",
|
|
||||||
"name": "database",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "database_type",
|
|
||||||
"type": "enum",
|
|
||||||
"title": "Database backend type",
|
|
||||||
"required": false,
|
|
||||||
"default": "sqlite",
|
|
||||||
"config": {
|
|
||||||
"options": [
|
|
||||||
"sqlite",
|
|
||||||
"postgres",
|
|
||||||
"mysql"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "database_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Database name",
|
|
||||||
"required": false,
|
|
||||||
"default": "forgejo",
|
|
||||||
"needs": [
|
|
||||||
"database_type=postgres,mysql"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "forgejo"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "database_user",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Database user",
|
|
||||||
"required": false,
|
|
||||||
"default": "forgejo",
|
|
||||||
"needs": [
|
|
||||||
"database_type=postgres,mysql"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "forgejo"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "database_host",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Database host",
|
|
||||||
"required": false,
|
|
||||||
"default": "postgres",
|
|
||||||
"needs": [
|
|
||||||
"database_type=postgres,mysql;database_external=true"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"placeholder": "postgres"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "database_password",
|
|
||||||
"type": "secret",
|
|
||||||
"title": "Database password",
|
|
||||||
"required": false,
|
|
||||||
"needs": [
|
|
||||||
"database_type=postgres,mysql"
|
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"autogenerated": {
|
|
||||||
"length": 32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "database_external",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "External Database",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"needs": [
|
|
||||||
"database_type=postgres,mysql"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Ports",
|
|
||||||
"name": "ports",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "ports_http",
|
|
||||||
"type": "str",
|
|
||||||
"title": "HTTP Port",
|
|
||||||
"required": false,
|
|
||||||
"default": 3000,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "3000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ports_ssh",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Ports Ssh",
|
|
||||||
"required": false,
|
|
||||||
"default": 2222,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "2222"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Traefik",
|
|
||||||
"name": "traefik",
|
|
||||||
"toggle": "traefik_enabled",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "traefik_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Traefik",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_host",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Host",
|
|
||||||
"required": true,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "forgejo"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_domain",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Domain",
|
|
||||||
"required": true,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "home.arpa"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_entrypoint",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Entrypoint",
|
|
||||||
"required": true,
|
|
||||||
"default": "web",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "web"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_network",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Network",
|
|
||||||
"required": true,
|
|
||||||
"default": "traefik",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "traefik"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_tls_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "TLS",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_tls_entrypoint",
|
|
||||||
"type": "str",
|
|
||||||
"title": "TLS Entrypoint",
|
|
||||||
"required": true,
|
|
||||||
"default": "websecure",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "websecure"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"traefik_tls_enabled=true"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_tls_certresolver",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Cert Resolver",
|
|
||||||
"required": true,
|
|
||||||
"default": "cloudflare",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "cloudflare"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"traefik_tls_enabled=true"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
# Gitea database credentials
|
|
||||||
<%- if database_type != 'sqlite' %>
|
|
||||||
DATABASE_USER=<< database_user >>
|
|
||||||
DATABASE_PASSWORD=<< database_password >>
|
|
||||||
<%- endif %>
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
services:
|
|
||||||
<< service_name >>:
|
|
||||||
image: docker.io/gitea/gitea:1.26.1
|
|
||||||
restart: << restart_policy >>
|
|
||||||
environment:
|
|
||||||
- USER_UID=<< user_uid >>
|
|
||||||
- USER_GID=<< user_gid >>
|
|
||||||
<%- if database_type != 'sqlite' %>
|
|
||||||
- GITEA__database__DB_TYPE=<< database_type >>
|
|
||||||
<%- if database_external %>
|
|
||||||
- GITEA__database__HOST=<< database_host >>
|
|
||||||
<%- else %>
|
|
||||||
- GITEA__database__HOST=<< service_name >>_db
|
|
||||||
<%- endif %>
|
|
||||||
- GITEA__database__NAME=<< database_name >>
|
|
||||||
- GITEA__database__USER=${DATABASE_USER}
|
|
||||||
- GITEA__database__PASSWD=${DATABASE_PASSWORD}
|
|
||||||
<%- endif %>
|
|
||||||
- GITEA__server__SSH_PORT=<< ports_ssh >>
|
|
||||||
<%- if not traefik_enabled %>
|
|
||||||
- GITEA__server__ROOT_URL=<< gitea_url >>
|
|
||||||
<%- else %>
|
|
||||||
- GITEA__server__ROOT_URL=https://<< traefik_host >>.<< traefik_domain >>
|
|
||||||
<%- endif %>
|
|
||||||
<%- if not database_external and (database_type == "postgres" or database_type == "mysql") or traefik_enabled %>
|
|
||||||
networks:
|
|
||||||
<%- if not database_external and database_type != 'sqlite' %>
|
|
||||||
- << service_name >>_backend
|
|
||||||
<%- endif %>
|
|
||||||
<%- if traefik_enabled %>
|
|
||||||
- << traefik_network >>
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
ports:
|
|
||||||
<%- if not traefik_enabled %>
|
|
||||||
- "<< ports_http >>:3000"
|
|
||||||
<%- endif %>
|
|
||||||
- "<< ports_ssh >>:22"
|
|
||||||
volumes:
|
|
||||||
- << service_name >>_data:/data
|
|
||||||
- /etc/timezone:/etc/timezone:ro
|
|
||||||
- /etc/localtime:/etc/localtime:ro
|
|
||||||
<%- if traefik_enabled %>
|
|
||||||
labels:
|
|
||||||
- traefik.enable=true
|
|
||||||
- traefik.docker.network=<< traefik_network >>
|
|
||||||
- traefik.http.services.<< service_name >>_web.loadBalancer.server.port=3000
|
|
||||||
- traefik.http.routers.<< service_name >>_http.service=<< service_name >>_web
|
|
||||||
- traefik.http.routers.<< service_name >>_http.rule=Host(`<< traefik_host >>.<< traefik_domain >>`)
|
|
||||||
- traefik.http.routers.<< service_name >>_http.entrypoints=<< traefik_entrypoint >>
|
|
||||||
<%- if traefik_tls_enabled %>
|
|
||||||
- traefik.http.routers.<< service_name >>_https.service=<< service_name >>_web
|
|
||||||
- traefik.http.routers.<< service_name >>_https.rule=Host(`<< traefik_host >>.<< traefik_domain >>`)
|
|
||||||
- traefik.http.routers.<< service_name >>_https.entrypoints=<< traefik_tls_entrypoint >>
|
|
||||||
- traefik.http.routers.<< service_name >>_https.tls=true
|
|
||||||
- traefik.http.routers.<< service_name >>_https.tls.certresolver=<< traefik_tls_certresolver >>
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
<%- if not database_external and database_type != 'sqlite' %>
|
|
||||||
depends_on:
|
|
||||||
- << service_name >>_db
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
<%- if not database_external and database_type == "postgres" %>
|
|
||||||
<< service_name >>_db:
|
|
||||||
image: docker.io/library/postgres:17.9
|
|
||||||
restart: << restart_policy >>
|
|
||||||
environment:
|
|
||||||
- TZ=<< container_timezone >>
|
|
||||||
- POSTGRES_USER=${DATABASE_USER}
|
|
||||||
- POSTGRES_PASSWORD=${DATABASE_PASSWORD}
|
|
||||||
- POSTGRES_DB=<< database_name >>
|
|
||||||
networks:
|
|
||||||
- << service_name >>_backend
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD-SHELL", "pg_isready -U << database_user >>"]
|
|
||||||
start_period: 30s
|
|
||||||
interval: 10s
|
|
||||||
timeout: 10s
|
|
||||||
retries: 5
|
|
||||||
volumes:
|
|
||||||
- << service_name >>_db:/var/lib/postgresql/data
|
|
||||||
<%- elif not database_external and database_type == "mysql" %>
|
|
||||||
<< service_name >>_db:
|
|
||||||
image: docker.io/library/mysql:8.1
|
|
||||||
restart: << restart_policy >>
|
|
||||||
environment:
|
|
||||||
- MYSQL_USER=${DATABASE_USER}
|
|
||||||
- MYSQL_PASSWORD=${DATABASE_PASSWORD}
|
|
||||||
- MYSQL_DATABASE=<< database_name >>
|
|
||||||
- MYSQL_ROOT_PASSWORD=${DATABASE_PASSWORD}
|
|
||||||
networks:
|
|
||||||
- << service_name >>_backend
|
|
||||||
volumes:
|
|
||||||
- << service_name >>_db:/var/lib/mysql
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
<< service_name >>_data:
|
|
||||||
driver: local
|
|
||||||
<%- if not database_external %>
|
|
||||||
<%- if database_type == "postgres" or database_type == "mysql" %>
|
|
||||||
<< service_name >>_db:
|
|
||||||
driver: local
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
|
|
||||||
<%- if not database_external and (database_type == "postgres" or database_type == "mysql") or traefik_enabled %>
|
|
||||||
networks:
|
|
||||||
<%- if not database_external %>
|
|
||||||
<< service_name >>_backend:
|
|
||||||
driver: bridge
|
|
||||||
<%- endif %>
|
|
||||||
<%- if traefik_enabled %>
|
|
||||||
<< traefik_network >>:
|
|
||||||
external: true
|
|
||||||
<%- endif %>
|
|
||||||
<%- endif %>
|
|
||||||
@@ -1,291 +0,0 @@
|
|||||||
{
|
|
||||||
"slug": "gitea",
|
|
||||||
"kind": "compose",
|
|
||||||
"metadata": {
|
|
||||||
"name": "Gitea",
|
|
||||||
"description": "Lightweight, self-hosted Git service with a web interface for repository hosting, code review, issue tracking, and team collaboration. Written in Go.",
|
|
||||||
"tags": [
|
|
||||||
"traefik"
|
|
||||||
],
|
|
||||||
"icon": {
|
|
||||||
"provider": "selfhst",
|
|
||||||
"id": "gitea",
|
|
||||||
"color": "emerald"
|
|
||||||
},
|
|
||||||
"draft": false,
|
|
||||||
"version": {
|
|
||||||
"name": "1.26.1-1",
|
|
||||||
"source_dep_name": "docker.io/gitea/gitea",
|
|
||||||
"source_dep_version": "1.26.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"name": "general",
|
|
||||||
"title": "General",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "service_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Service Name",
|
|
||||||
"required": false,
|
|
||||||
"default": "gitea",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "gitea"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "container_timezone",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Container Timezone",
|
|
||||||
"required": false,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "Europe/Berlin"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "user_uid",
|
|
||||||
"type": "int",
|
|
||||||
"title": "User Uid",
|
|
||||||
"required": false,
|
|
||||||
"default": 1000,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "1000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "user_gid",
|
|
||||||
"type": "int",
|
|
||||||
"title": "User Gid",
|
|
||||||
"required": false,
|
|
||||||
"default": 1000,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "1000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "restart_policy",
|
|
||||||
"type": "enum",
|
|
||||||
"title": "Restart Policy",
|
|
||||||
"required": true,
|
|
||||||
"default": "unless-stopped",
|
|
||||||
"config": {
|
|
||||||
"options": [
|
|
||||||
"unless-stopped",
|
|
||||||
"always",
|
|
||||||
"on-failure",
|
|
||||||
"no"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "gitea_url",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Public URL",
|
|
||||||
"required": false,
|
|
||||||
"default": "https://git.home.arpa",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "https://git.home.arpa"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"traefik_enabled=false"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "database",
|
|
||||||
"title": "Database",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "database_type",
|
|
||||||
"type": "enum",
|
|
||||||
"title": "Database backend type",
|
|
||||||
"required": false,
|
|
||||||
"default": "sqlite",
|
|
||||||
"config": {
|
|
||||||
"options": [
|
|
||||||
"sqlite",
|
|
||||||
"postgres",
|
|
||||||
"mysql"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "database_name",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Database name",
|
|
||||||
"required": false,
|
|
||||||
"default": "gitea",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "gitea"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"database_type=postgres,mysql"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "database_user",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Database user",
|
|
||||||
"required": false,
|
|
||||||
"default": "gitea",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "gitea"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"database_type=postgres,mysql"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "database_host",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Database host",
|
|
||||||
"required": false,
|
|
||||||
"default": "postgres",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "postgres"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"database_type=postgres,mysql;database_external=true"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "database_password",
|
|
||||||
"type": "secret",
|
|
||||||
"title": "Database password",
|
|
||||||
"required": false,
|
|
||||||
"config": {
|
|
||||||
"autogenerated": {
|
|
||||||
"length": 32
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"database_type=postgres,mysql"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "database_external",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "External Database",
|
|
||||||
"required": false,
|
|
||||||
"default": false,
|
|
||||||
"needs": [
|
|
||||||
"database_type=postgres,mysql"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ports",
|
|
||||||
"title": "Ports",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "ports_http",
|
|
||||||
"type": "str",
|
|
||||||
"title": "HTTP Port",
|
|
||||||
"required": false,
|
|
||||||
"default": 3000,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "3000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ports_ssh",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Ports Ssh",
|
|
||||||
"required": false,
|
|
||||||
"default": 2221,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "2221"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik",
|
|
||||||
"title": "Traefik",
|
|
||||||
"toggle": "traefik_enabled",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "traefik_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "Traefik",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_host",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Host",
|
|
||||||
"required": true,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "gitea"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_domain",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Domain",
|
|
||||||
"required": true,
|
|
||||||
"config": {
|
|
||||||
"placeholder": "home.arpa"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_entrypoint",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Entrypoint",
|
|
||||||
"required": true,
|
|
||||||
"default": "web",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "web"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_network",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Network",
|
|
||||||
"required": true,
|
|
||||||
"default": "traefik",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "traefik"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_tls_enabled",
|
|
||||||
"type": "bool",
|
|
||||||
"title": "TLS",
|
|
||||||
"required": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_tls_entrypoint",
|
|
||||||
"type": "str",
|
|
||||||
"title": "TLS Entrypoint",
|
|
||||||
"required": true,
|
|
||||||
"default": "websecure",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "websecure"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"traefik_tls_enabled=true"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "traefik_tls_certresolver",
|
|
||||||
"type": "str",
|
|
||||||
"title": "Cert Resolver",
|
|
||||||
"required": true,
|
|
||||||
"default": "cloudflare",
|
|
||||||
"config": {
|
|
||||||
"placeholder": "cloudflare"
|
|
||||||
},
|
|
||||||
"needs": [
|
|
||||||
"traefik_tls_enabled=true"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
services:
|
|
||||||
<< service_name >>:
|
|
||||||
image: docker.io/gitlab/gitlab-runner:alpine-v17.9.1
|
|
||||||
container_name: << container_name >>
|
|
||||||
volumes:
|
|
||||||
- ./config/config.toml:/etc/gitlab-runner/config.toml:ro
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
|
||||||
restart: << restart_policy >>
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user