diff --git a/ansible/roles/deploy_container_healthchecks/README.md b/ansible/roles/deploy_container_healthchecks/README.md new file mode 100644 index 0000000..07a7131 --- /dev/null +++ b/ansible/roles/deploy_container_healthchecks/README.md @@ -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) + +``` \ No newline at end of file diff --git a/ansible/roles/deploy_container_healthchecks/defaults/main.yml b/ansible/roles/deploy_container_healthchecks/defaults/main.yml new file mode 100644 index 0000000..6d5eff9 --- /dev/null +++ b/ansible/roles/deploy_container_healthchecks/defaults/main.yml @@ -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" diff --git a/ansible/roles/deploy_container_healthchecks/files/.gitkeep b/ansible/roles/deploy_container_healthchecks/files/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/ansible/roles/deploy_container_healthchecks/handlers/main.yml b/ansible/roles/deploy_container_healthchecks/handlers/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/ansible/roles/deploy_container_healthchecks/meta/main.yml b/ansible/roles/deploy_container_healthchecks/meta/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/ansible/roles/deploy_container_healthchecks/tasks/main.yml b/ansible/roles/deploy_container_healthchecks/tasks/main.yml new file mode 100644 index 0000000..bef8104 --- /dev/null +++ b/ansible/roles/deploy_container_healthchecks/tasks/main.yml @@ -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 diff --git a/ansible/roles/deploy_container_healthchecks/templates/.env.j2 b/ansible/roles/deploy_container_healthchecks/templates/.env.j2 new file mode 100644 index 0000000..9721a0d --- /dev/null +++ b/ansible/roles/deploy_container_healthchecks/templates/.env.j2 @@ -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 }} \ No newline at end of file diff --git a/ansible/roles/deploy_container_healthchecks/templates/docker-compose.yml.j2 b/ansible/roles/deploy_container_healthchecks/templates/docker-compose.yml.j2 new file mode 100644 index 0000000..2882bc9 --- /dev/null +++ b/ansible/roles/deploy_container_healthchecks/templates/docker-compose.yml.j2 @@ -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: \ No newline at end of file diff --git a/ansible/roles/deploy_container_healthchecks/vars/main.yml b/ansible/roles/deploy_container_healthchecks/vars/main.yml new file mode 100644 index 0000000..7ccedd8 --- /dev/null +++ b/ansible/roles/deploy_container_healthchecks/vars/main.yml @@ -0,0 +1 @@ +container_base_dir : "/opt/docker/healthchecks" \ No newline at end of file diff --git a/ansible/roles/deploy_container_ittools/defaults/main.yml b/ansible/roles/deploy_container_ittools/defaults/main.yml new file mode 100644 index 0000000..973fdda --- /dev/null +++ b/ansible/roles/deploy_container_ittools/defaults/main.yml @@ -0,0 +1,5 @@ +############ +# IT-Tools # +############ +container_ittools_version: latest +container_ittools_domain: ittools.example.com diff --git a/ansible/roles/deploy_container_ittools/files/.gitkeep b/ansible/roles/deploy_container_ittools/files/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/ansible/roles/deploy_container_ittools/handlers/main.yml b/ansible/roles/deploy_container_ittools/handlers/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/ansible/roles/deploy_container_ittools/meta/main.yml b/ansible/roles/deploy_container_ittools/meta/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/ansible/roles/deploy_container_ittools/tasks/main.yml b/ansible/roles/deploy_container_ittools/tasks/main.yml new file mode 100644 index 0000000..d4b4c2e --- /dev/null +++ b/ansible/roles/deploy_container_ittools/tasks/main.yml @@ -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 diff --git a/ansible/roles/deploy_container_ittools/templates/.env.j2 b/ansible/roles/deploy_container_ittools/templates/.env.j2 new file mode 100644 index 0000000..df01641 --- /dev/null +++ b/ansible/roles/deploy_container_ittools/templates/.env.j2 @@ -0,0 +1,2 @@ +ITTOOLS_VERSION: {{ container_ittools_version }} +ITTOOLS_DOMAIN: {{ container_ittools_domain }} \ No newline at end of file diff --git a/ansible/roles/deploy_container_ittools/templates/docker-compose.yml.j2 b/ansible/roles/deploy_container_ittools/templates/docker-compose.yml.j2 new file mode 100644 index 0000000..4ef8616 --- /dev/null +++ b/ansible/roles/deploy_container_ittools/templates/docker-compose.yml.j2 @@ -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 \ No newline at end of file diff --git a/ansible/roles/deploy_container_ittools/vars/main.yml b/ansible/roles/deploy_container_ittools/vars/main.yml new file mode 100644 index 0000000..5dd3918 --- /dev/null +++ b/ansible/roles/deploy_container_ittools/vars/main.yml @@ -0,0 +1 @@ +container_base_dir: /opt/docker/ittools \ No newline at end of file diff --git a/ansible/roles/deploy_container_limesurvey/defaults/main.yml b/ansible/roles/deploy_container_limesurvey/defaults/main.yml new file mode 100644 index 0000000..0dd9e4f --- /dev/null +++ b/ansible/roles/deploy_container_limesurvey/defaults/main.yml @@ -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 diff --git a/ansible/roles/deploy_container_limesurvey/files/.gitkeep b/ansible/roles/deploy_container_limesurvey/files/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/ansible/roles/deploy_container_limesurvey/handlers/main.yml b/ansible/roles/deploy_container_limesurvey/handlers/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/ansible/roles/deploy_container_limesurvey/meta/main.yml b/ansible/roles/deploy_container_limesurvey/meta/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/ansible/roles/deploy_container_limesurvey/tasks/main.yml b/ansible/roles/deploy_container_limesurvey/tasks/main.yml new file mode 100644 index 0000000..314363b --- /dev/null +++ b/ansible/roles/deploy_container_limesurvey/tasks/main.yml @@ -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 diff --git a/ansible/roles/deploy_container_limesurvey/templates/.env.j2 b/ansible/roles/deploy_container_limesurvey/templates/.env.j2 new file mode 100644 index 0000000..c93184a --- /dev/null +++ b/ansible/roles/deploy_container_limesurvey/templates/.env.j2 @@ -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 }} \ No newline at end of file diff --git a/ansible/roles/deploy_container_limesurvey/templates/docker-compose.yml.j2 b/ansible/roles/deploy_container_limesurvey/templates/docker-compose.yml.j2 new file mode 100644 index 0000000..7057041 --- /dev/null +++ b/ansible/roles/deploy_container_limesurvey/templates/docker-compose.yml.j2 @@ -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 diff --git a/ansible/roles/deploy_container_limesurvey/vars/main.yml b/ansible/roles/deploy_container_limesurvey/vars/main.yml new file mode 100644 index 0000000..74f6233 --- /dev/null +++ b/ansible/roles/deploy_container_limesurvey/vars/main.yml @@ -0,0 +1 @@ +container_base_dir: /opt/docker/limesurvey diff --git a/ansible/roles/deploy_container_netalertx/defaults/main.yml b/ansible/roles/deploy_container_netalertx/defaults/main.yml new file mode 100644 index 0000000..04aced8 --- /dev/null +++ b/ansible/roles/deploy_container_netalertx/defaults/main.yml @@ -0,0 +1,5 @@ +############# +# NetAlertX # +############# +container_netalertx_version: latest +container_netalertx_domain: netalertx.example.com diff --git a/ansible/roles/deploy_container_netalertx/files/.gitkeep b/ansible/roles/deploy_container_netalertx/files/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/ansible/roles/deploy_container_netalertx/handlers/main.yml b/ansible/roles/deploy_container_netalertx/handlers/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/ansible/roles/deploy_container_netalertx/meta/main.yml b/ansible/roles/deploy_container_netalertx/meta/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/ansible/roles/deploy_container_netalertx/tasks/main.yml b/ansible/roles/deploy_container_netalertx/tasks/main.yml new file mode 100644 index 0000000..afbe6fc --- /dev/null +++ b/ansible/roles/deploy_container_netalertx/tasks/main.yml @@ -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 diff --git a/ansible/roles/deploy_container_netalertx/templates/.env.j2 b/ansible/roles/deploy_container_netalertx/templates/.env.j2 new file mode 100644 index 0000000..0dd4206 --- /dev/null +++ b/ansible/roles/deploy_container_netalertx/templates/.env.j2 @@ -0,0 +1,2 @@ +NETALERTX_VERSION={{ container_netalertx_version }} +NETALERTX_DOMAIN={{ container_netalertx_domain }} \ No newline at end of file diff --git a/ansible/roles/deploy_container_netalertx/templates/docker-compose.yml.j2 b/ansible/roles/deploy_container_netalertx/templates/docker-compose.yml.j2 new file mode 100644 index 0000000..2705107 --- /dev/null +++ b/ansible/roles/deploy_container_netalertx/templates/docker-compose.yml.j2 @@ -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 \ No newline at end of file diff --git a/ansible/roles/deploy_container_netalertx/vars/main.yml b/ansible/roles/deploy_container_netalertx/vars/main.yml new file mode 100644 index 0000000..632933a --- /dev/null +++ b/ansible/roles/deploy_container_netalertx/vars/main.yml @@ -0,0 +1 @@ +container_base_dir: /opt/docker/netalertx \ No newline at end of file diff --git a/ansible/roles/deploy_container_netbox/defaults/main.yml b/ansible/roles/deploy_container_netbox/defaults/main.yml new file mode 100644 index 0000000..eb1a081 --- /dev/null +++ b/ansible/roles/deploy_container_netbox/defaults/main.yml @@ -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 diff --git a/ansible/roles/deploy_container_netbox/files/Dockerfile-Plugins b/ansible/roles/deploy_container_netbox/files/Dockerfile-Plugins new file mode 100644 index 0000000..4302f29 --- /dev/null +++ b/ansible/roles/deploy_container_netbox/files/Dockerfile-Plugins @@ -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 \ No newline at end of file diff --git a/ansible/roles/deploy_container_netbox/files/plugin_requirements.txt b/ansible/roles/deploy_container_netbox/files/plugin_requirements.txt new file mode 100644 index 0000000..bc6462e --- /dev/null +++ b/ansible/roles/deploy_container_netbox/files/plugin_requirements.txt @@ -0,0 +1,3 @@ +netbox-plugin-dns +netbox-topology-views +netbox-qrcode \ No newline at end of file diff --git a/ansible/roles/deploy_container_netbox/files/plugins.py b/ansible/roles/deploy_container_netbox/files/plugins.py new file mode 100644 index 0000000..500223f --- /dev/null +++ b/ansible/roles/deploy_container_netbox/files/plugins.py @@ -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 + } + } +} \ No newline at end of file diff --git a/ansible/roles/deploy_container_netbox/handlers/main.yml b/ansible/roles/deploy_container_netbox/handlers/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/ansible/roles/deploy_container_netbox/meta/main.yml b/ansible/roles/deploy_container_netbox/meta/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/ansible/roles/deploy_container_netbox/tasks/main.yml b/ansible/roles/deploy_container_netbox/tasks/main.yml new file mode 100644 index 0000000..383ddb2 --- /dev/null +++ b/ansible/roles/deploy_container_netbox/tasks/main.yml @@ -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 \ No newline at end of file diff --git a/ansible/roles/deploy_container_netbox/templates/.env.j2 b/ansible/roles/deploy_container_netbox/templates/.env.j2 new file mode 100644 index 0000000..a0f25d1 --- /dev/null +++ b/ansible/roles/deploy_container_netbox/templates/.env.j2 @@ -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 }} \ No newline at end of file diff --git a/ansible/roles/deploy_container_netbox/templates/docker-compose.yml.j2 b/ansible/roles/deploy_container_netbox/templates/docker-compose.yml.j2 new file mode 100644 index 0000000..5701baa --- /dev/null +++ b/ansible/roles/deploy_container_netbox/templates/docker-compose.yml.j2 @@ -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: \ No newline at end of file diff --git a/ansible/roles/deploy_container_netbox/vars/main.yml b/ansible/roles/deploy_container_netbox/vars/main.yml new file mode 100644 index 0000000..ade3d90 --- /dev/null +++ b/ansible/roles/deploy_container_netbox/vars/main.yml @@ -0,0 +1 @@ +container_base_dir: /opt/docker/netbox \ No newline at end of file diff --git a/ansible/roles/deploy_container_plausible/defaults/main.yml b/ansible/roles/deploy_container_plausible/defaults/main.yml new file mode 100644 index 0000000..37f34fc --- /dev/null +++ b/ansible/roles/deploy_container_plausible/defaults/main.yml @@ -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" diff --git a/ansible/roles/deploy_container_plausible/files/disable-internal-memory-tracker.xml b/ansible/roles/deploy_container_plausible/files/disable-internal-memory-tracker.xml new file mode 100644 index 0000000..b005e0a --- /dev/null +++ b/ansible/roles/deploy_container_plausible/files/disable-internal-memory-tracker.xml @@ -0,0 +1,3 @@ + + true + \ No newline at end of file diff --git a/ansible/roles/deploy_container_plausible/files/ipv4-only.xml b/ansible/roles/deploy_container_plausible/files/ipv4-only.xml new file mode 100644 index 0000000..e4f4b22 --- /dev/null +++ b/ansible/roles/deploy_container_plausible/files/ipv4-only.xml @@ -0,0 +1,3 @@ + + 0.0.0.0 + \ No newline at end of file diff --git a/ansible/roles/deploy_container_plausible/files/logs.xml b/ansible/roles/deploy_container_plausible/files/logs.xml new file mode 100644 index 0000000..3ffd303 --- /dev/null +++ b/ansible/roles/deploy_container_plausible/files/logs.xml @@ -0,0 +1,28 @@ + + + warning + true + + + + system + query_log
+ 7500 + + ENGINE = MergeTree + PARTITION BY event_date + ORDER BY (event_time) + TTL event_date + interval 30 day + SETTINGS ttl_only_drop_parts=1 + +
+ + + + + + + + + +
\ No newline at end of file diff --git a/ansible/roles/deploy_container_plausible/files/low-resources.xml b/ansible/roles/deploy_container_plausible/files/low-resources.xml new file mode 100644 index 0000000..aab3cd8 --- /dev/null +++ b/ansible/roles/deploy_container_plausible/files/low-resources.xml @@ -0,0 +1,23 @@ + + + + 524288000 + + + + + 1 + + 8192 + + 1 + + 0 + + 0 + + + \ No newline at end of file diff --git a/ansible/roles/deploy_container_plausible/handlers/main.yml b/ansible/roles/deploy_container_plausible/handlers/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/ansible/roles/deploy_container_plausible/meta/main.yml b/ansible/roles/deploy_container_plausible/meta/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/ansible/roles/deploy_container_plausible/tasks/main.yml b/ansible/roles/deploy_container_plausible/tasks/main.yml new file mode 100644 index 0000000..8950db1 --- /dev/null +++ b/ansible/roles/deploy_container_plausible/tasks/main.yml @@ -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 diff --git a/ansible/roles/deploy_container_plausible/templates/.env.j2 b/ansible/roles/deploy_container_plausible/templates/.env.j2 new file mode 100644 index 0000000..be0775b --- /dev/null +++ b/ansible/roles/deploy_container_plausible/templates/.env.j2 @@ -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 }} \ No newline at end of file diff --git a/ansible/roles/deploy_container_plausible/templates/docker-compose.yml.j2 b/ansible/roles/deploy_container_plausible/templates/docker-compose.yml.j2 new file mode 100644 index 0000000..2d373bc --- /dev/null +++ b/ansible/roles/deploy_container_plausible/templates/docker-compose.yml.j2 @@ -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: \ No newline at end of file diff --git a/ansible/roles/deploy_container_plausible/vars/main.yml b/ansible/roles/deploy_container_plausible/vars/main.yml new file mode 100644 index 0000000..ce84700 --- /dev/null +++ b/ansible/roles/deploy_container_plausible/vars/main.yml @@ -0,0 +1 @@ +container_base_dir: /opt/docker/plausible diff --git a/ansible/roles/deploy_container_stirlingpdf/README.md b/ansible/roles/deploy_container_stirlingpdf/README.md new file mode 100644 index 0000000..bf9f40d --- /dev/null +++ b/ansible/roles/deploy_container_stirlingpdf/README.md @@ -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) + +``` \ No newline at end of file diff --git a/ansible/roles/deploy_container_stirlingpdf/defaults/main.yml b/ansible/roles/deploy_container_stirlingpdf/defaults/main.yml new file mode 100644 index 0000000..e6ccb63 --- /dev/null +++ b/ansible/roles/deploy_container_stirlingpdf/defaults/main.yml @@ -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 diff --git a/ansible/roles/deploy_container_stirlingpdf/files/footer.html b/ansible/roles/deploy_container_stirlingpdf/files/footer.html new file mode 100644 index 0000000..4cdd468 --- /dev/null +++ b/ansible/roles/deploy_container_stirlingpdf/files/footer.html @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/ansible/roles/deploy_container_stirlingpdf/files/navbar.html b/ansible/roles/deploy_container_stirlingpdf/files/navbar.html new file mode 100644 index 0000000..c4874f7 --- /dev/null +++ b/ansible/roles/deploy_container_stirlingpdf/files/navbar.html @@ -0,0 +1,277 @@ +
+ + + + + + + +
+ + + + + + +
\ No newline at end of file diff --git a/ansible/roles/deploy_container_stirlingpdf/handlers/main.yml b/ansible/roles/deploy_container_stirlingpdf/handlers/main.yml new file mode 100644 index 0000000..73b314f --- /dev/null +++ b/ansible/roles/deploy_container_stirlingpdf/handlers/main.yml @@ -0,0 +1 @@ +--- \ No newline at end of file diff --git a/ansible/roles/deploy_container_stirlingpdf/meta/main.yml b/ansible/roles/deploy_container_stirlingpdf/meta/main.yml new file mode 100644 index 0000000..66f2c52 --- /dev/null +++ b/ansible/roles/deploy_container_stirlingpdf/meta/main.yml @@ -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: [] diff --git a/ansible/roles/deploy_container_stirlingpdf/tasks/main.yml b/ansible/roles/deploy_container_stirlingpdf/tasks/main.yml new file mode 100644 index 0000000..f9a15e6 --- /dev/null +++ b/ansible/roles/deploy_container_stirlingpdf/tasks/main.yml @@ -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 diff --git a/ansible/roles/deploy_container_stirlingpdf/templates/.env.j2 b/ansible/roles/deploy_container_stirlingpdf/templates/.env.j2 new file mode 100644 index 0000000..3c62355 --- /dev/null +++ b/ansible/roles/deploy_container_stirlingpdf/templates/.env.j2 @@ -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 }} \ No newline at end of file diff --git a/ansible/roles/deploy_container_stirlingpdf/templates/docker-compose.yml.j2 b/ansible/roles/deploy_container_stirlingpdf/templates/docker-compose.yml.j2 new file mode 100644 index 0000000..b3998b7 --- /dev/null +++ b/ansible/roles/deploy_container_stirlingpdf/templates/docker-compose.yml.j2 @@ -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 \ No newline at end of file diff --git a/ansible/roles/deploy_container_stirlingpdf/vars/main.yml b/ansible/roles/deploy_container_stirlingpdf/vars/main.yml new file mode 100644 index 0000000..c767edc --- /dev/null +++ b/ansible/roles/deploy_container_stirlingpdf/vars/main.yml @@ -0,0 +1 @@ +container_base_dir: /opt/docker/stirlingpdf diff --git a/ansible/roles/deploy_container_ticky/defaults/main.yml b/ansible/roles/deploy_container_ticky/defaults/main.yml new file mode 100644 index 0000000..bf753b5 --- /dev/null +++ b/ansible/roles/deploy_container_ticky/defaults/main.yml @@ -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 diff --git a/ansible/roles/deploy_container_ticky/files/.gitkeep b/ansible/roles/deploy_container_ticky/files/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/ansible/roles/deploy_container_ticky/handlers/main.yml b/ansible/roles/deploy_container_ticky/handlers/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/ansible/roles/deploy_container_ticky/meta/main.yml b/ansible/roles/deploy_container_ticky/meta/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/ansible/roles/deploy_container_ticky/tasks/main.yml b/ansible/roles/deploy_container_ticky/tasks/main.yml new file mode 100644 index 0000000..2910371 --- /dev/null +++ b/ansible/roles/deploy_container_ticky/tasks/main.yml @@ -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 diff --git a/ansible/roles/deploy_container_ticky/templates/.env.j2 b/ansible/roles/deploy_container_ticky/templates/.env.j2 new file mode 100644 index 0000000..c262849 --- /dev/null +++ b/ansible/roles/deploy_container_ticky/templates/.env.j2 @@ -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 }} \ No newline at end of file diff --git a/ansible/roles/deploy_container_ticky/templates/docker-compose.yml.j2 b/ansible/roles/deploy_container_ticky/templates/docker-compose.yml.j2 new file mode 100644 index 0000000..8ef645c --- /dev/null +++ b/ansible/roles/deploy_container_ticky/templates/docker-compose.yml.j2 @@ -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 \ No newline at end of file diff --git a/ansible/roles/deploy_container_ticky/vars/main.yml b/ansible/roles/deploy_container_ticky/vars/main.yml new file mode 100644 index 0000000..f86a2b9 --- /dev/null +++ b/ansible/roles/deploy_container_ticky/vars/main.yml @@ -0,0 +1 @@ +container_base_dir: /opt/docker/ticky \ No newline at end of file diff --git a/ansible/roles/deploy_container_traefik_with_letsencrypt/README.md b/ansible/roles/deploy_container_traefik_with_letsencrypt/README.md new file mode 100644 index 0000000..85d7fa8 --- /dev/null +++ b/ansible/roles/deploy_container_traefik_with_letsencrypt/README.md @@ -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$" +``` + +## 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//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) + +``` \ No newline at end of file diff --git a/ansible/roles/deploy_container_traefik_with_letsencrypt/defaults/main.yml b/ansible/roles/deploy_container_traefik_with_letsencrypt/defaults/main.yml new file mode 100644 index 0000000..bd2ef86 --- /dev/null +++ b/ansible/roles/deploy_container_traefik_with_letsencrypt/defaults/main.yml @@ -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 diff --git a/ansible/roles/deploy_container_traefik_with_letsencrypt/files/middlewares.yml b/ansible/roles/deploy_container_traefik_with_letsencrypt/files/middlewares.yml new file mode 100644 index 0000000..d910a21 --- /dev/null +++ b/ansible/roles/deploy_container_traefik_with_letsencrypt/files/middlewares.yml @@ -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" \ No newline at end of file diff --git a/ansible/roles/deploy_container_traefik_with_letsencrypt/handlers/main.yml b/ansible/roles/deploy_container_traefik_with_letsencrypt/handlers/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/ansible/roles/deploy_container_traefik_with_letsencrypt/meta/main.yml b/ansible/roles/deploy_container_traefik_with_letsencrypt/meta/main.yml new file mode 100644 index 0000000..6ddaa3d --- /dev/null +++ b/ansible/roles/deploy_container_traefik_with_letsencrypt/meta/main.yml @@ -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: [] diff --git a/ansible/roles/deploy_container_traefik_with_letsencrypt/tasks/main.yml b/ansible/roles/deploy_container_traefik_with_letsencrypt/tasks/main.yml new file mode 100644 index 0000000..cd0ef05 --- /dev/null +++ b/ansible/roles/deploy_container_traefik_with_letsencrypt/tasks/main.yml @@ -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 diff --git a/ansible/roles/deploy_container_traefik_with_letsencrypt/templates/.env.j2 b/ansible/roles/deploy_container_traefik_with_letsencrypt/templates/.env.j2 new file mode 100644 index 0000000..137f5db --- /dev/null +++ b/ansible/roles/deploy_container_traefik_with_letsencrypt/templates/.env.j2 @@ -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') }}" \ No newline at end of file diff --git a/ansible/roles/deploy_container_traefik_with_letsencrypt/templates/docker-compose.yml.j2 b/ansible/roles/deploy_container_traefik_with_letsencrypt/templates/docker-compose.yml.j2 new file mode 100644 index 0000000..85fef04 --- /dev/null +++ b/ansible/roles/deploy_container_traefik_with_letsencrypt/templates/docker-compose.yml.j2 @@ -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 \ No newline at end of file diff --git a/ansible/roles/deploy_container_traefik_with_letsencrypt/templates/routers_services.yml.j2 b/ansible/roles/deploy_container_traefik_with_letsencrypt/templates/routers_services.yml.j2 new file mode 100644 index 0000000..92dafbd --- /dev/null +++ b/ansible/roles/deploy_container_traefik_with_letsencrypt/templates/routers_services.yml.j2 @@ -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 %} \ No newline at end of file diff --git a/ansible/roles/deploy_container_traefik_with_letsencrypt/templates/traefik.yml.j2 b/ansible/roles/deploy_container_traefik_with_letsencrypt/templates/traefik.yml.j2 new file mode 100644 index 0000000..ac1a4ad --- /dev/null +++ b/ansible/roles/deploy_container_traefik_with_letsencrypt/templates/traefik.yml.j2 @@ -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: {} \ No newline at end of file diff --git a/ansible/roles/deploy_container_traefik_with_letsencrypt/vars/main.yml b/ansible/roles/deploy_container_traefik_with_letsencrypt/vars/main.yml new file mode 100644 index 0000000..0fcca69 --- /dev/null +++ b/ansible/roles/deploy_container_traefik_with_letsencrypt/vars/main.yml @@ -0,0 +1 @@ +container_base_dir : "/opt/docker/traefik-letsencrypt" \ No newline at end of file diff --git a/ansible/roles/deploy_container_vaultwarden/README.md b/ansible/roles/deploy_container_vaultwarden/README.md new file mode 100644 index 0000000..8a837ab --- /dev/null +++ b/ansible/roles/deploy_container_vaultwarden/README.md @@ -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) + +``` \ No newline at end of file diff --git a/ansible/roles/deploy_container_vaultwarden/defaults/main.yml b/ansible/roles/deploy_container_vaultwarden/defaults/main.yml new file mode 100644 index 0000000..39371ea --- /dev/null +++ b/ansible/roles/deploy_container_vaultwarden/defaults/main.yml @@ -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 diff --git a/ansible/roles/deploy_container_vaultwarden/files/.gitkeep b/ansible/roles/deploy_container_vaultwarden/files/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/ansible/roles/deploy_container_vaultwarden/handlers/main.yml b/ansible/roles/deploy_container_vaultwarden/handlers/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/ansible/roles/deploy_container_vaultwarden/meta/main.yml b/ansible/roles/deploy_container_vaultwarden/meta/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/ansible/roles/deploy_container_vaultwarden/tasks/main.yml b/ansible/roles/deploy_container_vaultwarden/tasks/main.yml new file mode 100644 index 0000000..c829d46 --- /dev/null +++ b/ansible/roles/deploy_container_vaultwarden/tasks/main.yml @@ -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 diff --git a/ansible/roles/deploy_container_vaultwarden/templates/.env.j2 b/ansible/roles/deploy_container_vaultwarden/templates/.env.j2 new file mode 100644 index 0000000..d50d123 --- /dev/null +++ b/ansible/roles/deploy_container_vaultwarden/templates/.env.j2 @@ -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}} \ No newline at end of file diff --git a/ansible/roles/deploy_container_vaultwarden/templates/docker-compose.yml.j2 b/ansible/roles/deploy_container_vaultwarden/templates/docker-compose.yml.j2 new file mode 100644 index 0000000..6b250c8 --- /dev/null +++ b/ansible/roles/deploy_container_vaultwarden/templates/docker-compose.yml.j2 @@ -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 \ No newline at end of file diff --git a/ansible/roles/deploy_container_vaultwarden/vars/main.yml b/ansible/roles/deploy_container_vaultwarden/vars/main.yml new file mode 100644 index 0000000..52fd9f9 --- /dev/null +++ b/ansible/roles/deploy_container_vaultwarden/vars/main.yml @@ -0,0 +1 @@ +container_base_dir: /opt/docker/vaultwarden \ No newline at end of file