69 Commits

Author SHA1 Message Date
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
98be926e89 chore: add ansible collection metadata 2023-07-19 19:14:47 +02:00
0fc751f7d6 chore(nginx): add README 2023-07-19 19:10:16 +02:00
271410f4c6 update(jellyfin): bump version to 10.8.10 2023-07-19 19:09:56 +02:00
e17369ae38 chore(jellyfin): add README 2023-07-19 19:08:36 +02:00
a3c2716b7f chore(ghost): add README 2023-07-19 19:08:10 +02:00
c8802b9dbf chore(vouch-proxy)!: rename role to vouch_proxy 2023-07-19 19:07:44 +02:00
4ef456efdf chore: update metadata 2023-07-17 21:05:05 +02:00
cd31d8b6af feat(nginx): add ansible role 2023-07-16 19:01:55 +02:00
20cb480915 feat(vouch-proxy): add ansible role for vouch-proxy 2023-07-16 18:58:33 +02:00
e1756fd4b0 update(authelia): bump version to 4.37.5 2023-07-14 12:15:16 +02:00
1e12c0fcfd update(gitea): bump version to 1.19.4 2023-07-14 12:07:25 +02:00
f368107966 update(gitea): bump version to 1.18.3 2023-02-09 21:09:49 +01:00
0aa621b510 feat(ghost): add role for deployment using docker 2023-02-06 21:22:21 +01:00
0c509f6b66 update(jellyfin): bump version to 10.8.6 2022-10-31 10:56:25 +01:00
a364a58717 update(elasticsearch): bump version to 7.17.7 2022-10-31 10:55:14 +01:00
ccd50cb8cf update(gitea): bump version to 1.17.3 2022-10-31 10:53:59 +01:00
1fe626fad5 feat(elasticsearch): add role for single-node deployment using docker containers 2022-08-26 09:00:02 +02:00
d4858c89f4 feat(authelia): allow customizing authelia by mapping the asset folder from the host 2022-08-26 08:48:36 +02:00
6658d7226c fix(authelia): notifier.smtp.startup_check_address changed from bool to email address 2022-08-11 16:52:52 +02:00
53 changed files with 831 additions and 449 deletions

View File

