54 Commits

Author SHA1 Message Date
98c60a73c6 meta: bump version to 0.1.6 2024-10-22 20:42:24 +02:00
5ac019bace docs: fix typo 2024-10-19 17:33:13 +02:00
43fd798712 feat(vaultwarden): add ansible role 2024-10-19 17:26:50 +02:00
88dc6377ce fix(hedgedoc): incorrect module used 2024-10-19 17:13:24 +02:00
0a132b0ad5 meta: update collection version to 0.1.5, add galaxy tags 2024-10-10 17:01:35 +02:00
72942ee382 update(hedgedoc): bump version to 1.10.0 2024-10-10 16:59:06 +02:00
755e5d55f2 update(ghost): bump version to 5.96.0 2024-10-10 16:58:01 +02:00
5023a56b29 update(authelia): bump version to 4.38.15 2024-10-10 16:56:49 +02:00
17dfe4b2bb update(gitea): bump version to 1.22.3 2024-10-10 16:55:57 +02:00
cd122ebbdb fix(gitea): typo in variable name 2024-10-10 16:55:27 +02:00
0d914bd11c feat(hedgedoc): add deployment_method=podman, add docs 2024-10-09 20:06:48 +02:00
49ed240f10 fix(hedgedoc): add options ports and user to container creation task 2024-10-08 17:55:06 +02:00
81d6f809d7 meta: bump collection version to 0.1.4 2024-10-07 19:44:08 +02:00
b24ea1e925 feat(jellyfin): add playbook to collection, add state=absent support to role 2024-10-07 19:42:22 +02:00
912c32cb3e feat(hedgedoc): add ansible role for deployment 2024-10-07 19:09:52 +02:00
cde5f12e79 meta: bump galaxy version to 0.1.3 2024-10-03 22:37:43 +02:00
a8f5507eab meta: add role descriptions 2024-10-03 22:34:28 +02:00
ddfa8d6687 chore(jellyfin): migrate to fully-qualified module names 2024-10-03 22:25:46 +02:00
fd4cc0fe6a meta: require community.crypto@^2.0.0 in collection 2024-10-03 22:24:30 +02:00
3a15ed1157 chore(gitea): migrate to fully-qualified module names 2024-10-03 22:22:31 +02:00
a7fad79d05 chore(authelia): add container recreation option 2024-10-03 22:19:16 +02:00
f3d3617ec0 chore(authelia): migrate to fully-qualified module names 2024-10-03 22:18:34 +02:00
908b579f2c chore(authelia): more config migration in preparation for authelia 5.0.x 2024-10-03 22:05:08 +02:00
bab5b94500 update(ghost): bump version to 5.95.0 2024-10-03 21:30:48 +02:00
b5b4f67a08 chore(authelia): migrate away from deprecated config options 2024-10-03 18:01:40 +02:00
5e29e174d5 chore(authelia): add etc_hosts container option 2024-10-03 17:06:49 +02:00
6001399569 meta: bump collection version to 0.1.2, take issues on codeberg repo, require community.general>=3.0.0 2024-10-03 16:58:58 +02:00
87df054977 update(authelia): bump version to 4.38.15 2024-10-03 16:57:00 +02:00
8c89d40fcd chore(authelia): split container image into parts 2024-10-03 16:55:46 +02:00
f231d4e7d3 chore(gitea): split container_image_name into parts for easier overriding 2024-10-03 14:05:35 +02:00
80077af008 meta: bump collection version to 0.1.1 2024-09-21 11:29:19 +02:00
eeb66de8a4 update(ghost): bump version to 5.94.1 2024-09-21 11:28:56 +02:00
396f1b3a57 update(vouch_proxy): bump version to 0.40.0 2024-09-21 11:27:20 +02:00
be66a3fe7a update(jellyfin): bump version to 10.9.11 2024-09-21 11:26:19 +02:00
5bfca1a55c meta: require atleast ansible >= 2.15.0 2024-09-21 11:25:19 +02:00
70238d3bd4 meta: update galaxy collection version to 0.1.0 2024-09-21 10:25:17 +02:00
f6a97805de docs: update README links 2024-09-21 10:24:17 +02:00
b350a19bcc update(gitea): bump version to 1.22.2 2024-09-19 14:57:47 +02:00
74a3216a41 update(jellyfin): bump version to 10.9.8 2024-07-21 19:23:05 +02:00
ef6da18172 feat(openproject): add deployment using docker-compose 2024-03-31 14:27:53 +02:00
65a256e8b5 update(ghost): bump version to 5.78.0 2024-02-04 10:53:50 +01:00
6547f15bb4 update(gitea): bump version to 1.21.5 2024-02-04 10:44:19 +01:00
5f19b5d9a9 refactor(gitea): support using forgejo in the role 2023-10-07 22:18:02 +02:00
4a2d1dec92 update(gitea): bump version to 1.20.5 2023-10-07 17:46:02 +02:00
4632a1263a update(ghost): bump version to 5.67.0 2023-10-07 16:21:20 +02:00
e5924d5ecb chore(ghost): improve role task names and fix mount permissions 2023-10-07 16:16:53 +02:00
f2fe2fb034 meta: update collection to 0.0.3 2023-08-05 18:34:31 +02:00
e8e97a5d89 update(gitea): bump version to 1.20.2 2023-08-05 18:20:53 +02:00
5ea358e65d update(ghost): bump version to 5.58.0 2023-08-05 18:20:31 +02:00
82ff46ee99 meta: bump galaxy version to 0.0.2 2023-07-28 15:47:05 +02:00
8a2993e9c3 chore(restic)!: migrate restic role to finallycoffee.base collection 2023-07-28 15:33:53 +02:00
87094b81ec chore(minio)!: migrate minio role to finallycoffee.base collection 2023-07-28 15:24:08 +02:00
bbe369d525 chore(elasticsearch)!: migrate elasticsearch role to finallycoffee.base collection 2023-07-28 15:23:55 +02:00
ed56665ed8 chore(nginx)!: migrate nginx role to finallycoffee.base collection 2023-07-28 15:11:09 +02:00
64 changed files with 893 additions and 655 deletions

View File

