add new container
This commit is contained in:
parent
e0436feaf3
commit
bcc7fb55d5
92 changed files with 1996 additions and 0 deletions
72
ansible/roles/deploy_container_healthchecks/README.md
Normal file
72
ansible/roles/deploy_container_healthchecks/README.md
Normal file
|
@ -0,0 +1,72 @@
|
|||
# Role: deploy_container_traefik
|
||||
|
||||
## Purpose
|
||||
This role deploys and configures a Healthchecks.io Container with Docker Compose
|
||||
|
||||
## Variables
|
||||
|
||||
### Default Variables (`defaults/main.yml`)
|
||||
```yaml
|
||||
container_healthchecks_domain: health.example.com
|
||||
container_healthchecks_version: v3.10
|
||||
container_healthchecks_email_from: "healthchecks@your.domain.com"
|
||||
container_healthchecks_email_host: smtp.your.domain.com
|
||||
container_healthchecks_email_password: your_email_password
|
||||
container_healthchecks_email_user: healthchecks@your.domain.com
|
||||
container_healthchecks_email_port: 587
|
||||
container_healthchecks_email_tls: true
|
||||
container_healthchecks_email_user_verification: true
|
||||
container_healthchecks_secret_key: your_secret_key
|
||||
container_healthchecks_site_name: "Healthchecks"
|
||||
```
|
||||
|
||||
### Secret Key Generation
|
||||
Generate a secure secret key for Django
|
||||
You can use
|
||||
´´´
|
||||
python3 -c "import secrets; print(secrets.token_urlsafe(50))"
|
||||
´´´
|
||||
to generate a new key or use an online Generator like https://djecrety.ir/
|
||||
|
||||
### Static Variables (`vars/main.yml`)
|
||||
```yaml
|
||||
container_base_dir: /opt/docker/healthchecks
|
||||
```
|
||||
|
||||
### Role Usage
|
||||
|
||||
```yaml
|
||||
- name: Deploy Healthchecks.io container
|
||||
hosts: docker
|
||||
roles:
|
||||
- role: deploy_container_healthchecks
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
* Linux system (tested on Debian)
|
||||
* Docker Engine
|
||||
* Docker Compose v2 plugin (`docker compose` CLI)
|
||||
* Ansible 2.11 or higher
|
||||
* `community.docker` collection
|
||||
|
||||
Install the required collection:
|
||||
|
||||
```bash
|
||||
ansible-galaxy collection install community.docker
|
||||
```
|
||||
|
||||
Or via `requirements.yml`:
|
||||
|
||||
```yaml
|
||||
collections:
|
||||
- name: community.docker
|
||||
version: ">=3.4.0"
|
||||
```
|
||||
|
||||
## Authors
|
||||
|
||||
* Kevin Heyer
|
||||
📧 [kevin.heyer@wira-gmbh.de](mailto:kevin.heyer@wira-gmbh.de)
|
||||
|
||||
```
|
|
@ -0,0 +1,13 @@
|
|||
container_healthchecks_domain: health.example.com
|
||||
container_healthchecks_version: v3.10
|
||||
container_healthchecks_email_from: "healthchecks@your.domain.com"
|
||||
container_healthchecks_email_host: smtp.your.domain.com
|
||||
container_healthchecks_email_password: your_email_password
|
||||
container_healthchecks_email_user: healthchecks@your.domain.com
|
||||
container_healthchecks_email_port: 587
|
||||
container_healthchecks_email_tls: true
|
||||
container_healthchecks_email_user_verification: true
|
||||
# Generate a secure secret key for Django
|
||||
# You can use `python3 -c "import secrets; print(secrets.token_urlsafe(50))"` to generate a new key
|
||||
container_healthchecks_secret_key: your_secret_key
|
||||
container_healthchecks_site_name: "Healthchecks"
|
28
ansible/roles/deploy_container_healthchecks/tasks/main.yml
Normal file
28
ansible/roles/deploy_container_healthchecks/tasks/main.yml
Normal file
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
- name: Create Container Structure
|
||||
ansible.builtin.file:
|
||||
path: "{{ container_base_dir }}"
|
||||
state: directory
|
||||
mode: '0775'
|
||||
recurse: true
|
||||
|
||||
- name: Deploy Docker Compose and .env files
|
||||
ansible.builtin.template:
|
||||
src: '{{ item.src }}'
|
||||
dest: '{{ item.dest }}'
|
||||
mode: '0775'
|
||||
loop:
|
||||
- {src: '.env.j2', dest: '{{ container_base_dir }}/.env'}
|
||||
- {src: 'docker-compose.yml.j2', dest: '{{ container_base_dir }}/docker-compose.yml'}
|
||||
|
||||
- name: Stop Container
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ container_base_dir }}"
|
||||
state: absent
|
||||
|
||||
- name: Start Container
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ container_base_dir }}"
|
||||
state: present
|
||||
pull: always
|
||||
recreate: always
|
|
@ -0,0 +1,14 @@
|
|||
ALLOWED_HOSTS={{ container_healthchecks_domain }}
|
||||
HEALTHCHECKS_DOMAIN={{ container_healthchecks_domain }}
|
||||
HEALTHCHECKS_VERSION={{ container_healthchecks_version }}
|
||||
SITE_ROOT=https://{{ container_healthchecks_domain }}
|
||||
SECRET_KEY={{ container_healthchecks_secret_key }}
|
||||
EMAIL_USE_TLS={{ container_healthchecks_email_tls }}
|
||||
EMAIL_PORT={{ container_healthchecks_email_port }}
|
||||
EMAIL_HOST_USER={{ container_healthchecks_email_user }}
|
||||
EMAIL_HOST_PASSWORD={{ container_healthchecks_email_password }}
|
||||
EMAIL_HOST={{ container_healthchecks_email_host }}
|
||||
DEFAULT_FROM_EMAIL={{ container_healthchecks_email_from }}
|
||||
EMAIL_USE_VERIFICATION={{ container_healthchecks_email_user_verification }}
|
||||
PING_ENDPOINT=https://{{ container_healthchecks_domain }}/ping/
|
||||
SITE_NAME={{ container_healthchecks_site_name }}
|
|
@ -0,0 +1,49 @@
|
|||
services:
|
||||
healthchecks:
|
||||
image: healthchecks/healthchecks:${HEALTHCHECKS_VERSION}
|
||||
container_name: healthchecks
|
||||
restart: always
|
||||
volumes:
|
||||
- db:/data
|
||||
networks:
|
||||
traefik:
|
||||
environment:
|
||||
- DB=sqlite
|
||||
- DB_NAME=/data/hc.sqlite
|
||||
- DEBUG=False
|
||||
- DEFAULT_FROM_EMAIL=${DEFAULT_FROM_EMAIL}
|
||||
- EMAIL_HOST=${EMAIL_HOST}
|
||||
- EMAIL_HOST_PASSWORD=${EMAIL_HOST_PASSWORD}
|
||||
- EMAIL_HOST_USER=${EMAIL_HOST_USER}
|
||||
- EMAIL_PORT=${EMAIL_PORT}
|
||||
- EMAIL_USE_TLS=${EMAIL_USE_TLS}
|
||||
- EMAIL_USE_VERIFICATION=${EMAIL_USE_VERIFICATION}
|
||||
- SECRET_KEY=${SECRET_KEY}
|
||||
- SITE_ROOT=${SITE_ROOT}
|
||||
- ALLOWED_HOSTS=${ALLOWED_HOSTS}
|
||||
- PING_ENDPOINT=${PING_ENDPOINT}
|
||||
- SITE_NAME=${SITE_NAME}
|
||||
{% if container_traefik_auth == 'sso' %}
|
||||
- REMOTE_USER_HEADER=HTTP_REMOTE_EMAIL
|
||||
{% endif %}
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=traefik"
|
||||
- "traefik.http.routers.healthchecks.entrypoints=http"
|
||||
- "traefik.http.routers.healthchecks.rule=Host(`${HEALTHCHECKS_DOMAIN}`)"
|
||||
- "traefik.http.middlewares.healthchecks-https-redirect.redirectscheme.scheme=https"
|
||||
- "traefik.http.routers.healthchecks.middlewares=traefik-https-redirect"
|
||||
- "traefik.http.routers.healthchecks-secure.entrypoints=https"
|
||||
- "traefik.http.routers.healthchecks-secure.rule=Host(`${HEALTHCHECKS_DOMAIN}`)"
|
||||
- "traefik.http.routers.healthchecks-secure.tls=true"
|
||||
- "traefik.http.services.healthchecks.loadbalancer.server.port=8000"
|
||||
{% if container_traefik_auth == 'sso' %}
|
||||
- "traefik.http.routers.healthchecks-secure.middlewares=middlewares-authelia@file"
|
||||
{% endif %}
|
||||
|
||||
networks:
|
||||
traefik:
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
db:
|
|
@ -0,0 +1 @@
|
|||
container_base_dir : "/opt/docker/healthchecks"
|
5
ansible/roles/deploy_container_ittools/defaults/main.yml
Normal file
5
ansible/roles/deploy_container_ittools/defaults/main.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
############
|
||||
# IT-Tools #
|
||||
############
|
||||
container_ittools_version: latest
|
||||
container_ittools_domain: ittools.example.com
|
0
ansible/roles/deploy_container_ittools/files/.gitkeep
Normal file
0
ansible/roles/deploy_container_ittools/files/.gitkeep
Normal file
0
ansible/roles/deploy_container_ittools/handlers/main.yml
Normal file
0
ansible/roles/deploy_container_ittools/handlers/main.yml
Normal file
0
ansible/roles/deploy_container_ittools/meta/main.yml
Normal file
0
ansible/roles/deploy_container_ittools/meta/main.yml
Normal file
27
ansible/roles/deploy_container_ittools/tasks/main.yml
Normal file
27
ansible/roles/deploy_container_ittools/tasks/main.yml
Normal file
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
- name: Ensure data directories exist
|
||||
ansible.builtin.file:
|
||||
path: "{{ container_base_dir }}/"
|
||||
state: directory
|
||||
mode: '0755'
|
||||
|
||||
- name: Deploy Docker Compose and .env files
|
||||
ansible.builtin.template:
|
||||
src: '{{ item.src }}'
|
||||
dest: '{{ item.dest }}'
|
||||
mode: '0775'
|
||||
loop:
|
||||
- {src: '.env.j2', dest: '{{ container_base_dir }}/.env'}
|
||||
- {src: 'docker-compose.yml.j2', dest: '{{ container_base_dir }}/docker-compose.yml'}
|
||||
|
||||
- name: Stop Container
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ container_base_dir }}"
|
||||
state: absent
|
||||
|
||||
- name: Start Container
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ container_base_dir }}"
|
||||
state: present
|
||||
pull: always
|
||||
recreate: always
|
2
ansible/roles/deploy_container_ittools/templates/.env.j2
Normal file
2
ansible/roles/deploy_container_ittools/templates/.env.j2
Normal file
|
@ -0,0 +1,2 @@
|
|||
ITTOOLS_VERSION: {{ container_ittools_version }}
|
||||
ITTOOLS_DOMAIN: {{ container_ittools_domain }}
|
|
@ -0,0 +1,29 @@
|
|||
---
|
||||
services:
|
||||
it-tools:
|
||||
image: corentinth/it-tools:${ITTOOLS_VERSION}
|
||||
container_name: ittools
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
traefik:
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.ittools.entrypoints=http"
|
||||
- "traefik.http.routers.ittools.rule=Host(`${ITTOOLS_DOMAIN:?error}`)"
|
||||
- "traefik.http.middlewares.ittools-https-redirect.redirectscheme.scheme=https"
|
||||
- "traefik.http.routers.ittools.middlewares=traefik-https-redirect"
|
||||
- "traefik.http.routers.ittools-secure.entrypoints=https"
|
||||
- "traefik.http.routers.ittools-secure.rule=Host(`${ITTOOLS_DOMAIN:?error}`)"
|
||||
- "traefik.http.routers.ittools-secure.tls=true"
|
||||
- "traefik.http.services.ittools.loadbalancer.server.port=80"
|
||||
- "traefik.docker.network=traefik"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -fsS -m 5 http://127.0.0.1/ >/dev/null || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
|
||||
networks:
|
||||
traefik:
|
||||
external: true
|
1
ansible/roles/deploy_container_ittools/vars/main.yml
Normal file
1
ansible/roles/deploy_container_ittools/vars/main.yml
Normal file
|
@ -0,0 +1 @@
|
|||
container_base_dir: /opt/docker/ittools
|
11
ansible/roles/deploy_container_limesurvey/defaults/main.yml
Normal file
11
ansible/roles/deploy_container_limesurvey/defaults/main.yml
Normal file
|
@ -0,0 +1,11 @@
|
|||
##############
|
||||
# Limesurvey #
|
||||
##############
|
||||
container_limesurvey_version: latest
|
||||
container_limesurvey_domain: limesurvey.example.com
|
||||
container_limesurvey_user: limesurvey
|
||||
container_limesurvey_password: limesurvey_password
|
||||
container_limesurvey_name: "LimeSurvey Admin"
|
||||
container_limesurvey_email: admin@example.com
|
||||
container_mariadb_version: 10.5
|
||||
container_mariadb_password: mariadb_password
|
0
ansible/roles/deploy_container_limesurvey/files/.gitkeep
Normal file
0
ansible/roles/deploy_container_limesurvey/files/.gitkeep
Normal file
0
ansible/roles/deploy_container_limesurvey/meta/main.yml
Normal file
0
ansible/roles/deploy_container_limesurvey/meta/main.yml
Normal file
32
ansible/roles/deploy_container_limesurvey/tasks/main.yml
Normal file
32
ansible/roles/deploy_container_limesurvey/tasks/main.yml
Normal file
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
- name: Ensure data directories exist
|
||||
ansible.builtin.file:
|
||||
path: "{{ container_base_dir }}/data/{{ item }}"
|
||||
state: directory
|
||||
mode: '0755'
|
||||
loop:
|
||||
- "plugins"
|
||||
- "upload"
|
||||
- "sessions"
|
||||
- "data/images"
|
||||
|
||||
- name: Deploy Docker Compose and .env files
|
||||
ansible.builtin.template:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ container_base_dir }}/{{ item.dest }}"
|
||||
mode: '0644'
|
||||
loop:
|
||||
- { src: 'docker-compose.yml.j2', dest: 'docker-compose.yml' }
|
||||
- { src: '.env.j2', dest: '.env' }
|
||||
|
||||
- name: Stop Container
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ container_base_dir }}"
|
||||
state: absent
|
||||
|
||||
- name: Start Container
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ container_base_dir }}"
|
||||
state: present
|
||||
pull: always
|
||||
recreate: always
|
|
@ -0,0 +1,8 @@
|
|||
LIMESURVEY_VERSION={{ container_limesurvey_version }}
|
||||
LIMESURVEY_DOMAIN={{ container_limesurvey_domain }}
|
||||
LIMESURVEY_USER={{ container_limesurvey_user }}
|
||||
LIMESURVEY_PASSWORD={{ container_limesurvey_password }}
|
||||
LIMESURVEY_NAME={{ container_limesurvey_name }}
|
||||
LIMESURVEY_EMAIL={{ container_limesurvey_email }}
|
||||
MARIADB_VERSION={{ container_mariadb_version }}
|
||||
MARIADB_PASSWORD={{ container_mariadb_password }}
|
|
@ -0,0 +1,64 @@
|
|||
---
|
||||
services:
|
||||
limesurvey:
|
||||
image: adamzammit/limesurvey:${LIMESURVEY_VERSION}
|
||||
container_name: limesurvey
|
||||
restart: always
|
||||
networks:
|
||||
traefik:
|
||||
limesurvey:
|
||||
volumes:
|
||||
- ./data/plugins:/var/www/html/plugins
|
||||
- ./data/upload:/var/www/html/upload
|
||||
- ./data/config:/var/www/html/application/config
|
||||
- ./data/sessions:/var/lime/sessions
|
||||
- ./data/images/logo.png:/var/www/html/assets/images/logo-icon-white.png
|
||||
- ./data/images/logo.png:/var/www/html/assets/images/Limesurvey_logo-big.png
|
||||
- ./data/images/logo.png:/var/www/html/assets/images/Logo_LimeSurvey.png
|
||||
- ./data/images/logo.png:/var/www/html/assets/images/__Limesurvey_logo.png
|
||||
- ./data/images/logo.png:/var/www/html/assets/images/logo-white.png
|
||||
- ./data/images/logo.png:/var/www/html/tmp/assets/aa2d5407/survey_list_header.png
|
||||
environment:
|
||||
LIMESURVEY_DB_PASSWORD: ${MARIADB_PASSWORD}
|
||||
LIMESURVEY_ADMIN_USER: ${LIMESURVEY_USER}
|
||||
LIMESURVEY_ADMIN_PASSWORD: ${LIMESURVEY_PASSWORD}
|
||||
LIMESURVEY_ADMIN_NAME: ${LIMESURVEY_NAME}
|
||||
LIMESURVEY_ADMIN_EMAIL: ${LIMESURVEY_EMAIL}
|
||||
TZ: Europe/Berlin
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.limesurvey.entrypoints=https"
|
||||
- "traefik.http.routers.limesurvey.rule=Host(`${LIMESURVEY_DOMAIN}`)"
|
||||
- "traefik.http.routers.limesurvey.tls=true"
|
||||
- "traefik.http.routers.limesurvey.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.limesurvey.loadbalancer.server.port=80"
|
||||
- "traefik.docker.network=traefik"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -fsS -m 5 http://127.0.0.1/ >/dev/null || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
start_period: 60s
|
||||
|
||||
mysql:
|
||||
image: mariadb:${MARIADB_VERSION}
|
||||
container_name: limesurvey_db
|
||||
restart: always
|
||||
networks:
|
||||
limesurvey:
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: ${MARIADB_PASSWORD}
|
||||
volumes:
|
||||
- ./data/mysql:/var/lib/mysql
|
||||
healthcheck:
|
||||
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 60s
|
||||
|
||||
networks:
|
||||
traefik:
|
||||
external: true
|
||||
limesurvey:
|
||||
driver: bridge
|
1
ansible/roles/deploy_container_limesurvey/vars/main.yml
Normal file
1
ansible/roles/deploy_container_limesurvey/vars/main.yml
Normal file
|
@ -0,0 +1 @@
|
|||
container_base_dir: /opt/docker/limesurvey
|
|
@ -0,0 +1,5 @@
|
|||
#############
|
||||
# NetAlertX #
|
||||
#############
|
||||
container_netalertx_version: latest
|
||||
container_netalertx_domain: netalertx.example.com
|
0
ansible/roles/deploy_container_netalertx/files/.gitkeep
Normal file
0
ansible/roles/deploy_container_netalertx/files/.gitkeep
Normal file
0
ansible/roles/deploy_container_netalertx/meta/main.yml
Normal file
0
ansible/roles/deploy_container_netalertx/meta/main.yml
Normal file
31
ansible/roles/deploy_container_netalertx/tasks/main.yml
Normal file
31
ansible/roles/deploy_container_netalertx/tasks/main.yml
Normal file
|
@ -0,0 +1,31 @@
|
|||
---
|
||||
- name: Ensure data directories exist
|
||||
ansible.builtin.file:
|
||||
path: "{{ container_base_dir }}/data/{{ item }}"
|
||||
state: directory
|
||||
mode: '0755'
|
||||
loop:
|
||||
- "config"
|
||||
- "db"
|
||||
- "logs"
|
||||
|
||||
- name: Deploy Docker Compose and .env files
|
||||
ansible.builtin.template:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ container_base_dir }}/{{ item.dest }}"
|
||||
mode: '0644'
|
||||
loop:
|
||||
- { src: 'docker-compose.yml.j2', dest: 'docker-compose.yml' }
|
||||
- { src: '.env.j2', dest: '.env' }
|
||||
|
||||
- name: Stop Container
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ container_base_dir }}"
|
||||
state: absent
|
||||
|
||||
- name: Start Container
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ container_base_dir }}"
|
||||
state: present
|
||||
pull: always
|
||||
recreate: always
|
|
@ -0,0 +1,2 @@
|
|||
NETALERTX_VERSION={{ container_netalertx_version }}
|
||||
NETALERTX_DOMAIN={{ container_netalertx_domain }}
|
|
@ -0,0 +1,37 @@
|
|||
services:
|
||||
netalertx:
|
||||
image: jokobsk/netalertx:${NETALERTX_VERSION}
|
||||
container_name: netalertx
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
traefik:
|
||||
volumes:
|
||||
- ./data/config:/app/config
|
||||
- ./data/db:/app/db
|
||||
- ./data/logs:/app/front/log
|
||||
environment:
|
||||
- TZ=Europe/Berlin
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.netalertx.entrypoints=http"
|
||||
- "traefik.http.routers.netalertx.rule=Host(`${NETALERTX_DOMAIN}`)"
|
||||
- "traefik.http.middlewares.netalertx-https-redirect.redirectscheme.scheme=https"
|
||||
- "traefik.http.routers.netalertx.middlewares=traefik-https-redirect"
|
||||
- "traefik.http.routers.netalertx-secure.entrypoints=https"
|
||||
- "traefik.http.routers.netalertx-secure.rule=Host(`${NETALERTX_DOMAIN}`)"
|
||||
- "traefik.http.routers.netalertx-secure.tls=true"
|
||||
- "traefik.http.services.netalertx.loadbalancer.server.port=20211"
|
||||
{% if container_traefik_auth == 'sso' %}
|
||||
- "traefik.http.routers.netalertx-secure.middlewares=middlewares-authelia@file"
|
||||
{% endif %}
|
||||
- "traefik.docker.network=traefik"
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "127.0.0.1:20211/php/server/query_json.php?file=app_state.json"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
start_period: 15s
|
||||
retries: 2
|
||||
|
||||
networks:
|
||||
traefik:
|
||||
external: true
|
1
ansible/roles/deploy_container_netalertx/vars/main.yml
Normal file
1
ansible/roles/deploy_container_netalertx/vars/main.yml
Normal file
|
@ -0,0 +1 @@
|
|||
container_base_dir: /opt/docker/netalertx
|
13
ansible/roles/deploy_container_netbox/defaults/main.yml
Normal file
13
ansible/roles/deploy_container_netbox/defaults/main.yml
Normal file
|
@ -0,0 +1,13 @@
|
|||
##########
|
||||
# Netbox #
|
||||
##########
|
||||
container_netbox_postgres_version: 16
|
||||
container_netbox_postgres_db: netbox
|
||||
container_netbox_postgres_user: netbox
|
||||
container_netbox_postgres_password: random_password_here
|
||||
|
||||
container_netbox_redis_version: 7
|
||||
|
||||
container_netbox_version: latest
|
||||
container_netbox_secret_key: "random_secret_key_here"
|
||||
container_netbox_domain: netbox.example.com
|
|
@ -0,0 +1,14 @@
|
|||
ARG NETBOX_VERSION
|
||||
|
||||
FROM netboxcommunity/netbox:$NETBOX_VERSION
|
||||
|
||||
COPY ./data/plugin_requirements.txt /opt/netbox/
|
||||
RUN /usr/local/bin/uv pip install -r /opt/netbox/plugin_requirements.txt
|
||||
|
||||
# For the toplogical_view Plugin
|
||||
RUN mkdir -p /opt/netbox/netbox/static/netbox_topology_views/img
|
||||
|
||||
# These lines are only required if your plugin has its own static files.
|
||||
COPY ./data/configuration/plugins.py /etc/netbox/config/plugins.py
|
||||
RUN DEBUG="true" SECRET_KEY="dummydummydummydummydummydummydummydummydummydummy" \
|
||||
/opt/netbox/venv/bin/python /opt/netbox/netbox/manage.py collectstatic --no-input
|
|
@ -0,0 +1,3 @@
|
|||
netbox-plugin-dns
|
||||
netbox-topology-views
|
||||
netbox-qrcode
|
13
ansible/roles/deploy_container_netbox/files/plugins.py
Normal file
13
ansible/roles/deploy_container_netbox/files/plugins.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
PLUGINS = [
|
||||
"netbox_dns",
|
||||
"netbox_topology_views",
|
||||
"netbox_qrcode"
|
||||
]
|
||||
|
||||
PLUGINS_CONFIG = {
|
||||
'netbox_qrcode': {
|
||||
'models': {
|
||||
'dcim.device': {}, # QR-Codes für Geräte aktivieren
|
||||
}
|
||||
}
|
||||
}
|
0
ansible/roles/deploy_container_netbox/handlers/main.yml
Normal file
0
ansible/roles/deploy_container_netbox/handlers/main.yml
Normal file
0
ansible/roles/deploy_container_netbox/meta/main.yml
Normal file
0
ansible/roles/deploy_container_netbox/meta/main.yml
Normal file
51
ansible/roles/deploy_container_netbox/tasks/main.yml
Normal file
51
ansible/roles/deploy_container_netbox/tasks/main.yml
Normal file
|
@ -0,0 +1,51 @@
|
|||
---
|
||||
- name: Ensure data directories exist
|
||||
ansible.builtin.file:
|
||||
path: "{{ container_base_dir }}/{{ item }}"
|
||||
state: directory
|
||||
mode: '0755'
|
||||
loop:
|
||||
- "data/backup"
|
||||
- "data/configuration"
|
||||
- "data/netbox"
|
||||
- "data/static/netbox_topology_views/img"
|
||||
- "data/static/netbox_topology_views/js"
|
||||
- "data/static/netbox_topology_views/css"
|
||||
|
||||
- name: Ensure Docker BuildX Plugin is installed
|
||||
ansible.builtin.apt:
|
||||
package:
|
||||
- docker-buildx-plugin
|
||||
state: present
|
||||
cache_valid_time: 3600
|
||||
|
||||
- name: Copy Files
|
||||
ansible.builtin.copy:
|
||||
src: '{{ item.src }}'
|
||||
dest: '{{ item.dest }}'
|
||||
mode: "0664"
|
||||
loop:
|
||||
- {src: 'Dockerfile-Plugins', dest: '{{ container_base_dir }}/Dockerfile-Plugins'}
|
||||
- {src: 'plugins.py', dest: '{{ container_base_dir }}/data/configuration/plugins.py'}
|
||||
- {src: 'plugin_requirements.txt', dest: '{{ container_base_dir }}/data/plugin_requirements.txt'}
|
||||
|
||||
- name: Render Template Files
|
||||
ansible.builtin.template:
|
||||
src: '{{ item.src }}'
|
||||
dest: '{{ item.dest }}'
|
||||
mode: "0664"
|
||||
loop:
|
||||
- {src: .env.j2, dest: '{{ container_base_dir }}/.env'}
|
||||
- {src: 'docker-compose.yml.j2', dest: '{{ container_base_dir }}/docker-compose.yml'}
|
||||
|
||||
- name: Stop Container
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ container_base_dir }}"
|
||||
state: absent
|
||||
|
||||
- name: Start Container
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ container_base_dir }}"
|
||||
state: present
|
||||
pull: always
|
||||
recreate: always
|
13
ansible/roles/deploy_container_netbox/templates/.env.j2
Normal file
13
ansible/roles/deploy_container_netbox/templates/.env.j2
Normal file
|
@ -0,0 +1,13 @@
|
|||
# Netbox
|
||||
NETBOX_VERSION={{ container_netbox_version }}
|
||||
NETBOX_SECRET_KEY={{ container_netbox_secret_key }}
|
||||
NETBOX_DOMAIN={{ container_netbox_domain }}
|
||||
|
||||
# Redis
|
||||
NETBOX_REDIS_VERSION={{ container_netbox_redis_version }}
|
||||
|
||||
# PostgreSQL
|
||||
POSTGRES_VERSION={{ container_netbox_postgres_version }}
|
||||
POSTGRES_DB= {{ container_netbox_postgres_db }}
|
||||
POSTGRES_USER={{ container_netbox_postgres_user }}
|
||||
POSTGRES_PASSWORD={{ container_netbox_postgres_password }}
|
|
@ -0,0 +1,96 @@
|
|||
---
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:${POSTGRES_VERSION:-16}
|
||||
container_name: netbox-db
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- netbox
|
||||
volumes:
|
||||
- netbox-db:/var/lib/postgresql/data
|
||||
- ./data/backup:/backup # Volume for Cronjob: 0 2 * * * /usr/bin/docker exec netbox-db /bin/bash -c 'PGPASSWORD=changeMeNow! pg_dump --username=netbox netbox > >
|
||||
environment:
|
||||
POSTGRES_DB: ${POSTGRES_DB}
|
||||
POSTGRES_USER: ${POSTGRES_USER}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "sh -c 'pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}'"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
|
||||
redis:
|
||||
image: redis:${NETBOX_REDIS_VERSION:-7}
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- netbox
|
||||
volumes:
|
||||
- netbox-redis:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 3s
|
||||
retries: 5
|
||||
|
||||
netbox:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile-Plugins
|
||||
args:
|
||||
NETBOX_VERSION: ${NETBOX_VERSION:-latest}
|
||||
container_name: netbox
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- traefik
|
||||
- netbox
|
||||
env_file: .env
|
||||
environment:
|
||||
DB_NAME: ${POSTGRES_DB}
|
||||
DB_USER: ${POSTGRES_USER}
|
||||
DB_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
DB_HOST: postgres
|
||||
REDIS_HOST: redis
|
||||
REDIS_DATABASE: 0
|
||||
REDIS_CACHE_DATABASE: 1
|
||||
SECRET_KEY: ${NETBOX_SECRET_KEY}
|
||||
ALLOWED_HOSTS: "*"
|
||||
volumes:
|
||||
- netbox-static:/opt/netbox/netbox/static
|
||||
- netbox-media:/etc/netbox/media
|
||||
- ./data/configuration/plugins.py:/etc/netbox/config/plugins.py
|
||||
- ./data/netbox/static/img:/opt/netbox/netbox/static/netbox_topology_views/img
|
||||
- ./data/netbox/static/js:/opt/netbox/netbox/static/netbox_topology_views/js
|
||||
- ./data/netbox/static/css:/opt/netbox/netbox/static/netbox_topology_views/css
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.netbox.entrypoints=http"
|
||||
- "traefik.http.routers.netbox.rule=Host(`${NETBOX_DOMAIN:?error}`)"
|
||||
- "traefik.http.middlewares.netbox-https-redirect.redirectscheme.scheme=https"
|
||||
- "traefik.http.routers.netbox.middlewares=traefik-https-redirect"
|
||||
- "traefik.http.routers.netbox-secure.entrypoints=https"
|
||||
- "traefik.http.routers.netbox-secure.rule=Host(`${NETBOX_DOMAIN:?error}`)"
|
||||
- "traefik.http.routers.netbox-secure.tls=true"
|
||||
- "traefik.http.services.netbox.loadbalancer.server.port=8080"
|
||||
- "traefik.docker.network=traefik"
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
start_period: 60s
|
||||
timeout: 3s
|
||||
interval: 15s
|
||||
test: "curl -f http://localhost:8080/login/ || exit 1"
|
||||
|
||||
networks:
|
||||
traefik:
|
||||
external: true
|
||||
netbox:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
netbox-db:
|
||||
netbox-redis:
|
||||
netbox-static:
|
||||
netbox-media:
|
1
ansible/roles/deploy_container_netbox/vars/main.yml
Normal file
1
ansible/roles/deploy_container_netbox/vars/main.yml
Normal file
|
@ -0,0 +1 @@
|
|||
container_base_dir: /opt/docker/netbox
|
|
@ -0,0 +1,8 @@
|
|||
#############
|
||||
# Plausible #
|
||||
#############
|
||||
container_plausible_version: "latest"
|
||||
container_plausible_clickhouse_version: "latest"
|
||||
container_plausible_postgres_version: "latest"
|
||||
container_plausible_secret_key: "randon_secret_key" # openssl rand -base64 48
|
||||
container_plausible_domain: "plausible.example.com"
|
|
@ -0,0 +1,3 @@
|
|||
<clickhouse>
|
||||
<disable_internal_memory_tracker>true</disable_internal_memory_tracker>
|
||||
</clickhouse>
|
|
@ -0,0 +1,3 @@
|
|||
<clickhouse>
|
||||
<listen_host>0.0.0.0</listen_host>
|
||||
</clickhouse>
|
28
ansible/roles/deploy_container_plausible/files/logs.xml
Normal file
28
ansible/roles/deploy_container_plausible/files/logs.xml
Normal file
|
@ -0,0 +1,28 @@
|
|||
<clickhouse>
|
||||
<logger>
|
||||
<level>warning</level>
|
||||
<console>true</console>
|
||||
</logger>
|
||||
|
||||
<query_log replace="1">
|
||||
<database>system</database>
|
||||
<table>query_log</table>
|
||||
<flush_interval_milliseconds>7500</flush_interval_milliseconds>
|
||||
<engine>
|
||||
ENGINE = MergeTree
|
||||
PARTITION BY event_date
|
||||
ORDER BY (event_time)
|
||||
TTL event_date + interval 30 day
|
||||
SETTINGS ttl_only_drop_parts=1
|
||||
</engine>
|
||||
</query_log>
|
||||
|
||||
<!-- Stops unnecessary logging -->
|
||||
<metric_log remove="remove" />
|
||||
<asynchronous_metric_log remove="remove" />
|
||||
<query_thread_log remove="remove" />
|
||||
<text_log remove="remove" />
|
||||
<trace_log remove="remove" />
|
||||
<session_log remove="remove" />
|
||||
<part_log remove="remove" />
|
||||
</clickhouse>
|
|
@ -0,0 +1,23 @@
|
|||
<!-- https://clickhouse.com/docs/en/operations/tips#using-less-than-16gb-of-ram -->
|
||||
<clickhouse>
|
||||
<!--
|
||||
https://clickhouse.com/docs/en/operations/server-configuration-parameters/settings#mark_cache_size -->
|
||||
<mark_cache_size>524288000</mark_cache_size>
|
||||
|
||||
<profile>
|
||||
<default>
|
||||
<!-- https://clickhouse.com/docs/en/operations/settings/settings#max_threads -->
|
||||
<max_threads>1</max_threads>
|
||||
<!-- https://clickhouse.com/docs/en/operations/settings/settings#max_block_size -->
|
||||
<max_block_size>8192</max_block_size>
|
||||
<!-- https://clickhouse.com/docs/en/operations/settings/settings#max_download_threads -->
|
||||
<max_download_threads>1</max_download_threads>
|
||||
<!--
|
||||
https://clickhouse.com/docs/en/operations/settings/settings#input_format_parallel_parsing -->
|
||||
<input_format_parallel_parsing>0</input_format_parallel_parsing>
|
||||
<!--
|
||||
https://clickhouse.com/docs/en/operations/settings/settings#output_format_parallel_formatting -->
|
||||
<output_format_parallel_formatting>0</output_format_parallel_formatting>
|
||||
</default>
|
||||
</profile>
|
||||
</clickhouse>
|
0
ansible/roles/deploy_container_plausible/meta/main.yml
Normal file
0
ansible/roles/deploy_container_plausible/meta/main.yml
Normal file
41
ansible/roles/deploy_container_plausible/tasks/main.yml
Normal file
41
ansible/roles/deploy_container_plausible/tasks/main.yml
Normal file
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
- name: Ensure data directories exist
|
||||
ansible.builtin.file:
|
||||
path: "{{ container_base_dir }}/data/{{ item }}"
|
||||
state: directory
|
||||
mode: '0755'
|
||||
loop:
|
||||
- "clickhouse"
|
||||
|
||||
- name: Copy config files
|
||||
ansible.builtin.copy:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ container_base_dir }}/data/{{ item.dest }}"
|
||||
mode: '0644'
|
||||
loop:
|
||||
- { src: 'ipv4-only.xml', dest: '/clickhouse/ipv4-only.xml' }
|
||||
- { src: 'logs.xml', dest: '/clickhouse/logs.xml' }
|
||||
- { src: 'low-resources.xml', dest: '/clickhouse/low-resources.xml' }
|
||||
- { src: 'disable-internal-memory-tracker.xml', dest: '/clickhouse/disable-internal-memory-tracker.xml' }
|
||||
become: false
|
||||
|
||||
- name: Render Docker Compose and config files
|
||||
ansible.builtin.template:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ container_base_dir }}/{{ item.dest }}"
|
||||
mode: '0644'
|
||||
loop:
|
||||
- { src: 'docker-compose.yml.j2', dest: 'docker-compose.yml' }
|
||||
- { src: '.env.j2', dest: '.env' }
|
||||
|
||||
- name: Stop Container
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ container_base_dir }}"
|
||||
state: absent
|
||||
|
||||
- name: Start Container
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ container_base_dir }}"
|
||||
state: present
|
||||
pull: always
|
||||
recreate: always
|
|
@ -0,0 +1,5 @@
|
|||
PLAUSIBLE_VERSION={{ container_plausible_version }}
|
||||
PLAUSIBLE_DOMAIN={{ container_plausible_domain }}
|
||||
PLAUSIBLE_SECRET_KEY={{ container_plausible_secret_key }}
|
||||
POSTGRES_VERSION={{ container_plausible_postgres_version }}
|
||||
CLICKHOUSE_VERSION={{ container_plausible_clickhouse_version }}
|
|
@ -0,0 +1,127 @@
|
|||
---
|
||||
services:
|
||||
plausible_db:
|
||||
image: postgres:${POSTGRES_VERSION}
|
||||
container_name: plausible-db
|
||||
restart: always
|
||||
networks:
|
||||
- plausible
|
||||
volumes:
|
||||
- db-data:/var/lib/postgresql/data
|
||||
environment:
|
||||
- POSTGRES_PASSWORD=postgres
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||
start_period: 1m
|
||||
|
||||
plausible_events_db:
|
||||
image: clickhouse/clickhouse-server:${CLICKHOUSE_VERSION}
|
||||
restart: always
|
||||
container_name: plausible-events
|
||||
networks:
|
||||
- plausible
|
||||
volumes:
|
||||
- event-data:/var/lib/clickhouse
|
||||
- event-logs:/var/log/clickhouse-server
|
||||
- ./data/clickhouse/logs.xml:/etc/clickhouse-server/config.d/logs.xml:ro
|
||||
- ./data/clickhouse/disable-internal-memory-tracker.xml:/etc/clickhouse-server/config.d/disable-internal-memory-tracker.xml:ro
|
||||
# This makes ClickHouse bind to IPv4 only, since Docker doesn't enable IPv6 in bridge networks by default.
|
||||
# Fixes "Listen [::]:9000 failed: Address family for hostname not supported" warnings.
|
||||
- ./data/clickhouse/ipv4-only.xml:/etc/clickhouse-server/config.d/ipv4-only.xml:ro
|
||||
# This makes ClickHouse consume less resources, which is useful for small setups.
|
||||
# https://clickhouse.com/docs/en/operations/tips#using-less-than-16gb-of-ram
|
||||
- ./data/clickhouse/low-resources.xml:/etc/clickhouse-server/config.d/low-resources.xml:ro
|
||||
ulimits:
|
||||
nofile:
|
||||
soft: 262144
|
||||
hard: 262144
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget --no-verbose --tries=1 -O - http://127.0.0.1:8123/ping || exit 1"]
|
||||
start_period: 1m
|
||||
|
||||
plausible:
|
||||
image: ghcr.io/plausible/community-edition:${PLAUSIBLE_VERSION}
|
||||
container_name: plausible
|
||||
restart: always
|
||||
command: sh -c "/entrypoint.sh db createdb && /entrypoint.sh db migrate && /entrypoint.sh run"
|
||||
depends_on:
|
||||
plausible_db:
|
||||
condition: service_healthy
|
||||
plausible_events_db:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- traefik
|
||||
- plausible
|
||||
volumes:
|
||||
- plausible:/var/lib/plausible
|
||||
ulimits:
|
||||
nofile:
|
||||
soft: 65535
|
||||
hard: 65535
|
||||
environment:
|
||||
- TMPDIR=/var/lib/plausible/tmp
|
||||
# required: https://github.com/plausible/community-edition/wiki/configuration#required
|
||||
- BASE_URL=https://${PLAUSIBLE_DOMAIN}
|
||||
- SECRET_KEY_BASE=${PLAUSIBLE_SECRET_KEY}
|
||||
# optional: https://github.com/plausible/community-edition/wiki/configuration#optional
|
||||
# registration: https://github.com/plausible/community-edition/wiki/configuration#registration
|
||||
- TOTP_VAULT_KEY
|
||||
- DISABLE_REGISTRATION
|
||||
- ENABLE_EMAIL_VERIFICATION
|
||||
# web: https://github.com/plausible/community-edition/wiki/configuration#web
|
||||
- PHX_SERVER=true
|
||||
- HTTP_PORT=8000
|
||||
- HTTPS_PORT
|
||||
- PORT=8000
|
||||
# databases: https://github.com/plausible/community-edition/wiki/configuration#database
|
||||
- DATABASE_URL
|
||||
- CLICKHOUSE_DATABASE_URL
|
||||
# Google: https://github.com/plausible/community-edition/wiki/configuration#google
|
||||
- GOOGLE_CLIENT_ID
|
||||
- GOOGLE_CLIENT_SECRET
|
||||
# geolocation: https://github.com/plausible/community-edition/wiki/configuration#ip-geolocation
|
||||
- IP_GEOLOCATION_DB
|
||||
- GEONAMES_SOURCE_FILE
|
||||
- MAXMIND_LICENSE_KEY
|
||||
- MAXMIND_EDITION
|
||||
# email: https://github.com/plausible/community-edition/wiki/configuration#email
|
||||
- MAILER_ADAPTER
|
||||
- MAILER_EMAIL
|
||||
- MAILER_NAME
|
||||
- SMTP_HOST_ADDR
|
||||
- SMTP_HOST_PORT
|
||||
- SMTP_USER_NAME
|
||||
- SMTP_USER_PWD
|
||||
- SMTP_HOST_SSL_ENABLED
|
||||
- POSTMARK_API_KEY
|
||||
- MAILGUN_API_KEY
|
||||
- MAILGUN_DOMAIN
|
||||
- MAILGUN_BASE_URI
|
||||
- MANDRILL_API_KEY
|
||||
- SENDGRID_API_KEY
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.plausible.entrypoints=https"
|
||||
- "traefik.http.routers.plausible.rule=Host(`${PLAUSIBLE_DOMAIN}`)"
|
||||
- "traefik.http.routers.plausible.tls=true"
|
||||
- "traefik.http.routers.plausible.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.plausible.loadbalancer.server.port=8000"
|
||||
- "traefik.docker.network=traefik"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -q -T 5 -O - http://127.0.0.1:8000/ >/dev/null 2>&1 || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 2
|
||||
start_period: 60s
|
||||
|
||||
networks:
|
||||
traefik:
|
||||
external: true
|
||||
plausible:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
db-data:
|
||||
event-data:
|
||||
event-logs:
|
||||
plausible:
|
1
ansible/roles/deploy_container_plausible/vars/main.yml
Normal file
1
ansible/roles/deploy_container_plausible/vars/main.yml
Normal file
|
@ -0,0 +1 @@
|
|||
container_base_dir: /opt/docker/plausible
|
58
ansible/roles/deploy_container_stirlingpdf/README.md
Normal file
58
ansible/roles/deploy_container_stirlingpdf/README.md
Normal file
|
@ -0,0 +1,58 @@
|
|||
# Role: deploy_container_traefik
|
||||
|
||||
## Purpose
|
||||
This role deploys and configures a StirlingPDF Container with Docker Compose
|
||||
|
||||
## Variables
|
||||
|
||||
### Default Variables (`defaults/main.yml`)
|
||||
```yaml
|
||||
container_stirlingpdf_version: latest
|
||||
container_stirlingpdf_app_name: StirlingPDF
|
||||
container_stirlingpdf_app_description: Your PDF Source
|
||||
container_stirlingpdf_domain: stirlingpdf.example.com
|
||||
|
||||
```
|
||||
|
||||
### Static Variables (`vars/main.yml`)
|
||||
```yaml
|
||||
container_base_dir: /opt/docker/stirlingpdf
|
||||
```
|
||||
|
||||
### Role Usage
|
||||
|
||||
```yaml
|
||||
- name: Deploy StirlingPDF container
|
||||
hosts: docker
|
||||
roles:
|
||||
- role: deploy_container_stirlingpdf
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
* Linux system (tested on Debian)
|
||||
* Docker Engine
|
||||
* Docker Compose v2 plugin (`docker compose` CLI)
|
||||
* Ansible 2.11 or higher
|
||||
* `community.docker` collection
|
||||
|
||||
Install the required collection:
|
||||
|
||||
```bash
|
||||
ansible-galaxy collection install community.docker
|
||||
```
|
||||
|
||||
Or via `requirements.yml`:
|
||||
|
||||
```yaml
|
||||
collections:
|
||||
- name: community.docker
|
||||
version: ">=3.4.0"
|
||||
```
|
||||
|
||||
## Authors
|
||||
|
||||
* Kevin Heyer
|
||||
📧 [kevin.heyer@wira-gmbh.de](mailto:kevin.heyer@wira-gmbh.de)
|
||||
|
||||
```
|
|
@ -0,0 +1,4 @@
|
|||
container_stirlingpdf_version: latest
|
||||
container_stirlingpdf_app_name: StirlingPDF
|
||||
container_stirlingpdf_app_description: Your PDF Source
|
||||
container_stirlingpdf_domain: stirlingpdf.example.com
|
|
@ -0,0 +1,6 @@
|
|||
<footer th:fragment="footer" id="footer" class="text-center">
|
||||
|
||||
<script type="module" th:src="@{'/js/thirdParty/cookieconsent-config.js'}"></script>
|
||||
<div class="footer-center">
|
||||
</div>
|
||||
</footer>
|
277
ansible/roles/deploy_container_stirlingpdf/files/navbar.html
Normal file
277
ansible/roles/deploy_container_stirlingpdf/files/navbar.html
Normal file
|
@ -0,0 +1,277 @@
|
|||
<div th:fragment="navbar" class="mx-auto" style="position: sticky; top:0; z-index:10000; width:100%">
|
||||
<script th:src="@{'/js/languageSelection.js'}"></script>
|
||||
<script th:src="@{'/js/navbar.js'}"></script>
|
||||
<script th:src="@{'/js/additionalLanguageCode.js'}"></script>
|
||||
<script th:inline="javascript">
|
||||
// Initializing the scripts
|
||||
initLanguageSettings();
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
toolsManager();
|
||||
});
|
||||
</script>
|
||||
<script th:inline="javascript">
|
||||
const currentVersion = /*[[${@appVersion}]]*/ '';
|
||||
const noFavourites = /*[[#{noFavourites}]]*/ '';
|
||||
console.log(noFavourites);
|
||||
const updateAvailable = /*[[#{settings.updateAvailable}]]*/ '';
|
||||
</script>
|
||||
<script th:src="@{'/js/homecard.js'}"></script>
|
||||
<script th:src="@{'/js/githubVersion.js'}"></script>
|
||||
<form th:action="@{'/dummyFormToPopulateCSRF'}" method="post" enctype="multipart/form-data"></form>
|
||||
<nav class="navbar navbar-expand-xl" style="
|
||||
background: var(--md-nav-background);
|
||||
border-bottom-style: solid;
|
||||
border-bottom-width: 1px;
|
||||
border-color: var(--md-nav-color-on-separator)">
|
||||
<div class="container " style="max-width: 100%;">
|
||||
<a class="navbar-brand" th:href="${@contextPath}" style="display: flex;">
|
||||
<img class="main-icon" th:src="@{'/favicon.svg'}" alt="icon">
|
||||
<span class="icon-text" th:text="${@navBarText}"></span>
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
|
||||
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="material-symbols-rounded">
|
||||
menu
|
||||
</span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav me-auto flex-nowrap">
|
||||
|
||||
<!-- All Tools -->
|
||||
<li id="navItemToHide" class="nav-item dropdown dropdown-mega position-static">
|
||||
<a class="nav-link" id="navbarDropdown-1" href="#" role="button" data-bs-toggle="dropdown"
|
||||
aria-haspopup="true" aria-expanded="false">
|
||||
<span class="material-symbols-rounded">
|
||||
apps
|
||||
</span>
|
||||
<span class="icon-text" th:data-text="#{navbar.allTools}" th:text="#{navbar.allTools}"></span>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-tp" aria-labelledby="navbarDropdown-1">
|
||||
<div class="dropdown-menu-wrapper" style="justify-content: center; display:flex">
|
||||
<div class="feature-rows">
|
||||
|
||||
<th:block th:insert="~{fragments/navElements.html :: navElements}"></th:block>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="nav-item" th:if="${@endpointConfiguration.isEndpointEnabled('multi-tool')}">
|
||||
<a class="nav-link" href="#" th:href="@{'/multi-tool'}"
|
||||
th:classappend="${currentPage}=='multi-tool' ? 'active' : ''" th:title="#{home.multiTool.desc}">
|
||||
<span class="material-symbols-rounded">
|
||||
construction
|
||||
</span>
|
||||
<span class="icon-text" th:data-text="#{navbar.multiTool}" th:text="#{navbar.multiTool}"></span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item" th:if="${@endpointConfiguration.isEndpointEnabled('pipeline')}">
|
||||
<a class="nav-link" href="#" th:href="@{'/pipeline'}"
|
||||
th:classappend="${currentPage}=='pipeline' ? 'active' : ''" th:title="#{home.pipeline.desc}">
|
||||
<span class="material-symbols-rounded">
|
||||
family_history
|
||||
</span>
|
||||
<span class="icon-text" th:data-text="#{home.pipeline.title}" th:text="#{home.pipeline.title}"></span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item" th:if="${@endpointConfiguration.isEndpointEnabled('compress-pdf')}">
|
||||
<a class="nav-link" href="#" title="#{home.compressPdfs.title}" th:href="@{'/compress-pdf'}"
|
||||
th:classappend="${currentPage}=='compress-pdf' ? 'active' : ''" th:title="#{home.compressPdfs.desc}">
|
||||
<span class="material-symbols-rounded">
|
||||
zoom_in_map
|
||||
</span>
|
||||
<span class="icon-text" th:data-text="#{home.compressPdfs.title}"
|
||||
th:text="#{home.compressPdfs.title}"></span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#" th:href="@{'/view-pdf'}"
|
||||
th:classappend="${currentPage}=='view-pdf' ? 'active' : ''" th:title="#{home.viewPdf.desc}">
|
||||
<span class="material-symbols-rounded">
|
||||
menu_book
|
||||
</span>
|
||||
<span class="icon-text" th:data-text="#{home.viewPdf.title}" th:text="#{home.viewPdf.title}"></span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<!-- <li class="nav-item">
|
||||
<a class="nav-link" href="#" th:href="@{'/merge-pdfs'}"
|
||||
th:classappend="${currentPage}=='merge-pdfs' ? 'active' : ''" th:title="#{home.merge.desc}">
|
||||
<span class="material-symbols-rounded">
|
||||
add_to_photos
|
||||
</span>
|
||||
<span class="icon-text" th:data-text="#{home.merge.title}" th:text="#{home.merge.title}"></span>
|
||||
</a>
|
||||
</li> -->
|
||||
|
||||
</ul>
|
||||
<ul class="navbar-nav flex-nowrap">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link" id="navbarDropdown-5" href="#" role="button" data-bs-toggle="dropdown"
|
||||
aria-haspopup="true" aria-expanded="false" th:title="#{navbar.favorite}">
|
||||
<span class="material-symbols-rounded">
|
||||
star
|
||||
</span>
|
||||
<span class="icon-text icon-hide" th:data-text="#{navbar.favorite}" th:text="#{navbar.favorite}"></span>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-tp dropdown-mw-28" aria-labelledby="navbarDropdown-5">
|
||||
<div class="dropdown-menu-wrapper px-xl-2 px-2" id="favoritesDropdown">
|
||||
<!-- Dropdown items will be added here by JavaScript -->
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="dark-mode-toggle" href="#" th:title="#{navbar.darkmode}">
|
||||
<span class="material-symbols-rounded" id="dark-mode-icon">
|
||||
dark_mode
|
||||
</span>
|
||||
<span class="icon-text icon-hide" id="dark-mode-text" th:data-text="#{navbar.darkmode}"
|
||||
th:text="#{navbar.darkmode}"></span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link" href="#" id="languageDropdown" role="button" data-bs-toggle="dropdown"
|
||||
aria-haspopup="true" aria-expanded="false" th:title="#{navbar.language}">
|
||||
<span class="material-symbols-rounded">
|
||||
language
|
||||
</span>
|
||||
<span class="icon-text icon-hide" th:data-text="#{navbar.language}" th:text="#{navbar.language}"></span>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-tp" aria-labelledby="languageDropdown">
|
||||
<div class="dropdown-menu-wrapper px-xl-2 px-2">
|
||||
<div id="languageSelection" class="scrollable-y lang_dropdown-mw scalable-languages-container">
|
||||
<th:block th:insert="~{fragments/languages :: langs}"></th:block>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link" href="#" id="searchDropdown" role="button" data-bs-toggle="dropdown"
|
||||
aria-haspopup="true" aria-expanded="false" th:title="#{navbar.search}">
|
||||
<span class="material-symbols-rounded">
|
||||
search
|
||||
</span>
|
||||
<span class="icon-text icon-hide">Search</span>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-tp" aria-labelledby="searchDropdown">
|
||||
<div class="dropdown-menu-wrapper px-xl-2 px-2">
|
||||
<form th:action="@{''}" class="d-flex p-2 search-form" id="searchForm">
|
||||
<input class="form-control search-input" type="search" th:placeholder="#{navbar.search}"
|
||||
aria-label="Search" id="navbarSearchInput">
|
||||
</form>
|
||||
<!-- Search Results -->
|
||||
<div id="searchResults" class="search-results scrollable-y dropdown-mw-20"></div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<!-- Settings Button -->
|
||||
<a href="#" class="nav-link" data-bs-toggle="modal" data-bs-target="#settingsModal"
|
||||
th:title="#{navbar.settings}">
|
||||
<span class="material-symbols-rounded">
|
||||
settings
|
||||
</span>
|
||||
<span class="icon-text icon-hide" th:data-text="#{navbar.settings}" th:text="#{navbar.settings}"></span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<script th:src="@{'/js/favourites.js'}"></script>
|
||||
<script th:src="@{'/js/search.js'}"></script>
|
||||
</nav>
|
||||
|
||||
<th:block th:insert="~{fragments/errorBannerPerPage.html :: errorBannerPerPage}"></th:block>
|
||||
<div class="modal fade" id="settingsModal" tabindex="-1" role="dialog" aria-labelledby="settingsModalLabel"
|
||||
aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="settingsModalLabel" th:text="#{settings.title}"></h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close">
|
||||
<span class="material-symbols-rounded">
|
||||
close
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p class="mb-0" th:utext="#{settings.appVersion} + ' ' + ${@appVersion}"></p>
|
||||
<div class="d-flex justify-content-between align-items-center mb-3 mt-3">
|
||||
<div class="footer-center" style="flex-direction: row;">
|
||||
<a href="https://github.com/Stirling-Tools/Stirling-PDF" class="mx-1" role="button" target="_blank"
|
||||
th:title="#{visitGithub}">
|
||||
<img th:src="@{'/images/github.svg'}" alt="github">
|
||||
</a>
|
||||
<a href="https://hub.docker.com/r/stirlingtools/stirling-pdf" class="mx-1" role="button" target="_blank"
|
||||
th:title="#{seeDockerHub}">
|
||||
<img th:src="@{'/images/docker.svg'}" alt="docker">
|
||||
</a>
|
||||
<a href="https://discord.gg/Cn8pWhQRxZ" class="mx-1" role="button" target="_blank"
|
||||
th:title="#{joinDiscord}">
|
||||
<img th:src="@{'/images/discord.svg'}" alt="discord">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<a th:href="@{'/swagger-ui/index.html'}" class="btn btn-sm btn-outline-primary mx-1" role="button"
|
||||
target="_blank">API</a>
|
||||
<a href="https://github.com/Stirling-Tools/Stirling-PDF/releases"
|
||||
class="btn btn-sm btn-outline-primary mx-1" id="update-btn" th:utext="#{settings.update}" role="button"
|
||||
target="_blank"></a>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="downloadOption" th:utext="#{settings.downloadOption.title}"></label>
|
||||
<select class="form-control" id="downloadOption">
|
||||
<option value="sameWindow" th:utext="#{settings.downloadOption.1}"></option>
|
||||
<option value="newWindow" th:utext="#{settings.downloadOption.2}"></option>
|
||||
<option value="downloadFile" th:utext="#{settings.downloadOption.3}"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="zipThreshold" th:utext="#{settings.zipThreshold}"></label><br />
|
||||
<input type="range" class="form-range" min="1" max="9" step="1" id="zipThreshold" value="4">
|
||||
<span id="zipThresholdValue" class="ms-2"></span>
|
||||
</div>
|
||||
<div class="form-check mb-3">
|
||||
<input type="checkbox" id="boredWaiting" th:title="#{settings.bored.help}">
|
||||
<label for="boredWaiting" th:text="#{bored}"></label>
|
||||
</div>
|
||||
<div class="form-check mb-3">
|
||||
<input type="checkbox" id="cacheInputs" th:title="#{settings.cacheInputs.help}">
|
||||
<label for="cacheInputs" th:text="#{settings.cacheInputs.name}"></label>
|
||||
</div>
|
||||
|
||||
<a th:if="${@loginEnabled and @activeSecurity}" th:href="@{'/account'}" class="btn btn-sm btn-outline-primary"
|
||||
role="button" th:text="#{settings.accountSettings}" target="_blank">Account Settings</a>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a th:if="${@loginEnabled and @activeSecurity}" class="btn btn-danger" role="button"
|
||||
th:text="#{settings.signOut}" th:href="@{'/logout'}">Sign Out</a>
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" th:text="#{close}"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script th:src="@{'/js/settings.js'}"></script>
|
||||
<script th:inline="javascript">
|
||||
window.onload = function () {
|
||||
updateFavoritesDropdown();
|
||||
|
||||
}
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const navbarLink = document.querySelector(".navbar-brand");
|
||||
const contentPath = /*[[${@contextPath}]]*/ '';
|
||||
if (localStorage.getItem("defaultView") === "home-legacy") {
|
||||
navbarLink.setAttribute("href", contentPath + "home-legacy");
|
||||
} else {
|
||||
navbarLink.setAttribute("href", contentPath);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</div>
|
|
@ -0,0 +1 @@
|
|||
---
|
21
ansible/roles/deploy_container_stirlingpdf/meta/main.yml
Normal file
21
ansible/roles/deploy_container_stirlingpdf/meta/main.yml
Normal file
|
@ -0,0 +1,21 @@
|
|||
galaxy_info:
|
||||
role_name: container_stirlingpdf
|
||||
author: Kevin Heyer
|
||||
description: |
|
||||
Deploys and configures a StirlingPDF Container in a Docker.
|
||||
license: MIT
|
||||
min_ansible_version: "2.11"
|
||||
platforms:
|
||||
- name: Debian
|
||||
versions:
|
||||
- bookworm
|
||||
- bullseye
|
||||
|
||||
galaxy_tags:
|
||||
- docker
|
||||
- pdf
|
||||
- stirlingpdf
|
||||
- container
|
||||
- ansible
|
||||
|
||||
dependencies: []
|
42
ansible/roles/deploy_container_stirlingpdf/tasks/main.yml
Normal file
42
ansible/roles/deploy_container_stirlingpdf/tasks/main.yml
Normal file
|
@ -0,0 +1,42 @@
|
|||
---
|
||||
- name: Ensure data directories exist
|
||||
ansible.builtin.file:
|
||||
path: "{{ container_base_dir }}/data/{{ item }}"
|
||||
state: directory
|
||||
mode: '0755'
|
||||
loop:
|
||||
- "trainingData"
|
||||
- "extraConfigs"
|
||||
- "customFiles/templates/fragments"
|
||||
- "logs"
|
||||
- "pipeline"
|
||||
|
||||
- name: Copy custom HTML files
|
||||
ansible.builtin.copy:
|
||||
src: '{{ item.src }}'
|
||||
dest: '{{ item.dest }}'
|
||||
mode: '0755'
|
||||
loop:
|
||||
- { src: navbar.html, dest: '{{ container_base_dir }}/data/customFiles/templates/fragments/navbar.html' }
|
||||
- { src: footer.html, dest: '{{ container_base_dir }}/data/customFiles/templates/fragments/footer.html' }
|
||||
|
||||
- name: Deploy Docker Compose and .env files
|
||||
ansible.builtin.template:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ container_base_dir }}/{{ item.dest }}"
|
||||
mode: '0644'
|
||||
loop:
|
||||
- { src: 'docker-compose.yml.j2', dest: 'docker-compose.yml' }
|
||||
- { src: '.env.j2', dest: '.env' }
|
||||
|
||||
- name: Stop Container
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ container_base_dir }}"
|
||||
state: absent
|
||||
|
||||
- name: Start Container
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ container_base_dir }}"
|
||||
state: present
|
||||
pull: always
|
||||
recreate: always
|
11
ansible/roles/deploy_container_stirlingpdf/templates/.env.j2
Normal file
11
ansible/roles/deploy_container_stirlingpdf/templates/.env.j2
Normal file
|
@ -0,0 +1,11 @@
|
|||
# Version of the StirlingPDF container
|
||||
STIRLINGPDF_VERSION={{ container_stirlingpdf_version}}
|
||||
|
||||
# Application name (UI)
|
||||
STIRLINGPDF_APPNAME={{ container_stirlingpdf_app_name }}
|
||||
|
||||
# Application description (UI)
|
||||
STIRLINGPDF_DESCRIPTION={{ container_stirlingpdf_app_description }}
|
||||
|
||||
# Domain for the StirlingPDF service (replace this with the actual domain)
|
||||
STIRLINGPDF_DOMAIN={{ container_stirlingpdf_domain }}
|
|
@ -0,0 +1,47 @@
|
|||
---
|
||||
services:
|
||||
stirling-pdf:
|
||||
image: docker.stirlingpdf.com/stirlingtools/stirling-pdf:${STIRLINGPDF_VERSION}
|
||||
container_name: stirlingpdf
|
||||
networks:
|
||||
- traefik
|
||||
volumes:
|
||||
- ./data/trainingData:/usr/share/tessdata # Required for extra OCR languages
|
||||
- ./data/extraConfigs:/configs
|
||||
- ./data/customFiles:/customFiles/
|
||||
- ./data/logs:/logs/
|
||||
- ./data/pipeline:/pipeline/
|
||||
environment:
|
||||
- DOCKER_ENABLE_SECURITY=false
|
||||
- LANGS=de_DE
|
||||
- SYSTEM_DEFAULTLOCALE=de-DE
|
||||
- INSTALL_BOOK_AND_ADVANCED_HTML_OPS=false
|
||||
- UI_APPNAME=${STIRLINGPDF_APPNAME:-StirlingPDF}
|
||||
- UI_HOMEDESCRIPTION=${STIRLINGPDF_DESCRIPTION:-Your PDF Source}
|
||||
- UI_APPNAMENAVBAR=${STIRLINGPDF_APPNAME:-StirlingPDF}
|
||||
- SYSTEM_CUSTOMHTMLFILES=true
|
||||
- DISABLE_PIXEL=true
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=traefik"
|
||||
- "traefik.http.routers.stirlingpdf.entrypoints=http"
|
||||
- "traefik.http.routers.stirlingpdf.rule=Host(`${STIRLINGPDF_DOMAIN:?error}`)"
|
||||
- "traefik.http.middlewares.stirlingpdf-https-redirect.redirectscheme.scheme=https"
|
||||
- "traefik.http.routers.stirlingpdf.middlewares=traefik-https-redirect"
|
||||
- "traefik.http.routers.stirlingpdf-secure.entrypoints=https"
|
||||
- "traefik.http.routers.stirlingpdf-secure.rule=Host(`${STIRLINGPDF_DOMAIN:?error}`)"
|
||||
- "traefik.http.routers.stirlingpdf-secure.tls=true"
|
||||
- "traefik.http.routers.stirlingpdf-secure.service=stirlingpdf"
|
||||
- "traefik.http.services.stirlingpdf.loadbalancer.server.port=8080"
|
||||
{% if container_traefik_auth == 'sso' %}
|
||||
- "traefik.http.routers.stirlingpdf-secure.middlewares=middlewares-authelia@file"
|
||||
{% endif %}
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -f http://localhost:8080/api/v1/info/status | grep -q 'UP'"]
|
||||
interval: 5s
|
||||
timeout: 10s
|
||||
retries: 16
|
||||
|
||||
networks:
|
||||
traefik:
|
||||
external: true
|
1
ansible/roles/deploy_container_stirlingpdf/vars/main.yml
Normal file
1
ansible/roles/deploy_container_stirlingpdf/vars/main.yml
Normal file
|
@ -0,0 +1 @@
|
|||
container_base_dir: /opt/docker/stirlingpdf
|
8
ansible/roles/deploy_container_ticky/defaults/main.yml
Normal file
8
ansible/roles/deploy_container_ticky/defaults/main.yml
Normal file
|
@ -0,0 +1,8 @@
|
|||
#########
|
||||
# Ticky #
|
||||
#########
|
||||
container_ticky_version: latest
|
||||
contaner_ticky_domain: kanban.example.com
|
||||
container_ticky_mysql_version: 8
|
||||
container_ticky_mysql_username: ticky
|
||||
container_ticky_mysql_password: random_password
|
0
ansible/roles/deploy_container_ticky/files/.gitkeep
Normal file
0
ansible/roles/deploy_container_ticky/files/.gitkeep
Normal file
0
ansible/roles/deploy_container_ticky/handlers/main.yml
Normal file
0
ansible/roles/deploy_container_ticky/handlers/main.yml
Normal file
0
ansible/roles/deploy_container_ticky/meta/main.yml
Normal file
0
ansible/roles/deploy_container_ticky/meta/main.yml
Normal file
30
ansible/roles/deploy_container_ticky/tasks/main.yml
Normal file
30
ansible/roles/deploy_container_ticky/tasks/main.yml
Normal file
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
- name: Ensure data directories exist
|
||||
ansible.builtin.file:
|
||||
path: "{{ container_base_dir }}/data/{{ item }}"
|
||||
state: directory
|
||||
mode: '0755'
|
||||
loop:
|
||||
- "upload"
|
||||
- "mysql"
|
||||
|
||||
- name: Deploy Docker Compose and .env files
|
||||
ansible.builtin.template:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ container_base_dir }}/{{ item.dest }}"
|
||||
mode: '0644'
|
||||
loop:
|
||||
- { src: 'docker-compose.yml.j2', dest: 'docker-compose.yml' }
|
||||
- { src: '.env.j2', dest: '.env' }
|
||||
|
||||
- name: Stop Container
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ container_base_dir }}"
|
||||
state: absent
|
||||
|
||||
- name: Start Container
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ container_base_dir }}"
|
||||
state: present
|
||||
pull: always
|
||||
recreate: always
|
6
ansible/roles/deploy_container_ticky/templates/.env.j2
Normal file
6
ansible/roles/deploy_container_ticky/templates/.env.j2
Normal file
|
@ -0,0 +1,6 @@
|
|||
TICKY_VERSION={{ container_ticky_version }}
|
||||
TICKY_DOMAIN={{ contaner_ticky_domain }}
|
||||
|
||||
MYSQL_VERSION={{ container_ticky_mysql_version }}
|
||||
MYSQL_USERNAME={{ container_ticky_mysql_username }}
|
||||
MYSQL_PASSWORD={{ container_ticky_mysql_password }}
|
|
@ -0,0 +1,70 @@
|
|||
---
|
||||
services:
|
||||
ticky:
|
||||
image: ghcr.io/dkorecko/ticky:${TICKY_VERSION}
|
||||
container_name: ticky
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- traefik
|
||||
- ticky
|
||||
volumes:
|
||||
- ./data/upload:/app/wwwroot/uploaded
|
||||
environment:
|
||||
- DB_HOST=ticky-db
|
||||
- DB_NAME=ticky
|
||||
- DB_USERNAME=${MYSQL_USERNAME}
|
||||
- DB_PASSWORD=${MYSQL_PASSWORD}
|
||||
- FULLY_OFFLINE=true
|
||||
- DISABLE_USER_SIGNUPS=true
|
||||
- SMTP_ENABLED=false
|
||||
- SMTP_HOST=your-smtp-host
|
||||
- SMTP_PORT=your-smtp-port
|
||||
- SMTP_DISPLAY_NAME=Ticky
|
||||
- SMTP_EMAIL=your-email@example.com
|
||||
- SMTP_USERNAME=your-smtp-username
|
||||
- SMTP_PASSWORD=your-smtp-password
|
||||
- SMTP_SECURITY=true
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=traefik"
|
||||
- "traefik.http.routers.ticky.entrypoints=http"
|
||||
- "traefik.http.routers.ticky.rule=Host(`${TICKY_DOMAIN}`)"
|
||||
- "traefik.http.middlewares.ticky-https-redirect.redirectscheme.scheme=https"
|
||||
- "traefik.http.routers.ticky.middlewares=traefik-https-redirect"
|
||||
- "traefik.http.routers.ticky-secure.entrypoints=https"
|
||||
- "traefik.http.routers.ticky-secure.rule=Host(`${TICKY_DOMAIN}`)"
|
||||
- "traefik.http.routers.ticky-secure.tls=true"
|
||||
- "traefik.http.services.ticky.loadbalancer.server.port=8080"
|
||||
depends_on:
|
||||
ticky-db:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl --fail --silent --max-time 5 http://localhost:8080/ || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
|
||||
ticky-db:
|
||||
image: mysql:${MYSQL_VERSION}
|
||||
container_name: ticky-db
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- ticky
|
||||
environment:
|
||||
MYSQL_DATABASE: ticky
|
||||
MYSQL_USER: ${MYSQL_USERNAME}
|
||||
MYSQL_RANDOM_ROOT_PASSWORD: true
|
||||
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
|
||||
timeout: 2s
|
||||
retries: 30
|
||||
volumes:
|
||||
- ./data/mysql:/var/lib/mysql
|
||||
|
||||
networks:
|
||||
traefik:
|
||||
external: true
|
||||
ticky:
|
||||
driver: bridge
|
1
ansible/roles/deploy_container_ticky/vars/main.yml
Normal file
1
ansible/roles/deploy_container_ticky/vars/main.yml
Normal file
|
@ -0,0 +1 @@
|
|||
container_base_dir: /opt/docker/ticky
|
|
@ -0,0 +1,112 @@
|
|||
# Role: deploy_container_traefik
|
||||
|
||||
## Purpose
|
||||
This role deploys and configures a Traefik reverse proxy using Docker Compose.
|
||||
It supports TLS, host-specific certificates, and renders all configuration files using Jinja2 templates.
|
||||
The configuration includes a fallback router/service to ensure safe defaults.
|
||||
|
||||
## Variables
|
||||
|
||||
### Default Variables (`defaults/main.yml`)
|
||||
```yaml
|
||||
|
||||
container_traefik_create_network: true
|
||||
container_traefik_subnet: 192.168.222.0/24
|
||||
container_traefik_gateway: 192.168.222.1
|
||||
|
||||
container_traefik_url: "traefik.example.com"
|
||||
container_traefik_version: "latest"
|
||||
|
||||
# Create with: echo $(htpasswd -nB user) | sed -e s/\\$/\\$\\$/g
|
||||
container_traefik_basicuser: "admin"
|
||||
container_traefik_basicpassword: "changeme"
|
||||
|
||||
container_traefik_http_port: 80
|
||||
container_traefik_https_port: 443
|
||||
|
||||
# Dummy router/service to avoid template errors if nothing is defined
|
||||
container_traefik_routers:
|
||||
dummy:
|
||||
entryPoints: ["https"]
|
||||
rule: "Host(`dummy.local`)"
|
||||
service: dummy
|
||||
tls: true
|
||||
|
||||
container_traefik_services:
|
||||
dummy:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "https://127.0.0.1:443"
|
||||
passHostHeader: true
|
||||
```
|
||||
|
||||
### Static Variables (`vars/main.yml`)
|
||||
```yaml
|
||||
container_traefik_base_dir: /opt/docker/traefik
|
||||
```
|
||||
|
||||
### Role Usage
|
||||
|
||||
```yaml
|
||||
- name: Deploy Traefik container
|
||||
hosts: traefik
|
||||
roles:
|
||||
- role: container_traefik
|
||||
vars:
|
||||
container_traefik_url: "traefik.example.com"
|
||||
container_traefik_basicuser: "admin"
|
||||
container_traefik_basicpassword: "$2y$05$<bcrypt_hash>"
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
* Linux system (tested on Debian)
|
||||
* Docker Engine
|
||||
* Docker Compose v2 plugin (`docker compose` CLI)
|
||||
* Ansible 2.11 or higher
|
||||
* `community.docker` collection
|
||||
|
||||
Install the required collection:
|
||||
|
||||
```bash
|
||||
ansible-galaxy collection install community.docker
|
||||
```
|
||||
|
||||
Or via `requirements.yml`:
|
||||
|
||||
```yaml
|
||||
collections:
|
||||
- name: community.docker
|
||||
version: ">=3.4.0"
|
||||
```
|
||||
|
||||
## Host-Specific Certificates
|
||||
|
||||
Location: `host_files/<inventory_hostname>/certs/`
|
||||
|
||||
Required files:
|
||||
|
||||
* `wildcard.crt`
|
||||
* `wildcard.key`
|
||||
|
||||
## Handlers
|
||||
|
||||
* `Stop traefik container`
|
||||
* `Start traefik container`
|
||||
|
||||
## Rendered Templates
|
||||
|
||||
| Template File | Description |
|
||||
| ------------------------- | ---------------------------------- |
|
||||
| `docker-compose.yml.j2` | Docker Compose definition |
|
||||
| `.env.j2` | Environment variable file |
|
||||
| `traefik.yml.j2` | Main Traefik config (static) |
|
||||
| `tls.yml.j2` | TLS certificate reference |
|
||||
| `routers_services.yml.j2` | Static routers and services config |
|
||||
|
||||
## Authors
|
||||
|
||||
* Kevin Heyer
|
||||
📧 [kevin.heyer@wira-gmbh.de](mailto:kevin.heyer@wira-gmbh.de)
|
||||
|
||||
```
|
|
@ -0,0 +1,30 @@
|
|||
###########
|
||||
# Traefik #
|
||||
###########
|
||||
container_traefik_url: "traefik.example.com"
|
||||
container_traefik_version: "latest"
|
||||
container_traefik_basicuser: "admin"
|
||||
container_traefik_basicpassword: "changeme"
|
||||
container_traefik_http_port: 80
|
||||
container_traefik_https_port: 443
|
||||
container_traefik_auth: "basic" # Options: basic, sso
|
||||
container_traefik_dashboard_enabled: false
|
||||
container_traefik_letsencrypt_email: "mail@example.com"
|
||||
|
||||
container_traefik_routers:
|
||||
dummy:
|
||||
entryPoints: ["https"]
|
||||
rule: "Host(`dummy.local`)"
|
||||
service: dummy
|
||||
tls: true
|
||||
|
||||
container_traefik_services:
|
||||
dummy:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "https://127.0.0.1:443"
|
||||
passHostHeader: true
|
||||
|
||||
container_traefik_create_network: true
|
||||
container_traefik_subnet: 192.168.222.0/24
|
||||
container_traefik_gateway: 192.168.222.1
|
|
@ -0,0 +1,19 @@
|
|||
http:
|
||||
middlewares:
|
||||
https-redirect:
|
||||
redirectScheme:
|
||||
scheme: https
|
||||
|
||||
default-headers:
|
||||
headers:
|
||||
frameDeny: true
|
||||
sslRedirect: true
|
||||
browserXssFilter: true
|
||||
contentTypeNosniff: true
|
||||
forceSTSHeader: true
|
||||
stsIncludeSubdomains: true
|
||||
stsPreload: true
|
||||
stsSeconds: 15552000
|
||||
customFrameOptionsValue: "SAMEORIGIN"
|
||||
customRequestHeaders:
|
||||
X-Forwarded-Proto: "https"
|
|
@ -0,0 +1,24 @@
|
|||
galaxy_info:
|
||||
role_name: container_traefik_with_letsencrypt
|
||||
author: Kevin Heyer
|
||||
description: |
|
||||
Deploys and configures a Traefik container using Docker Compose.
|
||||
Includes support for custom .env, TLS with LetsEncrypt, routers/services config, and optional network creation.
|
||||
license: MIT
|
||||
min_ansible_version: "2.11"
|
||||
platforms:
|
||||
- name: Debian
|
||||
versions:
|
||||
- bookworm
|
||||
- bullseye
|
||||
|
||||
galaxy_tags:
|
||||
- docker
|
||||
- traefik
|
||||
- reverseproxy
|
||||
- container
|
||||
- https
|
||||
- router
|
||||
- ansible
|
||||
|
||||
dependencies: []
|
|
@ -0,0 +1,67 @@
|
|||
---
|
||||
- name: Ensure data directories exist
|
||||
ansible.builtin.file:
|
||||
path: "{{ container_base_dir }}/data/{{ item }}"
|
||||
state: directory
|
||||
mode: '0755'
|
||||
loop:
|
||||
- "certs"
|
||||
- "config.d"
|
||||
- "logs"
|
||||
|
||||
- name: Ensure log files exist
|
||||
ansible.builtin.file:
|
||||
path: "{{ container_base_dir }}/data/logs/{{ item }}"
|
||||
state: touch
|
||||
mode: '0644'
|
||||
loop:
|
||||
- "traefik.log"
|
||||
- "access.log"
|
||||
|
||||
- name: Ensure acme.json exist
|
||||
ansible.builtin.file:
|
||||
path: "{{ container_base_dir }}/data/certs/{{ item }}"
|
||||
state: touch
|
||||
mode: '0600'
|
||||
loop:
|
||||
- "acme.json"
|
||||
|
||||
- name: Create Docker network "traefik"
|
||||
community.docker.docker_network:
|
||||
name: traefik
|
||||
ipam_config:
|
||||
- subnet: "{{ container_traefik_subnet }}"
|
||||
gateway: "{{ container_traefik_gateway }}"
|
||||
when: container_traefik_create_network | default(true) | bool
|
||||
|
||||
- name: Copy config files
|
||||
ansible.builtin.copy:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ container_base_dir }}/data/{{ item.dest }}"
|
||||
mode: '0644'
|
||||
loop:
|
||||
- { src: 'middlewares.yml', dest: 'config.d/middlewares.yml' }
|
||||
become: false
|
||||
|
||||
- name: Render Docker Compose and config files
|
||||
ansible.builtin.template:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ container_base_dir }}/{{ item.dest }}"
|
||||
mode: '0644'
|
||||
loop:
|
||||
- { src: 'docker-compose.yml.j2', dest: 'docker-compose.yml' }
|
||||
- { src: '.env.j2', dest: '.env' }
|
||||
- { src: 'routers_services.yml.j2', dest: 'data/config.d/routers_services.yml' }
|
||||
- { src: 'traefik.yml.j2', dest: 'data/traefik.yml' }
|
||||
|
||||
- name: Stop Container
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ container_base_dir }}"
|
||||
state: absent
|
||||
|
||||
- name: Start Container
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ container_base_dir }}"
|
||||
state: present
|
||||
pull: always
|
||||
recreate: always
|
|
@ -0,0 +1,6 @@
|
|||
TRAEFIK_URL="{{ container_traefik_url }}"
|
||||
TRAEFIK_VERSION="{{ container_traefik_version | default('latest') }}"
|
||||
TRAEFIK_BASICAUTH_USER="{{ container_traefik_basicuser | default('user') }}"
|
||||
TRAEFIK_BASICAUTH_PASSWORD="{{ container_traefik_basicpassword | default('changeme') }}"
|
||||
TRAEFIK_HTTP_PORT="{{ container_traefik_http_port | default('80') }}"
|
||||
TRAEFIK_HTTPS_PORT="{{ container_traefik_https_port | default('443') }}"
|
|
@ -0,0 +1,56 @@
|
|||
---
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:${TRAEFIK_VERSION}
|
||||
container_name: traefik
|
||||
restart: unless-stopped
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
networks:
|
||||
traefik:
|
||||
ports:
|
||||
- "${TRAEFIK_HTTP_PORT}:80"
|
||||
- "${TRAEFIK_HTTPS_PORT}:443"
|
||||
volumes:
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- ./data/traefik.yml:/traefik.yml:ro
|
||||
- ./data/config.d:/config.d:ro
|
||||
- ./data/logs/traefik.log:/var/log/traefik.log
|
||||
- ./data/logs/access.log:/var/log/access.log
|
||||
- ./data/certs:/etc/certs:rw
|
||||
labels:
|
||||
# Basis
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.traefik.entrypoints=http"
|
||||
- "traefik.http.routers.traefik.rule=Host(`${TRAEFIK_URL}`)"
|
||||
|
||||
# Middlewares
|
||||
- "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https"
|
||||
- "traefik.http.middlewares.sslheader.headers.customrequestheaders.X-Forwarded-Proto=https"
|
||||
- "traefik.http.routers.traefik.middlewares=traefik-https-redirect"
|
||||
|
||||
# HTTPS
|
||||
- "traefik.http.routers.traefik-secure.entrypoints=https"
|
||||
- "traefik.http.routers.traefik-secure.rule=Host(`${TRAEFIK_URL}`)"
|
||||
- "traefik.http.routers.traefik-secure.tls=true"
|
||||
- "traefik.http.routers.traefik-secure.service=api@internal"
|
||||
|
||||
# Auth
|
||||
{% if container_traefik_auth == 'sso' %}
|
||||
- "traefik.http.routers.traefik-secure.middlewares=middlewares-authelia@file"
|
||||
{% elif container_traefik_auth == 'basic' or container_traefik_auth is not defined %}
|
||||
- "traefik.http.routers.traefik-secure.middlewares=basic-auth"
|
||||
- "traefik.http.middlewares.basic-auth.basicauth.users=${TRAEFIK_BASICAUTH_USER}:${TRAEFIK_BASICAUTH_PASSWORD}"
|
||||
{% endif %}
|
||||
|
||||
healthcheck:
|
||||
test: ["CMD", "traefik", "healthcheck"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
|
||||
networks:
|
||||
traefik:
|
||||
external: true
|
|
@ -0,0 +1,34 @@
|
|||
http:
|
||||
routers:
|
||||
{% for router_name, router in container_traefik_routers.items() %}
|
||||
{{ router_name }}:
|
||||
entryPoints:
|
||||
{% for ep in router.entryPoints %}
|
||||
- "{{ ep }}"
|
||||
{% endfor %}
|
||||
rule: "{{ router.rule }}"
|
||||
{% if router.middlewares is defined and router.middlewares %}
|
||||
middlewares:
|
||||
{% for m in router.middlewares %}
|
||||
- "{{ m }}"
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if router.tls is defined and router.tls %}
|
||||
tls: {}
|
||||
{% endif %}
|
||||
service: "{{ router.service }}"
|
||||
{% endfor %}
|
||||
|
||||
services:
|
||||
{% for service_name, service in container_traefik_services.items() %}
|
||||
{{ service_name }}:
|
||||
loadBalancer:
|
||||
servers:
|
||||
{% for server in service.loadBalancer.servers %}
|
||||
- url: "{{ server.url }}"
|
||||
{% endfor %}
|
||||
passHostHeader: {{ service.loadBalancer.passHostHeader | default(true) | lower }}
|
||||
{% if service.loadBalancer.serversTransport is defined %}
|
||||
serversTransport: "{{ service.loadBalancer.serversTransport }}"
|
||||
{% endif %}
|
||||
{% endfor %}
|
|
@ -0,0 +1,35 @@
|
|||
api:
|
||||
dashboard: {{ container_traefik_dashboard_enabled | lower }}
|
||||
insecure: false
|
||||
|
||||
log:
|
||||
level: "INFO"
|
||||
filePath: "/var/log/traefik.log"
|
||||
|
||||
accessLog:
|
||||
filePath: "/var/log/access.log"
|
||||
bufferingSize: 50
|
||||
|
||||
entryPoints:
|
||||
http:
|
||||
address: ":80"
|
||||
https:
|
||||
address: ":443"
|
||||
|
||||
ping:
|
||||
entryPoint: http
|
||||
|
||||
providers:
|
||||
docker:
|
||||
endpoint: "unix:///var/run/docker.sock"
|
||||
exposedByDefault: false
|
||||
file:
|
||||
directory: "/config.d/"
|
||||
watch: true
|
||||
|
||||
certificatesResolvers:
|
||||
letsencrypt:
|
||||
acme:
|
||||
email: {{ container_traefik_letsencrypt_email }}
|
||||
storage: /etc/certs/acme.json
|
||||
tlsChallenge: {}
|
|
@ -0,0 +1 @@
|
|||
container_base_dir : "/opt/docker/traefik-letsencrypt"
|
55
ansible/roles/deploy_container_vaultwarden/README.md
Normal file
55
ansible/roles/deploy_container_vaultwarden/README.md
Normal file
|
@ -0,0 +1,55 @@
|
|||
# Role: deploy_container_vaultwarden
|
||||
|
||||
## Purpose
|
||||
This role installs and configures Vaultwarden (a Bitwarden-compatible password manager) as a Docker container.
|
||||
It generates a `docker-compose.yml` and `.env` file based on the provided variables and integrates the container into an existing Traefik setup.
|
||||
|
||||
The role focuses solely on deployment and basic configuration of Vaultwarden, including SMTP settings and the admin token.
|
||||
|
||||
## Variables
|
||||
|
||||
### Default Variables (`defaults/main.yml`)
|
||||
```yaml
|
||||
container_vaultwarden_version: latest # (type: string) Vaultwarden container version
|
||||
container_vaultwarden_domain: vaultwarden.example.com # (type: string) Domain name for Vaultwarden
|
||||
container_vaultwarden_admin_token: generated_vaultwarden_hash # (type: string) Argon2 hash for admin login
|
||||
container_vaultwarden_smtp_host: ip_of_your_smtp_server # (type: string) SMTP server hostname/IP
|
||||
container_vaultwarden_smtp_from: mail@example.com # (type: string) Sender email address for notifications
|
||||
container_vaultwarden_smtp_port: 587 # (type: int) SMTP port (587 = TLS, 465 = SSL)
|
||||
container_vaultwarden_smtp_security: force_tls # (type: string) SMTP security ("force_tls", "starttls", "off")
|
||||
container_vaultwarden_smtp_username: your_smtp_username # (type: string) SMTP username
|
||||
container_vaultwarden_smtp_password: your_smtp_password # (type: string) SMTP password
|
||||
```
|
||||
Note: The admin token must be generated with
|
||||
```
|
||||
docker run --rm -it vaultwarden/server /vaultwarden hash
|
||||
```
|
||||
|
||||
### Static Variables (`vars/main.yml`)
|
||||
```yaml
|
||||
container_base_dir: /opt/docker/vaultwarden
|
||||
```
|
||||
|
||||
### Role Usage
|
||||
|
||||
```yaml
|
||||
roles:
|
||||
- role: deploy_container_vaultwarden
|
||||
vars:
|
||||
container_vaultwarden_domain: vault.yourdomain.tld
|
||||
container_vaultwarden_smtp_host: smtp.yourprovider.com
|
||||
container_vaultwarden_smtp_port: 465
|
||||
container_vaultwarden_smtp_security: force_tls
|
||||
```
|
||||
|
||||
## Requirements
|
||||
* Docker and Docker Compose must be installed
|
||||
* The Traefik network (traefik) must exist
|
||||
* Ansible access to the target system
|
||||
* Root/sudo privileges (become: true)
|
||||
|
||||
## Authors
|
||||
* Author
|
||||
📧 [Kevin Heyer](mailto:kevin.heyer@wira-gmbh.de)
|
||||
|
||||
```
|
16
ansible/roles/deploy_container_vaultwarden/defaults/main.yml
Normal file
16
ansible/roles/deploy_container_vaultwarden/defaults/main.yml
Normal file
|
@ -0,0 +1,16 @@
|
|||
###############
|
||||
# Vaultwarden #
|
||||
###############
|
||||
container_vaultwarden_version: latest
|
||||
container_vaultwarden_domain: vaultwarden.example.com
|
||||
|
||||
# docker run --rm -it vaultwarden/server /vaultwarden hash
|
||||
# you need to escape all five occurrences of the dollar sign $ in the generated argon2 PHC string
|
||||
container_vaultwarden_admin_token: generated_vaultwarden_hash
|
||||
|
||||
container_vaultwarden_smtp_host: ip_of_your_smtp_server
|
||||
container_vaultwarden_smtp_from: mail@example.com
|
||||
container_vaultwarden_smtp_port: 587 # or 465 for SSL
|
||||
container_vaultwarden_smtp_security: force_tls # or starttls or off
|
||||
container_vaultwarden_smtp_username: your_smtp_username
|
||||
container_vaultwarden_smtp_password: your_smtp_password
|
0
ansible/roles/deploy_container_vaultwarden/meta/main.yml
Normal file
0
ansible/roles/deploy_container_vaultwarden/meta/main.yml
Normal file
30
ansible/roles/deploy_container_vaultwarden/tasks/main.yml
Normal file
30
ansible/roles/deploy_container_vaultwarden/tasks/main.yml
Normal file
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
- name: Ensure data directories exist
|
||||
ansible.builtin.file:
|
||||
path: "{{ container_base_dir }}/data/{{ item }}"
|
||||
state: directory
|
||||
mode: '0755'
|
||||
loop:
|
||||
- "vaultwarden"
|
||||
- "attachments"
|
||||
|
||||
- name: Deploy Docker Compose and .env files
|
||||
ansible.builtin.template:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ container_base_dir }}/{{ item.dest }}"
|
||||
mode: '0644'
|
||||
loop:
|
||||
- { src: 'docker-compose.yml.j2', dest: 'docker-compose.yml' }
|
||||
- { src: '.env.j2', dest: '.env' }
|
||||
|
||||
- name: Stop Container
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ container_base_dir }}"
|
||||
state: absent
|
||||
|
||||
- name: Start Container
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ container_base_dir }}"
|
||||
state: present
|
||||
pull: always
|
||||
recreate: always
|
|
@ -0,0 +1,9 @@
|
|||
VAULTWARDEN_VERSION={{ container_vaultwarden_version }}
|
||||
VAULTWARDEN_DOMAIN={{ container_vaultwarden_domain }}
|
||||
VAULTWARDEN_ADMIN_TOKEN={{ container_vaultwarden_admin_token }}
|
||||
VAULTWARDEN_SMTP_HOST={{ container_vaultwarden_smtp_host }}
|
||||
VAULTWARDEN_SMTP_FROM={{ container_vaultwarden_smtp_from }}
|
||||
VAULTWARDEN_SMTP_PORT={{ container_vaultwarden_smtp_port }}
|
||||
VAULTWARDEN_SMTP_SECURITY={{ container_vaultwarden_smtp_security }}
|
||||
VAULTWARDEN_SMTP_USERNAME={{ container_vaultwarden_smtp_username }}
|
||||
VAULTWARDEN_SMTP_PASSWORD={{ container_vaultwarden_smtp_password}}
|
|
@ -0,0 +1,42 @@
|
|||
---
|
||||
services:
|
||||
vaultwarden:
|
||||
image: ghcr.io/dani-garcia/vaultwarden:${VAULTWARDEN_VERSION}
|
||||
container_name: vaultwarden
|
||||
restart: always
|
||||
volumes:
|
||||
- './data/vaultwarden/:/data/'
|
||||
- './data/attachments/:/attachments/'
|
||||
networks:
|
||||
- traefik
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.vaultwarden.entrypoints=http"
|
||||
- "traefik.http.routers.vaultwarden.rule=Host(`${VAULTWARDEN_DOMAIN}`)"
|
||||
- "traefik.http.middlewares.vaultwarden-https-redirect.redirectscheme.scheme=https"
|
||||
- "traefik.http.routers.vaultwarden.middlewares=traefik-https-redirect"
|
||||
- "traefik.http.routers.vaultwarden-secure.entrypoints=https"
|
||||
- "traefik.http.routers.vaultwarden-secure.rule=Host(`${VAULTWARDEN_DOMAIN}`)"
|
||||
- "traefik.http.routers.vaultwarden-secure.tls=true"
|
||||
- "traefik.http.services.vaultwarden.loadbalancer.server.port=80"
|
||||
- "traefik.docker.network=traefik"
|
||||
environment:
|
||||
DOMAIN: "https://${VAULTWARDEN_DOMAIN}"
|
||||
#SIGNUPS_ALLOWED: false
|
||||
#INVITATIONS_ALLOWED: false
|
||||
ADMIN_TOKEN: ${VAULTWARDEN_ADMIN_TOKEN}
|
||||
SMTP_HOST: ${VAULTWARDEN_SMTP_HOST}
|
||||
SMTP_FROM: ${VAULTWARDEN_SMTP_FROM}
|
||||
SMTP_PORT: ${VAULTWARDEN_SMTP_PORT}
|
||||
SMTP_SECURITY: ${VAULTWARDEN_SMTP_SECURITY}
|
||||
SMTP_USERNAME: ${VAULTWARDEN_SMTP_USERNAME}
|
||||
SMTP_PASSWORD: ${VAULTWARDEN_SMTP_PASSWORD}
|
||||
#LOG_FILE: /data/vaultwarden.log
|
||||
#LOG_LEVEL: warn
|
||||
EXTENDED_LOGGING: true
|
||||
SIGNUPS_VERIFY: false
|
||||
EXPERIMENTAL_CLIENT_FEATURE_FLAGS: fido2-vault-credentials,ssh-key-vault-item,ssh-agent
|
||||
|
||||
networks:
|
||||
traefik:
|
||||
external: true
|
1
ansible/roles/deploy_container_vaultwarden/vars/main.yml
Normal file
1
ansible/roles/deploy_container_vaultwarden/vars/main.yml
Normal file
|
@ -0,0 +1 @@
|
|||
container_base_dir: /opt/docker/vaultwarden
|
Loading…
Add table
Reference in a new issue