@ -8,20 +8,26 @@ concise area of concern.
## 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.
- [`roles/gitea`](roles/gitea/README.md): Deploy [gitea.io](https://gitea.io), a
- [`ghost`](roles/ghost/README.md): Deploys [ghost.org](https://ghost.org/), a simple to use
blogging and publishing platform.
- [`gitea`](roles/gitea/README.md): Deploy [gitea.io](https://gitea.io), a
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.
- [`roles/restic`](roles/restic/README.md): Manage backups using restic
and persist them to a configurable backend.
- [`openproject`](roles/openproject/README.md): Deploys an [openproject.org](https://www.openproject.org)
installation using the upstream provided docker-compose setup.
- [`roles/minio`](roles/minio/README.md): Deploy [min.io](https://min.io), an
s3-compatible object storage server, using docker containers.
- [`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

View File

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

3
meta/runtime.yml Normal file
View File

@ -0,0 +1,3 @@
---
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

@ -1,6 +1,5 @@
---
authelia_version: 4.36.4
authelia_version: "4.38.16"
authelia_user: authelia
authelia_base_dir: /opt/authelia
authelia_domain: authelia.example.org
@ -8,14 +7,26 @@ authelia_domain: authelia.example.org
authelia_config_dir: "{{ authelia_base_dir }}/config"
authelia_config_file: "{{ authelia_config_dir }}/config.yaml"
authelia_data_dir: "{{ authelia_base_dir }}/data"
authelia_asset_dir: "{{ authelia_base_dir }}/assets"
authelia_sqlite_storage_file: "{{ authelia_data_dir }}/authelia.sqlite3"
authelia_notification_storage_file: "{{ authelia_data_dir }}/notifications.txt"
authelia_user_storage_file: "{{ authelia_data_dir }}/user_database.yml"
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_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_env:
PUID: "{{ authelia_run_user }}"
@ -41,11 +52,22 @@ authelia_config_jwt_secret: ~
authelia_config_default_redirection_url: ~
authelia_config_server_host: 0.0.0.0
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_read_buffer_size: 4096
authelia_config_server_write_buffer_size: 4096
authelia_config_server_enable_pprof: true
authelia_config_server_enable_expvars: true
authelia_config_server_asset_path: "/config/assets/"
authelia_config_server_buffers_read: 4096
authelia_config_server_read_buffer_size: >-2
{{ authelia_config_server_buffers_read }}
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_tls_key: ~
authelia_config_server_tls_certificate: ~
@ -92,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_additional_groups_dn: "ou=groups"
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_username_attribute: uid
authelia_config_authentication_backend_ldap_mail_attribute: mail
authelia_config_authentication_backend_ldap_display_name_attribute: displayName
authelia_config_authentication_backend_ldap_attributes_group_name: >-2
{{ authelia_config_authentication_backend_ldap_group_name_attribute }}
authelia_config_authentication_backend_ldap_user: ~
authelia_config_authentication_backend_ldap_password: ~
authelia_config_authentication_backend_file_path: ~
@ -123,6 +153,8 @@ authelia_config_session_secret: ~
authelia_config_session_expiration: 1h
authelia_config_session_inactivity: 5m
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_port: "{{ authelia_redis_port }}"
authelia_config_session_redis_username: "{{ authelia_redis_user }}"
@ -147,15 +179,14 @@ authelia_config_storage_postgres_ssl_certificate: disable
authelia_config_storage_postgres_ssl_key: disable
authelia_config_notifier_disable_startup_check: false
authelia_config_notifier_filesystem_filename: ~
authelia_config_notifier_smtp_host: "{{ authelia_smtp_host }}"
authelia_config_notifier_smtp_port: "{{ authelia_stmp_port }}"
authelia_config_notifier_smtp_address: "{{ authelia_smtp_host }}:{{ authelia_stmp_port }}"
authelia_config_notifier_smtp_username: "{{ authelia_smtp_user }}"
authelia_config_notifier_smtp_password: "{{ authelia_smtp_pass }}"
authelia_config_notifier_smtp_timeout: 5s
authelia_config_notifier_smtp_sender: "Authelia on {{ authelia_domain }} <admin@{{ authelia_domain }}>"
authelia_config_notifier_smtp_identifier: "{{ authelia_domain }}"
authelia_config_notifier_smtp_subject: "[Authelia @ {{ authelia_domain }}] {title}"
authelia_config_notifier_smtp_startup_check_address: false
authelia_config_notifier_smtp_startup_check_address: "authelia-test@{{ authelia_domain }}"
authelia_config_notifier_smtp_disable_require_tls: false
authelia_config_notifier_smtp_disable_html_emails: false
authelia_config_notifier_smtp_tls_skip_verify: false
@ -164,6 +195,12 @@ authelia_config_notifier_smtp_tls_minimum_version: "{{ authelia_tls_minimum_vers
authelia_database_type: ~
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_pass: ~
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,19 +1,20 @@
---
- name: Ensure user {{ authelia_user }} exists
user:
ansible.builtin.user:
name: "{{ authelia_user }}"
state: present
system: true
register: authelia_user_info
- name: Ensure host directories are created with correct permissions
file:
ansible.builtin.file:
path: "{{ item.path }}"
state: directory
owner: "{{ item.owner | default(authelia_user) }}"
group: "{{ item.group | default(authelia_user) }}"
mode: "{{ item.mode | default('0750') }}"
when: item.path | default(false, true) | bool
loop:
- path: "{{ authelia_base_dir }}"
mode: "0755"
@ -21,9 +22,11 @@
mode: "0750"
- path: "{{ authelia_data_dir }}"
mode: "0750"
- path: "{{ authelia_asset_dir }}"
mode: "0750"
- name: Ensure config file is generated
copy:
ansible.builtin.copy:
content: "{{ authelia_config | to_nice_yaml(indent=2, width=10000) }}"
dest: "{{ authelia_config_file }}"
owner: "{{ authelia_run_user }}"
@ -32,7 +35,7 @@
notify: restart-authelia
- name: Ensure sqlite database file exists before mounting it
file:
ansible.builtin.file:
path: "{{ authelia_sqlite_storage_file }}"
state: touch
owner: "{{ authelia_run_user }}"
@ -43,7 +46,7 @@
when: authelia_config_storage_local_path | default(false, true)
- name: Ensure user database exists before mounting it
file:
ansible.builtin.file:
path: "{{ authelia_user_storage_file }}"
state: touch
owner: "{{ authelia_run_user }}"
@ -54,7 +57,7 @@
when: authelia_config_authentication_backend_file_path | default(false, true)
- name: Ensure notification reports file exists before mounting it
file:
ansible.builtin.file:
path: "{{ authelia_notification_storage_file }}"
state: touch
owner: "{{ authelia_run_user }}"
@ -73,7 +76,7 @@
register: authelia_container_image_info
- name: Ensure authelia container is running
docker_container:
community.docker.docker_container:
name: "{{ authelia_container_name }}"
image: "{{ authelia_container_image_ref }}"
env: "{{ authelia_container_env }}"
@ -82,7 +85,9 @@
labels: "{{ authelia_container_labels }}"
volumes: "{{ authelia_container_volumes }}"
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)}}"
restart_policy: "{{ authelia_container_restart_policy }}"
recreate: "{{ authelia_container_recreate | default(omit, true) }}"
state: "{{ authelia_container_state }}"
register: authelia_container_info

View File

@ -5,6 +5,7 @@ authelia_run_group: "{{ (authelia_user_info.group) if authelia_user_info is defi
authelia_container_base_volumes: >-2
{{ [ authelia_config_file + ":/config/configuration.yml:ro"]
+ ([authelia_asset_dir + '/:' + authelia_config_server_asset_path + ':ro'] if authelia_asset_dir | default(false, true) else [])
+ ([ authelia_sqlite_storage_file + ":" + authelia_config_storage_local_path + ":z" ]
if authelia_config_storage_local_path | default(false, true) else [])
+ ([ authelia_notification_storage_file + ":" + authelia_config_notifier_filesystem_filename + ":z" ]
@ -47,17 +48,20 @@ authelia_base_config: >-2
authelia_config_server: >-2
{{
{
"host": authelia_config_server_host,
"port": authelia_config_server_port,
"path": authelia_config_server_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,
"address": authelia_config_server_address,
"asset_path": authelia_config_server_asset_path,
"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}}
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:
key: "{{ authelia_config_server_tls_key }}"
certificate: "{{ authelia_config_server_tls_certificate }}"
@ -130,10 +134,11 @@ authelia_config_authentication_backend_ldap:
additional_groups_dn: "{{ authelia_config_authentication_backend_ldap_additional_groups_dn }}"
users_filter: "{{ authelia_config_authentication_backend_ldap_users_filter }}"
groups_filter: "{{ authelia_config_authentication_backend_ldap_groups_filter }}"
group_name_attribute: "{{ authelia_config_authentication_backend_ldap_group_name_attribute }}"
username_attribute: "{{ authelia_config_authentication_backend_ldap_username_attribute }}"
mail_attribute: "{{ authelia_config_authentication_backend_ldap_mail_attribute }}"
display_name_attribute: "{{ authelia_config_authentication_backend_ldap_display_name_attribute }}"
attributes:
username: "{{ authelia_config_authentication_backend_ldap_attributes_username }}"
mail: "{{ authelia_config_authentication_backend_ldap_attributes_mail }}"
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 }}"
password: "{{ authelia_config_authentication_backend_ldap_password }}"
authelia_config_authentication_backend_file:
@ -172,7 +177,7 @@ authelia_config_session:
secret: "{{ authelia_config_session_secret }}"
expiration: "{{ authelia_config_session_expiration }}"
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
{{
{
@ -216,15 +221,13 @@ authelia_config_storage: >-2
authelia_config_storage_local:
path: "{{ authelia_config_storage_local_path }}"
authelia_config_storage_mysql:
host: "{{ authelia_database_host }}"
port: "{{ authelia_config_storage_mysql_port }}"
host: "{{ authelia_database_address }}"
database: "{{ authelia_database_name }}"
username: "{{ authelia_database_user }}"
password: "{{ authelia_database_pass }}"
timeout: "{{ authelia_database_timeout }}"
authelia_config_storage_postgres:
host: "{{ authelia_database_host }}"
port: "{{ authelia_config_storage_postgres_port }}"
address: "{{ authelia_database_address }}"
database: "{{ authelia_database_name }}"
schema: public
username: "{{ authelia_database_user }}"
@ -248,8 +251,7 @@ authelia_config_notifier: >-2
authelia_config_notifier_filesystem:
filename: "{{ authelia_config_notifier_filesystem_filename }}"
authelia_config_notifier_smtp:
host: "{{ authelia_config_notifier_smtp_host }}"
port: "{{ authelia_config_notifier_smtp_port }}"
address: "{{ authelia_config_notifier_smtp_address }}"
timeout: "{{ authelia_config_notifier_smtp_timeout }}"
username: "{{ authelia_config_notifier_smtp_username }}"
password: "{{ authelia_config_notifier_smtp_password }}"

18
roles/ghost/README.md Normal file
View File

@ -0,0 +1,18 @@
# `finallycoffee.services.ghost` ansible role
[Ghost](https://ghost.org/) is a self-hosted blog with rich media capabilities,
which this role deploys in a docker container.
## Requirements
Ghost requires a MySQL-database (like mariadb) for storing it's data, which
can be configured using the `ghost_database_(host|username|password|database)` variables.
Setting `ghost_domain` to a fully-qualified domain on which ghost should be reachable
is also required.
Ghosts configuration can be changed using the `ghost_config` variable.
Container arguments which are equivalent to `community.docker.docker_container` can be
provided in the `ghost_container_[...]` syntax (e.g. `ghost_container_ports` to expose
ghosts port to the host).

View File

@ -0,0 +1,38 @@
---
ghost_domain: ~
ghost_version: "5.96.0"
ghost_user: ghost
ghost_user_group: ghost
ghost_base_path: /opt/ghost
ghost_data_path: "{{ ghost_base_path }}/data"
ghost_config_path: "{{ ghost_base_path }}/config"
ghost_config_file: "{{ ghost_config_path }}/ghost.env"
ghost_database_username: ghost
ghost_database_password: ~
ghost_database_database: ghost
ghost_database_host: ~
ghost_base_config:
url: "https://{{ ghost_domain }}"
database__client: mysql
database__connection__host: "{{ ghost_database_host }}"
database__connection__user: "{{ ghost_database_username }}"
database__connection__password: "{{ ghost_database_password }}"
database__connection__database: "{{ ghost_database_database }}"
ghost_config: {}
ghost_container_name: ghost
ghost_container_image_name: docker.io/ghost
ghost_container_image_tag: ~
ghost_container_base_volumes:
- "{{ ghost_data_path }}:{{ ghost_container_data_directory }}:rw"
ghost_container_extra_volumes: []
ghost_container_volumes:
"{{ ghost_container_base_volumes + ghost_container_extra_volumes }}"
ghost_container_base_labels:
version: "{{ ghost_version }}"
ghost_container_extra_labels: {}
ghost_container_restart_policy: "unless-stopped"
ghost_container_networks: ~
ghost_container_purge_networks: ~
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

@ -0,0 +1,57 @@
---
- name: Ensure ghost group is created
ansible.builtin.group:
name: "{{ ghost_user_group }}"
state: present
system: true
- name: Ensure ghost user is created
ansible.builtin.user:
name: "{{ ghost_user }}"
groups:
- "{{ ghost_user_group }}"
append: true
state: present
system: true
- name: Ensure host paths for docker volumes exist for ghost
ansible.builtin.file:
path: "{{ item.path }}"
state: directory
mode: "0750"
owner: "{{ item.owner | default(ghost_user) }}"
group: "{{ item.group | default(ghost_user_group) }}"
loop:
- path: "{{ ghost_base_path }}"
- path: "{{ ghost_data_path }}"
owner: "1000"
- path: "{{ ghost_config_path }}"
- name: Ensure ghost configuration file is templated
ansible.builtin.template:
src: "ghost.env.j2"
dest: "{{ ghost_config_file }}"
owner: "{{ ghost_user }}"
group: "{{ ghost_user_group }}"
mode: "0644"
- name: Ensure ghost container image is present on host
community.docker.docker_image:
name: "{{ ghost_container_image }}"
state: present
source: pull
force_source: "{{ ghost_container_image_tag is defined }}"
- name: Ensure ghost container '{{ ghost_container_name }}' is {{ ghost_container_state }}
community.docker.docker_container:
name: "{{ ghost_container_name }}"
image: "{{ ghost_container_image }}"
ports: "{{ ghost_container_ports | default(omit, true) }}"
labels: "{{ ghost_container_labels }}"
volumes: "{{ ghost_container_volumes }}"
env_file: "{{ ghost_config_file }}"
etc_hosts: "{{ ghost_container_etc_hosts | default(omit, true) }}"
networks: "{{ ghost_container_networks | default(omit, true) }}"
purge_networks: "{{ ghost_container_purge_networks | default(omit, true) }}"
restart_policy: "{{ ghost_container_restart_policy }}"
state: "{{ ghost_container_state }}"

View File

@ -0,0 +1,3 @@
{% for key, value in ghost_config_complete.items() %}
{{ key }}={{ value }}
{% endfor %}

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

@ -0,0 +1,10 @@
---
ghost_container_image: "{{ ghost_container_image_name}}:{{ ghost_container_image_tag | default(ghost_version, true) }}"
ghost_container_labels: >-2
{{ ghost_container_base_labels
| combine(ghost_container_extra_labels) }}
ghost_container_data_directory: "/var/lib/ghost/content"
ghost_config_complete: >-2
{{ ghost_base_config | combine(ghost_config, recursive=True) }}

View File

@ -1,7 +1,7 @@
---
gitea_version: "1.17.0"
gitea_version: "1.22.3"
gitea_user: git
gitea_run_user: "{{ gitea_user }}"
gitea_base_path: "/opt/gitea"
gitea_data_path: "{{ gitea_base_path }}/data"
@ -9,17 +9,29 @@ gitea_data_path: "{{ gitea_base_path }}/data"
gitea_domain: ~
# container config
gitea_container_name: "git"
gitea_container_image_name: "docker.io/gitea/gitea"
gitea_container_name: "{{ gitea_user }}"
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: "{{ 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_purge_networks: ~
gitea_container_restart_policy: "unless-stopped"
gitea_container_extra_env: {}
gitea_contianer_extra_labels: {}
gitea_container_extra_labels: {}
gitea_container_extra_ports: []
gitea_container_extra_volumes: []
gitea_container_state: started
# container defaults
gitea_container_base_volumes:
@ -40,10 +52,10 @@ gitea_container_base_labels:
gitea_config_mailer_enabled: false
gitea_config_mailer_type: ~
gitea_config_mailer_from_addr: ~
gitea_config_mailer_host: ~
gitea_config_mailer_smtp_addr: ~
gitea_config_mailer_user: ~
gitea_config_mailer_passwd: ~
gitea_config_mailer_tls: ~
gitea_config_mailer_protocol: ~
gitea_config_mailer_sendmail_path: ~
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
user:
- name: Ensure gitea user '{{ gitea_user }}' is present
ansible.builtin.user:
name: "{{ gitea_user }}"
state: present
system: no
state: "present"
system: false
create_home: true
register: gitea_user_res
- name: Ensure host directories exist
file:
ansible.builtin.file:
path: "{{ item }}"
owner: "{{ gitea_user_res.uid }}"
group: "{{ gitea_user_res.group }}"
@ -18,7 +19,7 @@
- "{{ gitea_data_path }}"
- name: Ensure .ssh folder for gitea user exists
file:
ansible.builtin.file:
path: "/home/{{ gitea_user }}/.ssh"
state: directory
owner: "{{ gitea_user_res.uid }}"
@ -37,16 +38,16 @@
register: gitea_user_ssh_key
- name: Create forwarding script
copy:
ansible.builtin.copy:
dest: "/usr/local/bin/gitea"
owner: "{{ gitea_user_res.uid }}"
group: "{{ gitea_user_res.group }}"
mode: 0700
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
lineinfile:
ansible.builtin.lineinfile:
path: "/home/{{ gitea_user }}/.ssh/authorized_keys"
line: "{{ gitea_user_ssh_key.public_key }} Gitea:Host2Container"
state: present
@ -56,26 +57,27 @@
mode: 0600
- name: Ensure gitea container image is present
docker_image:
community.docker.docker_image:
name: "{{ gitea_container_image }}"
state: present
source: pull
force_source: "{{ gitea_container_image.endswith(':latest') }}"
- name: Ensure container '{{ gitea_container_name }}' with gitea is running
docker_container:
- name: Ensure container '{{ gitea_container_name }}' with gitea is {{ gitea_container_state }}
community.docker.docker_container:
name: "{{ gitea_container_name }}"
image: "{{ gitea_container_image }}"
env: "{{ gitea_container_env }}"
labels: "{{ gitea_container_labels }}"
volumes: "{{ gitea_container_volumes }}"
networks: "{{ gitea_container_networks | default(omit, True) }}"
purge_networks: "{{ gitea_container_purge_networks | default(omit, True) }}"
published_ports: "{{ gitea_container_ports }}"
restart_policy: "{{ gitea_container_restart_policy }}"
state: started
state: "{{ gitea_container_state }}"
- name: Ensure given configuration is set in the config file
ini_file:
ansible.builtin.ini_file:
path: "{{ gitea_data_path }}/gitea/conf/app.ini"
section: "{{ section }}"
option: "{{ option }}"

View File

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

15
roles/jellyfin/README.md Normal file
View File

@ -0,0 +1,15 @@
# `finallycoffee.services.jellyfin` ansible role
This role runs [Jellyfin](https://jellyfin.org/), a free software media system,
in a docker container.
## Usage
`jellyfin_domain` contains the FQDN which jellyfin should listen to. Most configuration
is done in the software itself.
Jellyfin runs in host networking mode by default, as that is needed for some features like
network discovery with chromecasts and similar.
Media can be mounted into jellyfin using `jellyfin_media_volumes`, taking a list of strings
akin to `community.docker.docker_container`'s `volumes` key.

View File

@ -1,7 +1,7 @@
---
jellyfin_user: jellyfin
jellyfin_version: 10.8.1
jellyfin_version: 10.9.11
jellyfin_state: present
jellyfin_base_path: /opt/jellyfin
jellyfin_config_path: "{{ jellyfin_base_path }}/config"
@ -12,7 +12,11 @@ jellyfin_media_volumes: []
jellyfin_container_name: jellyfin
jellyfin_container_image_name: "docker.io/jellyfin/jellyfin"
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_networks: ~
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
user:
- name: Ensure jellyfin user '{{ jellyfin_user }}' is {{ jellyfin_state }}
ansible.builtin.user:
name: "{{ jellyfin_user }}"
state: present
system: yes
state: "{{ jellyfin_state }}"
system: "{{ jellyfin_user_system | default(true, true) }}"
register: jellyfin_user_info
- name: Ensure host directories for jellyfin exist
file:
- name: Ensure host directories for jellyfin are {{ jellyfin_state }}
ansible.builtin.file:
path: "{{ item.path }}"
state: directory
state: >-2
{{ (jellyfin_state == 'present') | ternary('directory', 'absent') }}
owner: "{{ item.owner | default(jellyfin_uid) }}"
group: "{{ item.group | default(jellyfin_gid) }}"
mode: "{{ item.mode }}"
loop: "{{ jellyfin_host_directories }}"
- name: Ensure container image for jellyfin is available
docker_image:
- name: Ensure container image '{{ jellyfin_container_image_ref }}' is {{ jellyfin_state }}
community.docker.docker_image:
name: "{{ jellyfin_container_image_ref }}"
state: present
source: pull
state: "{{ jellyfin_state }}"
source: "{{ jellyfin_container_image_source }}"
force_source: "{{ jellyfin_container_image_tag | default(false, true) }}"
register: jellyfin_container_image_pull_result
until: jellyfin_container_image_pull_result is succeeded
retries: 5
delay: 3
- name: Ensure container '{{ jellyfin_container_name }}' is running
docker_container:
- name: Ensure container '{{ jellyfin_container_name }}' is {{ jellyfin_container_state }}
community.docker.docker_container:
name: "{{ jellyfin_container_name }}"
image: "{{ jellyfin_container_image_ref }}"
user: "{{ jellyfin_uid }}:{{ jellyfin_gid }}"
@ -37,4 +44,4 @@
networks: "{{ jellyfin_container_networks | default(omit, True) }}"
network_mode: "{{ jellyfin_container_network_mode }}"
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_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

@ -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,16 @@
# `finallycoffee.services.vouch-proxy`
[Vouch-Proxy](https://github.com/vouch/vouch-proxy) can be used in combination with
nginx' `auth_request` module to secure web services with OIDC/OAuth. This role runs
vouch-proxys' official docker container.
## Usage
The `oauth` config section must be supplied in `vouch_proxy_oauth_config`, and the
`vouch` config section can be overridden in `vouch_proxy_vouch_config`. For possible
configuration values, see https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example.
For an example nginx config, see https://github.com/vouch/vouch-proxy#installation-and-configuration.
Passing container arguments in the same way as `community.docker.docker_container` is supported
using the `vouch_proxy_container_[...]` prefix (e.g. `vouch_proxy_container_ports`).

View File

@ -0,0 +1,51 @@
---
vouch_proxy_user: vouch-proxy
vouch_proxy_version: 0.40.0
vouch_proxy_base_path: /opt/vouch-proxy
vouch_proxy_config_path: "{{ vouch_proxy_base_path }}/config"
vouch_proxy_config_file: "{{ vouch_proxy_config_path }}/config.yaml"
vouch_proxy_container_name: vouch-proxy
vouch_proxy_container_image_name: vouch-proxy
vouch_proxy_container_image_namespace: vouch/
vouch_proxy_container_image_registry: quay.io
vouch_proxy_container_image_repository: >-
{{
(container_registries[vouch_proxy_container_image_registry] | default(vouch_proxy_container_image_registry))
+ '/' + (vouch_proxy_container_image_namespace | default(''))
+ vouch_proxy_container_image_name
}}
vouch_proxy_container_image_reference: >-
{{
vouch_proxy_container_image_repository + ':'
+ (vouch_proxy_container_image_tag | default(vouch_proxy_version))
}}
vouch_proxy_container_image_force_pull: "{{ vouch_proxy_container_image_tag is defined }}"
vouch_proxy_container_default_volumes:
- "{{ vouch_proxy_config_file }}:/config/config.yaml:ro"
vouch_proxy_container_volumes: >-
{{ vouch_proxy_container_default_volumes
+ vouch_proxy_container_extra_volumes | default([]) }}
vouch_proxy_container_restart_policy: "unless-stopped"
vouch_proxy_config_vouch_log_level: info
vouch_proxy_config_vouch_listen: 0.0.0.0
vouch_proxy_config_vouch_port: 9090
vouch_proxy_config_vouch_domains: []
vouch_proxy_config_vouch_document_root: ~
vouch_proxy_oauth_config: {}
vouch_proxy_vouch_config:
logLevel: "{{ vouch_proxy_config_vouch_log_level }}"
listen: "{{ vouch_proxy_config_vouch_listen }}"
port: "{{ vouch_proxy_config_vouch_port }}"
domains: "{{ vouch_proxy_config_vouch_domains }}"
document_root: "{{ vouch_proxy_config_vouch_document_root }}"
vouch_proxy_config:
vouch: "{{ vouch_proxy_vouch_config }}"
oauth: "{{ vouch_proxy_oauth_config }}"

View File

@ -0,0 +1,8 @@
---
- name: Ensure vouch-proxy was restarted
community.docker.docker_container:
name: "{{ vouch_proxy_container_name }}"
state: started
restart: yes
listen: restart-vouch-proxy

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

View File

@ -0,0 +1,50 @@
---
- name: Ensure vouch-proxy user '{{ vouch_proxy_user }}' exists
ansible.builtin.user:
name: "{{ vouch_proxy_user }}"
state: present
system: true
register: vouch_proxy_user_info
- name: Ensure mounts are created
ansible.builtin.file:
dest: "{{ item.path }}"
state: directory
owner: "{{ item.owner | default(vouch_proxy_user_info.uid | default(vouch_proxy_user)) }}"
group: "{{ item.owner | default(vouch_proxy_user_info.group | default(vouch_proxy_user)) }}"
mode: "{{ item.mode | default('0755') }}"
loop:
- path: "{{ vouch_proxy_base_path }}"
- path: "{{ vouch_proxy_config_path }}"
- name: Ensure config file is templated
ansible.builtin.copy:
dest: "{{ vouch_proxy_config_file }}"
content: "{{ vouch_proxy_config | to_nice_yaml }}"
owner: "{{ vouch_proxy_user_info.uid | default(vouch_proxy_user) }}"
group: "{{ vouch_proxy_user_info.group | default(vouch_proxy_user) }}"
mode: "0640"
notify:
- restart-vouch-proxy
- name: Ensure container image is present on host
community.docker.docker_image:
name: "{{ vouch_proxy_container_image_reference }}"
state: present
source: pull
force_source: "{{ vouch_proxy_container_image_force_pull | bool }}"
- name: Ensure container '{{ vouch_proxy_container_name }}' is running
community.docker.docker_container:
name: "{{ vouch_proxy_container_name }}"
image: "{{ vouch_proxy_container_image_reference }}"
env: "{{ vouch_proxy_container_env | default(omit) }}"
user: "{{ vouch_proxy_user_info.uid | default(vouch_proxy_user) }}"
ports: "{{ vouch_proxy_container_ports | default(omit) }}"
volumes: "{{ vouch_proxy_container_volumes | default(omit) }}"
networks: "{{ vouch_proxy_container_networks | default(omit) }}"
purge_networks: "{{ vouch_proxy_container_purge_networks | default(omit) }}"
etc_hosts: "{{ vouch_proxy_container_etc_hosts | default(omit) }}"
restart_policy: "{{ vouch_proxy_container_restart_policy }}"
state: started