new files from source
This commit is contained in:
132 files changed
+5335
No files matched your search
@@ -0,0 +1,2 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Icon=/home/thesabear/Downloads/App Images/devops_iac_publicreo.png
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
---
|
||||||
|
- hosts: Docker
|
||||||
|
become: true
|
||||||
|
become_method: sudo
|
||||||
|
become_user: root
|
||||||
|
vars:
|
||||||
|
GOTIFY_IP: xxx #[Your gotify host IP goes here]
|
||||||
|
GOTIFY_PORT: xxx #[Your gotify port goes here]
|
||||||
|
GOTIFY_TOKEN: xxx #[Your app token goes here]
|
||||||
|
ansible_python_interpreter: /usr/bin/python3
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
|
||||||
|
- name: prune non-dangling images
|
||||||
|
community.docker.docker_prune:
|
||||||
|
containers: false
|
||||||
|
images: true
|
||||||
|
images_filters:
|
||||||
|
dangling: false
|
||||||
|
networks: false
|
||||||
|
volumes: false
|
||||||
|
builder_cache: false
|
||||||
|
|
||||||
|
- name: Check if reboot is required
|
||||||
|
stat:
|
||||||
|
path: /var/run/reboot-required
|
||||||
|
register: reboot_required_file
|
||||||
|
|
||||||
|
- name: Show Output of required reboots
|
||||||
|
debug: msg="{{ reboot_required_file.stat.exists == true }}"
|
||||||
|
|
||||||
|
- name: Rebooting machine
|
||||||
|
shell: sleep 2 && shutdown -r now "Ansible updates triggered"
|
||||||
|
async: 1
|
||||||
|
poll: 0
|
||||||
|
ignore_errors: true
|
||||||
|
when: reboot_required_file.stat.exists
|
||||||
|
|
||||||
|
- name: Waiting for the machine to come back
|
||||||
|
local_action: wait_for host={{ ansible_host }} state=started port=22 delay=30
|
||||||
|
become: false
|
||||||
|
when: reboot_required_file.stat.exists
|
||||||
|
|
||||||
|
- name: notify via Gotify
|
||||||
|
uri:
|
||||||
|
url: 'http://{{ GOTIFY_IP }}:{{ GOTIFY_PORT }}/message?token={{ GOTIFY_TOKEN }}'
|
||||||
|
method: POST
|
||||||
|
body:
|
||||||
|
title:
|
||||||
|
content: clean docker hosts
|
||||||
|
message:
|
||||||
|
content: The clean docker playbook has completed for {{ ansible_host }} and is now updated. A required reboot is {{ reboot_required_file.stat.exists == true }}.
|
||||||
|
priority:
|
||||||
|
content: '5'
|
||||||
|
body_format: form-multipart
|
||||||
|
register: result
|
||||||
|
...
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
- name: ping test
|
||||||
|
hosts: all
|
||||||
|
become: true
|
||||||
|
vars:
|
||||||
|
ansible_python_interpreter: /usr/bin/python3
|
||||||
|
tasks:
|
||||||
|
- name: test ping
|
||||||
|
ansible.builtin.ping:
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
### This is just a sample showing the way of removing apps from a VM using Ansible
|
||||||
|
---
|
||||||
|
- hosts: all
|
||||||
|
become: yes
|
||||||
|
vars:
|
||||||
|
GOTIFY_IP: xxx #[Your gotify host IP goes here]
|
||||||
|
GOTIFY_PORT: xxx #[Your gotify port goes here]
|
||||||
|
GOTIFY_TOKEN: xxx #[Your app token goes here]
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
|
||||||
|
- name: Ansible apt remove crowdsec
|
||||||
|
apt:
|
||||||
|
name: crowdsec
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: Ansible apt remove zabbix
|
||||||
|
apt:
|
||||||
|
name: zabbix
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: Ansible apt remove zabbix-agent
|
||||||
|
apt:
|
||||||
|
name: zabbix-agent
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: Remove dependencies that are no longer required and purge their configuration files
|
||||||
|
ansible.builtin.apt:
|
||||||
|
autoremove: yes
|
||||||
|
purge: true
|
||||||
|
|
||||||
|
- name: Check if reboot is required
|
||||||
|
stat:
|
||||||
|
path: /var/run/reboot-required
|
||||||
|
register: reboot_required_file
|
||||||
|
|
||||||
|
- name: Show Output of required reboots
|
||||||
|
debug: msg="{{ reboot_required_file.stat.exists == true }}"
|
||||||
|
|
||||||
|
- name: Rebooting machine
|
||||||
|
shell: sleep 2 && shutdown -r now "Ansible updates triggered"
|
||||||
|
async: 1
|
||||||
|
poll: 0
|
||||||
|
ignore_errors: true
|
||||||
|
when: reboot_required_file.stat.exists
|
||||||
|
|
||||||
|
- name: Waiting for the machine to come back
|
||||||
|
local_action: wait_for host={{ ansible_host }} state=started port=22 delay=30
|
||||||
|
become: no
|
||||||
|
when: reboot_required_file.stat.exists
|
||||||
|
|
||||||
|
- name: notify via Gotify
|
||||||
|
uri:
|
||||||
|
url: 'http://{{ GOTIFY_IP }}:{{ GOTIFY_PORT }}/message?token={{ GOTIFY_TOKEN }}'
|
||||||
|
method: POST
|
||||||
|
body:
|
||||||
|
title:
|
||||||
|
content: APT Packages Update
|
||||||
|
message:
|
||||||
|
content: The remove apps playbook has completed for {{ ansible_host }} and is now updated. A required reboot is {{ reboot_required_file.stat.exists == true }}.
|
||||||
|
priority:
|
||||||
|
content: '5'
|
||||||
|
body_format: form-multipart
|
||||||
|
register: result
|
||||||
|
...
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
- hosts: all
|
||||||
|
become: true
|
||||||
|
tasks:
|
||||||
|
- name: Remove specified repository from sources list
|
||||||
|
ansible.builtin.apt_repository:
|
||||||
|
repo: xxx #put the reponame of the repo you no longer want here
|
||||||
|
state: absent
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
---
|
||||||
|
- name: Patching and Updating Linux Systems
|
||||||
|
hosts: all
|
||||||
|
become: true
|
||||||
|
vars:
|
||||||
|
GOTIFY_IP: xxx #[Your gotify host IP goes here]
|
||||||
|
GOTIFY_PORT: xxx #[Your gotify port goes here]
|
||||||
|
GOTIFY_TOKEN: xxx #[Your app token goes here]
|
||||||
|
ansible_python_interpreter: /usr/bin/python3
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Update Debian-based Systems
|
||||||
|
when: ansible_os_family == 'Debian' or ansible_os_family == 'Ubuntu'
|
||||||
|
apt:
|
||||||
|
update_cache: yes
|
||||||
|
upgrade: dist
|
||||||
|
|
||||||
|
- name: Update RHEL-based Systems
|
||||||
|
when: ansible_os_family == 'RedHat'
|
||||||
|
yum:
|
||||||
|
name: '*'
|
||||||
|
state: latest
|
||||||
|
|
||||||
|
- name: List installed and updated packages
|
||||||
|
shell: grep -E "^$(date +%Y-%m-%d).+ (install|upgrade) " /var/log/dpkg.log |cut -d " " -f 3-5
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Check if Docker is installed
|
||||||
|
command: which docker
|
||||||
|
register: docker_installed
|
||||||
|
ignore_errors: true
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Upgrade Python pip modules for Docker support (only if Docker is installed)
|
||||||
|
when: docker_installed.rc == 0 and ansible_os_family == 'RedHat'
|
||||||
|
pip:
|
||||||
|
name:
|
||||||
|
- docker
|
||||||
|
- requests
|
||||||
|
state: latest
|
||||||
|
executable: pip3
|
||||||
|
|
||||||
|
- name: Show Output of updated files
|
||||||
|
debug: msg="{{ result.stdout_lines }}"
|
||||||
|
|
||||||
|
- name: Check if reboot is required
|
||||||
|
stat:
|
||||||
|
path: /var/run/reboot-required
|
||||||
|
register: reboot_required_file
|
||||||
|
|
||||||
|
- name: Show Output of required reboots
|
||||||
|
debug: msg="{{ reboot_required_file.stat.exists == true }}"
|
||||||
|
|
||||||
|
- name: Rebooting machine
|
||||||
|
shell: sleep 2 && shutdown -r now "Ansible updates triggered"
|
||||||
|
async: 1
|
||||||
|
poll: 0
|
||||||
|
ignore_errors: true
|
||||||
|
when: reboot_required_file.stat.exists
|
||||||
|
|
||||||
|
- name: Waiting for the machine to come back
|
||||||
|
local_action: wait_for host={{ ansible_host }} state=started port=22 delay=30
|
||||||
|
become: false
|
||||||
|
when: reboot_required_file.stat.exists
|
||||||
|
###
|
||||||
|
- name: Remove DNF dependencies that are no longer required.
|
||||||
|
when: ansible_os_family == 'RedHat'
|
||||||
|
ansible.builtin.dnf:
|
||||||
|
autoremove: yes
|
||||||
|
|
||||||
|
- name: Remove APT dependencies that are no longer required.
|
||||||
|
when: ansible_os_family == 'Debian' or ansible_os_family == 'Ubuntu'
|
||||||
|
ansible.builtin.apt:
|
||||||
|
autoremove: yes
|
||||||
|
|
||||||
|
- name: notify via Gotify
|
||||||
|
uri:
|
||||||
|
url: 'http://{{ GOTIFY_IP }}:{{ GOTIFY_PORT }}/message?token={{ GOTIFY_TOKEN }}'
|
||||||
|
method: POST
|
||||||
|
body:
|
||||||
|
title:
|
||||||
|
content: All Packages Update
|
||||||
|
message:
|
||||||
|
content: The upgrade-packages playbook has completed for {{ ansible_host }} and is now updated. A required reboot is {{ reboot_required_file.stat.exists == true }}.
|
||||||
|
priority:
|
||||||
|
content: '5'
|
||||||
|
body_format: form-multipart
|
||||||
|
register: result
|
||||||
|
...
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
services:
|
||||||
|
actual_server:
|
||||||
|
image: actualbudget/actual-server:latest
|
||||||
|
container_name: actual
|
||||||
|
ports:
|
||||||
|
- 5006:5006
|
||||||
|
environment:
|
||||||
|
- PUID=PUID
|
||||||
|
- PGID=PGID
|
||||||
|
- TZ=timezone
|
||||||
|
# Uncomment any of the lines below to set configuration options.
|
||||||
|
# - ACTUAL_HTTPS_KEY=/data/selfhost.key
|
||||||
|
# - ACTUAL_HTTPS_CERT=/data/selfhost.crt
|
||||||
|
# See all options and more details at https://actualbudget.github.io/docs/Installing/Configuration
|
||||||
|
# !! If you are not using any of these options, remove the 'environment:' tag entirely.
|
||||||
|
volumes:
|
||||||
|
- /path/to/actual-data:/data
|
||||||
|
restart: unless-stopped
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
airsonic-advanced:
|
||||||
|
image: lscr.io/linuxserver/airsonic-advanced:latest
|
||||||
|
container_name: airsonic-advanced
|
||||||
|
environment:
|
||||||
|
- PUID=PUID
|
||||||
|
- PGID=PGID # Note that if you want to use Airsonic's Java jukebox player, then PGID will need to match the group of your sound device (e.g. /dev/snd).
|
||||||
|
- TZ=timezone
|
||||||
|
volumes:
|
||||||
|
- /path/toairsonic-advanced:/config
|
||||||
|
- /path/to/music:/music
|
||||||
|
- /path/to/playlists:/playlists
|
||||||
|
- /path/to/audiobooks:/audiobooks
|
||||||
|
- </path/to/other media:/media #optional
|
||||||
|
ports:
|
||||||
|
- 4040:4040
|
||||||
|
- 4041:4041
|
||||||
|
devices:
|
||||||
|
- /dev/snd:/dev/snd #need this to enable jukebox mode on the server
|
||||||
|
restart: unless-stopped
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgresql:
|
||||||
|
image: docker.io/library/postgres:16-alpine
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
|
||||||
|
start_period: 20s
|
||||||
|
interval: 30s
|
||||||
|
retries: 5
|
||||||
|
timeout: 5s
|
||||||
|
volumes:
|
||||||
|
- /path/to/authentik/database:/var/lib/postgresql/data
|
||||||
|
environment:
|
||||||
|
POSTGRES_PASSWORD: ${PG_PASS:?database password required}
|
||||||
|
POSTGRES_USER: ${PG_USER:-authentik}
|
||||||
|
POSTGRES_DB: ${PG_DB:-authentik}
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
redis:
|
||||||
|
image: docker.io/library/redis:alpine
|
||||||
|
command: --save 60 1 --loglevel warning
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
|
||||||
|
start_period: 20s
|
||||||
|
interval: 30s
|
||||||
|
retries: 5
|
||||||
|
timeout: 3s
|
||||||
|
volumes:
|
||||||
|
- /path/to/authentik/redis:/data
|
||||||
|
server:
|
||||||
|
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2024.4.2}
|
||||||
|
restart: unless-stopped
|
||||||
|
command: server
|
||||||
|
environment:
|
||||||
|
AUTHENTIK_REDIS__HOST: redis
|
||||||
|
AUTHENTIK_POSTGRESQL__HOST: postgresql
|
||||||
|
AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
|
||||||
|
AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
|
||||||
|
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
|
||||||
|
volumes:
|
||||||
|
- /path/to/authentik/media:/media
|
||||||
|
- /path/to/authentik/custom-templates:/templates
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
ports:
|
||||||
|
- "${HTTP_PORT}:9000"
|
||||||
|
- "${HTTPS_PORT}:9443"
|
||||||
|
depends_on:
|
||||||
|
- postgresql
|
||||||
|
- redis
|
||||||
|
worker:
|
||||||
|
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2024.4.2}
|
||||||
|
restart: unless-stopped
|
||||||
|
command: worker
|
||||||
|
environment:
|
||||||
|
AUTHENTIK_REDIS__HOST: redis
|
||||||
|
AUTHENTIK_POSTGRESQL__HOST: postgresql
|
||||||
|
AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
|
||||||
|
AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
|
||||||
|
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
|
||||||
|
user: root
|
||||||
|
volumes:
|
||||||
|
- /path/to/authentik/var/run/docker.sock:/var/run/docker.sock
|
||||||
|
- /path/to/authentik/media:/media
|
||||||
|
- /path/to/authentik/certs:/certs
|
||||||
|
- /path/to/authentik/custom-templates:/templates
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
depends_on:
|
||||||
|
- postgresql
|
||||||
|
- redis
|
||||||
|
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
services:
|
||||||
|
bookstack:
|
||||||
|
image: lscr.io/linuxserver/bookstack
|
||||||
|
container_name: bookstack
|
||||||
|
environment:
|
||||||
|
- PUID=${PUID}
|
||||||
|
- PGID=${PGID}
|
||||||
|
- TZ=${TZ}
|
||||||
|
- APP_URL=https://subdomain.example.com
|
||||||
|
- DB_HOST=bookstack_db
|
||||||
|
- DB_PORT=${DB_PORT}
|
||||||
|
- DB_USER=${DB_USER}
|
||||||
|
- DB_PASS=${DB_PASS}
|
||||||
|
- DB_DATABASE=${DB_DATABASE}
|
||||||
|
- APP_DEFAULT_DARK_MODE=true
|
||||||
|
volumes:
|
||||||
|
- /path/to/bookstack/bookstack_app_data:/config
|
||||||
|
ports:
|
||||||
|
- ${HTTP_PORT}:80
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
- bookstack_db
|
||||||
|
|
||||||
|
bookstack_db:
|
||||||
|
image: lscr.io/linuxserver/mariadb
|
||||||
|
container_name: bookstack_db
|
||||||
|
environment:
|
||||||
|
- PUID=${PUID}
|
||||||
|
- PGID=${PGID}
|
||||||
|
- TZ=${TZ}
|
||||||
|
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
|
||||||
|
- MYSQL_DATABASE=${MYSQL_DATABASE}
|
||||||
|
- MYSQL_USER=${MYSQL_USER}
|
||||||
|
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
|
||||||
|
volumes:
|
||||||
|
- /path/to/bookstack/bookstack_db_data:/config
|
||||||
|
restart: unless-stopped
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
version: '3'
|
||||||
|
services:
|
||||||
|
calibre-web:
|
||||||
|
image: lscr.io/linuxserver/calibre-web:latest
|
||||||
|
container_name: calibre-web
|
||||||
|
environment:
|
||||||
|
- PUID=PUID
|
||||||
|
- PGID=PGID
|
||||||
|
- TZ=timezone
|
||||||
|
volumes:
|
||||||
|
- /path/to/calibre-web:/config
|
||||||
|
- /path/to/books:/books
|
||||||
|
ports:
|
||||||
|
- 8083:8083
|
||||||
|
restart: unless-stopped
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
version: '3'
|
||||||
|
services:
|
||||||
|
calibre:
|
||||||
|
image: lscr.io/linuxserver/calibre:latest
|
||||||
|
container_name: calibre
|
||||||
|
environment:
|
||||||
|
- PUID=PUID
|
||||||
|
- PGID=PGID
|
||||||
|
- TZ=timezone
|
||||||
|
- CUSTOM_USER=user
|
||||||
|
- PASSWORD=password
|
||||||
|
volumes:
|
||||||
|
- /path/to/calibre:/config
|
||||||
|
- /path/to/books:/books
|
||||||
|
ports:
|
||||||
|
- 8080:8080
|
||||||
|
- 8081:8081
|
||||||
|
restart: unless-stopped
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
services:
|
||||||
|
cloudcmd:
|
||||||
|
image: coderaiser/cloudcmd
|
||||||
|
container_name: cloudcmd
|
||||||
|
ports:
|
||||||
|
- 8000:8000
|
||||||
|
volumes:
|
||||||
|
- ~:/root
|
||||||
|
- /:/mnt/fs
|
||||||
|
restart: unless-stopped
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
services:
|
||||||
|
diun:
|
||||||
|
image: crazymax/diun:latest
|
||||||
|
container_name: diun
|
||||||
|
command: serve
|
||||||
|
volumes:
|
||||||
|
- /path/to/diun/data:/data
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
environment:
|
||||||
|
- PUID=${PUID}
|
||||||
|
- PGID=${PGID}
|
||||||
|
- TZ=${TZ}
|
||||||
|
- LOG_LEVEL=info
|
||||||
|
- DIUN_WATCH_WORKERS=20
|
||||||
|
- DIUN_WATCH_SCHEDULE=0 7 * * MON ### At 07:00 AM, only on Monday
|
||||||
|
- DIUN_WATCH_JITTER=30s
|
||||||
|
- DIUN_WATCH_RUNONSTARTUP=true
|
||||||
|
- DIUN_PROVIDERS_DOCKER=true
|
||||||
|
- DIUN_PROVIDERS_DOCKER_WATCHBYDEFAULT=true
|
||||||
|
- DIUN_NOTIF_GOTIFY_ENDPOINT=${DIUN_NOTIF_GOTIFY_ENDPOINT}
|
||||||
|
- DIUN_NOTIF_GOTIFY_TOKEN=${DIUN_NOTIF_GOTIFY_TOKEN}
|
||||||
|
- DIUN_NOTIF_GOTIFY_PRIORITY=1
|
||||||
|
- DIUN_NOTIF_GOTIFY_TIMEOUT=10s
|
||||||
|
labels:
|
||||||
|
- diun.enable=true
|
||||||
|
restart: always
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
services:
|
||||||
|
node_exporter:
|
||||||
|
image: quay.io/prometheus/node-exporter:latest
|
||||||
|
container_name: node_exporter
|
||||||
|
command:
|
||||||
|
- "--path.rootfs=/host"
|
||||||
|
network_mode: host
|
||||||
|
pid: host
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- "/:/host:ro,rslave"
|
||||||
|
|
||||||
|
cadvisor:
|
||||||
|
image: gcr.io/cadvisor/cadvisor:latest
|
||||||
|
container_name: cadvisor
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- /:/rootfs:ro
|
||||||
|
- /var/run:/var/run:ro
|
||||||
|
- /sys:/sys:ro
|
||||||
|
- /var/lib/docker/:/var/lib/docker:ro
|
||||||
|
- /dev/disk/:/dev/disk:ro
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
services:
|
||||||
|
duplicati:
|
||||||
|
image: lscr.io/linuxserver/duplicati:latest
|
||||||
|
container_name: duplicati
|
||||||
|
environment:
|
||||||
|
- PUID=PUID #setting PUID as 0 (root) is required to give permissions for all tasks
|
||||||
|
- PGID=PGID #setting PGID as 0 (root) is required to give permissions for all tasks
|
||||||
|
- TZ=timezone
|
||||||
|
volumes:
|
||||||
|
- /path/to/appdata/config:/config
|
||||||
|
- /path/to/backups:/backups
|
||||||
|
- /path/to/source:/source
|
||||||
|
ports:
|
||||||
|
- 8200:8200
|
||||||
|
restart: unless-stopped
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
services:
|
||||||
|
gitlab:
|
||||||
|
image: gitlab/gitlab-ce:latest
|
||||||
|
container_name: gitlab
|
||||||
|
restart: always
|
||||||
|
hostname: "gitlab.example.com"
|
||||||
|
environment:
|
||||||
|
GITLAB_OMNIBUS_CONFIG: |
|
||||||
|
# Add any other gitlab.rb configuration here, each on its own line
|
||||||
|
external_url 'http://gitlab.example.com:8929'
|
||||||
|
gitlab_rails['gitlab_shell_ssh_port'] = 2424
|
||||||
|
ports:
|
||||||
|
- "${HTTP_PORT}:80"
|
||||||
|
- "${HTTPS_PORT}:443"
|
||||||
|
- "${SSH_PORT}:22"
|
||||||
|
volumes:
|
||||||
|
- "/path/to/gitlab/config:/etc/gitlab"
|
||||||
|
- "/path/to/gitlab/logs:/var/log/gitlab"
|
||||||
|
- "/path/to/gitlab/data:/var/opt/gitlab"
|
||||||
|
shm_size: "2gb"
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
services:
|
||||||
|
gotify:
|
||||||
|
image: gotify/server
|
||||||
|
container_name: gotify
|
||||||
|
ports:
|
||||||
|
- ${HTTP_PORT}:80
|
||||||
|
- ${HTTPS_PORT}:443
|
||||||
|
volumes:
|
||||||
|
- /path/to/gotify:/app/data
|
||||||
|
restart: always
|
||||||
|
security_opt:
|
||||||
|
- no-new-privileges:true
|
||||||
|
environment:
|
||||||
|
- PUID=${PUID}
|
||||||
|
- PGID=${PGID}
|
||||||
|
- TZ=${TZ}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
services:
|
||||||
|
prometheus:
|
||||||
|
image: prom/prometheus:latest
|
||||||
|
container_name: prometheus
|
||||||
|
restart: unless-stopped
|
||||||
|
user: "PUID"
|
||||||
|
environment:
|
||||||
|
- PUID:PUID
|
||||||
|
- PGID:PGID
|
||||||
|
ports:
|
||||||
|
- 9090:9090
|
||||||
|
volumes:
|
||||||
|
- /path/to/prometheus/config/prometheus.yml:/etc/prometheus/prometheus.yml
|
||||||
|
- /path/to/prometheus/prometheus-data:/prometheus
|
||||||
|
command:
|
||||||
|
- "--web.enable-lifecycle"
|
||||||
|
- "--config.file=/etc/prometheus/prometheus.yml"
|
||||||
|
|
||||||
|
node_exporter:
|
||||||
|
image: quay.io/prometheus/node-exporter:latest
|
||||||
|
container_name: node_exporter
|
||||||
|
command:
|
||||||
|
- "--path.rootfs=/host"
|
||||||
|
network_mode: host
|
||||||
|
pid: host
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- "/:/host:ro,rslave"
|
||||||
|
|
||||||
|
grafana:
|
||||||
|
container_name: grafana
|
||||||
|
image: grafana/grafana-oss:latest
|
||||||
|
ports:
|
||||||
|
- 3000:3000
|
||||||
|
user: "0"
|
||||||
|
volumes:
|
||||||
|
- /path/to/grafana-data:/var/lib/grafana
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
pve-exporter:
|
||||||
|
image: prompve/prometheus-pve-exporter:latest
|
||||||
|
container_name: pve-exporter
|
||||||
|
ports:
|
||||||
|
- "9221:9221"
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- /path/to/pve/pve.yml:/etc/prometheus/pve.yml
|
||||||
|
|
||||||
|
cadvisor:
|
||||||
|
image: gcr.io/cadvisor/cadvisor:latest
|
||||||
|
container_name: cadvisor
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- /:/rootfs:ro
|
||||||
|
- /var/run:/var/run:ro
|
||||||
|
- /sys:/sys:ro
|
||||||
|
- /var/lib/docker/:/var/lib/docker:ro
|
||||||
|
- /dev/disk/:/dev/disk:ro
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
version: '3'
|
||||||
|
services:
|
||||||
|
grocy:
|
||||||
|
image: lscr.io/linuxserver/grocy
|
||||||
|
container_name: grocy
|
||||||
|
environment:
|
||||||
|
- PUID=PUID
|
||||||
|
- PGID=PGID
|
||||||
|
- TZ=timezone
|
||||||
|
volumes:
|
||||||
|
- /path/to/grocy:/config
|
||||||
|
ports:
|
||||||
|
- 80:80
|
||||||
|
restart: unless-stopped
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
services:
|
||||||
|
homeassistant:
|
||||||
|
container_name: home-assistant
|
||||||
|
image: "ghcr.io/home-assistant/home-assistant:stable"
|
||||||
|
volumes:
|
||||||
|
- /path/to/home-assistant/config:/config
|
||||||
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
environment:
|
||||||
|
- PUID=${PUID}
|
||||||
|
- PGID=${PGID}
|
||||||
|
- TZ=${TZ}
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- ${HTTP_PORT}:8123
|
||||||
|
depends_on:
|
||||||
|
- homeassistant-db
|
||||||
|
privileged: true
|
||||||
|
|
||||||
|
homeassistant-db:
|
||||||
|
image: docker.io/postgres:16.3
|
||||||
|
container_name: homeassistant-db
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- POSTGRES_USER=${POSTGRES_USER}
|
||||||
|
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
||||||
|
- POSTGRES_DB=${POSTGRES_DB}
|
||||||
|
# ensure the database gets created correctly
|
||||||
|
# https://github.com/matrix-org/synapse/blob/master/docs/postgres.md#set-up-database
|
||||||
|
- POSTGRES_INITDB_ARGS=--encoding=UTF-8
|
||||||
|
volumes:
|
||||||
|
- /path/to/home-assistant/schemas:/var/lib/postgresql/data
|
||||||
|
security_opt:
|
||||||
|
- no-new-privileges:true
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
services:
|
||||||
|
it-tools:
|
||||||
|
image: 'corentinth/it-tools:latest'
|
||||||
|
ports:
|
||||||
|
- '${HTTP_PORT}:80'
|
||||||
|
restart: unless-stopped
|
||||||
|
container_name: it-tools
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
services:
|
||||||
|
immich-server:
|
||||||
|
container_name: immich_server
|
||||||
|
environment:
|
||||||
|
- PUID=${PUID}
|
||||||
|
- PGID=${PGID}
|
||||||
|
- TZ=${TZ}
|
||||||
|
image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
|
||||||
|
command: [ "start.sh", "immich" ]
|
||||||
|
volumes:
|
||||||
|
- /path/to/upload:/usr/src/app/upload
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
ports:
|
||||||
|
- ${HTTP_PORT}:3001
|
||||||
|
depends_on:
|
||||||
|
- redis
|
||||||
|
- database
|
||||||
|
restart: always
|
||||||
|
|
||||||
|
immich-microservices:
|
||||||
|
container_name: immich_microservices
|
||||||
|
environment:
|
||||||
|
- PUID=${PUID}
|
||||||
|
- PGID=${PGID}
|
||||||
|
- TZ=${TZ}
|
||||||
|
image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
|
||||||
|
extends:
|
||||||
|
file: hwaccel.yml
|
||||||
|
service: hwaccel
|
||||||
|
command: [ "start.sh", "microservices" ]
|
||||||
|
volumes:
|
||||||
|
- /path/to/upload:/usr/src/app/upload
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
depends_on:
|
||||||
|
- redis
|
||||||
|
- database
|
||||||
|
restart: always
|
||||||
|
|
||||||
|
immich-machine-learning:
|
||||||
|
container_name: immich_machine_learning
|
||||||
|
environment:
|
||||||
|
- PUID=${PUID}
|
||||||
|
- PGID=${PGID}
|
||||||
|
- TZ=${TZ}
|
||||||
|
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}
|
||||||
|
volumes:
|
||||||
|
- /path/to/immich/model-cache:/cache
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
restart: always
|
||||||
|
|
||||||
|
redis:
|
||||||
|
container_name: immich_redis
|
||||||
|
environment:
|
||||||
|
- PUID=${PUID}
|
||||||
|
- PGID=${PGID}
|
||||||
|
- TZ=${TZ}
|
||||||
|
image: redis:6.2-alpine@sha256:70a7a5b641117670beae0d80658430853896b5ef269ccf00d1827427e3263fa3
|
||||||
|
restart: always
|
||||||
|
|
||||||
|
database:
|
||||||
|
container_name: immich_postgres
|
||||||
|
image: registry.hub.docker.com/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
environment:
|
||||||
|
- PUID=${PUID}
|
||||||
|
- PGID=${PGID}
|
||||||
|
- TZ=${TZ}
|
||||||
|
- POSTGRES_PASSWORD=${DB_PASSWORD}
|
||||||
|
- POSTGRES_USER=${DB_USERNAME}
|
||||||
|
- POSTGRES_DB=${DB_DATABASE_NAME}
|
||||||
|
volumes:
|
||||||
|
- /path/to/immich/pgdata:/var/lib/postgresql/data
|
||||||
|
restart: always
|
||||||
|
|
||||||
|
## there is a known issue with Traefik: see here https://github.com/immich-app/immich/discussions/437#discussioncomment-3609797
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
services:
|
||||||
|
jenkins-master:
|
||||||
|
image: jenkins/jenkins:latest
|
||||||
|
container_name: jenkins-master
|
||||||
|
privileged: true
|
||||||
|
user: root
|
||||||
|
environment:
|
||||||
|
- PUID=PUID
|
||||||
|
- PGID=PGID
|
||||||
|
ports:
|
||||||
|
- 8080:8080
|
||||||
|
- 50000:50000
|
||||||
|
volumes:
|
||||||
|
- /path/to/jenkins/jenkins-data:/var/jenkins_home
|
||||||
|
- /path/to/jenkins/var/run/docker.sock:/var/run/docker.sock
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
@@ -0,0 +1,447 @@
|
|||||||
|
services:
|
||||||
|
# Frontend
|
||||||
|
web:
|
||||||
|
image: jitsi/web:${JITSI_IMAGE_VERSION:-stable-9457-2}
|
||||||
|
restart: ${RESTART_POLICY:-unless-stopped}
|
||||||
|
ports:
|
||||||
|
- '${HTTP_PORT}:80'
|
||||||
|
- '${HTTPS_PORT}:443'
|
||||||
|
volumes:
|
||||||
|
- ${CONFIG}/web:/config:Z
|
||||||
|
- ${CONFIG}/web/crontabs:/var/spool/cron/crontabs:Z
|
||||||
|
- ${CONFIG}/transcripts:/usr/share/jitsi-meet/transcripts:Z
|
||||||
|
environment:
|
||||||
|
- AMPLITUDE_ID
|
||||||
|
- ANALYTICS_SCRIPT_URLS
|
||||||
|
- ANALYTICS_WHITELISTED_EVENTS
|
||||||
|
- AUDIO_QUALITY_OPUS_BITRATE
|
||||||
|
- AUTO_CAPTION_ON_RECORD
|
||||||
|
- BRANDING_DATA_URL
|
||||||
|
- BOSH_RELATIVE
|
||||||
|
- CHROME_EXTENSION_BANNER_JSON
|
||||||
|
- COLIBRI_WEBSOCKET_PORT
|
||||||
|
- COLIBRI_WEBSOCKET_JVB_LOOKUP_NAME
|
||||||
|
- COLIBRI_WEBSOCKET_REGEX
|
||||||
|
- CONFCODE_URL
|
||||||
|
- CORS_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN
|
||||||
|
- DEFAULT_LANGUAGE
|
||||||
|
- DEPLOYMENTINFO_ENVIRONMENT
|
||||||
|
- DEPLOYMENTINFO_ENVIRONMENT_TYPE
|
||||||
|
- DEPLOYMENTINFO_REGION
|
||||||
|
- DEPLOYMENTINFO_SHARD
|
||||||
|
- DEPLOYMENTINFO_USERREGION
|
||||||
|
- DESKTOP_SHARING_FRAMERATE_AUTO
|
||||||
|
- DESKTOP_SHARING_FRAMERATE_MIN
|
||||||
|
- DESKTOP_SHARING_FRAMERATE_MAX
|
||||||
|
- DIALIN_NUMBERS_URL
|
||||||
|
- DIALOUT_AUTH_URL
|
||||||
|
- DIALOUT_CODES_URL
|
||||||
|
- DISABLE_AUDIO_LEVELS
|
||||||
|
- DISABLE_COLIBRI_WEBSOCKET_JVB_LOOKUP
|
||||||
|
- DISABLE_DEEP_LINKING
|
||||||
|
- DISABLE_GRANT_MODERATOR
|
||||||
|
- DISABLE_HTTPS
|
||||||
|
- DISABLE_KICKOUT
|
||||||
|
- DISABLE_LOCAL_RECORDING
|
||||||
|
- DISABLE_POLLS
|
||||||
|
- DISABLE_PRIVATE_CHAT
|
||||||
|
- DISABLE_PROFILE
|
||||||
|
- DISABLE_REACTIONS
|
||||||
|
- DISABLE_REMOTE_VIDEO_MENU
|
||||||
|
- DISABLE_START_FOR_ALL
|
||||||
|
- DROPBOX_APPKEY
|
||||||
|
- DROPBOX_REDIRECT_URI
|
||||||
|
- DYNAMIC_BRANDING_URL
|
||||||
|
- ENABLE_AUDIO_PROCESSING
|
||||||
|
- ENABLE_AUTH
|
||||||
|
- ENABLE_AUTH_DOMAIN
|
||||||
|
- ENABLE_BREAKOUT_ROOMS
|
||||||
|
- ENABLE_CALENDAR
|
||||||
|
- ENABLE_COLIBRI_WEBSOCKET
|
||||||
|
- ENABLE_COLIBRI_WEBSOCKET_UNSAFE_REGEX
|
||||||
|
- ENABLE_E2EPING
|
||||||
|
- ENABLE_FILE_RECORDING_SHARING
|
||||||
|
- ENABLE_GUESTS
|
||||||
|
- ENABLE_HSTS
|
||||||
|
- ENABLE_HTTP_REDIRECT
|
||||||
|
- ENABLE_IPV6
|
||||||
|
- ENABLE_LETSENCRYPT
|
||||||
|
- ENABLE_NO_AUDIO_DETECTION
|
||||||
|
- ENABLE_NOISY_MIC_DETECTION
|
||||||
|
- ENABLE_OCTO
|
||||||
|
- ENABLE_OPUS_RED
|
||||||
|
- ENABLE_PREJOIN_PAGE
|
||||||
|
- ENABLE_P2P
|
||||||
|
- ENABLE_WELCOME_PAGE
|
||||||
|
- ENABLE_CLOSE_PAGE
|
||||||
|
- ENABLE_LIVESTREAMING
|
||||||
|
- ENABLE_LIVESTREAMING_DATA_PRIVACY_LINK
|
||||||
|
- ENABLE_LIVESTREAMING_HELP_LINK
|
||||||
|
- ENABLE_LIVESTREAMING_TERMS_LINK
|
||||||
|
- ENABLE_LIVESTREAMING_VALIDATOR_REGEXP_STRING
|
||||||
|
- ENABLE_LOAD_TEST_CLIENT
|
||||||
|
- ENABLE_LOCAL_RECORDING_NOTIFY_ALL_PARTICIPANT
|
||||||
|
- ENABLE_LOCAL_RECORDING_SELF_START
|
||||||
|
- ENABLE_RECORDING
|
||||||
|
- ENABLE_REMB
|
||||||
|
- ENABLE_REQUIRE_DISPLAY_NAME
|
||||||
|
- ENABLE_SERVICE_RECORDING
|
||||||
|
- ENABLE_SIMULCAST
|
||||||
|
- ENABLE_STATS_ID
|
||||||
|
- ENABLE_STEREO
|
||||||
|
- ENABLE_SUBDOMAINS
|
||||||
|
- ENABLE_TALK_WHILE_MUTED
|
||||||
|
- ENABLE_TCC
|
||||||
|
- ENABLE_TRANSCRIPTIONS
|
||||||
|
- ENABLE_XMPP_WEBSOCKET
|
||||||
|
- ENABLE_JAAS_COMPONENTS
|
||||||
|
- ETHERPAD_PUBLIC_URL
|
||||||
|
- ETHERPAD_URL_BASE
|
||||||
|
- E2EPING_NUM_REQUESTS
|
||||||
|
- E2EPING_MAX_CONFERENCE_SIZE
|
||||||
|
- E2EPING_MAX_MESSAGE_PER_SECOND
|
||||||
|
- GOOGLE_ANALYTICS_ID
|
||||||
|
- GOOGLE_API_APP_CLIENT_ID
|
||||||
|
- HIDE_PREMEETING_BUTTONS
|
||||||
|
- HIDE_PREJOIN_DISPLAY_NAME
|
||||||
|
- HIDE_PREJOIN_EXTRA_BUTTONS
|
||||||
|
- INVITE_SERVICE_URL
|
||||||
|
- JVB_PREFER_SCTP
|
||||||
|
- LETSENCRYPT_DOMAIN
|
||||||
|
- LETSENCRYPT_EMAIL
|
||||||
|
- LETSENCRYPT_USE_STAGING
|
||||||
|
- MATOMO_ENDPOINT
|
||||||
|
- MATOMO_SITE_ID
|
||||||
|
- MICROSOFT_API_APP_CLIENT_ID
|
||||||
|
- NGINX_RESOLVER
|
||||||
|
- NGINX_WORKER_PROCESSES
|
||||||
|
- NGINX_WORKER_CONNECTIONS
|
||||||
|
- PEOPLE_SEARCH_URL
|
||||||
|
- PREFERRED_LANGUAGE
|
||||||
|
- PUBLIC_URL
|
||||||
|
- P2P_PREFERRED_CODEC
|
||||||
|
- RESOLUTION
|
||||||
|
- RESOLUTION_MIN
|
||||||
|
- RESOLUTION_WIDTH
|
||||||
|
- RESOLUTION_WIDTH_MIN
|
||||||
|
- START_AUDIO_MUTED
|
||||||
|
- START_AUDIO_ONLY
|
||||||
|
- START_SILENT
|
||||||
|
- START_WITH_AUDIO_MUTED
|
||||||
|
- START_VIDEO_MUTED
|
||||||
|
- START_WITH_VIDEO_MUTED
|
||||||
|
- TESTING_AV1_SUPPORT
|
||||||
|
- TOKEN_AUTH_URL
|
||||||
|
- TOOLBAR_BUTTONS
|
||||||
|
- TRANSLATION_LANGUAGES
|
||||||
|
- TRANSLATION_LANGUAGES_HEAD
|
||||||
|
- TZ
|
||||||
|
- USE_APP_LANGUAGE
|
||||||
|
- VIDEOQUALITY_BITRATE_H264_LOW
|
||||||
|
- VIDEOQUALITY_BITRATE_H264_STANDARD
|
||||||
|
- VIDEOQUALITY_BITRATE_H264_HIGH
|
||||||
|
- VIDEOQUALITY_BITRATE_H264_FULL
|
||||||
|
- VIDEOQUALITY_BITRATE_H264_ULTRA
|
||||||
|
- VIDEOQUALITY_BITRATE_H264_SS_HIGH
|
||||||
|
- VIDEOQUALITY_BITRATE_VP8_LOW
|
||||||
|
- VIDEOQUALITY_BITRATE_VP8_STANDARD
|
||||||
|
- VIDEOQUALITY_BITRATE_VP8_HIGH
|
||||||
|
- VIDEOQUALITY_BITRATE_VP8_FULL
|
||||||
|
- VIDEOQUALITY_BITRATE_VP8_ULTRA
|
||||||
|
- VIDEOQUALITY_BITRATE_VP8_SS_HIGH
|
||||||
|
- VIDEOQUALITY_BITRATE_VP9_LOW
|
||||||
|
- VIDEOQUALITY_BITRATE_VP9_STANDARD
|
||||||
|
- VIDEOQUALITY_BITRATE_VP9_HIGH
|
||||||
|
- VIDEOQUALITY_BITRATE_VP9_FULL
|
||||||
|
- VIDEOQUALITY_BITRATE_VP9_ULTRA
|
||||||
|
- VIDEOQUALITY_BITRATE_VP9_SS_HIGH
|
||||||
|
- VIDEOQUALITY_BITRATE_AV1_LOW
|
||||||
|
- VIDEOQUALITY_BITRATE_AV1_STANDARD
|
||||||
|
- VIDEOQUALITY_BITRATE_AV1_HIGH
|
||||||
|
- VIDEOQUALITY_BITRATE_AV1_FULL
|
||||||
|
- VIDEOQUALITY_BITRATE_AV1_ULTRA
|
||||||
|
- VIDEOQUALITY_BITRATE_AV1_SS_HIGH
|
||||||
|
- VIDEOQUALITY_PREFERRED_CODEC
|
||||||
|
- XMPP_AUTH_DOMAIN
|
||||||
|
- XMPP_BOSH_URL_BASE
|
||||||
|
- XMPP_DOMAIN
|
||||||
|
- XMPP_GUEST_DOMAIN
|
||||||
|
- XMPP_MUC_DOMAIN
|
||||||
|
- XMPP_RECORDER_DOMAIN
|
||||||
|
- XMPP_PORT
|
||||||
|
- WHITEBOARD_ENABLED
|
||||||
|
- WHITEBOARD_COLLAB_SERVER_PUBLIC_URL
|
||||||
|
depends_on:
|
||||||
|
- jvb
|
||||||
|
|
||||||
|
# XMPP server
|
||||||
|
prosody:
|
||||||
|
image: jitsi/prosody:${JITSI_IMAGE_VERSION:-stable-9457-2}
|
||||||
|
restart: ${RESTART_POLICY:-unless-stopped}
|
||||||
|
expose:
|
||||||
|
- '${XMPP_PORT:-5222}'
|
||||||
|
- '${PROSODY_S2S_PORT:-5269}'
|
||||||
|
- '5347'
|
||||||
|
- '${PROSODY_HTTP_PORT:-5280}'
|
||||||
|
volumes:
|
||||||
|
- ${CONFIG}/prosody/config:/config:Z
|
||||||
|
- ${CONFIG}/prosody/prosody-plugins-custom:/prosody-plugins-custom:Z
|
||||||
|
environment:
|
||||||
|
- AUTH_TYPE
|
||||||
|
- DISABLE_POLLS
|
||||||
|
- ENABLE_AUTH
|
||||||
|
- ENABLE_AV_MODERATION
|
||||||
|
- ENABLE_BREAKOUT_ROOMS
|
||||||
|
- ENABLE_END_CONFERENCE
|
||||||
|
- ENABLE_GUESTS
|
||||||
|
- ENABLE_IPV6
|
||||||
|
- ENABLE_LOBBY
|
||||||
|
- ENABLE_RECORDING
|
||||||
|
- ENABLE_S2S
|
||||||
|
- ENABLE_VISITORS
|
||||||
|
- ENABLE_XMPP_WEBSOCKET
|
||||||
|
- ENABLE_JAAS_COMPONENTS
|
||||||
|
- GC_TYPE
|
||||||
|
- GC_INC_TH
|
||||||
|
- GC_INC_SPEED
|
||||||
|
- GC_INC_STEP_SIZE
|
||||||
|
- GC_GEN_MIN_TH
|
||||||
|
- GC_GEN_MAX_TH
|
||||||
|
- GLOBAL_CONFIG
|
||||||
|
- GLOBAL_MODULES
|
||||||
|
- JIBRI_RECORDER_USER
|
||||||
|
- JIBRI_RECORDER_PASSWORD
|
||||||
|
- JIBRI_SIP_BREWERY_MUC
|
||||||
|
- JIBRI_XMPP_USER
|
||||||
|
- JIBRI_XMPP_PASSWORD
|
||||||
|
- JICOFO_AUTH_PASSWORD
|
||||||
|
- JICOFO_COMPONENT_SECRET
|
||||||
|
- JIGASI_XMPP_USER
|
||||||
|
- JIGASI_XMPP_PASSWORD
|
||||||
|
- JVB_AUTH_USER
|
||||||
|
- JVB_AUTH_PASSWORD
|
||||||
|
- JWT_APP_ID
|
||||||
|
- JWT_APP_SECRET
|
||||||
|
- JWT_ACCEPTED_ISSUERS
|
||||||
|
- JWT_ACCEPTED_AUDIENCES
|
||||||
|
- JWT_ASAP_KEYSERVER
|
||||||
|
- JWT_ALLOW_EMPTY
|
||||||
|
- JWT_AUTH_TYPE
|
||||||
|
- JWT_ENABLE_DOMAIN_VERIFICATION
|
||||||
|
- JWT_SIGN_TYPE
|
||||||
|
- JWT_TOKEN_AUTH_MODULE
|
||||||
|
- MATRIX_UVS_URL
|
||||||
|
- MATRIX_UVS_ISSUER
|
||||||
|
- MATRIX_UVS_AUTH_TOKEN
|
||||||
|
- MATRIX_UVS_SYNC_POWER_LEVELS
|
||||||
|
- MATRIX_LOBBY_BYPASS
|
||||||
|
- LOG_LEVEL
|
||||||
|
- LDAP_AUTH_METHOD
|
||||||
|
- LDAP_BASE
|
||||||
|
- LDAP_BINDDN
|
||||||
|
- LDAP_BINDPW
|
||||||
|
- LDAP_FILTER
|
||||||
|
- LDAP_VERSION
|
||||||
|
- LDAP_TLS_CIPHERS
|
||||||
|
- LDAP_TLS_CHECK_PEER
|
||||||
|
- LDAP_TLS_CACERT_FILE
|
||||||
|
- LDAP_TLS_CACERT_DIR
|
||||||
|
- LDAP_START_TLS
|
||||||
|
- LDAP_URL
|
||||||
|
- LDAP_USE_TLS
|
||||||
|
- MAX_PARTICIPANTS
|
||||||
|
- PROSODY_ADMINS
|
||||||
|
- PROSODY_AUTH_TYPE
|
||||||
|
- PROSODY_C2S_LIMIT
|
||||||
|
- PROSODY_C2S_REQUIRE_ENCRYPTION
|
||||||
|
- PROSODY_RESERVATION_ENABLED
|
||||||
|
- PROSODY_RESERVATION_REST_BASE_URL
|
||||||
|
- PROSODY_ENABLE_RATE_LIMITS
|
||||||
|
- PROSODY_ENABLE_S2S
|
||||||
|
- PROSODY_GUEST_AUTH_TYPE
|
||||||
|
- PROSODY_HTTP_PORT
|
||||||
|
- PROSODY_LOG_CONFIG
|
||||||
|
- PROSODY_MODE
|
||||||
|
- PROSODY_RATE_LIMIT_LOGIN_RATE
|
||||||
|
- PROSODY_RATE_LIMIT_SESSION_RATE
|
||||||
|
- PROSODY_RATE_LIMIT_TIMEOUT
|
||||||
|
- PROSODY_RATE_LIMIT_ALLOW_RANGES
|
||||||
|
- PROSODY_RATE_LIMIT_CACHE_SIZE
|
||||||
|
- PROSODY_S2S_LIMIT
|
||||||
|
- PROSODY_S2S_PORT
|
||||||
|
- PROSODY_TRUSTED_PROXIES
|
||||||
|
- PROSODY_VISITOR_INDEX
|
||||||
|
- PROSODY_VISITORS_MUC_PREFIX
|
||||||
|
- PUBLIC_URL
|
||||||
|
- STUN_HOST
|
||||||
|
- STUN_PORT
|
||||||
|
- TURN_CREDENTIALS
|
||||||
|
- TURN_HOST
|
||||||
|
- TURNS_HOST
|
||||||
|
- TURN_PORT
|
||||||
|
- TURNS_PORT
|
||||||
|
- TURN_TRANSPORT
|
||||||
|
- TZ
|
||||||
|
- VISITORS_MAX_VISITORS_PER_NODE
|
||||||
|
- VISITORS_XMPP_DOMAIN
|
||||||
|
- VISITORS_XMPP_SERVER
|
||||||
|
- VISITORS_XMPP_PORT
|
||||||
|
- XMPP_BREAKOUT_MUC_MODULES
|
||||||
|
- XMPP_CONFIGURATION
|
||||||
|
- XMPP_DOMAIN
|
||||||
|
- XMPP_AUTH_DOMAIN
|
||||||
|
- XMPP_GUEST_DOMAIN
|
||||||
|
- XMPP_MUC_DOMAIN
|
||||||
|
- XMPP_INTERNAL_MUC_DOMAIN
|
||||||
|
- XMPP_LOBBY_MUC_MODULES
|
||||||
|
- XMPP_MODULES
|
||||||
|
- XMPP_MUC_MODULES
|
||||||
|
- XMPP_MUC_CONFIGURATION
|
||||||
|
- XMPP_INTERNAL_MUC_MODULES
|
||||||
|
- XMPP_RECORDER_DOMAIN
|
||||||
|
- XMPP_PORT
|
||||||
|
- XMPP_SERVER_S2S_PORT
|
||||||
|
- XMPP_SPEAKERSTATS_MODULES
|
||||||
|
aliases:
|
||||||
|
- ${XMPP_SERVER:-xmpp.meet.jitsi}
|
||||||
|
|
||||||
|
# Focus component
|
||||||
|
jicofo:
|
||||||
|
image: jitsi/jicofo:${JITSI_IMAGE_VERSION:-stable-9457-2}
|
||||||
|
restart: ${RESTART_POLICY:-unless-stopped}
|
||||||
|
ports:
|
||||||
|
- '127.0.0.1:${JICOFO_REST_PORT:-8888}:8888'
|
||||||
|
volumes:
|
||||||
|
- ${CONFIG}/jicofo:/config:Z
|
||||||
|
environment:
|
||||||
|
- AUTH_TYPE
|
||||||
|
- BRIDGE_AVG_PARTICIPANT_STRESS
|
||||||
|
- BRIDGE_STRESS_THRESHOLD
|
||||||
|
- ENABLE_AUTH
|
||||||
|
- ENABLE_AUTO_OWNER
|
||||||
|
- ENABLE_CODEC_VP8
|
||||||
|
- ENABLE_CODEC_VP9
|
||||||
|
- ENABLE_CODEC_AV1
|
||||||
|
- ENABLE_CODEC_H264
|
||||||
|
- ENABLE_CODEC_OPUS_RED
|
||||||
|
- ENABLE_JVB_XMPP_SERVER
|
||||||
|
- ENABLE_OCTO
|
||||||
|
- ENABLE_OCTO_SCTP
|
||||||
|
- ENABLE_RECORDING
|
||||||
|
- ENABLE_SCTP
|
||||||
|
- ENABLE_VISITORS
|
||||||
|
- ENABLE_AUTO_LOGIN
|
||||||
|
- JICOFO_AUTH_LIFETIME
|
||||||
|
- JICOFO_AUTH_PASSWORD
|
||||||
|
- JICOFO_AUTH_TYPE
|
||||||
|
- JICOFO_BRIDGE_REGION_GROUPS
|
||||||
|
- JICOFO_ENABLE_AUTH
|
||||||
|
- JICOFO_ENABLE_BRIDGE_HEALTH_CHECKS
|
||||||
|
- JICOFO_CONF_INITIAL_PARTICIPANT_WAIT_TIMEOUT
|
||||||
|
- JICOFO_CONF_SINGLE_PARTICIPANT_TIMEOUT
|
||||||
|
- JICOFO_CONF_SOURCE_SIGNALING_DELAYS
|
||||||
|
- JICOFO_CONF_MAX_AUDIO_SENDERS
|
||||||
|
- JICOFO_CONF_MAX_VIDEO_SENDERS
|
||||||
|
- JICOFO_CONF_STRIP_SIMULCAST
|
||||||
|
- JICOFO_CONF_SSRC_REWRITING
|
||||||
|
- JICOFO_ENABLE_HEALTH_CHECKS
|
||||||
|
- JICOFO_ENABLE_REST
|
||||||
|
- JICOFO_HEALTH_CHECKS_USE_PRESENCE
|
||||||
|
- JICOFO_MAX_MEMORY
|
||||||
|
- JICOFO_MULTI_STREAM_BACKWARD_COMPAT
|
||||||
|
- JICOFO_OCTO_REGION
|
||||||
|
- JICOFO_TRUSTED_DOMAINS
|
||||||
|
- JIBRI_BREWERY_MUC
|
||||||
|
- JIBRI_REQUEST_RETRIES
|
||||||
|
- JIBRI_PENDING_TIMEOUT
|
||||||
|
- JIGASI_BREWERY_MUC
|
||||||
|
- JIGASI_SIP_URI
|
||||||
|
- JIGASI_TRUSTED_DOMAINS
|
||||||
|
- JVB_BREWERY_MUC
|
||||||
|
- JVB_XMPP_AUTH_DOMAIN
|
||||||
|
- JVB_XMPP_INTERNAL_MUC_DOMAIN
|
||||||
|
- JVB_XMPP_PORT
|
||||||
|
- JVB_XMPP_SERVER
|
||||||
|
- MAX_BRIDGE_PARTICIPANTS
|
||||||
|
- OCTO_BRIDGE_SELECTION_STRATEGY
|
||||||
|
- PROSODY_VISITORS_MUC_PREFIX
|
||||||
|
- SENTRY_DSN="${JICOFO_SENTRY_DSN:-0}"
|
||||||
|
- SENTRY_ENVIRONMENT
|
||||||
|
- SENTRY_RELEASE
|
||||||
|
- TZ
|
||||||
|
- VISITORS_MAX_PARTICIPANTS
|
||||||
|
- VISITORS_MAX_VISITORS_PER_NODE
|
||||||
|
- VISITORS_XMPP_AUTH_DOMAIN
|
||||||
|
- VISITORS_XMPP_SERVER
|
||||||
|
- VISITORS_XMPP_DOMAIN
|
||||||
|
- XMPP_DOMAIN
|
||||||
|
- XMPP_AUTH_DOMAIN
|
||||||
|
- XMPP_INTERNAL_MUC_DOMAIN
|
||||||
|
- XMPP_MUC_DOMAIN
|
||||||
|
- XMPP_RECORDER_DOMAIN
|
||||||
|
- XMPP_SERVER
|
||||||
|
- XMPP_PORT
|
||||||
|
- MAX_SSRCS_PER_USER
|
||||||
|
- MAX_SSRC_GROUPS_PER_USER
|
||||||
|
depends_on:
|
||||||
|
- prosody
|
||||||
|
|
||||||
|
# Video bridge
|
||||||
|
jvb:
|
||||||
|
image: jitsi/jvb:${JITSI_IMAGE_VERSION:-stable-9457-2}
|
||||||
|
restart: ${RESTART_POLICY:-unless-stopped}
|
||||||
|
ports:
|
||||||
|
- '${JVB_PORT:-10000}:${JVB_PORT:-10000}/udp'
|
||||||
|
- '127.0.0.1:${JVB_COLIBRI_PORT:-8686}:8080'
|
||||||
|
volumes:
|
||||||
|
- ${CONFIG}/jvb:/config:Z
|
||||||
|
environment:
|
||||||
|
- AUTOSCALER_SIDECAR_KEY_FILE
|
||||||
|
- AUTOSCALER_SIDECAR_KEY_ID
|
||||||
|
- AUTOSCALER_SIDECAR_GROUP_NAME
|
||||||
|
- AUTOSCALER_SIDECAR_HOST_ID
|
||||||
|
- AUTOSCALER_SIDECAR_INSTANCE_ID
|
||||||
|
- AUTOSCALER_SIDECAR_PORT
|
||||||
|
- AUTOSCALER_SIDECAR_REGION
|
||||||
|
- AUTOSCALER_SIDECAR_SHUTDOWN_POLLING_INTERVAL
|
||||||
|
- AUTOSCALER_SIDECAR_STATS_POLLING_INTERVAL
|
||||||
|
- DOCKER_HOST_ADDRESS
|
||||||
|
- ENABLE_COLIBRI_WEBSOCKET
|
||||||
|
- ENABLE_JVB_XMPP_SERVER
|
||||||
|
- ENABLE_OCTO
|
||||||
|
- JVB_ADVERTISE_IPS
|
||||||
|
- JVB_ADVERTISE_PRIVATE_CANDIDATES
|
||||||
|
- JVB_AUTH_USER
|
||||||
|
- JVB_AUTH_PASSWORD
|
||||||
|
- JVB_BREWERY_MUC
|
||||||
|
- JVB_DISABLE_STUN
|
||||||
|
- JVB_INSTANCE_ID
|
||||||
|
- JVB_PORT
|
||||||
|
- JVB_MUC_NICKNAME
|
||||||
|
- JVB_STUN_SERVERS
|
||||||
|
- JVB_LOG_FILE
|
||||||
|
- JVB_OCTO_BIND_ADDRESS
|
||||||
|
- JVB_OCTO_REGION
|
||||||
|
- JVB_OCTO_RELAY_ID
|
||||||
|
- JVB_REQUIRE_VALID_ADDRESS
|
||||||
|
- JVB_WS_DOMAIN
|
||||||
|
- JVB_WS_SERVER_ID
|
||||||
|
- JVB_XMPP_AUTH_DOMAIN
|
||||||
|
- JVB_XMPP_INTERNAL_MUC_DOMAIN
|
||||||
|
- JVB_XMPP_PORT
|
||||||
|
- JVB_XMPP_SERVER
|
||||||
|
- PUBLIC_URL
|
||||||
|
- SENTRY_DSN="${JVB_SENTRY_DSN:-0}"
|
||||||
|
- SENTRY_ENVIRONMENT
|
||||||
|
- SENTRY_RELEASE
|
||||||
|
- COLIBRI_REST_ENABLED
|
||||||
|
- SHUTDOWN_REST_ENABLED
|
||||||
|
- TZ
|
||||||
|
- VIDEOBRIDGE_MAX_MEMORY
|
||||||
|
- XMPP_AUTH_DOMAIN
|
||||||
|
- XMPP_INTERNAL_MUC_DOMAIN
|
||||||
|
- XMPP_SERVER
|
||||||
|
- XMPP_PORT
|
||||||
|
depends_on:
|
||||||
|
- prosody
|
||||||
|
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
services:
|
||||||
|
joplin-db:
|
||||||
|
image: postgres:15
|
||||||
|
container_name: joplin-db
|
||||||
|
volumes:
|
||||||
|
- /path/to/data:/var/lib/postgresql/data
|
||||||
|
ports:
|
||||||
|
- 5432:5432
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- POSTGRES_PASSWORD=db_password
|
||||||
|
- POSTGRES_USER=db_user
|
||||||
|
- POSTGRES_DB=joplin
|
||||||
|
|
||||||
|
joplin:
|
||||||
|
image: joplin/server:latest
|
||||||
|
container_name: joplin-server
|
||||||
|
depends_on:
|
||||||
|
- joplin-db
|
||||||
|
ports:
|
||||||
|
- 22300:22300
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- APP_PORT=22300
|
||||||
|
- APP_BASE_URL=https://subdomain.websiteurl.com
|
||||||
|
- DB_CLIENT=pg
|
||||||
|
- POSTGRES_PASSWORD=db_password
|
||||||
|
- POSTGRES_DATABASE=joplin
|
||||||
|
- POSTGRES_USER=db_user
|
||||||
|
- POSTGRES_PORT=5432
|
||||||
|
- POSTGRES_HOST=joplin-db
|
||||||
|
- MAILER_ENABLED=1
|
||||||
|
- MAILER_HOST=smtp.gmail.com
|
||||||
|
- MAILER_PORT=465
|
||||||
|
- MAILER_SECURE=1
|
||||||
|
- [email protected]
|
||||||
|
- MAILER_AUTH_PASSWORD=Y0urP@ssw0rd
|
||||||
|
- MAILER_NOREPLY_NAME=Joplin
|
||||||
|
- [email protected]
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
services:
|
||||||
|
mariadb:
|
||||||
|
image: lscr.io/linuxserver/mariadb:latest
|
||||||
|
container_name: mariadb
|
||||||
|
environment:
|
||||||
|
- PUID=PUID
|
||||||
|
- PGID=PGID
|
||||||
|
- TZ=timezone
|
||||||
|
- MYSQL_ROOT_PASSWORD=rootpassword
|
||||||
|
- MYSQL_DATABASE=database_name #optional
|
||||||
|
- MYSQL_USER=user #optional
|
||||||
|
- MYSQL_PASSWORD=userpassword #optional
|
||||||
|
- REMOTE_SQL=http://URL1/your.sql,https://URL2/your.sql #optional
|
||||||
|
volumes:
|
||||||
|
- /path/to/mariadb/config:/config
|
||||||
|
ports:
|
||||||
|
- 3306:3306
|
||||||
|
restart: unless-stopped
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
services:
|
||||||
|
db:
|
||||||
|
image: mariadb
|
||||||
|
restart: unless-stopped
|
||||||
|
command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW --innodb-file-per-table=1 --skip-innodb-read-only-compressed
|
||||||
|
volumes:
|
||||||
|
- /path/to/nextcloud/db:/var/lib/mysql
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis
|
||||||
|
restart: always
|
||||||
|
command: redis-server --requirepass ${REDIS_HOST_PASSWORD}
|
||||||
|
|
||||||
|
app:
|
||||||
|
image: nextcloud/nextcloud:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- ${HTTP_PORT}:80
|
||||||
|
links:
|
||||||
|
- db
|
||||||
|
- redis
|
||||||
|
volumes:
|
||||||
|
- /path/to/nextcloud/var:/var/www/html
|
||||||
|
environment:
|
||||||
|
- MYSQL_HOST=${MYSQL_HOST}
|
||||||
|
- REDIS_HOST_PASSWORD=${REDIS_HOST_PASSWORD}
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
- redis
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
services:
|
||||||
|
minio:
|
||||||
|
image: minio/minio
|
||||||
|
container_name: minio
|
||||||
|
ports:
|
||||||
|
- ${HTTP_PORT}:9000
|
||||||
|
- ${HTTP_PORT1}:9001
|
||||||
|
volumes:
|
||||||
|
- /path/to/minio:/data
|
||||||
|
environment:
|
||||||
|
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
|
||||||
|
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
|
||||||
|
command: server --console-address ":9001" /data
|
||||||
|
restart: always
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
services:
|
||||||
|
open-webui:
|
||||||
|
image: ghcr.io/open-webui/open-webui:ollama
|
||||||
|
container_name: open-webui
|
||||||
|
environment:
|
||||||
|
- PUID=${PUID}
|
||||||
|
- PGID=${PGID}
|
||||||
|
- TZ=${TZ}
|
||||||
|
ports:
|
||||||
|
- ${HTTP_PORT}:8080
|
||||||
|
volumes:
|
||||||
|
- /path/to/open-webui/ollama:/root/.ollama
|
||||||
|
- /path/to/open-webui/app:/app/backend/data
|
||||||
|
restart: unless-stopped
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
services:
|
||||||
|
organizr:
|
||||||
|
image: organizr/organizr
|
||||||
|
container_name: organizr
|
||||||
|
environment:
|
||||||
|
- PUID=PUID
|
||||||
|
- PGID=PGID
|
||||||
|
- TZ=timezone
|
||||||
|
ports:
|
||||||
|
- 80:80
|
||||||
|
volumes:
|
||||||
|
- /path/to/organizr:/config
|
||||||
|
restart: unless-stopped
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
services:
|
||||||
|
broker:
|
||||||
|
image: docker.io/library/redis:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- /path/to/paperless/redisdata:/data
|
||||||
|
networks:
|
||||||
|
paperless:
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: docker.io/library/postgres:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- /path/to/paperless/pgdata:/var/lib/postgresql/data
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: ${POSTGRES_DB}
|
||||||
|
POSTGRES_USER: ${POSTGRES_USER}
|
||||||
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
|
networks:
|
||||||
|
paperless:
|
||||||
|
|
||||||
|
webserver:
|
||||||
|
image: ghcr.io/paperless-ngx/paperless-ngx:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
- broker
|
||||||
|
- gotenberg
|
||||||
|
- tika
|
||||||
|
ports:
|
||||||
|
- "8005:8000"
|
||||||
|
volumes:
|
||||||
|
- /path/to/paperless/data:/usr/src/paperless/data
|
||||||
|
- /path/to/paperless/media:/usr/src/paperless/media
|
||||||
|
- /path/to/paperless/export:/usr/src/paperless/export
|
||||||
|
- /path/to/paperless/consume:/usr/src/paperless/consume
|
||||||
|
env_file: .env
|
||||||
|
environment:
|
||||||
|
PAPERLESS_REDIS: redis://broker:6379
|
||||||
|
PAPERLESS_DBHOST: db
|
||||||
|
PAPERLESS_DBPASS: ${PAPERLESS_DBPASS}
|
||||||
|
PAPERLESS_TIKA_ENABLED: 1
|
||||||
|
PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://gotenberg:3000
|
||||||
|
PAPERLESS_TIKA_ENDPOINT: http://tika:9998
|
||||||
|
PAPERLESS_URL: ${PAPERLESS_URL}
|
||||||
|
PAPERLESS_ADMIN_USER: ${PAPERLESS_ADMIN_USER}
|
||||||
|
PAPERLESS_ADMIN_PASSWORD: ${PAPERLESS_ADMIN_PASSWORD}
|
||||||
|
PAPERLESS_APPS: "allauth.socialaccount.providers.openid_connect"
|
||||||
|
# Find out how to configure Authentik: https://youtu.be/enwFWELCYJo
|
||||||
|
PAPERLESS_SOCIALACCOUNT_PROVIDERS: '{"openid_connect": {"APPS": [{"provider_id": "authentik","name": "Authentik SSO","client_id": "0gGOZHjx1iJAlh5wN8m1b7uZKwWnPaClGJNKhQDV","secret": "oqskOOlJ1TJzedWZR9WmcVKmxn1HFqGIroi6oiB5xh03qCofuyIDh2DDaf8OnlTybOMiBQkz9rLNO17s4Bx1aG8aGIErp1n6ly0WwQJOk38Tbq3ctOyZGFagEvysp6o2","settings": { "server_url": "https://authentik.local.thesabear.net/application/o/paperless/.well-known/openid-configuration"}}]}}'
|
||||||
|
networks:
|
||||||
|
paperless:
|
||||||
|
|
||||||
|
gotenberg:
|
||||||
|
image: docker.io/gotenberg/gotenberg:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# The gotenberg chromium route is used to convert .eml files. We do not
|
||||||
|
# want to allow external content like tracking pixels or even javascript.
|
||||||
|
command:
|
||||||
|
- "gotenberg"
|
||||||
|
- "--chromium-disable-javascript=true"
|
||||||
|
- "--chromium-allow-list=file:///tmp/.*"
|
||||||
|
networks:
|
||||||
|
paperless:
|
||||||
|
|
||||||
|
tika:
|
||||||
|
image: ghcr.io/paperless-ngx/tika:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
paperless:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
paperless:
|
||||||
|
external: true
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
services:
|
||||||
|
mysql:
|
||||||
|
restart: unless-stopped
|
||||||
|
image: mysql:8.0
|
||||||
|
hostname: mysql
|
||||||
|
volumes:
|
||||||
|
- /path/to/semaphore/semaphore-mysql:/var/lib/mysql
|
||||||
|
environment:
|
||||||
|
MYSQL_RANDOM_ROOT_PASSWORD: "yes"
|
||||||
|
MYSQL_DATABASE: ${MYSQL_DATABASE}
|
||||||
|
MYSQL_USER: ${MYSQL_USER}
|
||||||
|
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
|
||||||
|
|
||||||
|
semaphore:
|
||||||
|
container_name: ansiblesemaphore
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- ${HTTP_PORT}:3000
|
||||||
|
image: semaphoreui/semaphore:latest
|
||||||
|
environment:
|
||||||
|
SEMAPHORE_DB_USER: ${SEMAPHORE_DB_USER}
|
||||||
|
SEMAPHORE_DB_PASS: ${SEMAPHORE_DB_PASS}
|
||||||
|
SEMAPHORE_DB_HOST: ${SEMAPHORE_DB_HOST} # for postgres, change to: postgres
|
||||||
|
SEMAPHORE_DB_PORT: ${SEMAPHORE_DB_PORT} # change to 5432 for postgres
|
||||||
|
SEMAPHORE_DB_DIALECT: ${SEMAPHORE_DB_DIALECT} # for postgres, change to: postgres
|
||||||
|
SEMAPHORE_DB: ${SEMAPHORE_DB}
|
||||||
|
SEMAPHORE_PLAYBOOK_PATH: ${SEMAPHORE_PLAYBOOK_PATH}
|
||||||
|
SEMAPHORE_ADMIN_PASSWORD: ${SEMAPHORE_ADMIN_PASSWORD}
|
||||||
|
SEMAPHORE_ADMIN_NAME: ${SEMAPHORE_ADMIN_NAME}
|
||||||
|
SEMAPHORE_ADMIN_EMAIL: ${SEMAPHORE_ADMIN_EMAIL}
|
||||||
|
SEMAPHORE_ADMIN: ${SEMAPHORE_ADMIN}
|
||||||
|
SEMAPHORE_ACCESS_KEY_ENCRYPTION: ${SEMAPHORE_ACCESS_KEY_ENCRYPTION}
|
||||||
|
TZ: ${TZ}
|
||||||
|
volumes:
|
||||||
|
- /path/to/semaphore/requirements.txt:/etc/semaphore/requirements.txt
|
||||||
|
depends_on:
|
||||||
|
- mysql # for postgres, change to: postgres
|
||||||
|
volumes:
|
||||||
|
semaphore-mysql: # to use postgres, switch to: semaphore-postgres
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
services:
|
||||||
|
speedtest-tracker:
|
||||||
|
container_name: speedtest-tracker
|
||||||
|
image: lscr.io/linuxserver/speedtest-tracker:latest
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
environment:
|
||||||
|
- PUID=PUID
|
||||||
|
- PGID=PGID
|
||||||
|
- TZ=timezone
|
||||||
|
- APP_KEY=${APP_KEY} # Application key for Laravel framework security. Generate a App Key here - https://speedtest-tracker.dev
|
||||||
|
- APP_URL=${APP_URL} # Public URL where the Speedtest Tracker will be accessible.
|
||||||
|
- DB_CONNECTION=sqlite # Uses SQLite as the database.
|
||||||
|
- SPEEDTEST_SCHEDULE="0 */3 * * *" # Cron schedule, runs every 3 hours.
|
||||||
|
- DISPLAY_TIMEZONE=${DISPLAY_TIMEZONE} # Sets the timezone for displaying data in the UI.
|
||||||
|
volumes:
|
||||||
|
- /path/to/speedtest-tracker/data:/config # Mounts the directory for persistent data.
|
||||||
|
restart: unless-stopped
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
version: '3'
|
||||||
|
services:
|
||||||
|
uptime-kuma:
|
||||||
|
image: louislam/uptime-kuma:latest
|
||||||
|
container_name: uptime-kuma
|
||||||
|
environment:
|
||||||
|
- PUID=PUID
|
||||||
|
- PGID=PGID
|
||||||
|
- TZ=timezone
|
||||||
|
volumes:
|
||||||
|
- /path/to/uptime-kuma:/app/data
|
||||||
|
ports:
|
||||||
|
- 3001:3001
|
||||||
|
restart: always
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
services:
|
||||||
|
bitwarden:
|
||||||
|
image: vaultwarden/server:latest
|
||||||
|
container_name: vaultwarden
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- 80:80
|
||||||
|
volumes:
|
||||||
|
- /path/to/bw-data:/data
|
||||||
|
environment:
|
||||||
|
- PUID=PUID
|
||||||
|
- PGID=PGID
|
||||||
|
- TZ=timezone
|
||||||
|
- WEBSOCKET_ENABLED='true' # Required to use websockets
|
||||||
|
- SIGNUPS_ALLOWED='true' # set to false to disable signups
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
services:
|
||||||
|
whoogle:
|
||||||
|
image: benbusby/whoogle-search:latest
|
||||||
|
container_name: whoogle
|
||||||
|
environment:
|
||||||
|
- PUID=PUID
|
||||||
|
- PGID=PGID
|
||||||
|
- TZ=timezone
|
||||||
|
ports:
|
||||||
|
- 5000:5000
|
||||||
|
restart: unless-stopped
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
asupersecretpasswordfor ansiblevaultunlock
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Coming Soon...
|
||||||
|
|
||||||
|
There will soon be a full write-up of the way that the Ansible Roles and Tags laid out during the VM creation via Terraform, is used to configure a VM based on very specific use cases and criteria. The way I have designed the entire workflow is condusive to having a secure Packer built ISO expanded in its capabilites simply by the addition of a new Ansible Role and Tag.
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
[defaults]
|
||||||
|
inventory = ./inventory.ini
|
||||||
|
roles_path = ./roles:./roles/bootstrap_roles:./roles/cis_hardening:./roles/kestra:./roles/monitoring:./roles/secure_vault:./roles/wazuh_docker
|
||||||
|
ansible_python_interpreter = /path/to/ansible-modern/bin/python3
|
||||||
|
collections_paths = /path/to/ansible-modern/lib64/python3.11/site-packages/ansible_collections:/path/to/ansible_collections:/usr/share/ansible/collections
|
||||||
|
remote_user = ansible
|
||||||
|
private_key_file = /path/to/.ssh/key_file
|
||||||
|
host_key_checking = False
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
roles_metadata: "{{ lookup('file', 'roles_metadata.yml') | from_yaml }}"
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
$ANSIBLE_VAULT;1.1;AES256
|
||||||
|
64373439343462336430396135326665346633343564656532636363356339326561643161353635
|
||||||
|
3636363336663638373932643830646634366336366363370a616235646239386166343964636336
|
||||||
|
66303364663462396235626566613266313561376466646631346464653564623630333137383536
|
||||||
|
3630363935333333390a633633333264323834323863623035626662326639663731323938633534
|
||||||
|
65303062303837636430346435316538336434386464373836336538633933633465376162333138
|
||||||
|
63626433643734633634363433666139653736306630393031653566666362343833363936383265
|
||||||
|
38656136636434653135633561323839656337623963393731663762333836343665323239356536
|
||||||
|
35663433316535313063323264316338353761323537393035373338376634656265363361623037
|
||||||
|
32323935333262373437373662646538613665626265626534333862616138373361666639376437
|
||||||
|
36613238336332313734316235363265636164363566326636646534646561363666333637323737
|
||||||
|
63313336623130306636383362646138656130383661633738623365663762393761306164333536
|
||||||
|
39356564636164306332333763663461343462653562343330623862363131653863333363333332
|
||||||
|
3162
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
# VM metadata from Terraform provisioning
|
||||||
|
vmid: id number here
|
||||||
|
vm_name: "vm name"
|
||||||
|
target_node: "hypervisor node name"
|
||||||
|
template: "template-name"
|
||||||
|
cores: 4
|
||||||
|
sockets: 1
|
||||||
|
memory: 57344
|
||||||
|
bridge: vmbr0
|
||||||
|
macaddr: "xx:x:x:x:x:x"
|
||||||
|
disk_size: 250GB
|
||||||
|
disk_storage: "storage name here"
|
||||||
|
ip: xx.xx.xx.xx
|
||||||
|
vlan: 0
|
||||||
|
vm_tags:
|
||||||
|
- packages
|
||||||
|
- hostname_network
|
||||||
|
- root_password
|
||||||
|
- disk_resize
|
||||||
|
- base_users
|
||||||
|
- firewall_ssh
|
||||||
|
- endlessh
|
||||||
|
- zsh_custom
|
||||||
|
- ssh_hardening
|
||||||
|
- banners
|
||||||
|
- file_permissions
|
||||||
|
- service_disable
|
||||||
|
- kernel_hardening
|
||||||
|
- docker_gitlab_setup
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
# VM metadata from Terraform provisioning
|
||||||
|
vmid: id number here
|
||||||
|
vm_name: "vm name"
|
||||||
|
target_node: "hypervisor node name"
|
||||||
|
template: "template-name"
|
||||||
|
cores: 1
|
||||||
|
sockets: 1
|
||||||
|
memory: 4096
|
||||||
|
bridge: vmbr0
|
||||||
|
macaddr: "xx:x:x:x:x:x"
|
||||||
|
disk_size: 20GB
|
||||||
|
disk_storage: "storage name here"
|
||||||
|
ip: xx.xx.xx.xx
|
||||||
|
vlan: 0
|
||||||
|
vm_tags:
|
||||||
|
- packages
|
||||||
|
- hostname_network
|
||||||
|
- root_password
|
||||||
|
- disk_resize
|
||||||
|
- base_users
|
||||||
|
- firewall_ssh
|
||||||
|
- endlessh
|
||||||
|
- zsh_custom
|
||||||
|
- vault_agent
|
||||||
|
- haproxy
|
||||||
|
- ssh_hardening
|
||||||
|
- banners
|
||||||
|
- file_permissions
|
||||||
|
- service_disable
|
||||||
|
- kernel_hardening
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
all:
|
||||||
|
hosts:
|
||||||
|
haproxy:
|
||||||
|
ansible_host: xx.xx.xx.xx
|
||||||
|
ansible_port: xxxx
|
||||||
|
initialized: true
|
||||||
|
service: haproxy
|
||||||
|
docker:
|
||||||
|
ansible_host: xx.xx.xx.xx
|
||||||
|
ansible_port: xxxx
|
||||||
|
initialized: true
|
||||||
|
service: docker
|
||||||
|
vars:
|
||||||
|
ansible_python_interpreter: /usr/bin/python3
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
all:
|
||||||
|
vars:
|
||||||
|
ansible_python_interpreter: /usr/bin/python3
|
||||||
|
hosts:
|
||||||
|
haproxy:
|
||||||
|
ansible_host: xx.xx.xx.xx
|
||||||
|
ansible_port: 22
|
||||||
|
service: haproxy
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
---
|
||||||
|
- name: Compliance stage
|
||||||
|
hosts: all
|
||||||
|
become: true
|
||||||
|
gather_facts: true
|
||||||
|
|
||||||
|
vars:
|
||||||
|
stage_name: compliance
|
||||||
|
|
||||||
|
vars_files:
|
||||||
|
- /path/to/Infrastrucutre as Code/ansible/roles_metadata.yml
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Run roles for this stage
|
||||||
|
ansible.builtin.include_role:
|
||||||
|
name: "{{ item }}"
|
||||||
|
loop: >-
|
||||||
|
{{
|
||||||
|
vm_tags
|
||||||
|
| select('in',
|
||||||
|
roles_metadata
|
||||||
|
| dict2items
|
||||||
|
| selectattr('value.' ~ stage_name, 'defined')
|
||||||
|
| selectattr('value.' ~ stage_name)
|
||||||
|
| map(attribute='key')
|
||||||
|
| list
|
||||||
|
)
|
||||||
|
| list
|
||||||
|
}}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
---
|
||||||
|
- name: Initialization stage
|
||||||
|
hosts: all
|
||||||
|
become: true
|
||||||
|
gather_facts: true
|
||||||
|
|
||||||
|
vars:
|
||||||
|
stage_name: initialization
|
||||||
|
inventory_init: "/path/to/Infrastrucutre as Code/ansible/inventory_initialization.yml"
|
||||||
|
inventory_active: "/path/to/Infrastrucutre as Code/ansible/inventory.yml"
|
||||||
|
|
||||||
|
vars_files:
|
||||||
|
- /path/to/Infrastrucutre as Code/ansible/roles_metadata.yml
|
||||||
|
- /path/to/Infrastrucutre as Code/ansible/group_vars/all/vault_token.yml
|
||||||
|
|
||||||
|
pre_tasks:
|
||||||
|
- name: Ensure active inventory exists
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ inventory_active }}"
|
||||||
|
state: touch
|
||||||
|
delegate_to: localhost
|
||||||
|
run_once: true
|
||||||
|
|
||||||
|
- name: Load existing active inventory
|
||||||
|
ansible.builtin.slurp:
|
||||||
|
src: "{{ inventory_active }}"
|
||||||
|
register: active_inv_raw
|
||||||
|
delegate_to: localhost
|
||||||
|
run_once: true
|
||||||
|
|
||||||
|
- name: Parse active inventory YAML (or initialize empty)
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
active_inventory: >-
|
||||||
|
{{
|
||||||
|
(active_inv_raw.content | b64decode | from_yaml)
|
||||||
|
if (active_inv_raw.content | b64decode | from_yaml is mapping)
|
||||||
|
else {'all': {'hosts': {}}}
|
||||||
|
}}
|
||||||
|
run_once: true
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Run initialization roles for uninitialized hosts
|
||||||
|
ansible.builtin.include_role:
|
||||||
|
name: "{{ item }}"
|
||||||
|
loop: >-
|
||||||
|
{{
|
||||||
|
vm_tags
|
||||||
|
| select('in',
|
||||||
|
roles_metadata
|
||||||
|
| dict2items
|
||||||
|
| selectattr('value.' ~ stage_name, 'defined')
|
||||||
|
| selectattr('value.' ~ stage_name)
|
||||||
|
| map(attribute='key')
|
||||||
|
| list
|
||||||
|
)
|
||||||
|
| list
|
||||||
|
}}
|
||||||
|
|
||||||
|
post_tasks:
|
||||||
|
- name: Append or update host in active inventory
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
active_inventory: >-
|
||||||
|
{{
|
||||||
|
active_inventory |
|
||||||
|
combine({
|
||||||
|
'all': {
|
||||||
|
'hosts': (
|
||||||
|
active_inventory.all.hosts |
|
||||||
|
combine({
|
||||||
|
inventory_hostname: {
|
||||||
|
'ansible_host': hostvars[inventory_hostname]['ansible_host'],
|
||||||
|
'ansible_port': hostvars[inventory_hostname]['ssh_port'] | default(22),
|
||||||
|
'initialized': true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}, recursive=True)
|
||||||
|
}}
|
||||||
|
delegate_to: localhost
|
||||||
|
|
||||||
|
- name: Write updated active inventory back to file
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: "{{ inventory_active }}"
|
||||||
|
content: "{{ active_inventory | to_nice_yaml }}"
|
||||||
|
delegate_to: localhost
|
||||||
|
run_once: true
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
---
|
||||||
|
- name: Provisioning stage
|
||||||
|
hosts: all
|
||||||
|
become: true
|
||||||
|
gather_facts: true
|
||||||
|
|
||||||
|
vars:
|
||||||
|
stage_name: provisioning
|
||||||
|
|
||||||
|
vars_files:
|
||||||
|
- /path/to/Infrastrucutre as Code/ansible/roles_metadata.yml
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Run roles for this stage
|
||||||
|
ansible.builtin.include_role:
|
||||||
|
name: "{{ item }}"
|
||||||
|
loop: >-
|
||||||
|
{{
|
||||||
|
vm_tags
|
||||||
|
| select('in',
|
||||||
|
roles_metadata
|
||||||
|
| dict2items
|
||||||
|
| selectattr('value.' ~ stage_name, 'defined')
|
||||||
|
| selectattr('value.' ~ stage_name)
|
||||||
|
| map(attribute='key')
|
||||||
|
| list
|
||||||
|
)
|
||||||
|
| list
|
||||||
|
}}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
collections:
|
||||||
|
- name: community.hashi_vault
|
||||||
|
- name: community.general
|
||||||
|
- name: ansible.posix
|
||||||
|
- name: community.crypto
|
||||||
|
- name: community.dns
|
||||||
|
- name: middleware_automation.keycloak
|
||||||
|
- name: community.network
|
||||||
|
- name: community.docker
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
- name: Configure default home directory and shell for system users
|
||||||
|
block:
|
||||||
|
- name: Set default home directory and shell for system users
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/default/useradd
|
||||||
|
regexp: "^{{ setting.key }}="
|
||||||
|
line: "{{ setting.key }}={{ setting.value }}"
|
||||||
|
create: yes
|
||||||
|
backup: yes
|
||||||
|
loop:
|
||||||
|
- { key: "HOME", value: "/nonexistent" }
|
||||||
|
- { key: "SHELL", value: "/sbin/nologin" }
|
||||||
|
loop_control:
|
||||||
|
loop_var: setting
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
- name: Expand disk and root filesystem
|
||||||
|
block:
|
||||||
|
- name: Attempt to grow partition (safe if already full)
|
||||||
|
command: growpart /dev/sda 2
|
||||||
|
register: growpart_result
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: Determine if partition actually grew
|
||||||
|
set_fact:
|
||||||
|
partition_grew: >-
|
||||||
|
{{ growpart_result.rc == 0 and
|
||||||
|
(growpart_result.stdout is defined and 'NOCHANGE' not in growpart_result.stdout) }}
|
||||||
|
|
||||||
|
- name: Resize LVM physical volume if needed
|
||||||
|
command: pvresize /dev/sda2
|
||||||
|
when: partition_grew
|
||||||
|
register: pvresize_result
|
||||||
|
changed_when: "'Physical volume' in pvresize_result.stdout and 'resized' in pvresize_result.stdout"
|
||||||
|
|
||||||
|
- name: Extend logical volume if needed
|
||||||
|
command: lvextend -l +100%FREE /dev/mapper/rocky-lv_root
|
||||||
|
when: partition_grew
|
||||||
|
register: lvextend_result
|
||||||
|
changed_when: lvextend_result.rc == 0 and "'0 extents found" not in lvextend_result.stderr
|
||||||
|
|
||||||
|
- name: Grow the XFS filesystem if needed
|
||||||
|
command: xfs_growfs /
|
||||||
|
when: partition_grew and (lvextend_result is changed or lvextend_result is not defined)
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
docker_old_root: "/var/lib/docker"
|
||||||
|
docker_new_root_base: "/opt/docker/docker_data"
|
||||||
|
docker_new_root: "{{ docker_new_root_base }}/docker"
|
||||||
|
|
||||||
|
docker_volumes_dir: "/opt/docker/docker_volumes"
|
||||||
|
docker_homelab_dir: "/opt/docker/homelab"
|
||||||
|
|
||||||
|
docker_volumes_owner: "user"
|
||||||
|
docker_volumes_group: "group"
|
||||||
|
|
||||||
|
git_repo_url: "[email protected]:USER/REPO.git"
|
||||||
|
git_repo_version: "main"
|
||||||
|
|
||||||
|
ssh_key_path: "/home/USER/.ssh/id_rsa"
|
||||||
|
git_repo_owner: "user"
|
||||||
|
git_repo_group: "group"
|
||||||
|
|
||||||
|
docker_daemon_conf: "/etc/docker/daemon.json"
|
||||||
|
daemon_json_template: |
|
||||||
|
{
|
||||||
|
"data-root": "{{ docker_new_root }}"
|
||||||
|
}
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
- name: restart docker
|
||||||
|
service:
|
||||||
|
name: docker
|
||||||
|
state: restarted
|
||||||
+75
@@ -0,0 +1,75 @@
|
|||||||
|
---
|
||||||
|
# 1. Ensure SSH key exists so git clone works
|
||||||
|
- name: Ensure .ssh directory exists
|
||||||
|
file:
|
||||||
|
path: "{{ ssh_key_path | dirname }}"
|
||||||
|
state: directory
|
||||||
|
owner: "user"
|
||||||
|
group: "user"
|
||||||
|
mode: "0700"
|
||||||
|
|
||||||
|
- name: Ensure SSH key exists (don't overwrite)
|
||||||
|
copy:
|
||||||
|
src: "{{ ssh_key_path }}"
|
||||||
|
dest: "{{ ssh_key_path }}"
|
||||||
|
owner: "user"
|
||||||
|
group: "user"
|
||||||
|
mode: "0600"
|
||||||
|
|
||||||
|
# 2. Ensure docker_data directory exists
|
||||||
|
- name: Ensure new Docker data root base exists
|
||||||
|
file:
|
||||||
|
path: "{{ docker_new_root_base }}"
|
||||||
|
state: directory
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
# 3. Stop Docker ONLY if /var/lib/docker still exists
|
||||||
|
- name: Stop Docker if old root exists
|
||||||
|
service:
|
||||||
|
name: docker
|
||||||
|
state: stopped
|
||||||
|
when: docker_old_root is exists
|
||||||
|
|
||||||
|
# 4. Move /var/lib/docker → new location (idempotent)
|
||||||
|
- name: Move Docker data root to new location
|
||||||
|
command: "mv {{ docker_old_root }} {{ docker_new_root }}"
|
||||||
|
args:
|
||||||
|
creates: "{{ docker_new_root }}"
|
||||||
|
when: docker_old_root is exists
|
||||||
|
|
||||||
|
# 5. Ensure daemon.json points to new data-root
|
||||||
|
- name: Configure Docker daemon.json
|
||||||
|
copy:
|
||||||
|
dest: "{{ docker_daemon_conf }}"
|
||||||
|
content: "{{ daemon_json_template }}"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0644"
|
||||||
|
notify: restart docker
|
||||||
|
|
||||||
|
# 6. Ensure docker_volumes exists
|
||||||
|
- name: Ensure docker_volumes directory exists
|
||||||
|
file:
|
||||||
|
path: "{{ docker_volumes_dir }}"
|
||||||
|
state: directory
|
||||||
|
owner: "{{ docker_volumes_owner }}"
|
||||||
|
group: "{{ docker_volumes_group }}"
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
# 7. Ensure homelab directory exists
|
||||||
|
- name: Ensure homelab directory exists
|
||||||
|
file:
|
||||||
|
path: "{{ docker_homelab_dir }}"
|
||||||
|
state: directory
|
||||||
|
owner: "{{ git_repo_owner }}"
|
||||||
|
group: "{{ git_repo_group }}"
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
# 8. Start Docker if it was stopped
|
||||||
|
- name: Start Docker
|
||||||
|
service:
|
||||||
|
name: docker
|
||||||
|
state: started
|
||||||
|
when: docker_new_root is exists
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
endlessh_port: 22
|
||||||
|
endlessh_repo: https://github.com/skeeto/endlessh.git
|
||||||
|
endlessh_clone_path: /usr/local/src/endlessh
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
---
|
||||||
|
- name: Ensure endlessh group exists
|
||||||
|
ansible.builtin.group:
|
||||||
|
name: endlessh
|
||||||
|
system: true
|
||||||
|
|
||||||
|
- name: Ensure endlessh user exists
|
||||||
|
ansible.builtin.user:
|
||||||
|
name: endlessh
|
||||||
|
group: endlessh
|
||||||
|
system: true
|
||||||
|
shell: /usr/sbin/nologin
|
||||||
|
create_home: false
|
||||||
|
|
||||||
|
- name: Ensure Endlessh repo is cloned and updated
|
||||||
|
ansible.builtin.git:
|
||||||
|
repo: "{{ endlessh_repo }}"
|
||||||
|
dest: "{{ endlessh_clone_path }}"
|
||||||
|
version: master
|
||||||
|
update: yes
|
||||||
|
register: git_result
|
||||||
|
|
||||||
|
- name: Build Endlessh if repo was updated
|
||||||
|
ansible.builtin.command: make
|
||||||
|
args:
|
||||||
|
chdir: "{{ endlessh_clone_path }}"
|
||||||
|
when: git_result.after != git_result.before
|
||||||
|
register: make_result
|
||||||
|
# no changed_when needed; we'll rely on the copy step to track changes
|
||||||
|
|
||||||
|
- name: Copy Endlessh binary to /usr/local/bin if updated
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: "{{ endlessh_clone_path }}/endlessh"
|
||||||
|
dest: /usr/local/bin/endlessh
|
||||||
|
mode: "0755"
|
||||||
|
remote_src: true
|
||||||
|
when: git_result.after != git_result.before
|
||||||
|
register: copy_result
|
||||||
|
|
||||||
|
- name: Create Endlessh config directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /etc/endlessh
|
||||||
|
state: directory
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Deploy Endlessh config
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: endlessh_config.j2
|
||||||
|
dest: /etc/endlessh/config
|
||||||
|
mode: "0644"
|
||||||
|
|
||||||
|
- name: Deploy Endlessh systemd service
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: endlessh.service.j2
|
||||||
|
dest: /etc/systemd/system/endlessh.service
|
||||||
|
mode: "0644"
|
||||||
|
|
||||||
|
- name: Reload systemd daemon
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
daemon_reload: true
|
||||||
|
|
||||||
|
- name: Restart Endlessh if binary updated
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: endlessh
|
||||||
|
enabled: true
|
||||||
|
state: restarted
|
||||||
|
when: copy_result is changed
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Endlessh SSH Tarpit
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/usr/local/bin/endlessh -f /etc/endlessh/config
|
||||||
|
Restart=always
|
||||||
|
User=endlessh
|
||||||
|
Group=endlessh
|
||||||
|
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||||
|
NoNewPrivileges=true
|
||||||
|
ProtectSystem=full
|
||||||
|
ProtectHome=true
|
||||||
|
PrivateTmp=true
|
||||||
|
RestrictAddressFamilies=AF_INET AF_INET6
|
||||||
|
ReadWritePaths=/etc/endlessh
|
||||||
|
LockPersonality=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
Port {{ endlessh_port }}
|
||||||
|
Delay 10000
|
||||||
|
MaxLineLength 32
|
||||||
|
MaxClients 4096
|
||||||
|
LogLevel 1
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
# Customize if needed; this defaults to port 22 for endlessh
|
||||||
|
endlessh_port: 22
|
||||||
|
# The SSH port will be dynamically computed as: 10000 + (vmid % 100)
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
---
|
||||||
|
- name: Configure firewall and SSH port
|
||||||
|
block:
|
||||||
|
- name: Fail if vmid is not defined
|
||||||
|
ansible.builtin.fail:
|
||||||
|
msg: "'vmid' must be defined to calculate dynamic SSH port"
|
||||||
|
when: vmid is not defined
|
||||||
|
|
||||||
|
- name: Calculate SSH port from vmid
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
ssh_port: "{{ 10000 + (vmid | int % 100) }}"
|
||||||
|
|
||||||
|
- name: Enable and start firewalld
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: firewalld
|
||||||
|
state: started
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
- name: Set firewalld default zone to drop
|
||||||
|
ansible.posix.firewalld:
|
||||||
|
zone: public
|
||||||
|
state: enabled
|
||||||
|
permanent: yes
|
||||||
|
target: DROP
|
||||||
|
|
||||||
|
- name: Reload firewalld to apply permanent changes
|
||||||
|
ansible.builtin.command: firewall-cmd --reload
|
||||||
|
|
||||||
|
- name: Allow custom SSH port in firewalld
|
||||||
|
ansible.posix.firewalld:
|
||||||
|
port: "{{ ssh_port }}/tcp"
|
||||||
|
permanent: true
|
||||||
|
state: enabled
|
||||||
|
immediate: true
|
||||||
|
|
||||||
|
- name: Allow Endlessh port in firewalld
|
||||||
|
ansible.posix.firewalld:
|
||||||
|
port: "{{ endlessh_port }}/tcp"
|
||||||
|
permanent: true
|
||||||
|
state: enabled
|
||||||
|
immediate: true
|
||||||
|
|
||||||
|
- name: Ensure custom SSH port is set in sshd_config
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/ssh/sshd_config
|
||||||
|
regexp: '^#?Port\s+'
|
||||||
|
line: "Port {{ ssh_port }}"
|
||||||
|
backup: yes
|
||||||
|
validate: "/usr/sbin/sshd -T -f %s"
|
||||||
|
register: sshd_config_changed
|
||||||
|
|
||||||
|
- name: Gather SELinux facts
|
||||||
|
ansible.builtin.setup:
|
||||||
|
filter: ansible_selinux
|
||||||
|
|
||||||
|
- name: Allow SSH to use custom port in SELinux
|
||||||
|
ansible.builtin.command: >
|
||||||
|
semanage port -a -t ssh_port_t -p tcp {{ ssh_port }}
|
||||||
|
register: semanage_result
|
||||||
|
failed_when: semanage_result.rc not in [0, 1]
|
||||||
|
changed_when: semanage_result.rc == 0
|
||||||
|
when: ansible_selinux.status == "enabled"
|
||||||
|
|
||||||
|
- name: Restart and enable sshd service if needed
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: sshd
|
||||||
|
state: restarted
|
||||||
|
enabled: true
|
||||||
|
when: sshd_config_changed is changed
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
---
|
||||||
|
- name: Set hostname and update /etc/hosts
|
||||||
|
vars:
|
||||||
|
default_domain: subdomain.domain
|
||||||
|
block:
|
||||||
|
- name: Set hostname fact
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
short_hostname: "{{ vm_name }}"
|
||||||
|
custom_hostname: "{{ vm_name }}.{{ default_domain }}"
|
||||||
|
|
||||||
|
- name: Set system hostname
|
||||||
|
ansible.builtin.hostname:
|
||||||
|
name: "{{ custom_hostname }}"
|
||||||
|
|
||||||
|
- name: Ensure /etc/hosts contains loopback entry for hostname
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/hosts
|
||||||
|
regexp: '^127\.0\.1\.1\s+'
|
||||||
|
line: "127.0.1.1 {{ custom_hostname }} {{ short_hostname }}"
|
||||||
|
state: present
|
||||||
|
create: yes
|
||||||
|
|
||||||
|
- name: Ensure /etc/hosts contains primary network IP entry
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/hosts
|
||||||
|
regexp: '^{{ ip }}\s+'
|
||||||
|
line: "{{ ip }} {{ custom_hostname }} {{ short_hostname }}"
|
||||||
|
state: present
|
||||||
|
create: yes
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
base_packages:
|
||||||
|
- firewalld
|
||||||
|
- policycoreutils-python-utils
|
||||||
|
- git
|
||||||
|
- make
|
||||||
|
- gcc
|
||||||
|
- cloud-utils-growpart
|
||||||
|
- lvm2
|
||||||
|
- xfsprogs
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
- name: Package management tasks
|
||||||
|
tags: [packages]
|
||||||
|
block:
|
||||||
|
- name: Clean all cached metadata
|
||||||
|
ansible.builtin.command: dnf clean all
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Rebuild the DNF cache
|
||||||
|
ansible.builtin.command: dnf makecache
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Update all packages to latest
|
||||||
|
ansible.builtin.dnf:
|
||||||
|
name: "*"
|
||||||
|
state: latest
|
||||||
|
update_cache: true
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Reboot if kernel was upgraded
|
||||||
|
ansible.builtin.reboot:
|
||||||
|
reboot_timeout: 120
|
||||||
|
pre_reboot_delay: 10
|
||||||
|
when: ansible_facts.packages['kernel'] is defined
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Install base system packages
|
||||||
|
ansible.builtin.package:
|
||||||
|
name: "{{ base_packages }}"
|
||||||
|
state: present
|
||||||
|
update_cache: true
|
||||||
|
become: true
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
- name: Set Portainer Agent installation directory
|
||||||
|
vars:
|
||||||
|
portainer_agent_dir: /opt/portainer-agent
|
||||||
|
block:
|
||||||
|
- name: Create Portainer Agent directory
|
||||||
|
become: true
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ portainer_agent_dir }}"
|
||||||
|
state: directory
|
||||||
|
owner: user
|
||||||
|
group: user
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Create Portainer Agent docker-compose file
|
||||||
|
become: true
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: "{{ portainer_agent_dir }}/docker-compose.yml"
|
||||||
|
owner: user
|
||||||
|
group: user
|
||||||
|
mode: "0644"
|
||||||
|
content: |
|
||||||
|
services:
|
||||||
|
agent:
|
||||||
|
image: portainer/agent:latest
|
||||||
|
container_name: portainer_agent
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "9001:9001"
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
- /var/lib/docker/volumes:/var/lib/docker/volumes
|
||||||
|
|
||||||
|
- name: Ensure Portainer Agent is running
|
||||||
|
become: true
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ portainer_agent_dir }}"
|
||||||
|
state: present # ensures containers exist
|
||||||
|
recreate: always # recreates if the definition changed
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
root_password_plain: "{{ lookup('env', 'ROOT_PASSWORD') }}"
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
- name: Set root password
|
||||||
|
block:
|
||||||
|
- name: Fail if root password is not defined
|
||||||
|
fail:
|
||||||
|
msg: "The variable 'root_password_plain' must be provided (e.g., via GitLab CI/CD Variable)"
|
||||||
|
when: root_password_plain is not defined
|
||||||
|
|
||||||
|
- name: Generate root password hash
|
||||||
|
set_fact:
|
||||||
|
root_password_hash: "{{ root_password_plain | password_hash('sha512') }}"
|
||||||
|
|
||||||
|
- name: Set root user password
|
||||||
|
user:
|
||||||
|
name: root
|
||||||
|
password: "{{ root_password_hash }}"
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
---
|
||||||
|
- name: Customize Zsh for users
|
||||||
|
vars:
|
||||||
|
zsh_users:
|
||||||
|
- user
|
||||||
|
|
||||||
|
block:
|
||||||
|
- name: Ensure parent home directory exists (safety)
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "/home/{{ user }}"
|
||||||
|
state: directory
|
||||||
|
owner: "{{ user }}"
|
||||||
|
group: "{{ user }}"
|
||||||
|
mode: "0755"
|
||||||
|
loop: "{{ zsh_users }}"
|
||||||
|
loop_control:
|
||||||
|
loop_var: user
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Remove any old oh-my-zsh
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "/home/{{ user }}/.oh-my-zsh"
|
||||||
|
state: absent
|
||||||
|
loop: "{{ zsh_users }}"
|
||||||
|
loop_control:
|
||||||
|
loop_var: user
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Clone Oh My Zsh as root
|
||||||
|
ansible.builtin.git:
|
||||||
|
repo: "https://github.com/ohmyzsh/ohmyzsh.git"
|
||||||
|
dest: "/home/{{ user }}/.oh-my-zsh"
|
||||||
|
version: master
|
||||||
|
update: yes
|
||||||
|
force: yes
|
||||||
|
loop: "{{ zsh_users }}"
|
||||||
|
loop_control:
|
||||||
|
loop_var: user
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Add trusted safe.directory system-wide for Oh My Zsh
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: git config --system --add safe.directory /home/{{ user }}/.oh-my-zsh
|
||||||
|
loop: "{{ zsh_users }}"
|
||||||
|
loop_control:
|
||||||
|
loop_var: user
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Install syntax-highlighting plugin
|
||||||
|
ansible.builtin.git:
|
||||||
|
repo: "https://github.com/zsh-users/zsh-syntax-highlighting.git"
|
||||||
|
dest: "/home/{{ user }}/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting"
|
||||||
|
version: master
|
||||||
|
update: yes
|
||||||
|
force: yes
|
||||||
|
loop: "{{ zsh_users }}"
|
||||||
|
loop_control:
|
||||||
|
loop_var: user
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Deploy customized .zshrc
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: zshrc.j2
|
||||||
|
dest: "/home/{{ user }}/.zshrc"
|
||||||
|
owner: "{{ user }}"
|
||||||
|
group: "{{ user }}"
|
||||||
|
mode: "0644"
|
||||||
|
loop: "{{ zsh_users }}"
|
||||||
|
loop_control:
|
||||||
|
loop_var: user
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Fix ownership recursively for Oh My Zsh directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "/home/{{ user }}/.oh-my-zsh"
|
||||||
|
owner: "{{ user }}"
|
||||||
|
group: "{{ user }}"
|
||||||
|
recurse: yes
|
||||||
|
loop: "{{ zsh_users }}"
|
||||||
|
loop_control:
|
||||||
|
loop_var: user
|
||||||
|
become: true
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
export ZSH="\$HOME/.oh-my-zsh"
|
||||||
|
ZSH_THEME="robbyrussell"
|
||||||
|
plugins=(git zsh-autosuggestions zsh-syntax-highlighting)
|
||||||
|
source \$ZSH/oh-my-zsh.sh
|
||||||
|
|
||||||
|
# Where to save history and how much to keep
|
||||||
|
HISTFILE=~/.zsh_history
|
||||||
|
HISTSIZE=10000 # In-memory history
|
||||||
|
SAVEHIST=10000 # Lines to save to file
|
||||||
|
|
||||||
|
# Recommended options
|
||||||
|
setopt APPEND_HISTORY # Don’t overwrite history file; append to it
|
||||||
|
setopt SHARE_HISTORY # Share history across all sessions
|
||||||
|
setopt HIST_IGNORE_DUPS # Don’t record duplicate commands
|
||||||
|
setopt HIST_IGNORE_SPACE # Ignore commands starting with a space
|
||||||
|
setopt HIST_VERIFY # Edit a command before running from history
|
||||||
|
setopt INC_APPEND_HISTORY # Write history incrementally as commands are run
|
||||||
|
|
||||||
|
|
||||||
|
PS1='%F{51}%n%F{255}@%F{227}%m %F{84}%~%f %F{15}$ '
|
||||||
|
fastfetch
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
cis_banner: |
|
||||||
|
*********************************************************************
|
||||||
|
* WARNING: Unauthorized access to this system is prohibited. *
|
||||||
|
* All activities are monitored and recorded. *
|
||||||
|
*********************************************************************
|
||||||
|
|
||||||
|
cis_motd_banner: |
|
||||||
|
*********************************************************************
|
||||||
|
* Welcome to the system. Access is restricted to authorized users. *
|
||||||
|
*********************************************************************
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
# Login banners for /etc/motd, /etc/issue, /etc/issue.net
|
||||||
|
|
||||||
|
- name: Ensure /etc/motd contains standard CIS banner
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /etc/motd
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0644"
|
||||||
|
content: "{{ cis_motd_banner }}"
|
||||||
|
|
||||||
|
- name: Ensure /etc/issue contains standard CIS banner
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /etc/issue
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0644"
|
||||||
|
content: "{{ cis_motd_banner }}"
|
||||||
|
|
||||||
|
- name: Ensure /etc/issue.net contains standard CIS banner
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /etc/issue.net
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0644"
|
||||||
|
content: "{{ cis_banner }}"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
# Parent-level defaults
|
||||||
|
cis_tag: cis_hardening
|
||||||
|
audit_rules_file: /etc/audit/rules.d/cis.rules
|
||||||
|
rsyslog_remote: "" # set to "logserver.example.com:514" to forward logs
|
||||||
|
txt_grub_args: "" # additional kernel args if needed, e.g. "audit=1"
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
# Default ownership and permissions for critical files and directories
|
||||||
|
|
||||||
|
file_permissions_list:
|
||||||
|
- { path: "/root", mode: "0700", state: "directory" }
|
||||||
|
- { path: "/etc/passwd", mode: "0644", state: "file" }
|
||||||
|
- { path: "/etc/shadow", mode: "0400", state: "file" }
|
||||||
|
- { path: "/etc/group", mode: "0644", state: "file" }
|
||||||
|
- { path: "/etc/gshadow", mode: "0400", state: "file" }
|
||||||
|
- { path: "/etc/crontab", mode: "0600", state: "file" }
|
||||||
|
- { path: "/etc/cron.hourly", mode: "0700", state: "directory" }
|
||||||
|
- { path: "/etc/cron.daily", mode: "0700", state: "directory" }
|
||||||
|
- { path: "/etc/cron.weekly", mode: "0700", state: "directory" }
|
||||||
|
- { path: "/etc/cron.monthly", mode: "0700", state: "directory" }
|
||||||
|
- { path: "/etc/cron.d", mode: "0700", state: "directory" }
|
||||||
|
- { path: "/etc/rsyslog.conf", mode: "0640", state: "file" }
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
- name: Ensure system files and directories have correct ownership and permissions
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ file_item.path }}"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "{{ file_item.mode }}"
|
||||||
|
state: "{{ file_item.state }}"
|
||||||
|
loop: "{{ file_permissions_list }}"
|
||||||
|
loop_control:
|
||||||
|
loop_var: file_item
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
tmp_mount_options: "defaults,nosuid,nodev,noexec,relatime"
|
||||||
|
var_tmp_mount_options: "defaults,nosuid,nodev,noexec,relatime"
|
||||||
|
home_mount_options: "defaults,nosuid,nodev,relatime"
|
||||||
|
dev_shm_mount_options: "defaults,nosuid,nodev,noexec,relatime"
|
||||||
+34
@@ -0,0 +1,34 @@
|
|||||||
|
---
|
||||||
|
# Remount and persist secure options using defaults variables
|
||||||
|
|
||||||
|
- name: Gather mount facts
|
||||||
|
ansible.builtin.setup:
|
||||||
|
filter: ansible_mounts
|
||||||
|
|
||||||
|
- name: Ensure /tmp has secure mount options
|
||||||
|
ansible.builtin.mount:
|
||||||
|
path: /tmp
|
||||||
|
fstype: "{{ ansible_mounts | selectattr('mount','equalto','/tmp') | map(attribute='fstype') | first }}"
|
||||||
|
opts: "{{ tmp_mount_options }}"
|
||||||
|
state: mounted
|
||||||
|
|
||||||
|
- name: Ensure /var/tmp has secure mount options
|
||||||
|
ansible.builtin.mount:
|
||||||
|
path: /var/tmp
|
||||||
|
fstype: "{{ ansible_mounts | selectattr('mount','equalto','/var/tmp') | map(attribute='fstype') | first }}"
|
||||||
|
opts: "{{ var_tmp_mount_options }}"
|
||||||
|
state: mounted
|
||||||
|
|
||||||
|
- name: Ensure /home has secure mount options
|
||||||
|
ansible.builtin.mount:
|
||||||
|
path: /home
|
||||||
|
fstype: "{{ ansible_mounts | selectattr('mount','equalto','/home') | map(attribute='fstype') | first }}"
|
||||||
|
opts: "{{ home_mount_options }}"
|
||||||
|
state: mounted
|
||||||
|
|
||||||
|
- name: Ensure /dev/shm has secure mount options
|
||||||
|
ansible.builtin.mount:
|
||||||
|
path: /dev/shm
|
||||||
|
fstype: tmpfs
|
||||||
|
opts: "{{ dev_shm_mount_options }}"
|
||||||
|
state: mounted
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
- name: restart rsyslog
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: rsyslog
|
||||||
|
state: restarted
|
||||||
|
|
||||||
|
- name: restart auditd
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: auditd
|
||||||
|
state: restarted
|
||||||
|
|
||||||
|
- name: reload systemd
|
||||||
|
ansible.builtin.command: systemctl daemon-reexec
|
||||||
|
|
||||||
|
- name: update initramfs
|
||||||
|
ansible.builtin.command: dracut -f
|
||||||
|
when: ansible_facts['os_family'] == 'RedHat' or ansible_facts['distribution'] in ['Rocky','RedHat','CentOS']
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
# Kernel defaults (override per host if needed)
|
||||||
|
modprobe_blacklist_file: /etc/modprobe.d/cis_blacklist.conf
|
||||||
|
|
||||||
|
# Additional kernel modules to disable
|
||||||
|
blacklist_modules:
|
||||||
|
- tipc
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
# blacklist_module.yml
|
||||||
|
- name: Check if module {{ mod }} exists on system
|
||||||
|
ansible.builtin.shell: "modprobe -n -v {{ mod }}"
|
||||||
|
register: modprobe_check
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: Blacklist module {{ mod }} in {{ modprobe_blacklist_file }}
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: "{{ modprobe_blacklist_file }}"
|
||||||
|
line: "install {{ mod }} /bin/false"
|
||||||
|
create: yes
|
||||||
|
state: present
|
||||||
|
when: modprobe_check.rc == 0
|
||||||
|
|
||||||
|
- name: Unload module {{ mod }} if currently loaded
|
||||||
|
ansible.builtin.shell: "modprobe -r {{ mod }}"
|
||||||
|
ignore_errors: true
|
||||||
|
when: modprobe_check.rc == 0
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
---
|
||||||
|
# Kernel & sysctl hardening (CIS network/kernel items)
|
||||||
|
|
||||||
|
- name: Ensure IPv4 forwarding is disabled
|
||||||
|
ansible.builtin.sysctl:
|
||||||
|
name: net.ipv4.ip_forward
|
||||||
|
value: "0"
|
||||||
|
state: present
|
||||||
|
reload: yes
|
||||||
|
|
||||||
|
- name: Ensure IPv6 forwarding is disabled
|
||||||
|
ansible.builtin.sysctl:
|
||||||
|
name: net.ipv6.conf.all.forwarding
|
||||||
|
value: "0"
|
||||||
|
state: present
|
||||||
|
reload: yes
|
||||||
|
|
||||||
|
- name: Ensure source routed packets are not accepted
|
||||||
|
ansible.builtin.sysctl:
|
||||||
|
name: net.ipv4.conf.all.accept_source_route
|
||||||
|
value: "0"
|
||||||
|
state: present
|
||||||
|
reload: yes
|
||||||
|
|
||||||
|
- name: Ensure ICMP redirects are not accepted
|
||||||
|
ansible.builtin.sysctl:
|
||||||
|
name: net.ipv4.conf.all.accept_redirects
|
||||||
|
value: "0"
|
||||||
|
state: present
|
||||||
|
reload: yes
|
||||||
|
|
||||||
|
- name: Ensure secure ICMP redirects are not accepted
|
||||||
|
ansible.builtin.sysctl:
|
||||||
|
name: net.ipv4.conf.all.secure_redirects
|
||||||
|
value: "0"
|
||||||
|
state: present
|
||||||
|
reload: yes
|
||||||
|
|
||||||
|
- name: Ensure Address Space Layout Randomization (ASLR) is enabled
|
||||||
|
ansible.builtin.sysctl:
|
||||||
|
name: kernel.randomize_va_space
|
||||||
|
value: "2"
|
||||||
|
state: present
|
||||||
|
reload: yes
|
||||||
|
|
||||||
|
- name: Ensure fs.suid_dumpable is 0 (disable core dumps)
|
||||||
|
ansible.builtin.sysctl:
|
||||||
|
name: fs.suid_dumpable
|
||||||
|
value: "0"
|
||||||
|
state: present
|
||||||
|
reload: yes
|
||||||
|
|
||||||
|
- name: Create /etc/modprobe.d/cis_blacklist.conf with common blacklists
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /etc/modprobe.d/cis_blacklist.conf
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0644"
|
||||||
|
content: |
|
||||||
|
# CIS blacklist
|
||||||
|
install cramfs /bin/true
|
||||||
|
install freevxfs /bin/true
|
||||||
|
install jffs2 /bin/true
|
||||||
|
install hfs /bin/true
|
||||||
|
install hfsplus /bin/true
|
||||||
|
install squashfs /bin/true
|
||||||
|
install udf /bin/true
|
||||||
|
|
||||||
|
- name: Regenerate initramfs if modprobe blacklist changed
|
||||||
|
ansible.builtin.command: dracut -f
|
||||||
|
changed_when: false
|
||||||
|
when: ansible_facts.get('os_family') == 'RedHat' or ansible_facts.get('distribution') in ['Rocky', 'RedHat', 'CentOS']
|
||||||
|
|
||||||
|
- name: Blacklist all modules
|
||||||
|
include_tasks: blacklist_module.yml
|
||||||
|
loop: "{{ blacklist_modules }}"
|
||||||
|
loop_control:
|
||||||
|
loop_var: mod
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
# Password policy defaults
|
||||||
|
pw_minlen: 14
|
||||||
|
pw_minclass: 4
|
||||||
|
pw_max_days: 365
|
||||||
|
pw_min_days: 7
|
||||||
|
pw_warn_age: 7
|
||||||
|
faillock_deny: 5
|
||||||
|
faillock_unlock_time: 900
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
---
|
||||||
|
# Password and PAM related hardening
|
||||||
|
|
||||||
|
- name: Ensure password hashing algorithm is SHA512
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/login.defs
|
||||||
|
regexp: "^ENCRYPT_METHOD"
|
||||||
|
line: "ENCRYPT_METHOD SHA512"
|
||||||
|
create: yes
|
||||||
|
|
||||||
|
- name: Ensure PASS_MAX_DAYS is 365
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/login.defs
|
||||||
|
regexp: "^PASS_MAX_DAYS"
|
||||||
|
line: "PASS_MAX_DAYS 365"
|
||||||
|
create: yes
|
||||||
|
|
||||||
|
- name: Ensure PASS_MIN_DAYS is 7
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/login.defs
|
||||||
|
regexp: "^PASS_MIN_DAYS"
|
||||||
|
line: "PASS_MIN_DAYS 7"
|
||||||
|
create: yes
|
||||||
|
|
||||||
|
- name: Ensure PASS_WARN_AGE is 7
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/login.defs
|
||||||
|
regexp: "^PASS_WARN_AGE"
|
||||||
|
line: "PASS_WARN_AGE 7"
|
||||||
|
create: yes
|
||||||
|
|
||||||
|
- name: Ensure pwquality minlen and requirements
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/security/pwquality.conf
|
||||||
|
regexp: "^minlen"
|
||||||
|
line: "minlen = 14"
|
||||||
|
create: yes
|
||||||
|
|
||||||
|
- name: Ensure pwquality minclass (character classes) is 4
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/security/pwquality.conf
|
||||||
|
regexp: "^minclass"
|
||||||
|
line: "minclass = 4"
|
||||||
|
create: yes
|
||||||
|
|
||||||
|
- name: Ensure pam_faillock preauth is configured
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/pam.d/system-auth
|
||||||
|
insertafter: "^auth.*required.*pam_unix.so"
|
||||||
|
line: "auth required pam_faillock.so preauth silent audit deny=5 unlock_time=900"
|
||||||
|
state: present
|
||||||
|
backrefs: no
|
||||||
|
|
||||||
|
- name: Ensure pam_faillock authfail/account lines exist
|
||||||
|
ansible.builtin.blockinfile:
|
||||||
|
path: /etc/pam.d/system-auth
|
||||||
|
insertafter: "^auth.*required.*pam_unix.so"
|
||||||
|
block: |
|
||||||
|
auth [default=die] pam_faillock.so authfail deny=5 unlock_time=900 audit
|
||||||
|
account required pam_faillock.so
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
unused_services:
|
||||||
|
- avahi-daemon
|
||||||
|
- bluetooth
|
||||||
|
- cups
|
||||||
|
- rpcbind
|
||||||
|
- nfslock
|
||||||
|
- rsh.socket
|
||||||
|
- telnet.socket
|
||||||
|
- rsyncd
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
- name: Ensure list of unnecessary services are stopped and masked
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: "{{ svc }}"
|
||||||
|
enabled: no
|
||||||
|
state: stopped
|
||||||
|
masked: yes
|
||||||
|
loop: "{{ unused_services }}"
|
||||||
|
loop_control:
|
||||||
|
loop_var: svc
|
||||||
|
ignore_errors: true
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
# General settings
|
||||||
|
ssh_protocol: 2
|
||||||
|
ssh_permit_root_login: "no"
|
||||||
|
ssh_password_authentication: "no"
|
||||||
|
ssh_challenge_response_authentication: "no"
|
||||||
|
ssh_kerberos_authentication: "no"
|
||||||
|
ssh_gssapi_authentication: "no"
|
||||||
|
ssh_use_pam: "yes"
|
||||||
|
PrintLastLog: "yes"
|
||||||
|
|
||||||
|
# Session security
|
||||||
|
ssh_x11_forwarding: "no"
|
||||||
|
ssh_allow_tcp_forwarding: "yes"
|
||||||
|
ssh_permit_tunnel: "no"
|
||||||
|
ssh_allow_agent_forwarding: "no"
|
||||||
|
|
||||||
|
# Idle timeout / login attempts
|
||||||
|
ssh_client_alive_interval: 300
|
||||||
|
ssh_client_alive_count_max: 3
|
||||||
|
ssh_login_grace_time: 60
|
||||||
|
ssh_max_auth_tries: 3
|
||||||
|
ssh_max_sessions: 2
|
||||||
|
ssh_max_startups: "10:30:60"
|
||||||
|
|
||||||
|
# SSH access restrictions
|
||||||
|
ssh_allow_users: "adminuser ansibleuser"
|
||||||
|
|
||||||
|
# Strong encryption
|
||||||
|
ssh_ciphers: "aes256-ctr,aes192-ctr,aes128-ctr"
|
||||||
|
ssh_macs: "hmac-sha2-512,hmac-sha2-256"
|
||||||
|
ssh_kex_algorithms: "[email protected],diffie-hellman-group-exchange-sha256"
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
---
|
||||||
|
- name: Ensure OpenSSH server is installed
|
||||||
|
ansible.builtin.package:
|
||||||
|
name: openssh-server
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Ensure SSH daemon is enabled and running
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: sshd
|
||||||
|
enabled: true
|
||||||
|
state: started
|
||||||
|
|
||||||
|
- name: Backup current sshd_config
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: /etc/ssh/sshd_config
|
||||||
|
dest: /etc/ssh/sshd_config.bak
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0600"
|
||||||
|
remote_src: true
|
||||||
|
|
||||||
|
- name: Harden SSH configuration
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/ssh/sshd_config
|
||||||
|
regexp: "{{ ssh_item.regexp }}"
|
||||||
|
line: "{{ ssh_item.line }}"
|
||||||
|
state: present
|
||||||
|
backrefs: yes
|
||||||
|
loop:
|
||||||
|
- regexp: "^#?Protocol"
|
||||||
|
line: "Protocol {{ ssh_protocol }}"
|
||||||
|
- regexp: "^#?PermitRootLogin"
|
||||||
|
line: "PermitRootLogin {{ ssh_permit_root_login }}"
|
||||||
|
- regexp: "^#?PasswordAuthentication"
|
||||||
|
line: "PasswordAuthentication {{ ssh_password_authentication }}"
|
||||||
|
- regexp: "^#?ChallengeResponseAuthentication"
|
||||||
|
line: "ChallengeResponseAuthentication {{ ssh_challenge_response_authentication }}"
|
||||||
|
- regexp: "^#?KerberosAuthentication"
|
||||||
|
line: "KerberosAuthentication {{ ssh_kerberos_authentication }}"
|
||||||
|
- regexp: "^#?GSSAPIAuthentication"
|
||||||
|
line: "GSSAPIAuthentication {{ ssh_gssapi_authentication }}"
|
||||||
|
- regexp: "^#?UsePAM"
|
||||||
|
line: "UsePAM {{ ssh_use_pam }}"
|
||||||
|
- regexp: "^#?X11Forwarding"
|
||||||
|
line: "X11Forwarding {{ ssh_x11_forwarding }}"
|
||||||
|
- regexp: "^#?AllowTcpForwarding"
|
||||||
|
line: "AllowTcpForwarding {{ ssh_allow_tcp_forwarding }}"
|
||||||
|
- regexp: "^#?PermitTunnel"
|
||||||
|
line: "PermitTunnel {{ ssh_permit_tunnel }}"
|
||||||
|
- regexp: "^#?AllowAgentForwarding"
|
||||||
|
line: "AllowAgentForwarding {{ ssh_allow_agent_forwarding }}"
|
||||||
|
- regexp: "^#?ClientAliveInterval"
|
||||||
|
line: "ClientAliveInterval {{ ssh_client_alive_interval }}"
|
||||||
|
- regexp: "^#?ClientAliveCountMax"
|
||||||
|
line: "ClientAliveCountMax {{ ssh_client_alive_count_max }}"
|
||||||
|
- regexp: "^#?LoginGraceTime"
|
||||||
|
line: "LoginGraceTime {{ ssh_login_grace_time }}"
|
||||||
|
- regexp: "^#?MaxAuthTries"
|
||||||
|
line: "MaxAuthTries {{ ssh_max_auth_tries }}"
|
||||||
|
- regexp: "^#?MaxSessions"
|
||||||
|
line: "MaxSessions {{ ssh_max_sessions }}"
|
||||||
|
- regexp: "^#?MaxStartups"
|
||||||
|
line: "MaxStartups {{ ssh_max_startups }}"
|
||||||
|
- regexp: "^#?Ciphers"
|
||||||
|
line: "Ciphers {{ ssh_ciphers }}"
|
||||||
|
- regexp: "^#?MACs"
|
||||||
|
line: "MACs {{ ssh_macs }}"
|
||||||
|
- regexp: "^#?KexAlgorithms"
|
||||||
|
line: "KexAlgorithms {{ ssh_kex_algorithms }}"
|
||||||
|
- regexp: "^#?PrintLastLog"
|
||||||
|
line: "PrintLastLog {{ PrintLastLog }}"
|
||||||
|
- regexp: '^\s*#?\s*AllowUsers'
|
||||||
|
line: "AllowUsers {{ ssh_allow_users }}"
|
||||||
|
- regexp: "^#?Banner"
|
||||||
|
line: "Banner /etc/issue.net"
|
||||||
|
loop_control:
|
||||||
|
loop_var: ssh_item
|
||||||
|
|
||||||
|
- name: Restart SSH service to apply changes
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: sshd
|
||||||
|
state: restarted
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
---
|
||||||
|
# Parent CIS hardening role: import each subrole with single tag
|
||||||
|
- import_role:
|
||||||
|
name: cis_hardening/kernel_hardening
|
||||||
|
tags: [cis_hardening]
|
||||||
|
|
||||||
|
- import_role:
|
||||||
|
name: cis_hardening/password_policy
|
||||||
|
tags: [cis_hardening]
|
||||||
|
|
||||||
|
- import_role:
|
||||||
|
name: cis_hardening/file_permissions
|
||||||
|
tags: [cis_hardening]
|
||||||
|
|
||||||
|
- import_role:
|
||||||
|
name: cis_hardening/service_disable
|
||||||
|
tags: [cis_hardening]
|
||||||
|
|
||||||
|
- import_role:
|
||||||
|
name: cis_hardening/banners
|
||||||
|
tags: [cis_hardening]
|
||||||
|
|
||||||
|
- import_role:
|
||||||
|
name: cis_hardening/ssh_hardening
|
||||||
|
tags: [cis_hardening]
|
||||||
|
|
||||||
|
- import_role:
|
||||||
|
name: cis_hardening/filesystem_hardening
|
||||||
|
tags: [cis_hardening]
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
# Vault connection
|
||||||
|
vault_addr: "http://VAULT_IP:VAULT_PORT"
|
||||||
|
|
||||||
|
# Directory paths
|
||||||
|
haproxy_certs_dir: "/etc/haproxy/certs"
|
||||||
|
haproxy_cert_path: "{{ haproxy_pem_path }}"
|
||||||
|
haproxy_pem_path: "{{ haproxy_certs_dir }}/haproxy.pem"
|
||||||
|
haproxy_ca_path: "{{ haproxy_certs_dir }}/haproxy_ca.crt"
|
||||||
|
|
||||||
|
# Systemd service names
|
||||||
|
haproxy_service: "haproxy"
|
||||||
|
|
||||||
|
# HAProxy tuning
|
||||||
|
haproxy_global_maxconn: 4096
|
||||||
|
haproxy_timeout_connect_ms: 5000
|
||||||
|
haproxy_timeout_client_ms: 60000
|
||||||
|
haproxy_timeout_server_ms: 60000
|
||||||
|
haproxy_enable_hsts: true
|
||||||
|
|
||||||
|
vault_agent_templates:
|
||||||
|
- src: "haproxy.pem.ctmpl"
|
||||||
|
dest: "{{ haproxy_pem_path }}"
|
||||||
|
service: "haproxy"
|
||||||
|
- src: "haproxy_ca.ctmpl"
|
||||||
|
dest: "{{ haproxy_ca_path }}"
|
||||||
|
service: "haproxy"
|
||||||
|
|
||||||
|
# === Services routed internally through HAProxy ===
|
||||||
|
securemtls_services:
|
||||||
|
vault:
|
||||||
|
hostname: vault.local.DOMAIN_PLACEHOLDER
|
||||||
|
balance: roundrobin
|
||||||
|
mode: http
|
||||||
|
timeout_connect: 5s
|
||||||
|
timeout_server: 30s
|
||||||
|
default_server_inter: 3s
|
||||||
|
default_server_rise: 2
|
||||||
|
default_server_fall: 3
|
||||||
|
backend_servers:
|
||||||
|
- address: VAULT_IP
|
||||||
|
port: VAULT_PORT
|
||||||
|
proto: http
|
||||||
|
headers:
|
||||||
|
- "http-request set-header Host vault.local.DOMAIN_PLACEHOLDER"
|
||||||
|
- "http-request set-header X-Forwarded-Proto https"
|
||||||
|
rewrites:
|
||||||
|
- "http-response replace-header Location ^http://VAULT_IP:VAULT_PORT/(.*) https://vault.local.DOMAIN_PLACEHOLDER/\\1"
|
||||||
|
|
||||||
|
technitium:
|
||||||
|
hostname: "technitium.local.DOMAIN_PLACEHOLDER"
|
||||||
|
backend_mode: http
|
||||||
|
backend_servers:
|
||||||
|
- address: TECHNITIUM_IP
|
||||||
|
port: TECHNITIUM_PORT
|
||||||
|
proto: "http"
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
- name: Reload HAProxy
|
||||||
|
systemd:
|
||||||
|
name: haproxy
|
||||||
|
state: reloaded
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
---
|
||||||
|
- name: Install HAProxy
|
||||||
|
dnf:
|
||||||
|
name: haproxy
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Ensure firewalld is running and enabled
|
||||||
|
systemd:
|
||||||
|
name: firewalld
|
||||||
|
enabled: true
|
||||||
|
state: started
|
||||||
|
|
||||||
|
- name: Allow inbound HTTPS (443/tcp)
|
||||||
|
ansible.posix.firewalld:
|
||||||
|
service: https
|
||||||
|
permanent: true
|
||||||
|
state: enabled
|
||||||
|
immediate: true
|
||||||
|
|
||||||
|
- name: Ensure HAProxy certificate directories exist
|
||||||
|
file:
|
||||||
|
path: "{{ cert_dir }}"
|
||||||
|
state: directory
|
||||||
|
owner: haproxy
|
||||||
|
group: haproxy
|
||||||
|
mode: "0750"
|
||||||
|
loop:
|
||||||
|
- "{{ haproxy_certs_dir }}"
|
||||||
|
- "{{ haproxy_certs_dir }}/clients"
|
||||||
|
loop_control:
|
||||||
|
loop_var: cert_dir
|
||||||
|
|
||||||
|
- name: Apply SELinux context for HAProxy certs
|
||||||
|
command: semanage fcontext -a -t etc_t "{{ haproxy_certs_dir }}(/.*)?"
|
||||||
|
become: true
|
||||||
|
register: semanage_fcontext_result
|
||||||
|
failed_when: false
|
||||||
|
changed_when: semanage_fcontext_result.rc == 0
|
||||||
|
|
||||||
|
- name: Restore SELinux context for HAProxy certs
|
||||||
|
command: restorecon -Rv "{{ haproxy_certs_dir }}"
|
||||||
|
become: true
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Allow HAProxy to connect to any port (SELinux)
|
||||||
|
ansible.posix.seboolean:
|
||||||
|
name: haproxy_connect_any
|
||||||
|
state: true
|
||||||
|
persistent: true
|
||||||
|
|
||||||
|
- name: Wait for HAProxy PEM and CA files
|
||||||
|
wait_for:
|
||||||
|
path: "{{ pem_item }}"
|
||||||
|
state: present
|
||||||
|
timeout: 120
|
||||||
|
loop:
|
||||||
|
- "{{ haproxy_pem_path }}"
|
||||||
|
- "{{ haproxy_ca_path }}"
|
||||||
|
loop_control:
|
||||||
|
loop_var: pem_item
|
||||||
|
|
||||||
|
- name: Ensure permissions for HAProxy certs
|
||||||
|
file:
|
||||||
|
path: "{{ cert_item }}"
|
||||||
|
owner: haproxy
|
||||||
|
group: haproxy
|
||||||
|
mode: "0644"
|
||||||
|
loop:
|
||||||
|
- "{{ haproxy_pem_path }}"
|
||||||
|
- "{{ haproxy_ca_path }}"
|
||||||
|
loop_control:
|
||||||
|
loop_var: cert_item
|
||||||
|
|
||||||
|
- name: Deploy HAProxy configuration
|
||||||
|
template:
|
||||||
|
src: haproxy.cfg.j2
|
||||||
|
dest: /etc/haproxy/haproxy.cfg
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0644"
|
||||||
|
notify: Reload HAProxy
|
||||||
|
|
||||||
|
- name: Ensure HAProxy service starts after vault-agent
|
||||||
|
lineinfile:
|
||||||
|
path: /usr/lib/systemd/system/haproxy.service
|
||||||
|
regexp: "^After="
|
||||||
|
line: "After=network-online.target vault-agent.service"
|
||||||
|
backup: yes
|
||||||
|
|
||||||
|
- name: Reload systemd daemon
|
||||||
|
command: systemctl daemon-reload
|
||||||
|
|
||||||
|
- name: Enable and start HAProxy
|
||||||
|
systemd:
|
||||||
|
name: haproxy
|
||||||
|
enabled: yes
|
||||||
|
state: started
|
||||||
|
|
||||||
|
- name: Check SELinux mode
|
||||||
|
command: getenforce
|
||||||
|
register: selinux_state
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Warn if SELinux is not enforcing
|
||||||
|
debug:
|
||||||
|
msg: "⚠️ SELinux is not enforcing — HAProxy cert contexts may not be correctly applied."
|
||||||
|
when: selinux_state.stdout != "Enforcing"
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
# ==========================================
|
||||||
|
# HAProxy global settings
|
||||||
|
# ==========================================
|
||||||
|
global
|
||||||
|
log /dev/log local0
|
||||||
|
log /dev/log local1 notice
|
||||||
|
chroot /var/lib/haproxy
|
||||||
|
pidfile /run/haproxy.pid
|
||||||
|
maxconn {{ haproxy_global_maxconn | default(4096) }}
|
||||||
|
user haproxy
|
||||||
|
group haproxy
|
||||||
|
daemon
|
||||||
|
|
||||||
|
defaults
|
||||||
|
log global
|
||||||
|
option httplog
|
||||||
|
option dontlognull
|
||||||
|
timeout connect {{ haproxy_timeout_connect_ms | default('5000') }}
|
||||||
|
timeout client {{ haproxy_timeout_client_ms | default('60000') }}
|
||||||
|
timeout server {{ haproxy_timeout_server_ms | default('60000') }}
|
||||||
|
option http-server-close
|
||||||
|
option forwardfor
|
||||||
|
retries 3
|
||||||
|
maxconn 2000
|
||||||
|
|
||||||
|
# ==========================================
|
||||||
|
# HAProxy frontends and backends template
|
||||||
|
# ==========================================
|
||||||
|
|
||||||
|
frontend https-in
|
||||||
|
mode http
|
||||||
|
bind *:443 ssl crt {{ haproxy_pem_path }} ca-file {{ haproxy_ca_path }} verify required alpn h2,http/1.1
|
||||||
|
option httplog
|
||||||
|
option forwardfor
|
||||||
|
timeout client 30s
|
||||||
|
|
||||||
|
http-request set-header X-Client-Cert %[ssl_c_der,base64]
|
||||||
|
|
||||||
|
{% for service_name, service in securemtls_services.items() %}
|
||||||
|
acl host_{{ service_name }} hdr(host) -i {{ service.hostname }}
|
||||||
|
use_backend {{ service_name }} if host_{{ service_name }}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
# ==========================================
|
||||||
|
# Backends
|
||||||
|
# ==========================================
|
||||||
|
{% for service_name, service in securemtls_services.items() %}
|
||||||
|
backend {{ service_name }}
|
||||||
|
balance {{ service.balance | default('roundrobin') }}
|
||||||
|
mode {{ service.mode | default('http') }}
|
||||||
|
timeout connect {{ service.timeout_connect | default('5s') }}
|
||||||
|
timeout server {{ service.timeout_server | default('30s') }}
|
||||||
|
option {{ service.options | default('http-server-close') }}
|
||||||
|
default-server inter {{ service.default_server_inter | default('3s') }}
|
||||||
|
default-server rise {{ service.default_server_rise | default('2') }}
|
||||||
|
default-server fall {{ service.default_server_fall | default('3') }}
|
||||||
|
|
||||||
|
{% for server in service.backend_servers %}
|
||||||
|
{% if server.proto == "https" %}
|
||||||
|
server {{ service_name }}-{{ loop.index }} {{ server.address }}:{{ server.port }} ssl verify none check
|
||||||
|
{% else %}
|
||||||
|
server {{ service_name }}-{{ loop.index }} {{ server.address }}:{{ server.port }} check
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% if service.headers is defined %}
|
||||||
|
{% for hdr in service.headers %}
|
||||||
|
{{ hdr }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if service.rewrites is defined %}
|
||||||
|
{% for rewrite in service.rewrites %}
|
||||||
|
{{ rewrite }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
# ==========================================
|
||||||
|
# Vault backend for HAProxy
|
||||||
|
# ==========================================
|
||||||
|
backend vault_backend
|
||||||
|
mode tcp
|
||||||
|
option ssl-hello-chk
|
||||||
|
server vault1 VAULT_IP:VAULT_PORT ssl verify required ca-file {{ haproxy_ca_path }} crt {{ haproxy_cert_path }}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# Networking
|
||||||
|
technitium_port: 53
|
||||||
|
technitium_tls_port: 853
|
||||||
|
technitium_admin_port: TECHNITIUM_PORT
|
||||||
|
technitium_bind_address: "0.0.0.0"
|
||||||
|
|
||||||
|
# ==========================================================
|
||||||
|
# Directory paths
|
||||||
|
# ==========================================================
|
||||||
|
technitium_certs_dir: "/etc/technitium/certs"
|
||||||
|
technitium_crt_path: "{{ technitium_certs_dir }}/technitium.crt"
|
||||||
|
technitium_key_path: "{{ technitium_certs_dir }}/technitium.key"
|
||||||
|
technitium_ca_path: "{{ technitium_certs_dir }}/technitium_ca.crt"
|
||||||
|
|
||||||
|
# Install paths
|
||||||
|
technitium_install_dir: "/opt/technitium/dns"
|
||||||
|
technitium_data_dir: "{{ technitium_install_dir }}/data"
|
||||||
|
|
||||||
|
vault_agent_templates:
|
||||||
|
- src: "technitium_cert.ctmpl"
|
||||||
|
dest: "{{ technitium_crt_path }}"
|
||||||
|
service: "technitium"
|
||||||
|
- src: "technitium_key.ctmpl"
|
||||||
|
dest: "{{ technitium_key_path }}"
|
||||||
|
service: "technitium"
|
||||||
|
- src: "technitium_ca.ctmpl"
|
||||||
|
dest: "{{ technitium_ca_path }}"
|
||||||
|
service: "technitium"
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
- name: Reload systemd
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
daemon_reload: yes
|
||||||
|
|
||||||
|
- name: Restart technitium
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: technitium
|
||||||
|
state: restarted
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
---
|
||||||
|
# ==========================================================
|
||||||
|
# Install and configure Technitium DNS Server
|
||||||
|
# ==========================================================
|
||||||
|
|
||||||
|
- name: Ensure Technitium install directory exists
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ technitium_install_dir }}"
|
||||||
|
state: directory
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Ensure Technitium data directory exists
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ technitium_data_dir }}"
|
||||||
|
state: directory
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Ensure Technitium TLS directory exists
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ technitium_certs_dir }}"
|
||||||
|
state: directory
|
||||||
|
owner: vault
|
||||||
|
group: vault
|
||||||
|
mode: "0700"
|
||||||
|
|
||||||
|
# ==========================================================
|
||||||
|
# Install Technitium if not already installed
|
||||||
|
# ==========================================================
|
||||||
|
- name: Install Technitium DNS Server
|
||||||
|
ansible.builtin.command: bash install.sh
|
||||||
|
args:
|
||||||
|
chdir: /tmp
|
||||||
|
creates: "{{ technitium_install_dir }}/start.sh"
|
||||||
|
environment:
|
||||||
|
INSTALL_URL: "https://download.technitium.com/dns/install.sh"
|
||||||
|
register: technitium_install_result
|
||||||
|
ignore_errors: true
|
||||||
|
changed_when: technitium_install_result.rc == 0
|
||||||
|
|
||||||
|
# ==========================================================
|
||||||
|
# SELinux setup (idempotent)
|
||||||
|
# ==========================================================
|
||||||
|
- name: Apply SELinux context for Technitium certs
|
||||||
|
ansible.builtin.command: semanage fcontext -a -t etc_t '{{ technitium_certs_dir }}(/.*)?'
|
||||||
|
register: selinux_ctx
|
||||||
|
changed_when: selinux_ctx.rc == 0
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: Restore SELinux context for Technitium certs
|
||||||
|
ansible.builtin.command: restorecon -Rv "{{ technitium_certs_dir }}"
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
# ==========================================================
|
||||||
|
# Firewalld setup
|
||||||
|
# ==========================================================
|
||||||
|
- name: Ensure firewalld is running
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: firewalld
|
||||||
|
enabled: true
|
||||||
|
state: started
|
||||||
|
|
||||||
|
- name: Open Technitium DNS and admin ports
|
||||||
|
ansible.posix.firewalld:
|
||||||
|
port: "{{ item.port }}/{{ item.proto }}"
|
||||||
|
permanent: true
|
||||||
|
state: enabled
|
||||||
|
immediate: true
|
||||||
|
loop:
|
||||||
|
- { port: 53, proto: "udp" }
|
||||||
|
- { port: 53, proto: "tcp" }
|
||||||
|
- { port: 853, proto: "tcp" }
|
||||||
|
- { port: 443, proto: "tcp" }
|
||||||
|
- { port: 5380, proto: "tcp" }
|
||||||
|
|
||||||
|
# ==========================================================
|
||||||
|
# Systemd service deployment
|
||||||
|
# ==========================================================
|
||||||
|
- name: Deploy Technitium systemd unit
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: "technitium.service.j2"
|
||||||
|
dest: "/etc/systemd/system/technitium.service"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0644"
|
||||||
|
notify:
|
||||||
|
- Reload systemd
|
||||||
|
- Restart technitium
|
||||||
|
|
||||||
|
- name: Wait for Vault-Agent to render certificates
|
||||||
|
ansible.builtin.wait_for:
|
||||||
|
path: "{{ cert_path }}"
|
||||||
|
state: present
|
||||||
|
timeout: 60
|
||||||
|
loop:
|
||||||
|
- "{{ technitium_crt_path }}"
|
||||||
|
- "{{ technitium_key_path }}"
|
||||||
|
- "{{ technitium_ca_path }}"
|
||||||
|
loop_control:
|
||||||
|
loop_var: cert_path
|
||||||
|
|
||||||
|
- name: Fix ownership and permissions for Technitium certs
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ cert.path }}"
|
||||||
|
owner: vault
|
||||||
|
group: vault
|
||||||
|
mode: "{{ cert.mode }}"
|
||||||
|
loop:
|
||||||
|
- { path: "{{ technitium_crt_path }}", mode: "0644" }
|
||||||
|
- { path: "{{ technitium_key_path }}", mode: "0600" }
|
||||||
|
- { path: "{{ technitium_ca_path }}", mode: "0644" }
|
||||||
|
loop_control:
|
||||||
|
loop_var: cert
|
||||||
|
|
||||||
|
# ==========================================================
|
||||||
|
# Start and enable service
|
||||||
|
# ==========================================================
|
||||||
|
- name: Ensure Technitium DNS service is running
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: technitium
|
||||||
|
enabled: true
|
||||||
|
state: started
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Technitium DNS Server
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
WorkingDirectory={{ technitium_install_dir }}
|
||||||
|
#ExecStart={{ technitium_install_dir }}/start.sh
|
||||||
|
ExecStart={{ technitium_install_dir }}/start.sh --tls-cert /etc/technitium/certs/technitium.crt --tls-key /etc/technitium/certs/technitium.key
|
||||||
|
Restart=always
|
||||||
|
RestartSec=5
|
||||||
|
User=root
|
||||||
|
Group=root
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
technitium_service_name: "technitium"
|
||||||
|
technitium_binary_url: "https://download.technitium.com/dns/DnsServerPortable.tar.gz"
|
||||||
|
technitium_data_dir: "{{ technitium_install_dir }}/data"
|
||||||
|
technitium_conf_file: "{{ technitium_install_dir }}/Technitium.Dns.Server.json"
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
---
|
||||||
|
vault_addr: "http://VAULT_IP:VAULT_PORT"
|
||||||
|
|
||||||
|
vault_agent_config_path: "/etc/vault-agent-config.hcl"
|
||||||
|
vault_agent_pid_file: "/var/run/vault-agent.pid"
|
||||||
|
vault_agent_user: "root"
|
||||||
|
vault_agent_service: "vault-agent"
|
||||||
|
vault_agent_systemd_unit: "/etc/systemd/system/vault-agent.service"
|
||||||
|
|
||||||
|
# Paths to role_id / secret_id files (written by bootstrap process)
|
||||||
|
vault_role_id_file: "/etc/vault-agent/role_id"
|
||||||
|
vault_secret_id_file: "/etc/vault-agent/secret_id"
|
||||||
|
|
||||||
|
# Templates
|
||||||
|
vault_templates_dir: "/etc/vault-agent-templates"
|
||||||
|
|
||||||
|
vault_agent_templates:
|
||||||
|
# HAProxy
|
||||||
|
- src: "haproxy.pem.ctmpl"
|
||||||
|
dest: "/etc/haproxy/certs/haproxy.pem"
|
||||||
|
service: haproxy
|
||||||
|
- src: "haproxy_ca.ctmpl"
|
||||||
|
dest: "/etc/haproxy/certs/haproxy_ca.crt"
|
||||||
|
service: haproxy
|
||||||
|
- src: "thesabear-client.ctmpl"
|
||||||
|
dest: "/etc/haproxy/certs/clients/thesabear-client.pem"
|
||||||
|
service: "haproxy"
|
||||||
|
|
||||||
|
# Technitium
|
||||||
|
- src: "technitium_cert.ctmpl"
|
||||||
|
dest: "/etc/technitium/certs/technitium.crt"
|
||||||
|
service: technitium
|
||||||
|
- src: "technitium_key.ctmpl"
|
||||||
|
dest: "/etc/technitium/certs/technitium.key"
|
||||||
|
service: technitium
|
||||||
|
- src: "technitium_ca.ctmpl"
|
||||||
|
dest: "/etc/technitium/certs/technitium_ca.crt"
|
||||||
|
service: technitium
|
||||||
|
|
||||||
|
# Default Vault PKI options (can remain)
|
||||||
|
pki_mount_path: "pki"
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{{- with secret "pki/cert/ca" -}}
|
||||||
|
{{ trim .Data.certificate "\n" }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{% raw %}
|
||||||
|
{{- with secret "pki/issue/{{ wildcard_role_name }}" "common_name={{ common_name }}" -}}
|
||||||
|
{{ .Data.certificate }}
|
||||||
|
{{ .Data.private_key }}
|
||||||
|
{{ .Data.issuing_ca }}
|
||||||
|
{{- end }}
|
||||||
|
{% endraw %}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{{ with secret "pki/issue/securevault-wildcard" "common_name=*.local.DOMAIN_PLACEHOLDER" "ttl=8760h" }}
|
||||||
|
{{ .Data.certificate }}
|
||||||
|
{{ .Data.issuing_ca }}
|
||||||
|
{{ .Data.private_key }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
Loaded 100 of 132 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user