@ -1,4 +1,4 @@
# `finallycoffee.service` ansible collection # `finallycoffee.services` ansible collection
## Overview ## Overview
@ -8,24 +8,29 @@ concise area of concern.
## Roles ## Roles
- [`roles/authelia`](roles/authelia/README.md): Deploys an [authelia.com](https://www.authelia.com) - [`authelia`](roles/authelia/README.md): Deploys an [authelia.com](https://www.authelia.com)
instance, an authentication provider with beta OIDC provider support. instance, an authentication provider with beta OIDC provider support.
- [`roles/elasticsearch`](roles/elasticsearch/README.md): Deploy [elasticsearch](https://www.docker.elastic.co/r/elasticsearch/elasticsearch-oss), - [`ghost`](roles/ghost/README.md): Deploys [ghost.org](https://ghost.org/), a simple to use
a popular (distributed) search and analytics engine, mostly known by it's blogging and publishing platform.
letter "E" in the ELK-stack.
- [`roles/gitea`](roles/gitea/README.md): Deploy [gitea.io](https://gitea.io), a - [`gitea`](roles/gitea/README.md): Deploy [gitea.io](https://gitea.io), a
lightweight, self-hosted git service. lightweight, self-hosted git service.
- [`roles/jellyfin`](roles/jellyfin/README.md): Deploy [jellyfin.org](https://jellyfin.org), - [`hedgedoc`](roles/hedgedoc/README.md): Deploy [hedgedoc](https://hedgedoc.org/),
a collaborative real-time markdown editor using websockts
- [`jellyfin`](roles/jellyfin/README.md): Deploy [jellyfin.org](https://jellyfin.org),
the free software media system for streaming stored media to any device. the free software media system for streaming stored media to any device.
- [`roles/restic`](roles/restic/README.md): Manage backups using restic - [`openproject`](roles/openproject/README.md): Deploys an [openproject.org](https://www.openproject.org)
and persist them to a configurable backend. installation using the upstream provided docker-compose setup.
- [`roles/minio`](roles/minio/README.md): Deploy [min.io](https://min.io), an - [`vaultwarden`](roles/vaultwarden/README.md): Deploy [vaultwarden](https://github.com/dani-garcia/vaultwarden/),
s3-compatible object storage server, using docker containers. an open-source implementation of the Bitwarden Server (formerly Bitwarden\_RS).
- [`vouch_proxy`](roles/vouch_proxy/README.md): Deploys [vouch-proxy](https://github.com/vouch/vouch-proxy),
an authorization proxy for arbitrary webapps working with `nginx`s' `auth_request` module.
## License ## License

View File

@ -1,14 +1,22 @@
namespace: finallycoffee namespace: finallycoffee
name: services name: services
version: 0.0.1 version: 0.1.6
readme: README.md readme: README.md
authors: authors:
- transcaffeine <transcaffeine@finally.coffee> - transcaffeine <transcaffeine@finally.coffee>
description: Various ansible roles useful for automating infrastructure description: Various ansible roles useful for automating infrastructure
dependencies: dependencies:
"community.docker": "^1.10.0" "community.crypto": "^2.0.0"
"community.docker": "^3.0.0"
license_file: LICENSE.md license_file: LICENSE.md
build_ignore: build_ignore:
- '*.tar.gz' - '*.tar.gz'
repository: https://git.finally.coffee/finallycoffee/services repository: https://git.finally.coffee/finallycoffee/services
issues: https://git.finally.coffee/finallycoffee/services/issues issues: https://codeberg.org/finallycoffee/ansible-collection-services/issues
tags:
- authelia
- gitea
- hedgedoc
- jellyfin
- vaultwarden
- docker

View File

@ -1,3 +1,3 @@
--- ---
requires_ansible: ">=2.12" requires_ansible: ">=2.15"

6
playbooks/hedgedoc.yml Normal file
View File

@ -0,0 +1,6 @@
---
- name: Install and configure hedgedoc
hosts: "{{ hedgedoc_hosts | default('hedgedoc') }}"
become: "{{ hedgedoc_become | default(true, false) }}"
roles:
- role: finallycoffee.services.hedgedoc

6
playbooks/jellyfin.yml Normal file
View File

@ -0,0 +1,6 @@
---
- name: Install and configure jellyfin
hosts: "{{ jellyfin_hosts | default('jellyfin') }}"
become: "{{ jellyfin_become | default(true, false) }}"
roles:
- role: finallycoffee.services.jellyfin

View File

@ -0,0 +1,6 @@
---
- name: Install openproject
hosts: "{{ openproject_hosts | default('openproject') }}"
become: "{{ openproject_become | default(true, false) }}"
roles:
- role: finallycoffee.services.openproject

View File

@ -0,0 +1,6 @@
---
- name: Install and configure vaultwarden
hosts: "{{ vaultwarden_hosts | default('vaultwarden') }}"
become: "{{ vaultwarden_become | default(true, false) }}"
roles:
- role: finallycoffee.services.vaultwarden

View File

@ -1,6 +1,5 @@
--- ---
authelia_version: "4.38.16"
authelia_version: 4.37.5
authelia_user: authelia authelia_user: authelia
authelia_base_dir: /opt/authelia authelia_base_dir: /opt/authelia
authelia_domain: authelia.example.org authelia_domain: authelia.example.org
@ -14,9 +13,20 @@ authelia_notification_storage_file: "{{ authelia_data_dir }}/notifications.txt"
authelia_user_storage_file: "{{ authelia_data_dir }}/user_database.yml" authelia_user_storage_file: "{{ authelia_data_dir }}/user_database.yml"
authelia_container_name: authelia authelia_container_name: authelia
authelia_container_image_name: docker.io/authelia/authelia authelia_container_image_server: docker.io
authelia_container_image_namespace: authelia
authelia_container_image_name: authelia
authelia_container_image: >-2
{{
[
authelia_container_image_server,
authelia_container_image_namespace,
authelia_container_image_name
] | join('/')
}}
authelia_container_image_tag: ~ authelia_container_image_tag: ~
authelia_container_image_ref: "{{ authelia_container_image_name }}:{{ authelia_container_image_tag | default(authelia_version, true) }}" authelia_container_image_ref: >-2
{{ authelia_container_image }}:{{ authelia_container_image_tag | default(authelia_version, true) }}
authelia_container_image_force_pull: "{{ authelia_container_image_tag | default(false, True) }}" authelia_container_image_force_pull: "{{ authelia_container_image_tag | default(false, True) }}"
authelia_container_env: authelia_container_env:
PUID: "{{ authelia_run_user }}" PUID: "{{ authelia_run_user }}"
@ -42,12 +52,22 @@ authelia_config_jwt_secret: ~
authelia_config_default_redirection_url: ~ authelia_config_default_redirection_url: ~
authelia_config_server_host: 0.0.0.0 authelia_config_server_host: 0.0.0.0
authelia_config_server_port: "{{ authelia_container_listen_port }}" authelia_config_server_port: "{{ authelia_container_listen_port }}"
authelia_config_server_address: >-2
{{ authelia_config_server_host }}:{{ authelia_config_server_port }}
authelia_config_server_path: "" authelia_config_server_path: ""
authelia_config_server_asset_path: "/config/assets/" authelia_config_server_asset_path: "/config/assets/"
authelia_config_server_read_buffer_size: 4096 authelia_config_server_buffers_read: 4096
authelia_config_server_write_buffer_size: 4096 authelia_config_server_read_buffer_size: >-2
authelia_config_server_enable_pprof: true {{ authelia_config_server_buffers_read }}
authelia_config_server_enable_expvars: true authelia_config_server_buffers_write: 4096
authelia_config_server_write_buffer_size: >-2
{{ authelia_config_server_buffers_write }}
authelia_config_server_endpoints_enable_pprof: true
authelia_config_server_enable_pprof: >-2
{{ authelia_config_server_endpoints_enable_pprof }}
authelia_config_server_endpoints_enable_expvars: true
authelia_config_server_enable_expvars: >-2
{{ authelia_config_server_endpoints_enable_expvars }}
authelia_config_server_disable_healthcheck: authelia_config_server_disable_healthcheck:
authelia_config_server_tls_key: ~ authelia_config_server_tls_key: ~
authelia_config_server_tls_certificate: ~ authelia_config_server_tls_certificate: ~
@ -94,10 +114,18 @@ authelia_config_authentication_backend_ldap_additional_users_dn: "ou=users"
authelia_config_authentication_backend_ldap_users_filter: "(&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=inetOrgPerson))" authelia_config_authentication_backend_ldap_users_filter: "(&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=inetOrgPerson))"
authelia_config_authentication_backend_ldap_additional_groups_dn: "ou=groups" authelia_config_authentication_backend_ldap_additional_groups_dn: "ou=groups"
authelia_config_authentication_backend_ldap_groups_filter: "(member={dn})" authelia_config_authentication_backend_ldap_groups_filter: "(member={dn})"
authelia_config_authentication_backend_ldap_attributes_username: uid
authelia_config_authentication_backend_ldap_username_attribute: >-2
{{ authelia_config_authentication_backend_ldap_attributes_username }}
authelia_config_authentication_backend_ldap_attributes_mail: mail
authelia_config_authentication_backend_ldap_mail_attribute: >-2
{{ authelia_config_authentication_backend_ldap_attributes_mail }}
authelia_config_authentication_backend_ldap_attributes_display_name: displayName
authelia_config_authentication_backend_ldap_display_name_attribute: >-2
{{ authelia_config_authentication_backend_ldap_attributes_display_name }}
authelia_config_authentication_backend_ldap_group_name_attribute: cn authelia_config_authentication_backend_ldap_group_name_attribute: cn
authelia_config_authentication_backend_ldap_username_attribute: uid authelia_config_authentication_backend_ldap_attributes_group_name: >-2
authelia_config_authentication_backend_ldap_mail_attribute: mail {{ authelia_config_authentication_backend_ldap_group_name_attribute }}
authelia_config_authentication_backend_ldap_display_name_attribute: displayName
authelia_config_authentication_backend_ldap_user: ~ authelia_config_authentication_backend_ldap_user: ~
authelia_config_authentication_backend_ldap_password: ~ authelia_config_authentication_backend_ldap_password: ~
authelia_config_authentication_backend_file_path: ~ authelia_config_authentication_backend_file_path: ~
@ -125,6 +153,8 @@ authelia_config_session_secret: ~
authelia_config_session_expiration: 1h authelia_config_session_expiration: 1h
authelia_config_session_inactivity: 5m authelia_config_session_inactivity: 5m
authelia_config_session_remember_me_duration: 1M authelia_config_session_remember_me_duration: 1M
authelia_config_session_remember_me: >-2
{{ authelia_config_session_remember_me_duration }}
authelia_config_session_redis_host: "{{ authelia_redis_host }}" authelia_config_session_redis_host: "{{ authelia_redis_host }}"
authelia_config_session_redis_port: "{{ authelia_redis_port }}" authelia_config_session_redis_port: "{{ authelia_redis_port }}"
authelia_config_session_redis_username: "{{ authelia_redis_user }}" authelia_config_session_redis_username: "{{ authelia_redis_user }}"
@ -149,8 +179,7 @@ authelia_config_storage_postgres_ssl_certificate: disable
authelia_config_storage_postgres_ssl_key: disable authelia_config_storage_postgres_ssl_key: disable
authelia_config_notifier_disable_startup_check: false authelia_config_notifier_disable_startup_check: false
authelia_config_notifier_filesystem_filename: ~ authelia_config_notifier_filesystem_filename: ~
authelia_config_notifier_smtp_host: "{{ authelia_smtp_host }}" authelia_config_notifier_smtp_address: "{{ authelia_smtp_host }}:{{ authelia_stmp_port }}"
authelia_config_notifier_smtp_port: "{{ authelia_stmp_port }}"
authelia_config_notifier_smtp_username: "{{ authelia_smtp_user }}" authelia_config_notifier_smtp_username: "{{ authelia_smtp_user }}"
authelia_config_notifier_smtp_password: "{{ authelia_smtp_pass }}" authelia_config_notifier_smtp_password: "{{ authelia_smtp_pass }}"
authelia_config_notifier_smtp_timeout: 5s authelia_config_notifier_smtp_timeout: 5s
@ -166,6 +195,12 @@ authelia_config_notifier_smtp_tls_minimum_version: "{{ authelia_tls_minimum_vers
authelia_database_type: ~ authelia_database_type: ~
authelia_database_host: ~ authelia_database_host: ~
authelia_database_port: ~
authelia_database_address: >-2
{{ authelia_database_host }}{{
(authelia_database_port | default(false, true) | bool)
| ternary(':' + authelia_database_port, '')
}}
authelia_database_user: authelia authelia_database_user: authelia
authelia_database_pass: ~ authelia_database_pass: ~
authelia_database_name: authelia authelia_database_name: authelia

View File

@ -0,0 +1,9 @@
---
allow_duplicates: true
dependencies: []
galaxy_info:
role_name: authelia
description: Ansible role to deploy authelia using docker
galaxy_tags:
- authelia
- docker

View File

@ -1,14 +1,14 @@
--- ---
- name: Ensure user {{ authelia_user }} exists - name: Ensure user {{ authelia_user }} exists
user: ansible.builtin.user:
name: "{{ authelia_user }}" name: "{{ authelia_user }}"
state: present state: present
system: true system: true
register: authelia_user_info register: authelia_user_info
- name: Ensure host directories are created with correct permissions - name: Ensure host directories are created with correct permissions
file: ansible.builtin.file:
path: "{{ item.path }}" path: "{{ item.path }}"
state: directory state: directory
owner: "{{ item.owner | default(authelia_user) }}" owner: "{{ item.owner | default(authelia_user) }}"
@ -26,7 +26,7 @@
mode: "0750" mode: "0750"
- name: Ensure config file is generated - name: Ensure config file is generated
copy: ansible.builtin.copy:
content: "{{ authelia_config | to_nice_yaml(indent=2, width=10000) }}" content: "{{ authelia_config | to_nice_yaml(indent=2, width=10000) }}"
dest: "{{ authelia_config_file }}" dest: "{{ authelia_config_file }}"
owner: "{{ authelia_run_user }}" owner: "{{ authelia_run_user }}"
@ -35,7 +35,7 @@
notify: restart-authelia notify: restart-authelia
- name: Ensure sqlite database file exists before mounting it - name: Ensure sqlite database file exists before mounting it
file: ansible.builtin.file:
path: "{{ authelia_sqlite_storage_file }}" path: "{{ authelia_sqlite_storage_file }}"
state: touch state: touch
owner: "{{ authelia_run_user }}" owner: "{{ authelia_run_user }}"
@ -46,7 +46,7 @@
when: authelia_config_storage_local_path | default(false, true) when: authelia_config_storage_local_path | default(false, true)
- name: Ensure user database exists before mounting it - name: Ensure user database exists before mounting it
file: ansible.builtin.file:
path: "{{ authelia_user_storage_file }}" path: "{{ authelia_user_storage_file }}"
state: touch state: touch
owner: "{{ authelia_run_user }}" owner: "{{ authelia_run_user }}"
@ -57,7 +57,7 @@
when: authelia_config_authentication_backend_file_path | default(false, true) when: authelia_config_authentication_backend_file_path | default(false, true)
- name: Ensure notification reports file exists before mounting it - name: Ensure notification reports file exists before mounting it
file: ansible.builtin.file:
path: "{{ authelia_notification_storage_file }}" path: "{{ authelia_notification_storage_file }}"
state: touch state: touch
owner: "{{ authelia_run_user }}" owner: "{{ authelia_run_user }}"
@ -76,7 +76,7 @@
register: authelia_container_image_info register: authelia_container_image_info
- name: Ensure authelia container is running - name: Ensure authelia container is running
docker_container: community.docker.docker_container:
name: "{{ authelia_container_name }}" name: "{{ authelia_container_name }}"
image: "{{ authelia_container_image_ref }}" image: "{{ authelia_container_image_ref }}"
env: "{{ authelia_container_env }}" env: "{{ authelia_container_env }}"
@ -85,7 +85,9 @@
labels: "{{ authelia_container_labels }}" labels: "{{ authelia_container_labels }}"
volumes: "{{ authelia_container_volumes }}" volumes: "{{ authelia_container_volumes }}"
networks: "{{ authelia_container_networks | default(omit, true) }}" networks: "{{ authelia_container_networks | default(omit, true) }}"
etc_hosts: "{{ authelia_container_etc_hosts | default(omit, true) }}"
purge_networks: "{{ authelia_container_purge_networks | default(omit, true)}}" purge_networks: "{{ authelia_container_purge_networks | default(omit, true)}}"
restart_policy: "{{ authelia_container_restart_policy }}" restart_policy: "{{ authelia_container_restart_policy }}"
recreate: "{{ authelia_container_recreate | default(omit, true) }}"
state: "{{ authelia_container_state }}" state: "{{ authelia_container_state }}"
register: authelia_container_info register: authelia_container_info

View File

@ -48,18 +48,20 @@ authelia_base_config: >-2
authelia_config_server: >-2 authelia_config_server: >-2
{{ {{
{ {
"host": authelia_config_server_host, "address": authelia_config_server_address,
"port": authelia_config_server_port,
"path": authelia_config_server_path,
"asset_path": authelia_config_server_asset_path, "asset_path": authelia_config_server_asset_path,
"read_buffer_size": authelia_config_server_read_buffer_size,
"write_buffer_size": authelia_config_server_write_buffer_size,
"enable_pprof": authelia_config_server_enable_pprof,
"enable_expvars": authelia_config_server_enable_expvars,
"disable_healthcheck": authelia_config_server_disable_healthcheck, "disable_healthcheck": authelia_config_server_disable_healthcheck,
"endpoints": authelia_config_server_endpoints,
"buffers": authelia_config_server_buffers,
} | combine({"headers": {"csp_template": authelia_config_server_headers_csp_template}} } | combine({"headers": {"csp_template": authelia_config_server_headers_csp_template}}
if authelia_config_server_headers_csp_template | default(false, true) else {}) if authelia_config_server_headers_csp_template | default(false, true) else {})
}} }}
authelia_config_server_endpoints:
enable_expvars: "{{ authelia_config_server_endpoints_enable_expvars }}"
enable_pprof: "{{ authelia_config_server_endpoints_enable_pprof }}"
authelia_config_server_buffers:
read: "{{ authelia_config_server_buffers_read }}"
write: "{{ authelia_config_server_buffers_write }}"
authelia_config_server_tls: authelia_config_server_tls:
key: "{{ authelia_config_server_tls_key }}" key: "{{ authelia_config_server_tls_key }}"
certificate: "{{ authelia_config_server_tls_certificate }}" certificate: "{{ authelia_config_server_tls_certificate }}"
@ -132,10 +134,11 @@ authelia_config_authentication_backend_ldap:
additional_groups_dn: "{{ authelia_config_authentication_backend_ldap_additional_groups_dn }}" additional_groups_dn: "{{ authelia_config_authentication_backend_ldap_additional_groups_dn }}"
users_filter: "{{ authelia_config_authentication_backend_ldap_users_filter }}" users_filter: "{{ authelia_config_authentication_backend_ldap_users_filter }}"
groups_filter: "{{ authelia_config_authentication_backend_ldap_groups_filter }}" groups_filter: "{{ authelia_config_authentication_backend_ldap_groups_filter }}"
group_name_attribute: "{{ authelia_config_authentication_backend_ldap_group_name_attribute }}" attributes:
username_attribute: "{{ authelia_config_authentication_backend_ldap_username_attribute }}" username: "{{ authelia_config_authentication_backend_ldap_attributes_username }}"
mail_attribute: "{{ authelia_config_authentication_backend_ldap_mail_attribute }}" mail: "{{ authelia_config_authentication_backend_ldap_attributes_mail }}"
display_name_attribute: "{{ authelia_config_authentication_backend_ldap_display_name_attribute }}" display_name: "{{ authelia_config_authentication_backend_ldap_attributes_display_name }}"
group_name: "{{ authelia_config_authentication_backend_ldap_attributes_group_name }}"
user: "{{ authelia_config_authentication_backend_ldap_user }}" user: "{{ authelia_config_authentication_backend_ldap_user }}"
password: "{{ authelia_config_authentication_backend_ldap_password }}" password: "{{ authelia_config_authentication_backend_ldap_password }}"
authelia_config_authentication_backend_file: authelia_config_authentication_backend_file:
@ -174,7 +177,7 @@ authelia_config_session:
secret: "{{ authelia_config_session_secret }}" secret: "{{ authelia_config_session_secret }}"
expiration: "{{ authelia_config_session_expiration }}" expiration: "{{ authelia_config_session_expiration }}"
inactivity: "{{ authelia_config_session_inactivity }}" inactivity: "{{ authelia_config_session_inactivity }}"
remember_me_duration: "{{ authelia_config_session_remember_me_duration }}" remember_me: "{{ authelia_config_session_remember_me }}"
authelia_config_session_redis: >-2 authelia_config_session_redis: >-2
{{ {{
{ {
@ -218,15 +221,13 @@ authelia_config_storage: >-2
authelia_config_storage_local: authelia_config_storage_local:
path: "{{ authelia_config_storage_local_path }}" path: "{{ authelia_config_storage_local_path }}"
authelia_config_storage_mysql: authelia_config_storage_mysql:
host: "{{ authelia_database_host }}" host: "{{ authelia_database_address }}"
port: "{{ authelia_config_storage_mysql_port }}"
database: "{{ authelia_database_name }}" database: "{{ authelia_database_name }}"
username: "{{ authelia_database_user }}" username: "{{ authelia_database_user }}"
password: "{{ authelia_database_pass }}" password: "{{ authelia_database_pass }}"
timeout: "{{ authelia_database_timeout }}" timeout: "{{ authelia_database_timeout }}"
authelia_config_storage_postgres: authelia_config_storage_postgres:
host: "{{ authelia_database_host }}" address: "{{ authelia_database_address }}"
port: "{{ authelia_config_storage_postgres_port }}"
database: "{{ authelia_database_name }}" database: "{{ authelia_database_name }}"
schema: public schema: public
username: "{{ authelia_database_user }}" username: "{{ authelia_database_user }}"
@ -250,8 +251,7 @@ authelia_config_notifier: >-2
authelia_config_notifier_filesystem: authelia_config_notifier_filesystem:
filename: "{{ authelia_config_notifier_filesystem_filename }}" filename: "{{ authelia_config_notifier_filesystem_filename }}"
authelia_config_notifier_smtp: authelia_config_notifier_smtp:
host: "{{ authelia_config_notifier_smtp_host }}" address: "{{ authelia_config_notifier_smtp_address }}"
port: "{{ authelia_config_notifier_smtp_port }}"
timeout: "{{ authelia_config_notifier_smtp_timeout }}" timeout: "{{ authelia_config_notifier_smtp_timeout }}"
username: "{{ authelia_config_notifier_smtp_username }}" username: "{{ authelia_config_notifier_smtp_username }}"
password: "{{ authelia_config_notifier_smtp_password }}" password: "{{ authelia_config_notifier_smtp_password }}"

View File

@ -1,22 +0,0 @@
# `finallycoffee.services.elastiscsearch`
A simple ansible role which deploys a single-node elastic container to provide
an easy way to do some indexing.
## Usage
Per default, `/opt/elasticsearch/data` is used to persist data, it is
customizable by using either `elasticsearch_base_path` or `elasticsearch_data_path`.
As elasticsearch be can be quite memory heavy, the maximum amount of allowed RAM
can be configured using `elasticsearch_allocated_ram_mb`, defaulting to 512 (mb).
The cluster name and discovery type can be overridden using
`elasticsearch_config_cluster_name` (default: elastic) and
`elasticsearch_config_discovery_type` (default: single-node), should one
need a multi-node elasticsearch deployment.
Per default, no ports or networks are mapped, and explizit mapping using
either ports (`elasticsearch_container_ports`) or networks
(`elasticsearch_container_networks`) is required in order for other services
to use elastic.

View File

@ -1,35 +0,0 @@
---
elasticsearch_version: 7.17.7
elasticsearch_base_path: /opt/elasticsearch
elasticsearch_data_path: "{{ elasticsearch_base_path }}/data"
elasticsearch_config_cluster_name: elastic
elasticsearch_config_discovery_type: single-node
elasticsearch_config_boostrap_memory_lock: true
elasticsearch_allocated_ram_mb: 512
elasticsearch_container_image_name: docker.elastic.co/elasticsearch/elasticsearch-oss
elasticsearch_container_image_tag: ~
elasticsearch_container_image: >-
{{ elasticsearch_container_image_name }}:{{ elasticsearch_container_image_tag | default(elasticsearch_version, true) }}
elasticsearch_container_name: elasticsearch
elasticsearch_container_env:
"ES_JAVA_OPTS": "-Xms{{ elasticsearch_allocated_ram_mb }}m -Xmx{{ elasticsearch_allocated_ram_mb }}m"
"cluster.name": "{{ elasticsearch_config_cluster_name }}"
"discovery.type": "{{ elasticsearch_config_discovery_type }}"
"bootstrap.memory_lock": "{{ 'true' if elasticsearch_config_boostrap_memory_lock else 'false' }}"
elasticsearch_container_user: ~
elasticsearch_container_ports: ~
elasticsearch_container_labels:
version: "{{ elasticsearch_version }}"
elasticsearch_container_ulimits:
# - "memlock:{{ (1.5 * 1024 * elasticsearch_allocated_ram_mb) | int }}:{{ (1.5 * 1024 * elasticsearch_allocated_ram_mb) | int }}"
- "memlock:-1:-1"
elasticsearch_container_volumes:
- "{{ elasticsearch_data_path }}:/usr/share/elasticsearch/data:z"
elasticsearch_container_networks: ~
elasticsearch_container_purge_networks: ~
elasticsearch_container_restart_policy: unless-stopped

View File

@ -1,32 +0,0 @@
---
- name: Ensure host directories are present
file:
path: "{{ item }}"
state: directory
mode: "0777"
loop:
- "{{ elasticsearch_base_path }}"
- "{{ elasticsearch_data_path }}"
- name: Ensure elastic container image is present
docker_image:
name: "{{ elasticsearch_container_image }}"
state: present
source: pull
force_source: "{{ elasticsearch_container_image_tag|default(false, true)|bool }}"
- name: Ensure elastic container is running
docker_container:
name: "{{ elasticsearch_container_name }}"
image: "{{ elasticsearch_container_image }}"
env: "{{ elasticsearch_container_env | default(omit, True) }}"
user: "{{ elasticsearch_container_user | default(omit, True) }}"
ports: "{{ elasticsearch_container_ports | default(omit, True) }}"
labels: "{{ elasticsearch_container_labels | default(omit, True) }}"
volumes: "{{ elasticsearch_container_volumes }}"
ulimits: "{{ elasticsearch_container_ulimits }}"
networks: "{{ elasticsearch_container_networks | default(omit, True) }}"
purge_networks: "{{ elasticsearch_container_purge_networks | default(omit, True) }}"
restart_policy: "{{ elasticsearch_container_restart_policy }}"
state: started

View File

@ -1,7 +1,6 @@
--- ---
ghost_domain: ~ ghost_domain: ~
ghost_version: "5.33.6" ghost_version: "5.96.0"
ghost_user: ghost ghost_user: ghost
ghost_user_group: ghost ghost_user_group: ghost
ghost_base_path: /opt/ghost ghost_base_path: /opt/ghost
@ -36,3 +35,4 @@ ghost_container_restart_policy: "unless-stopped"
ghost_container_networks: ~ ghost_container_networks: ~
ghost_container_purge_networks: ~ ghost_container_purge_networks: ~
ghost_container_etc_hosts: ~ ghost_container_etc_hosts: ~
ghost_container_state: started

10
roles/ghost/meta/main.yml Normal file
View File

@ -0,0 +1,10 @@
---
allow_duplicates: true
dependencies: []
galaxy_info:
role_name: ghost
description: Ansible role to deploy ghost (https://ghost.org) using docker
galaxy_tags:
- ghost
- blog
- docker

View File

@ -16,15 +16,16 @@
- name: Ensure host paths for docker volumes exist for ghost - name: Ensure host paths for docker volumes exist for ghost
ansible.builtin.file: ansible.builtin.file:
path: "{{ item }}" path: "{{ item.path }}"
state: directory state: directory
mode: "0750" mode: "0750"
owner: "{{ ghost_user }}" owner: "{{ item.owner | default(ghost_user) }}"
group: "{{ ghost_user_group }}" group: "{{ item.group | default(ghost_user_group) }}"
loop: loop:
- "{{ ghost_base_path }}" - path: "{{ ghost_base_path }}"
- "{{ ghost_data_path }}" - path: "{{ ghost_data_path }}"
- "{{ ghost_config_path }}" owner: "1000"
- path: "{{ ghost_config_path }}"
- name: Ensure ghost configuration file is templated - name: Ensure ghost configuration file is templated
ansible.builtin.template: ansible.builtin.template:
@ -41,7 +42,7 @@
source: pull source: pull
force_source: "{{ ghost_container_image_tag is defined }}" force_source: "{{ ghost_container_image_tag is defined }}"
- name: Ensure ghost container is running - name: Ensure ghost container '{{ ghost_container_name }}' is {{ ghost_container_state }}
community.docker.docker_container: community.docker.docker_container:
name: "{{ ghost_container_name }}" name: "{{ ghost_container_name }}"
image: "{{ ghost_container_image }}" image: "{{ ghost_container_image }}"
@ -53,4 +54,4 @@
networks: "{{ ghost_container_networks | default(omit, true) }}" networks: "{{ ghost_container_networks | default(omit, true) }}"
purge_networks: "{{ ghost_container_purge_networks | default(omit, true) }}" purge_networks: "{{ ghost_container_purge_networks | default(omit, true) }}"
restart_policy: "{{ ghost_container_restart_policy }}" restart_policy: "{{ ghost_container_restart_policy }}"
state: started state: "{{ ghost_container_state }}"

View File

@ -1,7 +1,7 @@
--- ---
gitea_version: "1.22.3"
gitea_version: "1.19.4"
gitea_user: git gitea_user: git
gitea_run_user: "{{ gitea_user }}"
gitea_base_path: "/opt/gitea" gitea_base_path: "/opt/gitea"
gitea_data_path: "{{ gitea_base_path }}/data" gitea_data_path: "{{ gitea_base_path }}/data"
@ -9,17 +9,29 @@ gitea_data_path: "{{ gitea_base_path }}/data"
gitea_domain: ~ gitea_domain: ~
# container config # container config
gitea_container_name: "git" gitea_container_name: "{{ gitea_user }}"
gitea_container_image_name: "docker.io/gitea/gitea" gitea_container_image_server: "docker.io"
gitea_container_image_name: "gitea"
gitea_container_image_namespace: gitea
gitea_container_image_fq_name: >-
{{
[
gitea_container_image_server,
gitea_container_image_namespace,
gitea_container_image_name
] | join('/')
}}
gitea_container_image_tag: "{{ gitea_version }}" gitea_container_image_tag: "{{ gitea_version }}"
gitea_container_image: "{{ gitea_container_image_name }}:{{ gitea_container_image_tag }}" gitea_container_image: >-2
{{ gitea_container_image_fq_name }}:{{ gitea_container_image_tag }}
gitea_container_networks: [] gitea_container_networks: []
gitea_container_purge_networks: ~ gitea_container_purge_networks: ~
gitea_container_restart_policy: "unless-stopped" gitea_container_restart_policy: "unless-stopped"
gitea_container_extra_env: {} gitea_container_extra_env: {}
gitea_contianer_extra_labels: {} gitea_container_extra_labels: {}
gitea_container_extra_ports: [] gitea_container_extra_ports: []
gitea_container_extra_volumes: [] gitea_container_extra_volumes: []
gitea_container_state: started
# container defaults # container defaults
gitea_container_base_volumes: gitea_container_base_volumes:
@ -40,10 +52,10 @@ gitea_container_base_labels:
gitea_config_mailer_enabled: false gitea_config_mailer_enabled: false
gitea_config_mailer_type: ~ gitea_config_mailer_type: ~
gitea_config_mailer_from_addr: ~ gitea_config_mailer_from_addr: ~
gitea_config_mailer_host: ~ gitea_config_mailer_smtp_addr: ~
gitea_config_mailer_user: ~ gitea_config_mailer_user: ~
gitea_config_mailer_passwd: ~ gitea_config_mailer_passwd: ~
gitea_config_mailer_tls: ~ gitea_config_mailer_protocol: ~
gitea_config_mailer_sendmail_path: ~ gitea_config_mailer_sendmail_path: ~
gitea_config_metrics_enabled: false gitea_config_metrics_enabled: false

10
roles/gitea/meta/main.yml Normal file
View File

@ -0,0 +1,10 @@
---
allow_duplicates: true
dependencies: []
galaxy_info:
role_name: gitea
description: Ansible role to deploy gitea using docker
galaxy_tags:
- gitea
- git
- docker

View File

@ -1,14 +1,15 @@
--- ---
- name: Create gitea user - name: Ensure gitea user '{{ gitea_user }}' is present
user: ansible.builtin.user:
name: "{{ gitea_user }}" name: "{{ gitea_user }}"
state: present state: "present"
system: no system: false
create_home: true
register: gitea_user_res register: gitea_user_res
- name: Ensure host directories exist - name: Ensure host directories exist
file: ansible.builtin.file:
path: "{{ item }}" path: "{{ item }}"
owner: "{{ gitea_user_res.uid }}" owner: "{{ gitea_user_res.uid }}"
group: "{{ gitea_user_res.group }}" group: "{{ gitea_user_res.group }}"
@ -18,7 +19,7 @@
- "{{ gitea_data_path }}" - "{{ gitea_data_path }}"
- name: Ensure .ssh folder for gitea user exists - name: Ensure .ssh folder for gitea user exists
file: ansible.builtin.file:
path: "/home/{{ gitea_user }}/.ssh" path: "/home/{{ gitea_user }}/.ssh"
state: directory state: directory
owner: "{{ gitea_user_res.uid }}" owner: "{{ gitea_user_res.uid }}"
@ -37,16 +38,16 @@
register: gitea_user_ssh_key register: gitea_user_ssh_key
- name: Create forwarding script - name: Create forwarding script
copy: ansible.builtin.copy:
dest: "/usr/local/bin/gitea" dest: "/usr/local/bin/gitea"
owner: "{{ gitea_user_res.uid }}" owner: "{{ gitea_user_res.uid }}"
group: "{{ gitea_user_res.group }}" group: "{{ gitea_user_res.group }}"
mode: 0700 mode: 0700
content: | content: |
ssh -p {{ gitea_public_ssh_server_port }} -o StrictHostKeyChecking=no {{ gitea_user }}@127.0.0.1 -i /home/{{ gitea_user }}/.ssh/id_ssh_ed25519 "SSH_ORIGINAL_COMMAND=\"$SSH_ORIGINAL_COMMAND\" $0 $@" ssh -p {{ gitea_public_ssh_server_port }} -o StrictHostKeyChecking=no {{ gitea_run_user }}@127.0.0.1 -i /home/{{ gitea_user }}/.ssh/id_ssh_ed25519 "SSH_ORIGINAL_COMMAND=\"$SSH_ORIGINAL_COMMAND\" $0 $@"
- name: Add host pubkey to git users authorized_keys file - name: Add host pubkey to git users authorized_keys file
lineinfile: ansible.builtin.lineinfile:
path: "/home/{{ gitea_user }}/.ssh/authorized_keys" path: "/home/{{ gitea_user }}/.ssh/authorized_keys"
line: "{{ gitea_user_ssh_key.public_key }} Gitea:Host2Container" line: "{{ gitea_user_ssh_key.public_key }} Gitea:Host2Container"
state: present state: present
@ -56,26 +57,27 @@
mode: 0600 mode: 0600
- name: Ensure gitea container image is present - name: Ensure gitea container image is present
docker_image: community.docker.docker_image:
name: "{{ gitea_container_image }}" name: "{{ gitea_container_image }}"
state: present state: present
source: pull source: pull
force_source: "{{ gitea_container_image.endswith(':latest') }}" force_source: "{{ gitea_container_image.endswith(':latest') }}"
- name: Ensure container '{{ gitea_container_name }}' with gitea is running - name: Ensure container '{{ gitea_container_name }}' with gitea is {{ gitea_container_state }}
docker_container: community.docker.docker_container:
name: "{{ gitea_container_name }}" name: "{{ gitea_container_name }}"
image: "{{ gitea_container_image }}" image: "{{ gitea_container_image }}"
env: "{{ gitea_container_env }}" env: "{{ gitea_container_env }}"
labels: "{{ gitea_container_labels }}"
volumes: "{{ gitea_container_volumes }}" volumes: "{{ gitea_container_volumes }}"
networks: "{{ gitea_container_networks | default(omit, True) }}" networks: "{{ gitea_container_networks | default(omit, True) }}"
purge_networks: "{{ gitea_container_purge_networks | default(omit, True) }}" purge_networks: "{{ gitea_container_purge_networks | default(omit, True) }}"
published_ports: "{{ gitea_container_ports }}" published_ports: "{{ gitea_container_ports }}"
restart_policy: "{{ gitea_container_restart_policy }}" restart_policy: "{{ gitea_container_restart_policy }}"
state: started state: "{{ gitea_container_state }}"
- name: Ensure given configuration is set in the config file - name: Ensure given configuration is set in the config file
ini_file: ansible.builtin.ini_file:
path: "{{ gitea_data_path }}/gitea/conf/app.ini" path: "{{ gitea_data_path }}/gitea/conf/app.ini"
section: "{{ section }}" section: "{{ section }}"
option: "{{ option }}" option: "{{ option }}"

View File

@ -14,7 +14,7 @@ gitea_container_port_ssh: 22
gitea_config_base: gitea_config_base:
RUN_MODE: prod RUN_MODE: prod
RUN_USER: "{{ gitea_user }}" RUN_USER: "{{ gitea_run_user }}"
server: server:
SSH_DOMAIN: "{{ gitea_domain }}" SSH_DOMAIN: "{{ gitea_domain }}"
DOMAIN: "{{ gitea_domain }}" DOMAIN: "{{ gitea_domain }}"
@ -24,11 +24,11 @@ gitea_config_base:
mailer: mailer:
ENABLED: "{{ gitea_config_mailer_enabled }}" ENABLED: "{{ gitea_config_mailer_enabled }}"
MAILER_TYP: "{{ gitea_config_mailer_type }}" MAILER_TYP: "{{ gitea_config_mailer_type }}"
HOST: "{{ gitea_config_mailer_host }}" SMTP_ADDR: "{{ gitea_config_mailer_smtp_addr }}"
USER: "{{ gitea_config_mailer_user }}" USER: "{{ gitea_config_mailer_user }}"
PASSWD: "{{ gitea_config_mailer_passwd }}" PASSWD: "{{ gitea_config_mailer_passwd }}"
IS_TLS_ENABLED: "{{ gitea_config_mailer_tls }}" PROTOCOL: "{{ gitea_config_mailer_protocol }}"
FROM: "{{ gitea_config_mailer_from_addr }}" FROM: "{{ gitea_config_mailer_from }}"
SENDMAIL_PATH: "{{ gitea_config_mailer_sendmail_path }}" SENDMAIL_PATH: "{{ gitea_config_mailer_sendmail_path }}"
metrics: metrics:
ENABLED: "{{ gitea_config_metrics_enabled }}" ENABLED: "{{ gitea_config_metrics_enabled }}"

21
roles/hedgedoc/README.md Normal file
View File

@ -0,0 +1,21 @@
# `finallycoffee.services.hedgedoc` ansible role
Role to deploy and configure hedgedoc using `docker` or `podman`.
To configure hedgedoc, set either the config as complex data
directly in `hedgedoc_config` or use the flattened variables
from the `hedgedoc_config_*` prefix (see
[defaults/main/config.yml](defaults/main/config.yml)).
To remove hedgedoc, set `hedgedoc_state: absent`. Note that this
will delete all data directories aswell, removing any traces this
role created on the target (except database contents).
# Required configuration
- `hedgedoc_config_domain` - Domain of the hedgedoc instance
- `hedgedoc_config_session_secret` - session secret for hedgedoc
## Deployment methods
To set the desired deployment method, set `hedgedoc_deployment_method` to a
supported deployment methods (see [vars/main.yml](vars/main.yml#5)).

View File

@ -0,0 +1,52 @@
---
hedgedoc_config_domain: ~
hedgedoc_config_log_level: "info"
hedgedoc_config_session_secret: ~
hedgedoc_config_protocol_use_ssl: true
hedgedoc_config_hsts_enable: true
hedgedoc_config_csp_enable: true
hedgedoc_config_cookie_policy: 'lax'
hedgedoc_config_allow_free_url: true
hedgedoc_config_allow_email_register: false
hedgedoc_config_allow_anonymous: true
hedgedoc_config_allow_gravatar: true
hedgedoc_config_require_free_url_authentication: true
hedgedoc_config_default_permission: 'full'
hedgedoc_config_db_username: hedgedoc
hedgedoc_config_db_password: ~
hedgedoc_config_db_database: hedgedoc
hedgedoc_config_db_host: localhost
hedgedoc_config_db_port: 5432
hedgedoc_config_db_dialect: postgres
hedgedoc_config_database:
username: "{{ hedgedoc_config_db_username }}"
password: "{{ hedgedoc_config_db_password }}"
database: "{{ hedgedoc_config_db_database }}"
host: "{{ hedgedoc_config_db_host }}"
port: "{{ hedgedoc_config_db_port | int }}"
dialect: "{{ hedgedoc_config_db_dialect }}"
hedgedoc_config_base:
production:
domain: "{{ hedgedoc_config_domain }}"
loglevel: "{{ hedgedoc_config_log_level }}"
sessionSecret: "{{ hedgedoc_config_session_secret }}"
protocolUseSSL: "{{ hedgedoc_config_protocol_use_ssl }}"
cookiePolicy: "{{ hedgedoc_config_cookie_policy }}"
allowFreeURL: "{{ hedgedoc_config_allow_free_url }}"
allowAnonymous: "{{ hedgedoc_config_allow_anonymous }}"
allowEmailRegister: "{{ hedgedoc_config_allow_email_register }}"
allowGravatar: "{{ hedgedoc_config_allow_gravatar }}"
requireFreeURLAuthentication: >-2
{{ hedgedoc_config_require_free_url_authentication }}
defaultPermission: "{{ hedgedoc_config_default_permission }}"
hsts:
enable: "{{ hedgedoc_config_hsts_enable }}"
csp:
enable: "{{ hedgedoc_config_csp_enable }}"
db: "{{ hedgedoc_config_database }}"
hedgedoc_config: ~
hedgedoc_full_config: >-2
{{ hedgedoc_config_base | default({}, true)
| combine(hedgedoc_config | default({}, true), recursive=True) }}

View File

@ -0,0 +1,57 @@
---
hedgedoc_container_image_registry: quay.io
hedgedoc_container_image_namespace: hedgedoc
hedgedoc_container_image_name: hedgedoc
hedgedoc_container_image_flavour: alpine
hedgedoc_container_image_tag: ~
hedgedoc_container_image: >-2
{{
([
hedgedoc_container_image_registry,
hedgedoc_container_image_namespace | default([], true),
hedgedoc_container_image_name,
] | flatten | join('/'))
+ ':'
+ hedgedoc_container_image_tag | default(
hedgedoc_version + (
((hedgedoc_container_image_flavour is string)
and (hedgedoc_container_image_flavour | length > 0))
| ternary('-' +
hedgedoc_container_image_flavour | default('', true),
''
)
),
true
)
}}
hedgedoc_container_image_source: pull
hedgedoc_container_name: hedgedoc
hedgedoc_container_state: >-2
{{ (hedgedoc_state == 'present') | ternary('started', 'absent') }}
hedgedoc_container_config_file: "/hedgedoc/config.json"
hedgedoc_container_upload_path: "/hedgedoc/public/uploads"
hedgedoc_container_env: ~
hedgedoc_container_user: >-2
{{ hedgedoc_run_user_id }}:{{ hedgedoc_run_group_id }}
hedgedoc_container_ports: ~
hedgedoc_container_networks: ~
hedgedoc_container_etc_hosts: ~
hedgedoc_container_base_volumes:
- "{{ hedgedoc_config_file }}:{{ hedgedoc_container_config_file }}:ro"
- "{{ hedgedoc_uploads_path }}:{{ hedgedoc_container_upload_path }}:rw"
hedgedoc_container_volumes: ~
hedgedoc_container_all_volumes: >-2
{{ hedgedoc_container_base_volumes | default([], true)
+ hedgedoc_container_volumes | default([], true) }}
hedgedoc_container_base_labels:
version: "{{ hedgedoc_container_tag | default(hedgedoc_version, true) }}"
hedgedoc_container_labels: ~
hedgedoc_container_network_mode: ~
hedgedoc_container_all_labels: >-2
{{ hedgedoc_container_base_labels | default({}, true)
| combine(hedgedoc_container_labels | default({}, true)) }}
hedgedoc_container_restart_policy: >-2
{{ (hedgedoc_deployment_method === 'docker')
| ternary('unless-stopped', 'on-failure') }}

View File

@ -0,0 +1,9 @@
---
hedgedoc_user: hedgedoc
hedgedoc_version: "1.10.0"
hedgedoc_state: present
hedgedoc_deployment_method: docker
hedgedoc_config_file: "/etc/hedgedoc/config.json"
hedgedoc_uploads_path: "/var/lib/hedgedoc-uploads"

View File

@ -0,0 +1,5 @@
---
hedgedoc_run_user_id: >-2
{{ hedgedoc_user_info.uid | default(hedgedoc_user) }}
hedgedoc_run_group_id: >-2
{{ hedgedoc_user_info.group | default(hedgedoc_user) }}

View File

@ -0,0 +1,12 @@
---
allow_duplicates: true
dependencies: []
galaxy_info:
role_name: hedgedoc
description: >-2
Deploy hedgedoc, a collaborative markdown editor, using docker
galaxy_tags:
- hedgedoc
- markdown
- collaboration
- docker

View File

@ -0,0 +1,23 @@
---
- name: Check for valid state
ansible.builtin.fail:
msg: >-2
Unsupported state '{{ hedgedoc_state }}'. Supported
states are {{ hedgedoc_states | join(', ') }}.
when: hedgedoc_state not in hedgedoc_states
- name: Check for valid deployment method
ansible.builtin.fail:
msg: >-2
Deployment method '{{ hedgedoc_deployment_method }}'
is not supported. Supported are:
{{ hedgedoc_deployment_methods | join(', ') }}
when: hedgedoc_deployment_method not in hedgedoc_deployment_methods
- name: Ensure required variables are given
ansible.builtin.fail:
msg: "Required variable '{{ item }}' is undefined!"
loop: "{{ hedgedoc_required_arguments }}"
when: >-2
item not in hostvars[inventory_hostname]
or hostvars[inventory_hostname][item] | length == 0

View File

@ -0,0 +1,31 @@
---
- name: Ensure container image '{{ hedgedoc_container_image }}' is {{ hedgedoc_state }}
community.docker.docker_image:
name: "{{ hedgedoc_container_image }}"
state: "{{ hedgedoc_state }}"
source: "{{ hedgedoc_container_image_source }}"
force_source: >-2
{{ hedgedoc_container_force_source | default(
hedgedoc_container_image_tag | default(false, true), true) }}
register: hedgedoc_container_image_info
until: hedgedoc_container_image_info is success
retries: 5
delay: 3
- name: Ensure container '{{ hedgedoc_container_name }}' is {{ hedgedoc_container_state }}
community.docker.docker_container:
name: "{{ hedgedoc_container_name }}"
image: "{{ hedgedoc_container_image }}"
env: "{{ hedgedoc_container_env | default(omit, true) }}"
user: "{{ hedgedoc_container_user | default(omit, true) }}"
ports: "{{ hedgedoc_container_ports | default(omit, true) }}"
labels: "{{ hedgedoc_container_all_labels }}"
volumes: "{{ hedgedoc_container_all_volumes }}"
etc_hosts: "{{ hedgedoc_container_etc_hosts | default(omit, true) }}"
dns_servers: >-2
{{ hedgedoc_container_dns_servers | default(omit, true) }}
network_mode: >-2
{{ hedgedoc_container_network_mode | default(omit, true) }}
restart_policy: >-2
{{ hedgedoc_container_restart_policy | default(omit, true) }}
state: "{{ hedgedoc_container_state }}"

View File

@ -0,0 +1,21 @@
---
- name: Check preconditions
ansible.builtin.include_tasks:
file: "check.yml"
- name: Ensure user '{{ hedgedoc_user }}' is {{ hedgedoc_state }}
ansible.builtin.user:
name: "{{ hedgedoc_user }}"
state: "{{ hedgedoc_state }}"
system: "{{ hedgedoc_user_system | default(true, false) }}"
register: hedgedoc_user_info
- name: Ensure configuration file '{{ hedgedoc_config_file }}' is {{ hedgedoc_state }}
ansible.builtin.copy:
dest: "{{ hedgedoc_config_file }}"
content: "{{ hedgedoc_full_config | to_nice_json }}"
when: hedgedoc_state == 'present'
- name: Ensure hedgedoc is deployed using {{ hedgedoc_deployment_method }}
ansible.builtin.include_tasks:
file: "deploy-{{ hedgedoc_deployment_method }}.yml"

View File

@ -0,0 +1,11 @@
---
hedgedoc_states:
- present
- absent
hedgedoc_deployment_methods:
- docker
- podman
hedgedoc_required_arguments:
- hedgedoc_config_domain
- hedgedoc_config_session_secret

View File

@ -1,7 +1,7 @@
--- ---
jellyfin_user: jellyfin jellyfin_user: jellyfin
jellyfin_version: 10.8.10 jellyfin_version: 10.9.11
jellyfin_state: present
jellyfin_base_path: /opt/jellyfin jellyfin_base_path: /opt/jellyfin
jellyfin_config_path: "{{ jellyfin_base_path }}/config" jellyfin_config_path: "{{ jellyfin_base_path }}/config"
@ -12,7 +12,11 @@ jellyfin_media_volumes: []
jellyfin_container_name: jellyfin jellyfin_container_name: jellyfin
jellyfin_container_image_name: "docker.io/jellyfin/jellyfin" jellyfin_container_image_name: "docker.io/jellyfin/jellyfin"
jellyfin_container_image_tag: ~ jellyfin_container_image_tag: ~
jellyfin_container_image_ref: "{{ jellyfin_container_image_name }}:{{ jellyfin_container_image_tag | default(jellyfin_version, true) }}" jellyfin_container_image_ref: >-2
{{ jellyfin_container_image_name }}:{{ jellyfin_container_image_tag | default(jellyfin_version, true) }}
jellyfin_container_image_source: pull
jellyfin_container_state: >-2
{{ (jellyfin_state == 'present') | ternary('started', 'absent') }}
jellyfin_container_network_mode: host jellyfin_container_network_mode: host
jellyfin_container_networks: ~ jellyfin_container_networks: ~
jellyfin_container_volumes: "{{ jellyfin_container_base_volumes + jellyfin_media_volumes }}" jellyfin_container_volumes: "{{ jellyfin_container_base_volumes + jellyfin_media_volumes }}"

View File

@ -0,0 +1,10 @@
---
allow_duplicates: true
dependencies: []
galaxy_info:
role_name: jellyfin
description: Ansible role to deploy jellyfin using docker
galaxy_tags:
- jellyfin
- streaming
- docker

View File

@ -1,34 +1,41 @@
--- ---
- name: Check if state is valid
ansible.builtin.fail:
msg: >-2
Unsupported state '{{ jellyfin_state }}'. Supported
states are {{ jellyfin_states | join(', ') }}.
when: jellyfin_state not in jellyfin_states
- name: Ensure user '{{ jellyfin_user }}' for jellyfin is created - name: Ensure jellyfin user '{{ jellyfin_user }}' is {{ jellyfin_state }}
user: ansible.builtin.user:
name: "{{ jellyfin_user }}" name: "{{ jellyfin_user }}"
state: present state: "{{ jellyfin_state }}"
system: yes system: "{{ jellyfin_user_system | default(true, true) }}"
register: jellyfin_user_info register: jellyfin_user_info
- name: Ensure host directories for jellyfin exist - name: Ensure host directories for jellyfin are {{ jellyfin_state }}
file: ansible.builtin.file:
path: "{{ item.path }}" path: "{{ item.path }}"
state: directory state: >-2
{{ (jellyfin_state == 'present') | ternary('directory', 'absent') }}
owner: "{{ item.owner | default(jellyfin_uid) }}" owner: "{{ item.owner | default(jellyfin_uid) }}"
group: "{{ item.group | default(jellyfin_gid) }}" group: "{{ item.group | default(jellyfin_gid) }}"
mode: "{{ item.mode }}" mode: "{{ item.mode }}"
loop: "{{ jellyfin_host_directories }}" loop: "{{ jellyfin_host_directories }}"
- name: Ensure container image for jellyfin is available - name: Ensure container image '{{ jellyfin_container_image_ref }}' is {{ jellyfin_state }}
docker_image: community.docker.docker_image:
name: "{{ jellyfin_container_image_ref }}" name: "{{ jellyfin_container_image_ref }}"
state: present state: "{{ jellyfin_state }}"
source: pull source: "{{ jellyfin_container_image_source }}"
force_source: "{{ jellyfin_container_image_tag | default(false, true) }}" force_source: "{{ jellyfin_container_image_tag | default(false, true) }}"
register: jellyfin_container_image_pull_result register: jellyfin_container_image_pull_result
until: jellyfin_container_image_pull_result is succeeded until: jellyfin_container_image_pull_result is succeeded
retries: 5 retries: 5
delay: 3 delay: 3
- name: Ensure container '{{ jellyfin_container_name }}' is running - name: Ensure container '{{ jellyfin_container_name }}' is {{ jellyfin_container_state }}
docker_container: community.docker.docker_container:
name: "{{ jellyfin_container_name }}" name: "{{ jellyfin_container_name }}"
image: "{{ jellyfin_container_image_ref }}" image: "{{ jellyfin_container_image_ref }}"
user: "{{ jellyfin_uid }}:{{ jellyfin_gid }}" user: "{{ jellyfin_uid }}:{{ jellyfin_gid }}"
@ -37,4 +44,4 @@
networks: "{{ jellyfin_container_networks | default(omit, True) }}" networks: "{{ jellyfin_container_networks | default(omit, True) }}"
network_mode: "{{ jellyfin_container_network_mode }}" network_mode: "{{ jellyfin_container_network_mode }}"
restart_policy: "{{ jellyfin_container_restart_policy }}" restart_policy: "{{ jellyfin_container_restart_policy }}"
state: started state: "{{ jellyfin_container_state }}"

View File

@ -1,4 +1,7 @@
--- ---
jellyfin_states:
- present
- absent
jellyfin_container_base_volumes: jellyfin_container_base_volumes:
- "{{ jellyfin_config_path }}:/config:z" - "{{ jellyfin_config_path }}:/config:z"

View File

@ -1,29 +0,0 @@
# `finallycoffee.services.minio` ansible role
## Overview
This role deploys a [min.io](https://min.io) server (s3-compatible object storage server)
using the official docker container image.
## Configuration
The role requires setting the password for the `root` user (name can be changed by
setting `minio_root_username`) in `minio_root_password`. That user has full control
over the minio-server instance.
### Useful config hints
Most configuration is done by setting environment variables in
`minio_container_extra_env`, for example:
```yaml
minio_container_extra_env:
# disable the "console" web browser UI
MINIO_BROWSER: off
# enable public prometheus metrics on `/minio/v2/metrics/cluster`
MINIO_PROMETHEUS_AUTH_TYPE: public
```
When serving minio (or any s3-compatible server) on a "subfolder",
see https://docs.aws.amazon.com/AmazonS3/latest/userguide/RESTRedirect.html
and https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html

View File

@ -1,40 +0,0 @@
---
minio_user: ~
minio_data_path: /opt/minio
minio_create_user: false
minio_manage_host_filesystem: false
minio_root_username: root
minio_root_password: ~
minio_container_name: minio
minio_container_image_name: docker.io/minio/minio
minio_container_image_tag: latest
minio_container_image: "{{ minio_container_image_name }}:{{ minio_container_image_tag }}"
minio_container_networks: []
minio_container_ports: []
minio_container_base_volumes:
- "{{ minio_data_path }}:{{ minio_container_data_path }}:z"
minio_container_extra_volumes: []
minio_container_base_env:
MINIO_ROOT_USER: "{{ minio_root_username }}"
MINIO_ROOT_PASSWORD: "{{ minio_root_password }}"
minio_container_extra_env: {}
minio_container_labels: {}
minio_container_command:
- "server"
- "{{ minio_container_data_path }}"
- "--console-address \":{{ minio_container_listen_port_console }}\""
minio_container_restart_policy: "unless-stopped"
minio_container_image_force_source: "{{ (minio_container_image_tag == 'latest')|bool }}"
minio_container_listen_port_api: 9000
minio_container_listen_port_console: 8900
minio_container_data_path: /storage

View File

@ -1,37 +0,0 @@
---
- name: Ensure minio run user is present
user:
name: "{{ minio_user }}"
state: present
system: yes
when: minio_create_user
- name: Ensure filesystem mounts ({{ minio_data_path }}) for container volumes are present
file:
path: "{{ minio_data_path }}"
state: directory
user: "{{ minio_user|default(omit, True) }}"
group: "{{ minio_user|default(omit, True) }}"
when: minio_manage_host_filesystem
- name: Ensure container image for minio is present
community.docker.docker_image:
name: "{{ minio_container_image }}"
state: present
source: pull
force_source: "{{ minio_container_image_force_source }}"
- name: Ensure container {{ minio_container_name }} is running
docker_container:
name: "{{ minio_container_name }}"
image: "{{ minio_container_image }}"
volumes: "{{ minio_container_volumes }}"
env: "{{ minio_container_env }}"
labels: "{{ minio_container_labels }}"
networks: "{{ minio_container_networks }}"
ports: "{{ minio_container_ports }}"
user: "{{ minio_user|default(omit, True) }}"
command: "{{ minio_container_command }}"
restart_policy: "{{ minio_container_restart_policy }}"
state: started

View File

@ -1,5 +0,0 @@
---
minio_container_volumes: "{{ minio_container_base_volumes + minio_container_extra_volumes }}"
minio_container_env: "{{ minio_container_base_env | combine(minio_container_extra_env) }}"

View File

@ -1,28 +0,0 @@
# `finallycoffee.services.nginx` ansible role
## Description
Runs `nginx`, a HTTP reverse proxy, in a docker container.
## Usage
For the role to do anything, `nginx_config` needs to be populated with the configuration for nginx.
An example would be:
```yaml
nginx_config: |+
server {
listen 80 default_server;
server_name my.server.fqdn;
location / { return 200; }
}
```
The container is named `nginx` by default, this can be overridden in `nginx_container_name`.
When running this role multiple times, `nginx_base_path` should also be changed for each run,
otherwise the configuration files collide in the filesystem.
For exposing this server to the host and/or internet, the `nginx_container_ports` (port forwarding host
from host to container), `nginx_container_networks` (docker networking) or `nginx_container_labels`
(for label-based routing discovery like traefik) can be used. The options correspond to the arguments
of the `community.docker.docker_container` module.

View File

@ -1,33 +0,0 @@
---
nginx_version: "1.25.1"
nginx_flavour: alpine
nginx_base_path: /opt/nginx
nginx_config_file: "{{ nginx_base_path }}/nginx.conf"
nginx_container_name: nginx
nginx_container_image_reference: >-
{{
nginx_container_image_repository
+ ':' + (nginx_container_image_tag
| default(nginx_version
+ (('-' + nginx_flavour) if nginx_flavour is defined else ''), true))
}}
nginx_container_image_repository: >-
{{
(
container_registries[nginx_container_image_registry]
| default(nginx_container_image_registry)
)
+ '/'
+ nginx_container_image_namespace | default('')
+ nginx_container_image_name
}}
nginx_container_image_registry: "docker.io"
nginx_container_image_name: "nginx"
nginx_container_image_tag: ~
nginx_container_restart_policy: "unless-stopped"
nginx_container_volumes:
- "{{ nginx_config_file }}:/etc/nginx/conf.d/nginx.conf:ro"

View File

@ -1,8 +0,0 @@
---
- name: Ensure nginx container '{{ nginx_container_name }}' is restarted
community.docker.docker_container:
name: "{{ nginx_container_name }}"
state: started
restart: true
listen: restart-nginx

View File

@ -1,37 +0,0 @@
---
- name: Ensure base path '{{ nginx_base_path }}' exists
ansible.builtin.file:
path: "{{ nginx_base_path }}"
state: directory
mode: 0755
- name: Ensure nginx config file is templated
ansible.builtin.copy:
dest: "{{ nginx_config_file }}"
content: "{{ nginx_config }}"
mode: 0640
notify:
- restart-nginx
- name: Ensure docker container image is present
community.docker.docker_image:
name: "{{ nginx_container_image_reference }}"
state: present
source: pull
force_source: "{{ nginx_container_image_tag is defined and nginx_container_image_tag | string != '' }}"
- name: Ensure docker container '{{ nginx_container_name }}' is running
community.docker.docker_container:
name: "{{ nginx_container_name }}"
image: "{{ nginx_container_image_reference }}"
env: "{{ nginx_container_env | default(omit, true) }}"
user: "{{ nginx_container_user | default(omit, true) }}"
ports: "{{ nginx_container_ports | default(omit, true) }}"
labels: "{{ nginx_container_labels | default(omit, true) }}"
volumes: "{{ nginx_container_volumes | default(omit, true) }}"
etc_hosts: "{{ nginx_container_etc_hosts | default(omit, true) }}"
networks: "{{ nginx_container_networks | default(omit, true) }}"
purge_networks: "{{ nginx_container_purge_networks | default(omit, true) }}"
restart_policy: "{{ nginx_container_restart_policy }}"
state: started

View File

@ -0,0 +1,21 @@
# `finallycoffee.services.openproject` ansible role
Deploys [openproject](https://www.openproject.org/) using docker-compose.
## Configuration
To set configuration variables for OpenProject, set them in `openproject_compose_overrides`:
```yaml
openproject_compose_overrides:
version: "3.7"
services:
proxy:
[...]
volumes:
pgdata:
driver: local
driver_opts:
o: bind
type: none
device: /var/lib/postgresql
```

View File

@ -0,0 +1,11 @@
---
openproject_base_path: "/opt/openproject"
openproject_upstream_git_url: "https://github.com/opf/openproject-deploy.git"
openproject_upstream_git_branch: "stable/13"
openproject_compose_project_path: "{{ openproject_base_path }}/compose"
openproject_compose_project_name: "openproject"
openproject_compose_project_env_file: "{{ openproject_compose_project_path }}/.env"
openproject_compose_project_override_file: "{{ openproject_compose_project_path }}/docker-compose.override.yml"
openproject_compose_project_env: {}

View File

@ -0,0 +1,39 @@
---
- name: Ensure base directory '{{ openproject_base_path }}' is present
ansible.builtin.file:
path: "{{ openproject_base_path }}"
state: directory
- name: Ensure upstream repository is cloned
ansible.builtin.git:
dest: "{{ openproject_base_path }}"
repo: "{{ openproject_upstream_git_url }}"
version: "{{ openproject_upstream_git_branch }}"
clone: true
depth: 1
- name: Ensure environment is configured
ansible.builtin.lineinfile:
line: "{{ item.key}}={{ item.value}}"
path: "{{ openproject_compose_project_env_file }}"
state: present
create: true
loop: "{{ openproject_compose_project_env | dict2items(key_name='key', value_name='value') }}"
- name: Ensure docker compose overrides are set
ansible.builtin.copy:
dest: "{{ openproject_compose_project_override_file }}"
content: "{{ openproject_compose_overrides | default({}) | to_nice_yaml }}"
- name: Ensure containers are pulled
community.docker.docker_compose:
project_src: "{{ openproject_compose_project_path }}"
project_name: "{{ openproject_compose_project_name }}"
pull: true
- name: Ensure services are running
community.docker.docker_compose:
project_src: "{{ openproject_compose_project_path }}"
project_name: "{{ openproject_compose_project_name }}"
state: "present"
build: false

View File

@ -1,77 +0,0 @@
# `finallycoffee.services.restic`
Ansible role for backup up data using `restic`, utilizing `systemd` timers for scheduling.
## Overview
As restic encrypts the data before storing it, the `restic_repo_password` needs
to be populated with a strong key, and saved accordingly as only this key can
be used to decrypt the data for a restore!
### Backends
#### S3 Backend
To use a `s3`-compatible backend like AWS buckets or minio, both `restic_s3_key_id`
and `restic_s3_access_key` need to be populated, and the `restic_repo_url` has the
format `s3:https://my.s3.endpoint:port/bucket-name`.
#### SFTP Backend
Using the `sftp` backend requires the configured `restic_user` to be able to
authenticate to the configured SFTP-Server using password-less methods like
publickey-authentication. The `restic_repo_url` then follows the format
`sftp:{user}@{server}:/my-restic-repository` (or without leading `/` for relative
paths to the `{user}`s home directory.
### Backing up data
A job name like `$service-postgres` or similar needs to be set in `restic_job_name`,
which is used for naming the `systemd` units, their syslog identifiers etc.
If backing up filesystem locations, the paths need to be specified in
`restic_backup_paths` as lists of strings representing absolute filesystem
locations.
If backing up f.ex. database or other data which is generating backups using
a command like `pg_dump`, use `restic_backup_stdin_command` (which needs to output
to `stdout`) in conjunction with `restic_backup_stdin_command_filename` to name
the resulting output (required).
### Policy
The backup policy can be adjusted by overriding the `restic_policy_keep_*`
variables, with the defaults being:
```yaml
restic_policy_keep_all_within: 1d
restic_policy_keep_hourly: 6
restic_policy_keep_daily: 2
restic_policy_keep_weekly: 7
restic_policy_keep_monthly: 4
restic_policy_backup_frequency: hourly
```
**Note:** `restic_policy_backup_frequency` must conform to `systemd`s
`OnCalendar` syntax, which can be checked using `systemd-analyze calender $x`.
## Role behaviour
Per default, when the systemd unit for a job changes, the job is not immediately
started. This can be overridden using `restic_start_job_on_unit_change: true`,
which will immediately start the backup job if it's configuration changed.
The systemd unit runs with `restic_user`, which is root by default, guaranteeing
that filesystem paths are always readable. The `restic_user` can be overridden,
but care needs to be taken to ensure the user has permission to read all the
provided filesystem paths / the backup command may be executed by the user.
If ansible should create the user, set `restic_create_user` to `true`, which
will attempt to create the `restic_user` as a system user.
### Installing
For Debian and RedHat, the role attempts to install restic using the default
package manager's ansible module (apt/dnf). For other distributions, the generic
`package` module tries to install `restic_package_name` (default: `restic`),
which can be overridden if needed.

View File

@ -1,37 +0,0 @@
---
restic_repo_url: ~
restic_repo_password: ~
restic_s3_key_id: ~
restic_s3_access_key: ~
restic_backup_paths: []
restic_backup_stdin_command: ~
restic_backup_stdin_command_filename: ~
restic_policy_keep_all_within: 1d
restic_policy_keep_hourly: 6
restic_policy_keep_daily: 2
restic_policy_keep_weekly: 7
restic_policy_keep_monthly: 4
restic_policy_backup_frequency: hourly
restic_policy:
keep_within: "{{ restic_policy_keep_all_within }}"
hourly: "{{ restic_policy_keep_hourly }}"
daily: "{{ restic_policy_keep_daily }}"
weekly: "{{ restic_policy_keep_weekly }}"
monthly: "{{ restic_policy_keep_monthly }}"
frequency: "{{ restic_policy_backup_frequency }}"
restic_user: root
restic_create_user: false
restic_start_job_on_unit_change: false
restic_job_name: ~
restic_job_description: "Restic backup job for {{ restic_job_name }}"
restic_systemd_unit_naming_scheme: "restic.{{ restic_job_name }}"
restic_systemd_working_directory: /tmp
restic_systemd_syslog_identifier: "restic-{{ restic_job_name }}"
restic_package_name: restic

View File

@ -1,13 +0,0 @@
---
- name: Ensure system daemon is reloaded
listen: reload-systemd
systemd:
daemon_reload: true
- name: Ensure systemd service for '{{ restic_job_name }}' is started immediately
listen: trigger-restic
systemd:
name: "{{ restic_systemd_unit_naming_scheme }}.service"
state: started
when: restic_start_job_on_unit_change

View File

@ -1,77 +0,0 @@
---
- name: Ensure {{ restic_user }} system user exists
user:
name: "{{ restic_user }}"
state: present
system: true
when: restic_create_user
- name: Ensure either backup_paths or backup_stdin_command is populated
when: restic_backup_paths|length > 0 and restic_backup_stdin_command
fail:
msg: "Setting both `restic_backup_paths` and `restic_backup_stdin_command` is not supported"
- name: Ensure a filename for stdin_command backup is given
when: restic_backup_stdin_command and not restic_backup_stdin_command_filename
fail:
msg: "`restic_backup_stdin_command` was set but no filename for the resulting output was supplied in `restic_backup_stdin_command_filename`"
- name: Ensure backup frequency adheres to systemd's OnCalender syntax
command:
cmd: "systemd-analyze calendar {{ restic_policy.frequency }}"
register: systemd_calender_parse_res
failed_when: systemd_calender_parse_res.rc != 0
changed_when: false
- name: Ensure restic is installed
block:
- name: Ensure restic is installed via apt
apt:
package: restic
state: latest
when: ansible_os_family == 'Debian'
- name: Ensure restic is installed via dnf
dnf:
name: restic
state: latest
when: ansible_os_family == 'RedHat'
- name: Ensure restic is installed using the auto-detected package-manager
package:
name: "{{ restic_package_name }}"
state: present
when: ansible_os_family not in ['RedHat', 'Debian']
- name: Ensure systemd service file for '{{ restic_job_name }}' is templated
template:
dest: "/etc/systemd/system/{{ restic_systemd_unit_naming_scheme }}.service"
src: restic.service.j2
owner: root
group: root
mode: 0640
notify:
- reload-systemd
- trigger-restic
- name: Ensure systemd service file for '{{ restic_job_name }}' is templated
template:
dest: "/etc/systemd/system/{{ restic_systemd_unit_naming_scheme }}.timer"
src: restic.timer.j2
owner: root
group: root
mode: 0640
notify:
- reload-systemd
- name: Flush handlers to ensure systemd knows about '{{ restic_job_name }}'
meta: flush_handlers
- name: Ensure systemd timer for '{{ restic_job_name }}' is activated
systemd:
name: "{{ restic_systemd_unit_naming_scheme }}.timer"
enabled: true
- name: Ensure systemd timer for '{{ restic_job_name }}' is started
systemd:
name: "{{ restic_systemd_unit_naming_scheme }}.timer"
state: started

View File

@ -1,28 +0,0 @@
[Unit]
Description={{ restic_job_description }}
[Service]
Type=oneshot
User={{ restic_user }}
WorkingDirectory={{ restic_systemd_working_directory }}
SyslogIdentifier={{ restic_systemd_syslog_identifier }}
Environment=RESTIC_REPOSITORY={{ restic_repo_url }}
Environment=RESTIC_PASSWORD={{ restic_repo_password }}
{% if restic_s3_key_id and restic_s3_access_key %}
Environment=AWS_ACCESS_KEY_ID={{ restic_s3_key_id }}
Environment=AWS_SECRET_ACCESS_KEY={{ restic_s3_access_key }}
{% endif %}
ExecStartPre=-/bin/sh -c '/usr/bin/restic snapshots || /usr/bin/restic init'
{% if restic_backup_stdin_command %}
ExecStart=/bin/sh -c '{{ restic_backup_stdin_command }} | /usr/bin/restic backup --verbose --stdin --stdin-filename {{ restic_backup_stdin_command_filename }}'
{% else %}
ExecStart=/usr/bin/restic --verbose backup {{ restic_backup_paths | join(' ') }}
{% endif %}
ExecStartPost=/usr/bin/restic forget --prune --keep-within={{ restic_policy.keep_within }} --keep-hourly={{ restic_policy.hourly }} --keep-daily={{ restic_policy.daily }} --keep-weekly={{ restic_policy.weekly }} --keep-monthly={{ restic_policy.monthly }}
ExecStartPost=-/usr/bin/restic snapshots
ExecStartPost=/usr/bin/restic check
[Install]
WantedBy=multi-user.target

View File

@ -1,10 +0,0 @@
[Unit]
Description=Run {{ restic_job_name }}
[Timer]
OnCalendar={{ restic_policy.frequency }}
Persistent=True
Unit={{ restic_systemd_unit_naming_scheme }}.service
[Install]
WantedBy=timers.target

View File

@ -0,0 +1,54 @@
# `finallycoffee.services.vaultwarden` ansible role
Vaultwarden is an unofficial (not associated with Bitwarden) bitwarden API compatible
server backend, formally called `bitwarden_rs`, written in rust.
This ansible role can deploy and configure `vaultwarden`, and supports removing
itself using `vaultwarden_state: absent` (Warning: It does not ask for confirmation,
and will remove all user data when instructed to remove it).
## Configuration
To use this role, the following variables need to be populated:
- `vaultwarden_config_domain` - always. Changing this will lead to two-factor not working for two-factor methods registered in the past.
- `vaultwarden_config_admin_token` - if `vaultwarden_config_disable_admin_token` is `false`.
Setting other configuration values for vaultwarden can be done using role-provided flattened keys in the
`vaultwarden_config_*` namespace (see [`defaults/main/config.yml`](defaults/main/config.yml) for available variables),
or by setting the configuration directly in the same structure as the `config.json` would be in `vaultwarden_config`.
### Email
Configure mailing by first enabling SMTP using `vaultwarden_config_enable_smtp: true`,
then configure your email server like this:
```yaml
vaultwarden_config:
smtp_host: "mail.example.com"
smtp_explicit_tls: true
smtp_port: 465
smtp_from: "noreply+vaultwarden@example.com"
smtp_from_name: "'Example.com Vaultwarden instance' <noreply+vaultwarden@example.com>"
smtp_username: vaultwarden@example.com
smtp_password: i_hope_i_will_be_a_strong_one!
helo_name: "{{ vaultwarden_config_domain }}"
```
### 2FA via email
To enable email-based two-factor-authentication, set `vaultwarden_config_enable_email_2fa: true`
and optionally set the following configuration:
```yaml
vaultwarden_config:
email_token_size: 8
email_expiration_time: 300 # 300 seconds = 5min
email_attempts_limit: 3
```
### Feature flags
To enable more authentication methods, toggles are provided in
[`vaultwarden_config_enable_*`](defaults/main/config.yml#L18).
It is genereally recommended to simply keep unused methods off.
Per default, 'Sends' are allowed.

View File

@ -0,0 +1,68 @@
---
# Required configuration
vaultwarden_config_domain: ~
vaultwarden_config_admin_token: ~
# Invitations and signups
vaultwarden_config_invitations_allowed: false
vaultwarden_config_invitation_org_name: ~
vaultwarden_config_signups_allowed: false
vaultwarden_config_signups_verify: true
vaultwarden_config_signups_verify_resend_time: 3600
vaultwarden_config_signups_verify_resend_limit: 5
# Entry preview icons
vaultwarden_config_disable_icon_download: true
vaultwarden_config_icon_cache_ttl: 604800 # 7 days
vaultwarden_config_icon_cache_negttl: 259200 # 3 days
vaultwarden_config_icon_download_timeout: 30 # seconds
vaultwarden_config_icon_blacklist_non_global_ips: true
# Features
vaultwarden_config_sends_allowed: true
vaultwarden_config_enable_yubico: false
vaultwarden_config_enable_duo: false
vaultwarden_config_enable_smtp: false
vaultwarden_config_enable_email_2fa: false
# Security
vaultwarden_config_password_iterations: 100000
vaultwarden_config_show_password_hint: false
vaultwarden_config_disable_2fa_remember: false
vaultwarden_config_disable_admin_token: true
vaultwarden_config_require_device_email: false
vaultwarden_config_authenticator_disable_time_drift: true
# Other
vaultwarden_config_log_timestamp_format: "%Y-%m-%d %H:%M:%S.%3f"
vaultwarden_config_ip_header: "X-Real-IP"
vaultwarden_config_reload_templates: false
vaultwarden_base_config:
domain: "{{ vaultwarden_config_domain }}"
admin_token: "{{ vaultwarden_config_admin_token }}"
invitations_allowed: "{{ vaultwarden_config_invitations_allowed }}"
invitation_org_name: "{{ vaultwarden_config_invitation_org_name | default('', true) }}"
signups_allowed: "{{ vaultwarden_config_signups_allowed }}"
signups_verify: "{{ vaultwarden_config_signups_verify }}"
signups_verify_resend_time: "{{ vaultwarden_config_signups_verify_resend_time }}"
signups_verify_resend_limit: "{{ vaultwarden_config_signups_verify_resend_limit }}"
disable_icon_download: "{{ vaultwarden_config_disable_icon_download }}"
icon_cache_ttl: "{{ vaultwarden_config_icon_cache_ttl }}"
icon_cache_negttl: "{{ vaultwarden_config_icon_cache_negttl }}"
icon_download_timeout: "{{ vaultwarden_config_icon_download_timeout }}"
icon_blacklist_non_global_ips: "{{ vaultwarden_config_icon_blacklist_non_global_ips }}"
password_iterations: "{{ vaultwarden_config_password_iterations }}"
show_password_hint: "{{ vaultwarden_config_show_password_hint }}"
disable_2fa_remember: "{{ vaultwarden_config_disable_2fa_remember }}"
disable_admin_token: "{{ vaultwarden_config_disable_admin_token }}"
require_device_email: "{{ vaultwarden_config_require_device_email }}"
authenticator_disable_time_drift: "{{ vaultwarden_config_authenticator_disable_time_drift }}"
ip_header: "{{ vaultwarden_config_ip_header }}"
log_timestamp_format: "{{ vaultwarden_config_log_timestamp_format }}"
reload_templates: "{{ vaultwarden_config_reload_templates }}"
sends_allowed: "{{ vaultwarden_config_sends_allowed }}"
_enable_yubico: "{{ vaultwarden_config_enable_yubico }}"
_enable_duo: "{{ vaultwarden_config_enable_duo }}"
_enable_smtp: "{{ vaultwarden_config_enable_smtp }}"
_enable_email_2fa: "{{ vaultwarden_config_enable_email_2fa }}"
vaultwarden_config: ~
vaultwarden_merged_config: >-2
{{ vaultwarden_base_config | default({}, true)
| combine(vaultwarden_config | default({}, true), recursive=true) }}

View File

@ -0,0 +1,50 @@
---
vaultwarden_container_image_registry: docker.io
vaultwarden_container_image_namespace: vaultwarden
vaultwarden_container_image_name: server
vaultwarden_container_image_tag: ~
vaultwarden_container_image_flavour: alpine
vaultwarden_container_image_source: pull
vaultwarden_container_image_force_source: >-2
{{ vaultwarden_container_image_tag | default(false, true) | bool }}
vaultwarden_container_image: >-2
{{
([
vaultwarden_container_image_registry | default([], true),
vaultwarden_container_image_namespace | default([], true),
vaultwarden_container_image_name,
] | flatten | join('/'))
+ ':'
+ (vaultwarden_container_image_tag | default(
vaultwarden_version + (
((vaultwarden_container_image_flavour is string)
and (vaultwarden_container_image_flavour | length > 0))
| ternary(
'-' + vaultwarden_container_image_flavour | default('', true),
''
)
),
true
))
}}
vaultwarden_container_name: vaultwarden
vaultwarden_container_env: ~
vaultwarden_container_user: >-2
{{ vaultwarden_run_user_id }}:{{ vaultwarden_run_group_id }}
vaultwarden_container_ports: ~
vaultwarden_container_labels: ~
vaultwarden_container_networks: ~
vaultwarden_container_etc_hosts: ~
vaultwarden_container_dns_servers: ~
vaultwarden_container_restart_policy: >-2
{{ (vaultwarden_deployment_method == 'docker') | ternary(
'unless-stopped',
'on-failure',
)
}}
vaultwarden_container_state: >-2
{{ (vaultwarden_state == 'present') | ternary('started', 'absent') }}
vaultwarden_container_volumes:
- "{{ vaultwarden_data_directory }}:/data:rw"
- "{{ vaultwarden_config_file }}:/data/config.json:ro"

View File

@ -0,0 +1,10 @@
---
vaultwarden_user: vaultwarden
vaultwarden_version: "1.32.2"
vaultwarden_config_file: "/etc/vaultwarden/config.json"
vaultwarden_config_directory: "{{ vaultwarden_config_file | dirname }}"
vaultwarden_data_directory: "/var/lib/vaultwarden"
vaultwarden_state: present
vaultwarden_deployment_method: docker

View File

@ -0,0 +1,5 @@
---
vaultwarden_run_user_id: >-2
{{ vaultwarden_user_info.uid | default(vaultwarden_user, true) }}
vaultwarden_run_group_id: >-2
{{ vaultwarden_user_info.group | default(vaultwarden_user, true) }}

View File

@ -0,0 +1,9 @@
---
- name: Ensure vaultwarden container '{{ vaultwarden_container_name }}' is restarted
community.docker.docker_container:
name: "{{ vaultwarden_container_name }}"
state: "{{ vaultwarden_container_state }}"
restart: true
listen: vaultwarden-restart
when: vaultwarden_deployment_method == 'docker'
ignore_errors: "{{ ansible_check_mode }}"

View File

@ -0,0 +1,12 @@
---
allow_duplicates: true
dependencies: []
galaxy_info:
role_name: vaultwarden
description: >-2
Deploy vaultwarden, a bitwarden-compatible server backend
galaxy_tags:
- vaultwarden
- bitwarden
- passwordstore
- docker

View File

@ -0,0 +1,22 @@
---
- name: Ensure container image '{{ vaultwarden_container_image }}' is {{ vaultwarden_state }}
community.docker.docker_image:
name: "{{ vaultwarden_container_image }}"
state: "{{ vaultwarden_state }}"
source: "{{ vaultwarden_container_image_source }}"
force_source: "{{ vaultwarden_container_image_force_source }}"
- name: Ensure container '{{ vaultwarden_container_name }}' is {{ vaultwarden_container_state }}
community.docker.docker_container:
name: "{{ vaultwarden_container_name }}"
image: "{{ vaultwarden_container_image }}"
env: "{{ vaultwarden_container_env | default(omit, true) }}"
user: "{{ vaultwarden_container_user | default(omit, true) }}"
ports: "{{ vaultwarden_container_ports | default(omit, true) }}"
labels: "{{ vaultwarden_container_labels | default(omit, true) }}"
volumes: "{{ vaultwarden_container_volumes }}"
networks: "{{ vaultwarden_container_networks | default(omit, true) }}"
etc_hosts: "{{ vaultwarden_container_etc_hosts | default(omit, true) }}"
dns_servers: "{{ vaultwarden_container_dns_servers | default(omit, true) }}"
restart_policy: "{{ vaultwarden_container_restart_policy | default(omit, true) }}"
state: "{{ vaultwarden_container_state | default(omit, true) }}"

View File

@ -0,0 +1,78 @@
---
- name: Ensure state is valid
ansible.builtin.fail:
msg: >-2
Unsupported state '{{ vaultwarden_state }}'!
Supported states are {{ vaultwarden_states | join(', ') }}.
when: vaultwarden_state not in vaultwarden_states
- name: Ensure deployment method is valid
ansible.builtin.fail:
msg: >-2
Unsupported deployment method '{{ vaultwarden_deployment_method }}'!
Supported are {{ vaultwarden_deployment_methods | join(', ') }}.
when: vaultwarden_deployment_method not in vaultwarden_deployment_methods
- name: Ensure required variables are given
ansible.builtin.fail:
msg: "Required variable '{{ var }}' is undefined!"
loop: "{{ vaultwarden_required_variables }}"
loop_control:
loop_var: var
when: >-2
var not in hostvars[inventory_hostname]
or hostvars[inventory_hostname][var] | length == 0
- name: Ensure required variables are given
ansible.builtin.fail:
msg: "Required variable '{{ var.name }}' is undefined!"
loop: "{{ vaultwarden_conditionally_required_variables }}"
loop_control:
loop_var: var
label: "{{ var.name }}"
when: >-2
var.when and (
var.name not in hostvars[inventory_hostname]
or hostvars[inventory_hostname][var.name] | length == 0)
- name: Ensure vaultwarden user '{{ vaultwarden_user }}' is {{ vaultwarden_state }}
ansible.builtin.user:
name: "{{ vaultwarden_user }}"
state: "{{ vaultwarden_state }}"
system: "{{ vaultwarden_user_system | default(true, true) }}"
create_home: "{{ vaultwarden_user_create_home | default(false, true) }}"
groups: "{{ vaultwarden_user_groups | default(omit, true) }}"
append: >-2
{{ vaultwarden_user_append_groups | default(
(vaultwarden_user_groups | default([], true) | length > 0),
true,
) }}
register: vaultwarden_user_info
- name: Ensure base paths are {{ vaultwarden_state }}
ansible.builtin.file:
path: "{{ mount.path }}"
state: "{{ (vaultwarden_state == 'present') | ternary('directory', 'absent') }}"
owner: "{{ mount.owner | default(vaultwarden_run_user_id) }}"
group: "{{ mount.group | default(vaultwarden_run_group_id) }}"
mode: "{{ mount.mode | default('0755', true) }}"
loop:
- path: "{{ vaultwarden_config_directory }}"
- path: "{{ vaultwarden_data_directory }}"
loop_control:
loop_var: mount
label: "{{ mount.path }}"
- name: Ensure vaultwarden config file '{{ vaultwarden_config_file }}' is {{ vaultwarden_state }}
ansible.builtin.copy:
content: "{{ vaultwarden_merged_config | to_nice_json(indent=4) }}"
dest: "{{ vaultwarden_config_file }}"
owner: "{{ vaultwarden_run_user_id }}"
group: "{{ vaultwarden_run_group_id }}"
mode: "0640"
when: vaultwarden_state == 'present'
notify: vaultwarden-restart
- name: Deploy vaultwarden using {{ vaultwarden_deployment_method }}
ansible.builtin.include_tasks:
file: "deploy-{{ vaultwarden_deployment_method }}.yml"

View File

@ -0,0 +1,11 @@
---
vaultwarden_states:
- present
- absent
vaultwarden_deployment_methods:
- docker
vaultwarden_required_variables:
- vaultwarden_config_domain
vaultwarden_conditionally_required_variables:
- name: vaultwarden_config_admin_token
when: "{{ vaultwarden_config_disable_admin_token | default(true, true) | bool }}"

View File

@ -1,7 +1,7 @@
--- ---
vouch_proxy_user: vouch-proxy vouch_proxy_user: vouch-proxy
vouch_proxy_version: 0.39.0 vouch_proxy_version: 0.40.0
vouch_proxy_base_path: /opt/vouch-proxy vouch_proxy_base_path: /opt/vouch-proxy
vouch_proxy_config_path: "{{ vouch_proxy_base_path }}/config" vouch_proxy_config_path: "{{ vouch_proxy_base_path }}/config"
vouch_proxy_config_file: "{{ vouch_proxy_config_path }}/config.yaml" vouch_proxy_config_file: "{{ vouch_proxy_config_path }}/config.yaml"

View File

@ -0,0 +1,12 @@
---
allow_duplicates: true
dependencies: []
galaxy_info:
role_name: vouch_proxy
description: Ansible role to deploy vouch_proxy using docker
galaxy_tags:
- vouch_proxy
- oidc
- authentication
- authorization
- docker