From 989042f28a12a81d6b4e875e41a6eaca30067537 Mon Sep 17 00:00:00 2001 From: Julien Riou Date: Mon, 16 Feb 2026 09:19:09 +0100 Subject: [PATCH] Initial commit Signed-off-by: Julien Riou --- .forgejo/workflows/ansible-ci.yml | 35 ++ README.md | 4 +- roles/certbot/README.md | 45 +++ roles/certbot/meta/argument_specs.yml | 18 + roles/certbot/tasks/main.yml | 17 + roles/coller/README.md | 159 +++++++++ roles/coller/defaults/main.yml | 52 +++ roles/coller/handlers/main.yml | 4 + roles/coller/meta/argument_specs.yml | 52 +++ roles/coller/meta/main.yml | 3 + roles/coller/tasks/main.yml | 55 +++ roles/coller/tasks/manage-iptables.yml | 16 + roles/coller/templates/db.env.j2 | 6 + roles/coller/templates/docker-compose.yml.j2 | 32 ++ roles/firefly/README.md | 39 +++ roles/firefly/defaults/main.yml | 14 + roles/firefly/handlers/main.yml | 4 + roles/firefly/meta/main.yml | 3 + roles/firefly/tasks/main.yml | 40 +++ roles/firefly/templates/app.env.j2 | 132 +++++++ roles/firefly/templates/db.env.j2 | 5 + roles/firefly/templates/docker-compose.yml.j2 | 40 +++ roles/forgejo/README.md | 321 ++++++++++++++++++ roles/forgejo/TODO.txt | 1 + roles/forgejo/defaults/main.yml | 120 +++++++ roles/forgejo/handlers/main.yml | 17 + roles/forgejo/meta/argument_specs.yml | 84 +++++ roles/forgejo/meta/main.yml | 18 + roles/forgejo/tasks/deploy-runners.yml | 20 ++ roles/forgejo/tasks/deploy-server.yml | 61 ++++ roles/forgejo/tasks/main.yml | 21 ++ roles/forgejo/tasks/register-runner.yml | 39 +++ roles/forgejo/templates/db.env.j2 | 6 + roles/forgejo/templates/docker-compose.yml.j2 | 35 ++ roles/forgejo/templates/runners/config.yml.j2 | 44 +++ .../templates/runners/docker-compose.yml.j2 | 27 ++ roles/forgejo/templates/server.env.j2 | 19 ++ roles/forgejo_runners/README.md | 321 ++++++++++++++++++ roles/forgejo_runners/TODO.txt | 1 + roles/forgejo_runners/defaults/main.yml | 120 +++++++ roles/forgejo_runners/handlers/main.yml | 17 + roles/forgejo_runners/meta/argument_specs.yml | 30 ++ roles/forgejo_runners/meta/main.yml | 18 + .../forgejo_runners/tasks/deploy-runners.yml | 20 ++ roles/forgejo_runners/tasks/deploy-server.yml | 61 ++++ roles/forgejo_runners/tasks/main.yml | 21 ++ .../forgejo_runners/tasks/register-runner.yml | 39 +++ roles/forgejo_runners/templates/db.env.j2 | 6 + .../templates/docker-compose.yml.j2 | 35 ++ .../templates/runners/config.yml.j2 | 44 +++ .../templates/runners/docker-compose.yml.j2 | 27 ++ roles/forgejo_runners/templates/server.env.j2 | 19 ++ roles/galene/defaults/main.yml | 24 ++ roles/galene/handlers/main.yml | 9 + roles/galene/meta/main.yml | 3 + roles/galene/tasks/main.yml | 116 +++++++ roles/galene/templates/galene.service.j2 | 19 ++ roles/golang/defaults/main.yml | 2 + roles/golang/tasks/main.yml | 7 + roles/navidrome/.gitignore | 1 + roles/navidrome/README.md | 35 ++ roles/navidrome/defaults/main.yml | 14 + roles/navidrome/handlers/main.yml | 14 + roles/navidrome/tasks/main.yml | 62 ++++ roles/navidrome/templates/navidrome.toml.j2 | 10 + roles/navidrome/templates/override.conf.j2 | 5 + 66 files changed, 2706 insertions(+), 2 deletions(-) create mode 100644 .forgejo/workflows/ansible-ci.yml create mode 100644 roles/certbot/README.md create mode 100644 roles/certbot/meta/argument_specs.yml create mode 100644 roles/certbot/tasks/main.yml create mode 100644 roles/coller/README.md create mode 100644 roles/coller/defaults/main.yml create mode 100644 roles/coller/handlers/main.yml create mode 100644 roles/coller/meta/argument_specs.yml create mode 100644 roles/coller/meta/main.yml create mode 100644 roles/coller/tasks/main.yml create mode 100644 roles/coller/tasks/manage-iptables.yml create mode 100644 roles/coller/templates/db.env.j2 create mode 100644 roles/coller/templates/docker-compose.yml.j2 create mode 100644 roles/firefly/README.md create mode 100644 roles/firefly/defaults/main.yml create mode 100644 roles/firefly/handlers/main.yml create mode 100644 roles/firefly/meta/main.yml create mode 100644 roles/firefly/tasks/main.yml create mode 100644 roles/firefly/templates/app.env.j2 create mode 100644 roles/firefly/templates/db.env.j2 create mode 100644 roles/firefly/templates/docker-compose.yml.j2 create mode 100644 roles/forgejo/README.md create mode 100644 roles/forgejo/TODO.txt create mode 100644 roles/forgejo/defaults/main.yml create mode 100644 roles/forgejo/handlers/main.yml create mode 100644 roles/forgejo/meta/argument_specs.yml create mode 100644 roles/forgejo/meta/main.yml create mode 100644 roles/forgejo/tasks/deploy-runners.yml create mode 100644 roles/forgejo/tasks/deploy-server.yml create mode 100644 roles/forgejo/tasks/main.yml create mode 100644 roles/forgejo/tasks/register-runner.yml create mode 100644 roles/forgejo/templates/db.env.j2 create mode 100644 roles/forgejo/templates/docker-compose.yml.j2 create mode 100644 roles/forgejo/templates/runners/config.yml.j2 create mode 100644 roles/forgejo/templates/runners/docker-compose.yml.j2 create mode 100644 roles/forgejo/templates/server.env.j2 create mode 100644 roles/forgejo_runners/README.md create mode 100644 roles/forgejo_runners/TODO.txt create mode 100644 roles/forgejo_runners/defaults/main.yml create mode 100644 roles/forgejo_runners/handlers/main.yml create mode 100644 roles/forgejo_runners/meta/argument_specs.yml create mode 100644 roles/forgejo_runners/meta/main.yml create mode 100644 roles/forgejo_runners/tasks/deploy-runners.yml create mode 100644 roles/forgejo_runners/tasks/deploy-server.yml create mode 100644 roles/forgejo_runners/tasks/main.yml create mode 100644 roles/forgejo_runners/tasks/register-runner.yml create mode 100644 roles/forgejo_runners/templates/db.env.j2 create mode 100644 roles/forgejo_runners/templates/docker-compose.yml.j2 create mode 100644 roles/forgejo_runners/templates/runners/config.yml.j2 create mode 100644 roles/forgejo_runners/templates/runners/docker-compose.yml.j2 create mode 100644 roles/forgejo_runners/templates/server.env.j2 create mode 100644 roles/galene/defaults/main.yml create mode 100644 roles/galene/handlers/main.yml create mode 100644 roles/galene/meta/main.yml create mode 100644 roles/galene/tasks/main.yml create mode 100644 roles/galene/templates/galene.service.j2 create mode 100644 roles/golang/defaults/main.yml create mode 100644 roles/golang/tasks/main.yml create mode 100644 roles/navidrome/.gitignore create mode 100644 roles/navidrome/README.md create mode 100644 roles/navidrome/defaults/main.yml create mode 100644 roles/navidrome/handlers/main.yml create mode 100644 roles/navidrome/tasks/main.yml create mode 100644 roles/navidrome/templates/navidrome.toml.j2 create mode 100644 roles/navidrome/templates/override.conf.j2 diff --git a/.forgejo/workflows/ansible-ci.yml b/.forgejo/workflows/ansible-ci.yml new file mode 100644 index 0000000..fceb974 --- /dev/null +++ b/.forgejo/workflows/ansible-ci.yml @@ -0,0 +1,35 @@ +--- +on: + - push + +jobs: + ansible-docsmith: + runs-on: node-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install ansible-docsmith + run: | + apt-get update + apt-get install -y python3-pip + pip install ansible-docsmith --break-system-packages + + - name: Run ansible-docsmith + run: ansible-docsmith generate . + + - name: Verify changes + run: | + set -e + git diff > diff.txt + CHANGES=$(wc -l diff.txt | awk '{ print $1 }') + echo "Number of changes: ${CHANGES}" + if [ ${CHANGES} -gt 0 ] ; then + echo "" + cat diff.txt + echo "" + echo "Fix with the following command:" + echo "" + echo "run ansible-docsmith generate ${role_dir}" + exit 1 + fi diff --git a/README.md b/README.md index 450baf0..9dc8a84 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ -# ansible +# Ansible -My Ansible collection \ No newline at end of file +My Ansible collection. diff --git a/roles/certbot/README.md b/roles/certbot/README.md new file mode 100644 index 0000000..89ae0db --- /dev/null +++ b/roles/certbot/README.md @@ -0,0 +1,45 @@ +# Ansible Role Certbot + +## Table of content + + +* [Role variables](#variables) + * [`certbot_email`](#variable-certbot_email) + * [`certbot_domain`](#variable-certbot_domain) + + + + +## Role variables + +The following variables can be configured for this role: + +| Variable | Type | Required | Default | Description (abstract) | +|----------|------|----------|---------|------------------------| +| `certbot_email` | `str` | Yes | N/A | E-mail to register the certificate | +| `certbot_domain` | `str` | Yes | N/A | Domain name to register the certificate | + +### `certbot_email` + +[*⇑ Back to ToC ⇑*](#toc) + +E-mail to register the certificate + +- **Type**: `str` +- **Required**: Yes + + + +### `certbot_domain` + +[*⇑ Back to ToC ⇑*](#toc) + +Domain name to register the certificate + +- **Type**: `str` +- **Required**: Yes + + + + + diff --git a/roles/certbot/meta/argument_specs.yml b/roles/certbot/meta/argument_specs.yml new file mode 100644 index 0000000..76ec459 --- /dev/null +++ b/roles/certbot/meta/argument_specs.yml @@ -0,0 +1,18 @@ +--- +argument_specs: + main: + short_description: Install and configure a certbot + description: + - Install and configure a [certbot](https://certbot.eff.org/). + author: + - jriou + options: + certbot_email: + description: + - E-mail to register the certificate + required: true + + certbot_domain: + description: + - Domain name to register the certificate + required: true diff --git a/roles/certbot/tasks/main.yml b/roles/certbot/tasks/main.yml new file mode 100644 index 0000000..b7241ef --- /dev/null +++ b/roles/certbot/tasks/main.yml @@ -0,0 +1,17 @@ +--- +- name: Check requirements + ansible.builtin.assert: + that: + - certbot_email is defined + - certbot_domain is defined + +- name: Install packages + ansible.builtin.package: + name: certbot + +- name: Request certificate + ansible.builtin.command: + cmd: >- + certbot certonly --standalone -n --agree-tos + --email {{ certbot_email }} -d {{ certbot_domain }} + creates: /etc/letsencrypt/live/{{ certbot_domain }}/fullchain.pem diff --git a/roles/coller/README.md b/roles/coller/README.md new file mode 100644 index 0000000..c1da5ea --- /dev/null +++ b/roles/coller/README.md @@ -0,0 +1,159 @@ +# Ansible Role Coller + +Ansible role to manage a [coller](https://git.riou.xyz/jriou/coller) instance. + +## Configuration + +See [Variable +precedence](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_variables.html#ansible-variable-precedence) +to find where you should put your own variables. + +Then define at least `coller_db_password` with a strong and secure password, +encrypted using +[ansible-vault](https://docs.ansible.com/ansible/latest/cli/ansible-vault.html). + +## Table of content + + +* [Role variables](#variables) + * [`coller_version`](#variable-coller_version) + * [`coller_config_dir`](#variable-coller_config_dir) + * [`coller_port`](#variable-coller_port) + * [`coller_manage_iptables`](#variable-coller_manage_iptables) + * [`coller_allowed_sources`](#variable-coller_allowed_sources) + * [`coller_db_name`](#variable-coller_db_name) + * [`coller_db_user`](#variable-coller_db_user) + * [`coller_db_password`](#variable-coller_db_password) + + + + +## Role variables + +The following variables can be configured for this role: + +| Variable | Type | Required | Default | Description (abstract) | +|----------|------|----------|---------|------------------------| +| `coller_version` | `str` | No | `"1.3.1"` | Version of the binary. | +| `coller_config_dir` | `path` | No | `"/etc/coller"` | Directory of the configuration files. | +| `coller_port` | `int` | No | `8080` | Port to listen. | +| `coller_manage_iptables` | `bool` | No | `false` | Create iptables rule to allow the service. | +| `coller_allowed_sources` | `list` | No | N/A | List of allowed networks to allow.

Enabled when `coller_manage_iptables` is enabled. | +| `coller_db_name` | `str` | No | `"coller"` | Name of the database to connect. | +| `coller_db_user` | `str` | No | `"coller"` | User to connect to the database. | +| `coller_db_password` | `str` | Yes | N/A | Password to connect to the database. | + +### `coller_version` + +[*⇑ Back to ToC ⇑*](#toc) + +Version of the binary. + +- **Type**: `str` +- **Required**: No +- **Default**: `"1.3.1"` + + + +### `coller_config_dir` + +[*⇑ Back to ToC ⇑*](#toc) + +Directory of the configuration files. + +- **Type**: `path` +- **Required**: No +- **Default**: `"/etc/coller"` + + + +### `coller_port` + +[*⇑ Back to ToC ⇑*](#toc) + +Port to listen. + +- **Type**: `int` +- **Required**: No +- **Default**: `8080` + + + +### `coller_manage_iptables` + +[*⇑ Back to ToC ⇑*](#toc) + +Create iptables rule to allow the service. + +- **Type**: `bool` +- **Required**: No +- **Default**: `false` + + + +### `coller_allowed_sources` + +[*⇑ Back to ToC ⇑*](#toc) + +List of allowed networks to allow. + +Enabled when `coller_manage_iptables` is enabled. + +- **Type**: `list` +- **Required**: No + + + +### `coller_db_name` + +[*⇑ Back to ToC ⇑*](#toc) + +Name of the database to connect. + +- **Type**: `str` +- **Required**: No +- **Default**: `"coller"` + + + +### `coller_db_user` + +[*⇑ Back to ToC ⇑*](#toc) + +User to connect to the database. + +- **Type**: `str` +- **Required**: No +- **Default**: `"coller"` + + + +### `coller_db_password` + +[*⇑ Back to ToC ⇑*](#toc) + +Password to connect to the database. + +- **Type**: `str` +- **Required**: Yes + + + + + + +## Usage + +Example of a basic coller.yml playbook: + +```yaml +- hosts: coller + roles: + - coller +``` + +Then run the playbook: + +``` +ansible-playbook coller.yml +``` diff --git a/roles/coller/defaults/main.yml b/roles/coller/defaults/main.yml new file mode 100644 index 0000000..d8c5cde --- /dev/null +++ b/roles/coller/defaults/main.yml @@ -0,0 +1,52 @@ +--- + +# Version of the binary. +# +# - Type: str +# - Required: No +# - Default: 1.3.1 +coller_version: 1.3.1 + +# Directory of the configuration files. +# +# - Type: path +# - Required: No +# - Default: /etc/coller +coller_config_dir: /etc/coller + +# Port to listen. +# +# - Type: int +# - Required: No +# - Default: 8080 +coller_port: 8080 + +# Create iptables rule to allow the service. +# +# - Type: bool +# - Required: No +# - Default: false +coller_manage_iptables: false + +# List of allowed networks to allow. +# +# Enabled when `coller_manage_iptables` is enabled. +# +# - Type: list +# - Required: No +coller_allowed_sources: [] + +# Name of the database to connect. +# +# - Type: str +# - Required: No +# - Default: coller +coller_db_name: coller + +# User to connect to the database. +# +# - Type: str +# - Required: No +# - Default: coller +coller_db_user: coller +#coller_db_password: diff --git a/roles/coller/handlers/main.yml b/roles/coller/handlers/main.yml new file mode 100644 index 0000000..aa0f296 --- /dev/null +++ b/roles/coller/handlers/main.yml @@ -0,0 +1,4 @@ +--- +- name: save iptables + ansible.builtin.shell: + cmd: netfilter-persistent save diff --git a/roles/coller/meta/argument_specs.yml b/roles/coller/meta/argument_specs.yml new file mode 100644 index 0000000..a4b4744 --- /dev/null +++ b/roles/coller/meta/argument_specs.yml @@ -0,0 +1,52 @@ +--- +argument_specs: + main: + short_description: Install and configure a coller instance + description: + - Install and configure a [coller](https://git.riou.xyz/jriou/coller) instance. + author: + - jriou + options: + coller_version: + description: + - Version of the binary. + default: "1.3.1" + + coller_config_dir: + description: + - Directory of the configuration files. + type: path + default: /etc/coller + + coller_port: + description: + - Port to listen. + type: int + default: 8080 + + coller_manage_iptables: + description: + - Create iptables rule to allow the service. + type: bool + default: false + + coller_allowed_sources: + description: + - List of allowed networks to allow. + - Enabled when `coller_manage_iptables` is enabled. + type: list + + coller_db_name: + description: + - Name of the database to connect. + default: coller + + coller_db_user: + description: + - User to connect to the database. + default: coller + + coller_db_password: + description: + - Password to connect to the database. + required: true diff --git a/roles/coller/meta/main.yml b/roles/coller/meta/main.yml new file mode 100644 index 0000000..3f5647c --- /dev/null +++ b/roles/coller/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: +- role: geerlingguy.docker diff --git a/roles/coller/tasks/main.yml b/roles/coller/tasks/main.yml new file mode 100644 index 0000000..e7141be --- /dev/null +++ b/roles/coller/tasks/main.yml @@ -0,0 +1,55 @@ +--- +- name: check password + ansible.builtin.assert: + that: + - coller_db_password is defined + +- name: download source code + ansible.builtin.git: + repo: https://git.riou.xyz/jriou/coller.git + dest: /opt/coller + version: "{{ coller_version }}" + +- name: create directories + ansible.builtin.file: + path: "{{ item }}" + state: directory + owner: root + group: root + mode: "0755" + loop: + - "{{ coller_config_dir }}" + +- name: create docker-compose files + ansible.builtin.template: + src: "{{ item.src }}.j2" + dest: "{{ coller_config_dir }}/{{ item.src }}" + owner: root + group: root + mode: "{{ item.mode }}" + loop: + - src: docker-compose.yml + mode: "0644" + - src: db.env + mode: "0600" + +- name: create configuration file + ansible.builtin.copy: + content: + database_type: postgres + database_dsn: "host=db dbname={{ coller_db_name }} user={{ coller_db_user }} password={{ coller_db_password }}" + dest: "{{ coller_config_dir }}/collerd.json" + owner: root + group: root + mode: "0640" + no_log: true + +- name: start service + community.docker.docker_compose_v2: + project_src: "{{ coller_config_dir }}" + files: + - docker-compose.yml + +- name: manage iptables + when: coller_manage_iptables + ansible.builtin.include_tasks: manage-iptables.yml diff --git a/roles/coller/tasks/manage-iptables.yml b/roles/coller/tasks/manage-iptables.yml new file mode 100644 index 0000000..7626914 --- /dev/null +++ b/roles/coller/tasks/manage-iptables.yml @@ -0,0 +1,16 @@ +--- +- name: install packages + ansible.builtin.package: + name: netfilter-persistent + +- name: allow with iptables + ansible.builtin.iptables: + chain: INPUT + protocol: tcp + source: "{{ item }}" + destination_ports: + - "{{ coller_port }}" + jump: ACCEPT + comment: coller + loop: "{{ coller_allowed_sources }}" + notify: save iptables diff --git a/roles/coller/templates/db.env.j2 b/roles/coller/templates/db.env.j2 new file mode 100644 index 0000000..511cba4 --- /dev/null +++ b/roles/coller/templates/db.env.j2 @@ -0,0 +1,6 @@ +{{ ansible_managed | comment }} +POSTGRES_USER={{ coller_db_user }} +POSTGRES_PASSWORD={{ coller_db_password }} +POSTGRES_DB={{ coller_db_name }} +POSTGRES_INITDB_ARGS="--data-checksums" +POSTGRES_HOST_AUTH_METHOD=scram-sha-256 diff --git a/roles/coller/templates/docker-compose.yml.j2 b/roles/coller/templates/docker-compose.yml.j2 new file mode 100644 index 0000000..1d46c35 --- /dev/null +++ b/roles/coller/templates/docker-compose.yml.j2 @@ -0,0 +1,32 @@ +--- +{{ ansible_managed | comment }} +services: + server: + image: coller:{{ coller_version }} + build: /opt/coller + container_name: collerd + restart: always + networks: + - coller + ports: + - "{{ coller_port }}:8080" + volumes: + - "{{ coller_config_dir }}/collerd.json:/etc/collerd.json:ro" + command: collerd -config /etc/collerd.json + + db: + image: postgres:17 + hostname: db + container_name: collerd_db + restart: always + env_file: {{ coller_config_dir }}/db.env + networks: + - coller + volumes: + - coller:/var/lib/postgresql/data + +networks: + coller: + +volumes: + coller: diff --git a/roles/firefly/README.md b/roles/firefly/README.md new file mode 100644 index 0000000..feadf6b --- /dev/null +++ b/roles/firefly/README.md @@ -0,0 +1,39 @@ +# Ansible Role Firefly + +Ansible role to manage a [Firefly III](https://firefly-iii.org/) instance. + +## Configuration + +See [Variable +precedence](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_variables.html#ansible-variable-precedence) +to find where you should put your own variables. + +Then define at least `firefly_static_cron_token`, `firefly_db_password` and +`firefly_app_key` variables with a strong and secure password, encrypted using +[ansible-vault](https://docs.ansible.com/ansible/latest/cli/ansible-vault.html). + +See list of [default variables](defaults/main.yml). + + +## Usage + +Example of a basic firefly.yml playbook: + +```yaml +hosts: + - firefly + +roles: + - firefly +``` + +Then run the playbook: + +``` +ansible-playbook firefly.yml +``` + +## Donate + +As we all love FOSS projects, you should consider [sponsoring and/or +contribute](https://github.com/firefly-iii/firefly-iii). diff --git a/roles/firefly/defaults/main.yml b/roles/firefly/defaults/main.yml new file mode 100644 index 0000000..f01fe37 --- /dev/null +++ b/roles/firefly/defaults/main.yml @@ -0,0 +1,14 @@ +--- +firefly_version: latest +firefly_port: 8080 +firefly_static_cron_token: CHANGEME +firefly_home: /var/lib/firefly +firefly_site_owner: root@localhost +firefly_app_key: CHANGEME +firefly_language: en_US +firefly_tz: Etc/UTC +firefly_db_database: firefly +firefly_db_username: firefly +firefly_db_password: CHANGEME +firefly_manage_iptables: false +firefly_allowed_sources: [] diff --git a/roles/firefly/handlers/main.yml b/roles/firefly/handlers/main.yml new file mode 100644 index 0000000..aa0f296 --- /dev/null +++ b/roles/firefly/handlers/main.yml @@ -0,0 +1,4 @@ +--- +- name: save iptables + ansible.builtin.shell: + cmd: netfilter-persistent save diff --git a/roles/firefly/meta/main.yml b/roles/firefly/meta/main.yml new file mode 100644 index 0000000..3f5647c --- /dev/null +++ b/roles/firefly/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: +- role: geerlingguy.docker diff --git a/roles/firefly/tasks/main.yml b/roles/firefly/tasks/main.yml new file mode 100644 index 0000000..65be46c --- /dev/null +++ b/roles/firefly/tasks/main.yml @@ -0,0 +1,40 @@ +--- +- name: install dependencies + ansible.builtin.apt: + name: + - python3-docker + - python3-compose + +- name: create directories + ansible.builtin.file: + path: /etc/firefly + state: directory + +- name: create configuration files + ansible.builtin.template: + src: "{{ item }}.j2" + dest: "/etc/firefly/{{ item }}" + mode: "0600" + loop: + - docker-compose.yml + - db.env + - app.env + +- name: start service + community.docker.docker_compose_v2: + project_src: /etc/firefly + files: + - docker-compose.yml + +- name: allow with iptables + ansible.builtin.iptables: + chain: INPUT + protocol: tcp + source: "{{ item }}" + destination_ports: + - "{{ firefly_port }}" + jump: ACCEPT + comment: firefly + loop: "{{ firefly_allowed_sources }}" + notify: save iptables + when: firefly_manage_iptables diff --git a/roles/firefly/templates/app.env.j2 b/roles/firefly/templates/app.env.j2 new file mode 100644 index 0000000..89aa8aa --- /dev/null +++ b/roles/firefly/templates/app.env.j2 @@ -0,0 +1,132 @@ +APP_ENV=local +APP_DEBUG=false + +SITE_OWNER={{ firefly_site_owner }} + +APP_KEY={{ firefly_app_key }} + +DEFAULT_LANGUAGE={{ firefly_language }} +DEFAULT_LOCALE=equal + +TZ={{ firefly_tz }} + +TRUSTED_PROXIES=* + +LOG_CHANNEL=stack + +APP_LOG_LEVEL=notice + +AUDIT_LOG_LEVEL=emergency +AUDIT_LOG_CHANNEL= +PAPERTRAIL_HOST= +PAPERTRAIL_PORT= + +# Database credentials. Make sure the database exists. I recommend a dedicated user for Firefly III +# For other database types, please see the FAQ: https://docs.firefly-iii.org/firefly-iii/faq/self-hosted/#i-want-to-use-sqlite +# If you use Docker or similar, you can set these variables from a file by appending them with _FILE +# Use "pgsql" for PostgreSQL +# Use "mysql" for MySQL and MariaDB. +# Use "sqlite" for SQLite. +DB_CONNECTION=pgsql +DB_HOST=db +DB_PORT=5432 +DB_DATABASE={{ firefly_db_database }} +DB_USERNAME={{ firefly_db_username }} +DB_PASSWORD={{ firefly_db_password }} +DB_SOCKET= + +PGSQL_SSL_MODE=prefer +PGSQL_SCHEMA=public + +CACHE_DRIVER=file +SESSION_DRIVER=file + +REDIS_SCHEME=tcp +REDIS_PATH= +REDIS_HOST=redis +REDIS_PORT=6379 +REDIS_USERNAME=firefly +REDIS_PASSWORD= +REDIS_DB="0" +REDIS_CACHE_DB="1" + +COOKIE_PATH="/" +COOKIE_DOMAIN= +COOKIE_SECURE=false +COOKIE_SAMESITE=lax + +MAIL_MAILER=log +MAIL_HOST=null +MAIL_PORT=2525 +MAIL_FROM=changeme@example.com +MAIL_USERNAME=null +MAIL_PASSWORD=null +MAIL_ENCRYPTION=null +MAIL_SENDMAIL_COMMAND= +MAILGUN_DOMAIN= +MAILGUN_SECRET= +MAILGUN_ENDPOINT=api.mailgun.net +MANDRILL_SECRET= +SPARKPOST_SECRET= +SEND_ERROR_MESSAGE=true +SEND_REPORT_JOURNALS=true + +ENABLE_EXTERNAL_MAP=false +ENABLE_EXTERNAL_RATES=false +MAP_DEFAULT_LAT=51.983333 +MAP_DEFAULT_LONG=5.916667 +MAP_DEFAULT_ZOOM=6 + +VALID_URL_PROTOCOLS= + +AUTHENTICATION_GUARD=web +AUTHENTICATION_GUARD_HEADER=REMOTE_USER +AUTHENTICATION_GUARD_EMAIL= + +PASSPORT_PRIVATE_KEY= +PASSPORT_PUBLIC_KEY= + +CUSTOM_LOGOUT_URL= + +DISABLE_FRAME_HEADER=false +DISABLE_CSP_HEADER=false +TRACKER_SITE_ID= +TRACKER_URL= + +ALLOW_WEBHOOKS=false + +STATIC_CRON_TOKEN={{ firefly_static_cron_token }} + +DKR_BUILD_LOCALE=false +DKR_CHECK_SQLITE=true +DKR_RUN_MIGRATION=true +DKR_RUN_UPGRADE=true +DKR_RUN_VERIFY=true +DKR_RUN_REPORT=true +DKR_RUN_PASSPORT_INSTALL=true + +APP_NAME=FireflyIII +BROADCAST_DRIVER=log +QUEUE_DRIVER=sync +CACHE_PREFIX=firefly +PUSHER_KEY= +IPINFO_TOKEN= +PUSHER_SECRET= +PUSHER_ID= +DEMO_USERNAME= +DEMO_PASSWORD= +FIREFLY_III_LAYOUT=v1 + +# +# If you have trouble configuring your Firefly III installation, DON'T BOTHER setting this variable. +# It won't work. It doesn't do ANYTHING. Don't believe the lies you read online. I'm not joking. +# This configuration value WILL NOT HELP. +# +# Notable exception to this rule is Synology, which, according to some users, will use APP_URL to rewrite stuff. +# +# This variable is ONLY used in some of the emails Firefly III sends around. Nowhere else. +# So when configuring anything WEB related this variable doesn't do anything. Nothing +# +# If you're stuck I understand you get desperate but look SOMEWHERE ELSE. +# +APP_URL=http://localhost diff --git a/roles/firefly/templates/db.env.j2 b/roles/firefly/templates/db.env.j2 new file mode 100644 index 0000000..6805c19 --- /dev/null +++ b/roles/firefly/templates/db.env.j2 @@ -0,0 +1,5 @@ +POSTGRES_USER={{ firefly_db_username }} +POSTGRES_PASSWORD={{ firefly_db_password }} +POSTGRES_DB={{ firefly_db_database }} +POSTGRES_INITDB_ARGS="--data-checksums" +POSTGRES_HOST_AUTH_METHOD=scram-sha-256 diff --git a/roles/firefly/templates/docker-compose.yml.j2 b/roles/firefly/templates/docker-compose.yml.j2 new file mode 100644 index 0000000..81ae8f0 --- /dev/null +++ b/roles/firefly/templates/docker-compose.yml.j2 @@ -0,0 +1,40 @@ +--- +{{ ansible_managed | comment }} +services: + app: + image: fireflyiii/core:{{ firefly_version }} + hostname: app + container_name: firefly_iii_core + restart: always + volumes: + - {{ firefly_home }}/app/upload:/var/www/html/storage/upload + env_file: /etc/firefly/app.env + networks: + - firefly_iii + ports: + - {{ firefly_port }}:8080 + depends_on: + - db + db: + image: postgres:17 + hostname: db + container_name: firefly_iii_db + restart: always + env_file: /etc/firefly/db.env + networks: + - firefly_iii + volumes: + - {{ firefly_home }}/db/data:/var/lib/postgresql/data + - {{ firefly_home }}/db/backup:/var/lib/postgresql/backup + + cron: + image: alpine + restart: always + container_name: firefly_iii_cron + command: sh -c "echo \"0 3 * * * wget -qO- http://app:8080/api/v1/cron/{{ firefly_static_cron_token }}\" | crontab - && crond -f -L /dev/stdout" + networks: + - firefly_iii + +networks: + firefly_iii: + driver: bridge diff --git a/roles/forgejo/README.md b/roles/forgejo/README.md new file mode 100644 index 0000000..8b24841 --- /dev/null +++ b/roles/forgejo/README.md @@ -0,0 +1,321 @@ +# Ansible Role Forgejo + +Ansible role to manage a [Forgejo](https://forgejo.org/) instance. + +## Configuration + +See [Variable +precedence](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_variables.html#ansible-variable-precedence) +to find where you should put your own variables. + +Then define at least `forgejo_db_password` with a strong and secure password, +encrypted using +[ansible-vault](https://docs.ansible.com/ansible/latest/cli/ansible-vault.html). + + +## Table of Content + + +* [Role variables](#variables) + * [`forgejo_server`](#variable-forgejo_server) + * [`forgejo_version`](#variable-forgejo_version) + * [`forgejo_home_dir`](#variable-forgejo_home_dir) + * [`forgejo_config_dir`](#variable-forgejo_config_dir) + * [`forgejo_web_port`](#variable-forgejo_web_port) + * [`forgejo_ssh_port`](#variable-forgejo_ssh_port) + * [`forgejo_db_username`](#variable-forgejo_db_username) + * [`forgejo_db_password`](#variable-forgejo_db_password) + * [`forgejo_db_database`](#variable-forgejo_db_database) + * [`forgejo_mailer`](#variable-forgejo_mailer) + * [`forgejo_service`](#variable-forgejo_service) + * [`forgejo_manage_iptables`](#variable-forgejo_manage_iptables) + * [`forgejo_allowed_sources`](#variable-forgejo_allowed_sources) + * [`forgejo_runners_version`](#variable-forgejo_runners_version) + * [`forgejo_runners_config_dir`](#variable-forgejo_runners_config_dir) + * [`forgejo_runners_instance`](#variable-forgejo_runners_instance) + * [`forgejo_runners`](#variable-forgejo_runners) + + + +## Role variables + +The following variables can be configured for this role: + +| Variable | Type | Required | Default | Description (abstract) | +|----------|------|----------|---------|------------------------| +| `forgejo_server` | `bool` | No | `true` | Enable the server mode | +| `forgejo_version` | `int` | No | `14` | Version of the Forgejo binaries | +| `forgejo_home_dir` | `path` | No | `"/var/lib/forgejo"` | Path to the home directory | +| `forgejo_config_dir` | `path` | No | `"/etc/forgejo"` | Path to the configuration directory | +| `forgejo_web_port` | `int` | No | `3000` | Port to listen for the web UI | +| `forgejo_ssh_port` | `int` | No | `222` | Port to listen for SSH | +| `forgejo_db_username` | `str` | No | `"forgejo"` | Name of the user in the database | +| `forgejo_db_password` | `str` | Yes | N/A | Password of the user in the database | +| `forgejo_db_database` | `str` | No | `"forgejo"` | Name of the database | +| `forgejo_mailer` | `dict` | No | N/A | Configure the mailer to send e-mail notifications

Define a `enabled` key with a boolean to enable the mailer

Define a `from` key with the source e-mail address

See [Email setup](https://forgejo.org/docs/latest/admin/setup/email/) | +| `forgejo_service` | `dict` | No | N/A | Configure service settings

See [Service](https://forgejo.org/docs/latest/admin/config-cheat-sheet/#service-service) | +| `forgejo_manage_iptables` | `bool` | No | `false` | Configure iptables rules | +| `forgejo_allowed_sources` | `list` | No | N/A | List of IP ranges to allow when `forgejo_manage_iptables` is enabled | +| `forgejo_runners_version` | `str` | No | `"9.1.1"` | Version of the runners | +| `forgejo_runners_config_dir` | `path` | No | `"/etc/forgejo-runners"` | Path to the configuration directory of the runners | +| `forgejo_runners_instance` | `str` | No | N/A | URL of the Forgejo instance to register the runners | +| `forgejo_runners` | `dict` | No | N/A | List of runners to configure

The key is the name of the repository on the instance

The value is a dict with a `token` key and optionally a dict of `labels` | + +### `forgejo_server` + +[*⇑ Back to ToC ⇑*](#toc) + +Enable the server mode + +- **Type**: `bool` +- **Required**: No +- **Default**: `true` + + + +### `forgejo_version` + +[*⇑ Back to ToC ⇑*](#toc) + +Version of the Forgejo binaries + +- **Type**: `int` +- **Required**: No +- **Default**: `14` + + + +### `forgejo_home_dir` + +[*⇑ Back to ToC ⇑*](#toc) + +Path to the home directory + +- **Type**: `path` +- **Required**: No +- **Default**: `"/var/lib/forgejo"` + + + +### `forgejo_config_dir` + +[*⇑ Back to ToC ⇑*](#toc) + +Path to the configuration directory + +- **Type**: `path` +- **Required**: No +- **Default**: `"/etc/forgejo"` + + + +### `forgejo_web_port` + +[*⇑ Back to ToC ⇑*](#toc) + +Port to listen for the web UI + +- **Type**: `int` +- **Required**: No +- **Default**: `3000` + + + +### `forgejo_ssh_port` + +[*⇑ Back to ToC ⇑*](#toc) + +Port to listen for SSH + +- **Type**: `int` +- **Required**: No +- **Default**: `222` + + + +### `forgejo_db_username` + +[*⇑ Back to ToC ⇑*](#toc) + +Name of the user in the database + +- **Type**: `str` +- **Required**: No +- **Default**: `"forgejo"` + + + +### `forgejo_db_password` + +[*⇑ Back to ToC ⇑*](#toc) + +Password of the user in the database + +- **Type**: `str` +- **Required**: Yes + + + +### `forgejo_db_database` + +[*⇑ Back to ToC ⇑*](#toc) + +Name of the database + +- **Type**: `str` +- **Required**: No +- **Default**: `"forgejo"` + + + +### `forgejo_mailer` + +[*⇑ Back to ToC ⇑*](#toc) + +Configure the mailer to send e-mail notifications + +Define a `enabled` key with a boolean to enable the mailer + +Define a `from` key with the source e-mail address + +See [Email setup](https://forgejo.org/docs/latest/admin/setup/email/) + +- **Type**: `dict` +- **Required**: No + + + +### `forgejo_service` + +[*⇑ Back to ToC ⇑*](#toc) + +Configure service settings + +See [Service](https://forgejo.org/docs/latest/admin/config-cheat-sheet/#service-service) + +- **Type**: `dict` +- **Required**: No + + + +### `forgejo_manage_iptables` + +[*⇑ Back to ToC ⇑*](#toc) + +Configure iptables rules + +- **Type**: `bool` +- **Required**: No +- **Default**: `false` + + + +### `forgejo_allowed_sources` + +[*⇑ Back to ToC ⇑*](#toc) + +List of IP ranges to allow when `forgejo_manage_iptables` is enabled + +- **Type**: `list` +- **Required**: No + + + +### `forgejo_runners_version` + +[*⇑ Back to ToC ⇑*](#toc) + +Version of the runners + +- **Type**: `str` +- **Required**: No +- **Default**: `"9.1.1"` + + + +### `forgejo_runners_config_dir` + +[*⇑ Back to ToC ⇑*](#toc) + +Path to the configuration directory of the runners + +- **Type**: `path` +- **Required**: No +- **Default**: `"/etc/forgejo-runners"` + + + +### `forgejo_runners_instance` + +[*⇑ Back to ToC ⇑*](#toc) + +URL of the Forgejo instance to register the runners + +- **Type**: `str` +- **Required**: No + + + +### `forgejo_runners` + +[*⇑ Back to ToC ⇑*](#toc) + +List of runners to configure + +The key is the name of the repository on the instance + +The value is a dict with a `token` key and optionally a dict of `labels` + +- **Type**: `dict` +- **Required**: No + + + + + + +## Usage + +Example of a basic forgejo.yml playbook: + +```yaml +- hosts: forgejo + roles: + - jriou.forgejo +``` + +Then run the playbook: + +``` +ansible-playbook forgejo.yml +``` + +## Runners + +Example of runners configuration: + +```yaml +- hosts: forgejo + roles: + - jriou.forgejo + vars: + forgejo_server: false + forgejo_runners_instance: https://codeberg.org # FIXME + forgejo_runners: + coller: + token: **redacted** + labels: + debian12: docker://data.forgejo.org/oci/debian:bookworm + debian13: docker://data.forgejo.org/oci/debian:trixie + ansible: + token: **redacted** + labels: + docker: docker://data.forgejo.org/oci/node:latest +``` + + +## Donate + +As we all love FOSS projects, you should consider [donating to +Codeberg](https://donate.codeberg.org/), the non-profit organization behind +Forgejo. diff --git a/roles/forgejo/TODO.txt b/roles/forgejo/TODO.txt new file mode 100644 index 0000000..e1573c6 --- /dev/null +++ b/roles/forgejo/TODO.txt @@ -0,0 +1 @@ +Focus on server only diff --git a/roles/forgejo/defaults/main.yml b/roles/forgejo/defaults/main.yml new file mode 100644 index 0000000..1ba666e --- /dev/null +++ b/roles/forgejo/defaults/main.yml @@ -0,0 +1,120 @@ +--- + +# Enable the server mode +# +# - Type: bool +# - Required: No +# - Default: true +forgejo_server: true + +# Version of the Forgejo binaries +# +# - Type: int +# - Required: No +# - Default: 14 +forgejo_version: 14 + +# Path to the home directory +# +# - Type: path +# - Required: No +# - Default: /var/lib/forgejo +forgejo_home_dir: /var/lib/forgejo + +# Path to the configuration directory +# +# - Type: path +# - Required: No +# - Default: /etc/forgejo +forgejo_config_dir: /etc/forgejo + +# Port to listen for the web UI +# +# - Type: int +# - Required: No +# - Default: 3000 +forgejo_web_port: 3000 + +# Port to listen for SSH +# +# - Type: int +# - Required: No +# - Default: 222 +forgejo_ssh_port: 222 + +# Name of the user in the database +# +# - Type: str +# - Required: No +# - Default: forgejo +forgejo_db_username: forgejo + +# Password of the user in the database +# +# - Type: str +# - Required: Yes +forgejo_db_password: CHANGEME + +# Name of the database +# +# - Type: str +# - Required: No +# - Default: forgejo +forgejo_db_database: forgejo + +# Configure the mailer to send e-mail notifications +# +# Define a `enabled` key with a boolean to enable the mailer +# +# Define a `from` key with the source e-mail address +# +# See +# +# - Type: dict +# - Required: No +forgejo_mailer: {} + +# Configure service settings +# +# See +# +# - Type: dict +# - Required: No +forgejo_service: {} + +# Configure iptables rules +# +# - Type: bool +# - Required: No +# - Default: false +forgejo_manage_iptables: false + +# List of IP ranges to allow when `forgejo_manage_iptables` is enabled +# +# - Type: list +# - Required: No +forgejo_allowed_sources: [] + +# Version of the runners +# +# - Type: str +# - Required: No +# - Default: 9.1.1 +forgejo_runners_version: 9.1.1 + +# Path to the configuration directory of the runners +# +# - Type: path +# - Required: No +# - Default: /etc/forgejo-runners +forgejo_runners_config_dir: /etc/forgejo-runners + +# List of runners to configure +# +# The key is the name of the repository on the instance +# +# The value is a dict with a `token` key and optionally a dict of `labels` +# +# - Type: dict +# - Required: No +forgejo_runners: {} diff --git a/roles/forgejo/handlers/main.yml b/roles/forgejo/handlers/main.yml new file mode 100644 index 0000000..e371990 --- /dev/null +++ b/roles/forgejo/handlers/main.yml @@ -0,0 +1,17 @@ +--- +- name: save iptables + ansible.builtin.shell: + cmd: netfilter-persistent save + +- name: start runners + community.docker.docker_compose_v2: + project_src: "{{ forgejo_runners_config_dir }}" + files: + - docker-compose.yml + +- name: restart runners + community.docker.docker_compose_v2: + project_src: "{{ forgejo_runners_config_dir }}" + files: + - docker-compose.yml + state: restarted diff --git a/roles/forgejo/meta/argument_specs.yml b/roles/forgejo/meta/argument_specs.yml new file mode 100644 index 0000000..df523cc --- /dev/null +++ b/roles/forgejo/meta/argument_specs.yml @@ -0,0 +1,84 @@ +--- +argument_specs: + main: + short_description: Install and configure a Forgejo instance + description: + - Install and configure a [Forgejo](https://forgejo.org/) instance. + author: + - jriou + options: + forgejo_server: + description: + - Enable the server mode + type: bool + default: true + + forgejo_version: + description: + - Version of the Forgejo binaries + type: int + default: 14 + + forgejo_home_dir: + description: + - Path to the home directory + type: path + default: /var/lib/forgejo + + forgejo_config_dir: + description: + - Path to the configuration directory + type: path + default: /etc/forgejo + + forgejo_web_port: + description: + - Port to listen for the web UI + type: int + default: 3000 + + forgejo_ssh_port: + description: + - Port to listen for SSH + type: int + default: 222 + + forgejo_db_username: + description: + - Name of the user in the database + default: forgejo + + forgejo_db_password: + description: + - Password of the user in the database + required: true + + forgejo_db_database: + description: + - Name of the database + default: forgejo + + forgejo_mailer: + description: + - Configure the mailer to send e-mail notifications + - Define a `enabled` key with a boolean to enable the mailer + - Define a `from` key with the source e-mail address + - See [Email setup](https://forgejo.org/docs/latest/admin/setup/email/) + type: dict + + forgejo_service: + description: + - Configure service settings + - See [Service](https://forgejo.org/docs/latest/admin/config-cheat-sheet/#service-service) + type: dict + + forgejo_manage_iptables: + description: + - Configure iptables rules + type: bool + default: false + + forgejo_allowed_sources: + description: + - List of IP ranges to allow when `forgejo_manage_iptables` is enabled + type: list diff --git a/roles/forgejo/meta/main.yml b/roles/forgejo/meta/main.yml new file mode 100644 index 0000000..94ae890 --- /dev/null +++ b/roles/forgejo/meta/main.yml @@ -0,0 +1,18 @@ +--- +dependencies: +- role: geerlingguy.docker + +galaxy_info: + role_name: jriou.forgejo + author: jriou + description: Ansible role to manage a Forgejo instance + license_file: LICENSE + min_ansible_version: 2.18 + platforms: + - name: Debian + versions: + - bullseye + - bookworm + - trixie + galaxy_tags: + - forgejo diff --git a/roles/forgejo/tasks/deploy-runners.yml b/roles/forgejo/tasks/deploy-runners.yml new file mode 100644 index 0000000..6dc8e02 --- /dev/null +++ b/roles/forgejo/tasks/deploy-runners.yml @@ -0,0 +1,20 @@ +--- +- name: register runners + ansible.builtin.include_tasks: register-runner.yml + loop: "{{ forgejo_runners | dict2items }}" + loop_control: + label: "{{ item.key }}" + +- name: create runners configuration + ansible.builtin.template: + src: "runners/docker-compose.yml.j2" + dest: "{{ forgejo_runners_config_dir }}/docker-compose.yml" + owner: root + group: root + mode: "0644" + +- name: start runners service + community.docker.docker_compose_v2: + project_src: "{{ forgejo_runners_config_dir }}" + files: + - docker-compose.yml diff --git a/roles/forgejo/tasks/deploy-server.yml b/roles/forgejo/tasks/deploy-server.yml new file mode 100644 index 0000000..a2c7dbf --- /dev/null +++ b/roles/forgejo/tasks/deploy-server.yml @@ -0,0 +1,61 @@ +--- +- name: check database password + ansible.builtin.assert: + that: forgejo_db_password is defined + +- name: create directories + ansible.builtin.file: + state: directory + path: "{{ item }}" + owner: forgejo + group: forgejo + mode: "0755" + loop: &forgejo_directories + - "{{ forgejo_config_dir }}" + - "{{ forgejo_home_dir }}" + - "{{ forgejo_home_dir }}/server" + - "{{ forgejo_home_dir }}/db" + +- name: ensure permissions on those directories + ansible.builtin.command: + cmd: "chown -R forgejo:forgejo {{ item }}" + loop: *forgejo_directories + +- name: create docker-compose configuration + ansible.builtin.template: + src: "{{ item.name }}.j2" + dest: "{{ forgejo_config_dir }}/{{ item.name }}" + owner: root + group: root + mode: "{{ item.mode }}" + loop: + - name: docker-compose.yml + mode: "0644" + - name: server.env + mode: "0600" + - name: db.env + mode: "0600" + +- name: start service + community.docker.docker_compose_v2: + project_src: "{{ forgejo_config_dir }}" + files: + - docker-compose.yml + +- name: allow with iptables + ansible.builtin.iptables: + chain: INPUT + protocol: tcp + source: "{{ item }}" + destination_ports: + - "{{ forgejo_web_port }}" + - "{{ forgejo_ssh_port }}" + jump: ACCEPT + comment: forgejo + loop: "{{ forgejo_allowed_sources }}" + notify: save iptables + when: forgejo_manage_iptables + +- name: deploy runners + ansible.builtin.include_tasks: deploy-runners.yml + when: forgejo_runners diff --git a/roles/forgejo/tasks/main.yml b/roles/forgejo/tasks/main.yml new file mode 100644 index 0000000..c845b1c --- /dev/null +++ b/roles/forgejo/tasks/main.yml @@ -0,0 +1,21 @@ +--- +- name: add forgejo user + ansible.builtin.user: + name: forgejo + system: yes + password: '!' + home: "{{ forgejo_home_dir }}" + create_home: no + +- name: read forgejo attributes + ansible.builtin.getent: + database: passwd + key: forgejo + +- name: deploy server + ansible.builtin.include_tasks: deploy-server.yml + when: forgejo_server + +- name: deploy runners + ansible.builtin.include_tasks: deploy-runners.yml + when: forgejo_runners is defined diff --git a/roles/forgejo/tasks/register-runner.yml b/roles/forgejo/tasks/register-runner.yml new file mode 100644 index 0000000..9b63297 --- /dev/null +++ b/roles/forgejo/tasks/register-runner.yml @@ -0,0 +1,39 @@ +--- +- name: check variables + ansible.builtin.assert: + that: + - forgejo_runners_instance is defined + - forgejo_runners_version is defined + - forgejo_runners_config_dir is defined + - "'key' in item" + - "'value' in item" + +- name: create runner subdirectory + ansible.builtin.file: + path: "{{ forgejo_runners_config_dir }}/{{ item.key }}" + state: directory + mode: "0755" + owner: forgejo + group: forgejo + +- name: register runner + ansible.builtin.command: + cmd: >- + docker run + -v /var/run/docker.sock:/var/run/docker.sock + -v {{ forgejo_runners_config_dir }}/{{ item.key }}:/data + --rm + --user {{ ansible_facts.getent_passwd.forgejo[1] }}:{{ ansible_facts.getent_passwd.forgejo[2] }} + code.forgejo.org/forgejo/runner:{{ forgejo_runners_version }} + forgejo-runner register --no-interactive + --token {{ item.value.token }} + --name {{ item.key }} + --instance {{ forgejo_runners_instance }} + creates: "{{ forgejo_runners_config_dir }}/{{ item.key }}/.runner" + notify: start runners + +- name: create runner configuration + ansible.builtin.template: + src: runners/config.yml.j2 + dest: "{{ forgejo_runners_config_dir }}/{{ item.key }}/config.yml" + notify: restart runners diff --git a/roles/forgejo/templates/db.env.j2 b/roles/forgejo/templates/db.env.j2 new file mode 100644 index 0000000..ba5ecbd --- /dev/null +++ b/roles/forgejo/templates/db.env.j2 @@ -0,0 +1,6 @@ +{{ ansible_managed | comment }} +POSTGRES_USER="{{ forgejo_db_username }}" +POSTGRES_PASSWORD="{{ forgejo_db_password }}" +POSTGRES_DB="{{ forgejo_db_database }}" +POSTGRES_INITDB_ARGS="--data-checksums" +POSTGRES_HOST_AUTH_METHOD=scram-sha-256 diff --git a/roles/forgejo/templates/docker-compose.yml.j2 b/roles/forgejo/templates/docker-compose.yml.j2 new file mode 100644 index 0000000..d54e1d7 --- /dev/null +++ b/roles/forgejo/templates/docker-compose.yml.j2 @@ -0,0 +1,35 @@ +--- +{{ ansible_managed | comment }} +services: + server: + image: codeberg.org/forgejo/forgejo:{{ forgejo_version }} + container_name: forgejo-server + env_file: {{ forgejo_config_dir }}/server.env + restart: always + networks: + - forgejo + volumes: + - "{{ forgejo_home_dir }}/server:/data" + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + ports: + - "{{ forgejo_web_port }}:3000" + - "{{ forgejo_ssh_port }}:22" + depends_on: + - db + + db: + image: postgres:17 + hostname: db + container_name: forgejo-db + restart: always + env_file: {{ forgejo_config_dir }}/db.env + user: "{{ ansible_facts.getent_passwd.forgejo[1] }}:{{ ansible_facts.getent_passwd.forgejo[2] }}" + networks: + - forgejo + volumes: + - "{{ forgejo_home_dir }}/db:/var/lib/postgresql/data" + +networks: + forgejo: + external: false diff --git a/roles/forgejo/templates/runners/config.yml.j2 b/roles/forgejo/templates/runners/config.yml.j2 new file mode 100644 index 0000000..39eb084 --- /dev/null +++ b/roles/forgejo/templates/runners/config.yml.j2 @@ -0,0 +1,44 @@ +{{ ansible_managed | comment }} +log: + level: info + job_level: info + +runner: + file: .runner + capacity: 1 + timeout: 3h + shutdown_timeout: 3h + insecure: false + fetch_timeout: 5s + fetch_interval: 2s + report_interval: 1s +{% if item.value.labels | default({}) %} + labels: +{% for label_name, label_value in item.value.labels.items() %} + - "{{ label_name }}:{{ label_value }}" +{% endfor %} +{% endif %} + +cache: + enabled: true + port: 0 + dir: "" + external_server: "" + secret: "" + host: "" + proxy_port: 0 + actions_cache_url_override: "" + +container: + network: "" + enable_ipv6: false + privileged: false + options: + workdir_parent: + valid_volumes: [] + docker_host: "-" + force_pull: false + force_rebuild: false + +host: + workdir_parent: diff --git a/roles/forgejo/templates/runners/docker-compose.yml.j2 b/roles/forgejo/templates/runners/docker-compose.yml.j2 new file mode 100644 index 0000000..a6eb7f5 --- /dev/null +++ b/roles/forgejo/templates/runners/docker-compose.yml.j2 @@ -0,0 +1,27 @@ +--- +{{ ansible_managed | comment }} +services: + docker: + image: docker:dind + privileged: true + restart: always + volumes: + - certs:/certs + +{% for runner in forgejo_runners %} + runner-{{ runner }}: + image: code.forgejo.org/forgejo/runner:{{ forgejo_runners_version }} + user: {{ ansible_facts.getent_passwd.forgejo[1] }}:{{ ansible_facts.getent_passwd.forgejo[2] }} + environment: + DOCKER_HOST: tcp://docker:2376 + DOCKER_TLS_VERIFY: 1 + DOCKER_CERT_PATH: /certs/client + restart: always + volumes: + - {{ forgejo_runners_config_dir }}/{{ runner }}:/data + - certs:/certs + command: 'forgejo-runner --config config.yml daemon' +{% endfor %} + +volumes: + certs: diff --git a/roles/forgejo/templates/server.env.j2 b/roles/forgejo/templates/server.env.j2 new file mode 100644 index 0000000..0bf2d4c --- /dev/null +++ b/roles/forgejo/templates/server.env.j2 @@ -0,0 +1,19 @@ +{{ ansible_managed | comment }} +USER_UID={{ ansible_facts.getent_passwd.forgejo[1] }} +USER_GID={{ ansible_facts.getent_passwd.forgejo[2] }} +FORGEJO__server__SSH_PORT={{ forgejo_ssh_port }} +FORGEJO__database__DB_TYPE=postgres +FORGEJO__database__HOST=db:5432 +FORGEJO__database__NAME="{{ forgejo_db_database }}" +FORGEJO__database__USER="{{ forgejo_db_username }}" +FORGEJO__database__PASSWD="{{ forgejo_db_password }}" +{% if forgejo_mailer %} +{% for k, v in forgejo_mailer.items() %} +FORGEJO__mailer__{{ k | upper }}="{{ v }}" +{% endfor %} +{% endif %} +{% if forgejo_service %} +{% for k, v in forgejo_service.items() %} +FORGEJO__service__{{ k | upper }}="{{ v }}" +{% endfor %} +{% endif %} diff --git a/roles/forgejo_runners/README.md b/roles/forgejo_runners/README.md new file mode 100644 index 0000000..432dab3 --- /dev/null +++ b/roles/forgejo_runners/README.md @@ -0,0 +1,321 @@ +# Ansible Role Forgejo Runners + +Ansible role to manage [Forgejo](https://forgejo.org/) runners. + +## Configuration + +See [Variable +precedence](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_variables.html#ansible-variable-precedence) +to find where you should put your own variables. + +Then define at least `forgejo_db_password` with a strong and secure password, +encrypted using +[ansible-vault](https://docs.ansible.com/ansible/latest/cli/ansible-vault.html). + + +## Table of Content + + +* [Role variables](#variables) + * [`forgejo_server`](#variable-forgejo_server) + * [`forgejo_version`](#variable-forgejo_version) + * [`forgejo_home_dir`](#variable-forgejo_home_dir) + * [`forgejo_config_dir`](#variable-forgejo_config_dir) + * [`forgejo_web_port`](#variable-forgejo_web_port) + * [`forgejo_ssh_port`](#variable-forgejo_ssh_port) + * [`forgejo_db_username`](#variable-forgejo_db_username) + * [`forgejo_db_password`](#variable-forgejo_db_password) + * [`forgejo_db_database`](#variable-forgejo_db_database) + * [`forgejo_mailer`](#variable-forgejo_mailer) + * [`forgejo_service`](#variable-forgejo_service) + * [`forgejo_manage_iptables`](#variable-forgejo_manage_iptables) + * [`forgejo_allowed_sources`](#variable-forgejo_allowed_sources) + * [`forgejo_runners_version`](#variable-forgejo_runners_version) + * [`forgejo_runners_config_dir`](#variable-forgejo_runners_config_dir) + * [`forgejo_runners_instance`](#variable-forgejo_runners_instance) + * [`forgejo_runners`](#variable-forgejo_runners) + + + +## Role variables + +The following variables can be configured for this role: + +| Variable | Type | Required | Default | Description (abstract) | +|----------|------|----------|---------|------------------------| +| `forgejo_server` | `bool` | No | `true` | Enable the server mode | +| `forgejo_version` | `int` | No | `14` | Version of the Forgejo binaries | +| `forgejo_home_dir` | `path` | No | `"/var/lib/forgejo"` | Path to the home directory | +| `forgejo_config_dir` | `path` | No | `"/etc/forgejo"` | Path to the configuration directory | +| `forgejo_web_port` | `int` | No | `3000` | Port to listen for the web UI | +| `forgejo_ssh_port` | `int` | No | `222` | Port to listen for SSH | +| `forgejo_db_username` | `str` | No | `"forgejo"` | Name of the user in the database | +| `forgejo_db_password` | `str` | Yes | N/A | Password of the user in the database | +| `forgejo_db_database` | `str` | No | `"forgejo"` | Name of the database | +| `forgejo_mailer` | `dict` | No | N/A | Configure the mailer to send e-mail notifications

Define a `enabled` key with a boolean to enable the mailer

Define a `from` key with the source e-mail address

See [Email setup](https://forgejo.org/docs/latest/admin/setup/email/) | +| `forgejo_service` | `dict` | No | N/A | Configure service settings

See [Service](https://forgejo.org/docs/latest/admin/config-cheat-sheet/#service-service) | +| `forgejo_manage_iptables` | `bool` | No | `false` | Configure iptables rules | +| `forgejo_allowed_sources` | `list` | No | N/A | List of IP ranges to allow when `forgejo_manage_iptables` is enabled | +| `forgejo_runners_version` | `str` | No | `"9.1.1"` | Version of the runners | +| `forgejo_runners_config_dir` | `path` | No | `"/etc/forgejo-runners"` | Path to the configuration directory of the runners | +| `forgejo_runners_instance` | `str` | No | N/A | URL of the Forgejo instance to register the runners | +| `forgejo_runners` | `dict` | No | N/A | List of runners to configure

The key is the name of the repository on the instance

The value is a dict with a `token` key and optionally a dict of `labels` | + +### `forgejo_server` + +[*⇑ Back to ToC ⇑*](#toc) + +Enable the server mode + +- **Type**: `bool` +- **Required**: No +- **Default**: `true` + + + +### `forgejo_version` + +[*⇑ Back to ToC ⇑*](#toc) + +Version of the Forgejo binaries + +- **Type**: `int` +- **Required**: No +- **Default**: `14` + + + +### `forgejo_home_dir` + +[*⇑ Back to ToC ⇑*](#toc) + +Path to the home directory + +- **Type**: `path` +- **Required**: No +- **Default**: `"/var/lib/forgejo"` + + + +### `forgejo_config_dir` + +[*⇑ Back to ToC ⇑*](#toc) + +Path to the configuration directory + +- **Type**: `path` +- **Required**: No +- **Default**: `"/etc/forgejo"` + + + +### `forgejo_web_port` + +[*⇑ Back to ToC ⇑*](#toc) + +Port to listen for the web UI + +- **Type**: `int` +- **Required**: No +- **Default**: `3000` + + + +### `forgejo_ssh_port` + +[*⇑ Back to ToC ⇑*](#toc) + +Port to listen for SSH + +- **Type**: `int` +- **Required**: No +- **Default**: `222` + + + +### `forgejo_db_username` + +[*⇑ Back to ToC ⇑*](#toc) + +Name of the user in the database + +- **Type**: `str` +- **Required**: No +- **Default**: `"forgejo"` + + + +### `forgejo_db_password` + +[*⇑ Back to ToC ⇑*](#toc) + +Password of the user in the database + +- **Type**: `str` +- **Required**: Yes + + + +### `forgejo_db_database` + +[*⇑ Back to ToC ⇑*](#toc) + +Name of the database + +- **Type**: `str` +- **Required**: No +- **Default**: `"forgejo"` + + + +### `forgejo_mailer` + +[*⇑ Back to ToC ⇑*](#toc) + +Configure the mailer to send e-mail notifications + +Define a `enabled` key with a boolean to enable the mailer + +Define a `from` key with the source e-mail address + +See [Email setup](https://forgejo.org/docs/latest/admin/setup/email/) + +- **Type**: `dict` +- **Required**: No + + + +### `forgejo_service` + +[*⇑ Back to ToC ⇑*](#toc) + +Configure service settings + +See [Service](https://forgejo.org/docs/latest/admin/config-cheat-sheet/#service-service) + +- **Type**: `dict` +- **Required**: No + + + +### `forgejo_manage_iptables` + +[*⇑ Back to ToC ⇑*](#toc) + +Configure iptables rules + +- **Type**: `bool` +- **Required**: No +- **Default**: `false` + + + +### `forgejo_allowed_sources` + +[*⇑ Back to ToC ⇑*](#toc) + +List of IP ranges to allow when `forgejo_manage_iptables` is enabled + +- **Type**: `list` +- **Required**: No + + + +### `forgejo_runners_version` + +[*⇑ Back to ToC ⇑*](#toc) + +Version of the runners + +- **Type**: `str` +- **Required**: No +- **Default**: `"9.1.1"` + + + +### `forgejo_runners_config_dir` + +[*⇑ Back to ToC ⇑*](#toc) + +Path to the configuration directory of the runners + +- **Type**: `path` +- **Required**: No +- **Default**: `"/etc/forgejo-runners"` + + + +### `forgejo_runners_instance` + +[*⇑ Back to ToC ⇑*](#toc) + +URL of the Forgejo instance to register the runners + +- **Type**: `str` +- **Required**: No + + + +### `forgejo_runners` + +[*⇑ Back to ToC ⇑*](#toc) + +List of runners to configure + +The key is the name of the repository on the instance + +The value is a dict with a `token` key and optionally a dict of `labels` + +- **Type**: `dict` +- **Required**: No + + + + + + +## Usage + +Example of a basic forgejo.yml playbook: + +```yaml +- hosts: forgejo + roles: + - jriou.forgejo +``` + +Then run the playbook: + +``` +ansible-playbook forgejo.yml +``` + +## Runners + +Example of runners configuration: + +```yaml +- hosts: forgejo + roles: + - jriou.forgejo + vars: + forgejo_server: false + forgejo_runners_instance: https://codeberg.org # FIXME + forgejo_runners: + coller: + token: **redacted** + labels: + debian12: docker://data.forgejo.org/oci/debian:bookworm + debian13: docker://data.forgejo.org/oci/debian:trixie + ansible: + token: **redacted** + labels: + docker: docker://data.forgejo.org/oci/node:latest +``` + + +## Donate + +As we all love FOSS projects, you should consider [donating to +Codeberg](https://donate.codeberg.org/), the non-profit organization behind +Forgejo. diff --git a/roles/forgejo_runners/TODO.txt b/roles/forgejo_runners/TODO.txt new file mode 100644 index 0000000..7498d18 --- /dev/null +++ b/roles/forgejo_runners/TODO.txt @@ -0,0 +1 @@ +Focus on runners only diff --git a/roles/forgejo_runners/defaults/main.yml b/roles/forgejo_runners/defaults/main.yml new file mode 100644 index 0000000..1ba666e --- /dev/null +++ b/roles/forgejo_runners/defaults/main.yml @@ -0,0 +1,120 @@ +--- + +# Enable the server mode +# +# - Type: bool +# - Required: No +# - Default: true +forgejo_server: true + +# Version of the Forgejo binaries +# +# - Type: int +# - Required: No +# - Default: 14 +forgejo_version: 14 + +# Path to the home directory +# +# - Type: path +# - Required: No +# - Default: /var/lib/forgejo +forgejo_home_dir: /var/lib/forgejo + +# Path to the configuration directory +# +# - Type: path +# - Required: No +# - Default: /etc/forgejo +forgejo_config_dir: /etc/forgejo + +# Port to listen for the web UI +# +# - Type: int +# - Required: No +# - Default: 3000 +forgejo_web_port: 3000 + +# Port to listen for SSH +# +# - Type: int +# - Required: No +# - Default: 222 +forgejo_ssh_port: 222 + +# Name of the user in the database +# +# - Type: str +# - Required: No +# - Default: forgejo +forgejo_db_username: forgejo + +# Password of the user in the database +# +# - Type: str +# - Required: Yes +forgejo_db_password: CHANGEME + +# Name of the database +# +# - Type: str +# - Required: No +# - Default: forgejo +forgejo_db_database: forgejo + +# Configure the mailer to send e-mail notifications +# +# Define a `enabled` key with a boolean to enable the mailer +# +# Define a `from` key with the source e-mail address +# +# See +# +# - Type: dict +# - Required: No +forgejo_mailer: {} + +# Configure service settings +# +# See +# +# - Type: dict +# - Required: No +forgejo_service: {} + +# Configure iptables rules +# +# - Type: bool +# - Required: No +# - Default: false +forgejo_manage_iptables: false + +# List of IP ranges to allow when `forgejo_manage_iptables` is enabled +# +# - Type: list +# - Required: No +forgejo_allowed_sources: [] + +# Version of the runners +# +# - Type: str +# - Required: No +# - Default: 9.1.1 +forgejo_runners_version: 9.1.1 + +# Path to the configuration directory of the runners +# +# - Type: path +# - Required: No +# - Default: /etc/forgejo-runners +forgejo_runners_config_dir: /etc/forgejo-runners + +# List of runners to configure +# +# The key is the name of the repository on the instance +# +# The value is a dict with a `token` key and optionally a dict of `labels` +# +# - Type: dict +# - Required: No +forgejo_runners: {} diff --git a/roles/forgejo_runners/handlers/main.yml b/roles/forgejo_runners/handlers/main.yml new file mode 100644 index 0000000..e371990 --- /dev/null +++ b/roles/forgejo_runners/handlers/main.yml @@ -0,0 +1,17 @@ +--- +- name: save iptables + ansible.builtin.shell: + cmd: netfilter-persistent save + +- name: start runners + community.docker.docker_compose_v2: + project_src: "{{ forgejo_runners_config_dir }}" + files: + - docker-compose.yml + +- name: restart runners + community.docker.docker_compose_v2: + project_src: "{{ forgejo_runners_config_dir }}" + files: + - docker-compose.yml + state: restarted diff --git a/roles/forgejo_runners/meta/argument_specs.yml b/roles/forgejo_runners/meta/argument_specs.yml new file mode 100644 index 0000000..f50102e --- /dev/null +++ b/roles/forgejo_runners/meta/argument_specs.yml @@ -0,0 +1,30 @@ +--- +argument_specs: + main: + short_description: Install and configure Forgejo runners + description: + - Install and configure [Forgejo](https://forgejo.org/) runners. + author: + - jriou + options: + forgejo_runners_version: + description: + - Version of the runners + default: 9.1.1 + + forgejo_runners_config_dir: + description: + - Path to the configuration directory of the runners + type: path + default: /etc/forgejo-runners + + forgejo_runners_instance: + description: + - URL of the Forgejo instance to register the runners + + forgejo_runners_settings: + description: + - Dict of runners to configure + - The key is the name of the repository on the instance + - The value is a dict with a `token` key and optionally a dict of `labels` + type: dict diff --git a/roles/forgejo_runners/meta/main.yml b/roles/forgejo_runners/meta/main.yml new file mode 100644 index 0000000..94ae890 --- /dev/null +++ b/roles/forgejo_runners/meta/main.yml @@ -0,0 +1,18 @@ +--- +dependencies: +- role: geerlingguy.docker + +galaxy_info: + role_name: jriou.forgejo + author: jriou + description: Ansible role to manage a Forgejo instance + license_file: LICENSE + min_ansible_version: 2.18 + platforms: + - name: Debian + versions: + - bullseye + - bookworm + - trixie + galaxy_tags: + - forgejo diff --git a/roles/forgejo_runners/tasks/deploy-runners.yml b/roles/forgejo_runners/tasks/deploy-runners.yml new file mode 100644 index 0000000..6dc8e02 --- /dev/null +++ b/roles/forgejo_runners/tasks/deploy-runners.yml @@ -0,0 +1,20 @@ +--- +- name: register runners + ansible.builtin.include_tasks: register-runner.yml + loop: "{{ forgejo_runners | dict2items }}" + loop_control: + label: "{{ item.key }}" + +- name: create runners configuration + ansible.builtin.template: + src: "runners/docker-compose.yml.j2" + dest: "{{ forgejo_runners_config_dir }}/docker-compose.yml" + owner: root + group: root + mode: "0644" + +- name: start runners service + community.docker.docker_compose_v2: + project_src: "{{ forgejo_runners_config_dir }}" + files: + - docker-compose.yml diff --git a/roles/forgejo_runners/tasks/deploy-server.yml b/roles/forgejo_runners/tasks/deploy-server.yml new file mode 100644 index 0000000..a2c7dbf --- /dev/null +++ b/roles/forgejo_runners/tasks/deploy-server.yml @@ -0,0 +1,61 @@ +--- +- name: check database password + ansible.builtin.assert: + that: forgejo_db_password is defined + +- name: create directories + ansible.builtin.file: + state: directory + path: "{{ item }}" + owner: forgejo + group: forgejo + mode: "0755" + loop: &forgejo_directories + - "{{ forgejo_config_dir }}" + - "{{ forgejo_home_dir }}" + - "{{ forgejo_home_dir }}/server" + - "{{ forgejo_home_dir }}/db" + +- name: ensure permissions on those directories + ansible.builtin.command: + cmd: "chown -R forgejo:forgejo {{ item }}" + loop: *forgejo_directories + +- name: create docker-compose configuration + ansible.builtin.template: + src: "{{ item.name }}.j2" + dest: "{{ forgejo_config_dir }}/{{ item.name }}" + owner: root + group: root + mode: "{{ item.mode }}" + loop: + - name: docker-compose.yml + mode: "0644" + - name: server.env + mode: "0600" + - name: db.env + mode: "0600" + +- name: start service + community.docker.docker_compose_v2: + project_src: "{{ forgejo_config_dir }}" + files: + - docker-compose.yml + +- name: allow with iptables + ansible.builtin.iptables: + chain: INPUT + protocol: tcp + source: "{{ item }}" + destination_ports: + - "{{ forgejo_web_port }}" + - "{{ forgejo_ssh_port }}" + jump: ACCEPT + comment: forgejo + loop: "{{ forgejo_allowed_sources }}" + notify: save iptables + when: forgejo_manage_iptables + +- name: deploy runners + ansible.builtin.include_tasks: deploy-runners.yml + when: forgejo_runners diff --git a/roles/forgejo_runners/tasks/main.yml b/roles/forgejo_runners/tasks/main.yml new file mode 100644 index 0000000..c845b1c --- /dev/null +++ b/roles/forgejo_runners/tasks/main.yml @@ -0,0 +1,21 @@ +--- +- name: add forgejo user + ansible.builtin.user: + name: forgejo + system: yes + password: '!' + home: "{{ forgejo_home_dir }}" + create_home: no + +- name: read forgejo attributes + ansible.builtin.getent: + database: passwd + key: forgejo + +- name: deploy server + ansible.builtin.include_tasks: deploy-server.yml + when: forgejo_server + +- name: deploy runners + ansible.builtin.include_tasks: deploy-runners.yml + when: forgejo_runners is defined diff --git a/roles/forgejo_runners/tasks/register-runner.yml b/roles/forgejo_runners/tasks/register-runner.yml new file mode 100644 index 0000000..9b63297 --- /dev/null +++ b/roles/forgejo_runners/tasks/register-runner.yml @@ -0,0 +1,39 @@ +--- +- name: check variables + ansible.builtin.assert: + that: + - forgejo_runners_instance is defined + - forgejo_runners_version is defined + - forgejo_runners_config_dir is defined + - "'key' in item" + - "'value' in item" + +- name: create runner subdirectory + ansible.builtin.file: + path: "{{ forgejo_runners_config_dir }}/{{ item.key }}" + state: directory + mode: "0755" + owner: forgejo + group: forgejo + +- name: register runner + ansible.builtin.command: + cmd: >- + docker run + -v /var/run/docker.sock:/var/run/docker.sock + -v {{ forgejo_runners_config_dir }}/{{ item.key }}:/data + --rm + --user {{ ansible_facts.getent_passwd.forgejo[1] }}:{{ ansible_facts.getent_passwd.forgejo[2] }} + code.forgejo.org/forgejo/runner:{{ forgejo_runners_version }} + forgejo-runner register --no-interactive + --token {{ item.value.token }} + --name {{ item.key }} + --instance {{ forgejo_runners_instance }} + creates: "{{ forgejo_runners_config_dir }}/{{ item.key }}/.runner" + notify: start runners + +- name: create runner configuration + ansible.builtin.template: + src: runners/config.yml.j2 + dest: "{{ forgejo_runners_config_dir }}/{{ item.key }}/config.yml" + notify: restart runners diff --git a/roles/forgejo_runners/templates/db.env.j2 b/roles/forgejo_runners/templates/db.env.j2 new file mode 100644 index 0000000..ba5ecbd --- /dev/null +++ b/roles/forgejo_runners/templates/db.env.j2 @@ -0,0 +1,6 @@ +{{ ansible_managed | comment }} +POSTGRES_USER="{{ forgejo_db_username }}" +POSTGRES_PASSWORD="{{ forgejo_db_password }}" +POSTGRES_DB="{{ forgejo_db_database }}" +POSTGRES_INITDB_ARGS="--data-checksums" +POSTGRES_HOST_AUTH_METHOD=scram-sha-256 diff --git a/roles/forgejo_runners/templates/docker-compose.yml.j2 b/roles/forgejo_runners/templates/docker-compose.yml.j2 new file mode 100644 index 0000000..d54e1d7 --- /dev/null +++ b/roles/forgejo_runners/templates/docker-compose.yml.j2 @@ -0,0 +1,35 @@ +--- +{{ ansible_managed | comment }} +services: + server: + image: codeberg.org/forgejo/forgejo:{{ forgejo_version }} + container_name: forgejo-server + env_file: {{ forgejo_config_dir }}/server.env + restart: always + networks: + - forgejo + volumes: + - "{{ forgejo_home_dir }}/server:/data" + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + ports: + - "{{ forgejo_web_port }}:3000" + - "{{ forgejo_ssh_port }}:22" + depends_on: + - db + + db: + image: postgres:17 + hostname: db + container_name: forgejo-db + restart: always + env_file: {{ forgejo_config_dir }}/db.env + user: "{{ ansible_facts.getent_passwd.forgejo[1] }}:{{ ansible_facts.getent_passwd.forgejo[2] }}" + networks: + - forgejo + volumes: + - "{{ forgejo_home_dir }}/db:/var/lib/postgresql/data" + +networks: + forgejo: + external: false diff --git a/roles/forgejo_runners/templates/runners/config.yml.j2 b/roles/forgejo_runners/templates/runners/config.yml.j2 new file mode 100644 index 0000000..39eb084 --- /dev/null +++ b/roles/forgejo_runners/templates/runners/config.yml.j2 @@ -0,0 +1,44 @@ +{{ ansible_managed | comment }} +log: + level: info + job_level: info + +runner: + file: .runner + capacity: 1 + timeout: 3h + shutdown_timeout: 3h + insecure: false + fetch_timeout: 5s + fetch_interval: 2s + report_interval: 1s +{% if item.value.labels | default({}) %} + labels: +{% for label_name, label_value in item.value.labels.items() %} + - "{{ label_name }}:{{ label_value }}" +{% endfor %} +{% endif %} + +cache: + enabled: true + port: 0 + dir: "" + external_server: "" + secret: "" + host: "" + proxy_port: 0 + actions_cache_url_override: "" + +container: + network: "" + enable_ipv6: false + privileged: false + options: + workdir_parent: + valid_volumes: [] + docker_host: "-" + force_pull: false + force_rebuild: false + +host: + workdir_parent: diff --git a/roles/forgejo_runners/templates/runners/docker-compose.yml.j2 b/roles/forgejo_runners/templates/runners/docker-compose.yml.j2 new file mode 100644 index 0000000..a6eb7f5 --- /dev/null +++ b/roles/forgejo_runners/templates/runners/docker-compose.yml.j2 @@ -0,0 +1,27 @@ +--- +{{ ansible_managed | comment }} +services: + docker: + image: docker:dind + privileged: true + restart: always + volumes: + - certs:/certs + +{% for runner in forgejo_runners %} + runner-{{ runner }}: + image: code.forgejo.org/forgejo/runner:{{ forgejo_runners_version }} + user: {{ ansible_facts.getent_passwd.forgejo[1] }}:{{ ansible_facts.getent_passwd.forgejo[2] }} + environment: + DOCKER_HOST: tcp://docker:2376 + DOCKER_TLS_VERIFY: 1 + DOCKER_CERT_PATH: /certs/client + restart: always + volumes: + - {{ forgejo_runners_config_dir }}/{{ runner }}:/data + - certs:/certs + command: 'forgejo-runner --config config.yml daemon' +{% endfor %} + +volumes: + certs: diff --git a/roles/forgejo_runners/templates/server.env.j2 b/roles/forgejo_runners/templates/server.env.j2 new file mode 100644 index 0000000..0bf2d4c --- /dev/null +++ b/roles/forgejo_runners/templates/server.env.j2 @@ -0,0 +1,19 @@ +{{ ansible_managed | comment }} +USER_UID={{ ansible_facts.getent_passwd.forgejo[1] }} +USER_GID={{ ansible_facts.getent_passwd.forgejo[2] }} +FORGEJO__server__SSH_PORT={{ forgejo_ssh_port }} +FORGEJO__database__DB_TYPE=postgres +FORGEJO__database__HOST=db:5432 +FORGEJO__database__NAME="{{ forgejo_db_database }}" +FORGEJO__database__USER="{{ forgejo_db_username }}" +FORGEJO__database__PASSWD="{{ forgejo_db_password }}" +{% if forgejo_mailer %} +{% for k, v in forgejo_mailer.items() %} +FORGEJO__mailer__{{ k | upper }}="{{ v }}" +{% endfor %} +{% endif %} +{% if forgejo_service %} +{% for k, v in forgejo_service.items() %} +FORGEJO__service__{{ k | upper }}="{{ v }}" +{% endfor %} +{% endif %} diff --git a/roles/galene/defaults/main.yml b/roles/galene/defaults/main.yml new file mode 100644 index 0000000..56f3852 --- /dev/null +++ b/roles/galene/defaults/main.yml @@ -0,0 +1,24 @@ +--- +galene_version: galene-1.0 +galene_http_port: 443 +galene_turn: ":1194" +galene_user: galene +galene_group: galene +galene_base_directory: /var/lib/galene +galene_data_directory: "{{ galene_base_directory }}/data" +galene_groups_directory: "{{ galene_base_directory }}/groups" +galene_recording_directory: "{{ galene_base_directory }}/recordings" +galene_static_directory: "{{ galene_base_directory }}/static" +# galene_domain: + +# galene_config: +# canonicalHost: galene.example.org +galene_config: {} + +# galene_groups: +# example: +# users: +# bob: +# password: *** +# permissions: op +galene_groups: {} diff --git a/roles/galene/handlers/main.yml b/roles/galene/handlers/main.yml new file mode 100644 index 0000000..24198bf --- /dev/null +++ b/roles/galene/handlers/main.yml @@ -0,0 +1,9 @@ +--- +- name: Reload systemd + ansible.builtin.systemd_service: + daemon_reload: true + +- name: Restart galene + ansible.builtin.service: + name: galene + state: restarted diff --git a/roles/galene/meta/main.yml b/roles/galene/meta/main.yml new file mode 100644 index 0000000..affff51 --- /dev/null +++ b/roles/galene/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - role: golang diff --git a/roles/galene/tasks/main.yml b/roles/galene/tasks/main.yml new file mode 100644 index 0000000..e8570b4 --- /dev/null +++ b/roles/galene/tasks/main.yml @@ -0,0 +1,116 @@ +--- +# TODO: install in block +- name: Install requirements + ansible.builtin.package: + name: git + +- name: Clone source code + ansible.builtin.git: + repo: https://github.com/jech/galene + dest: /opt/galene + version: "{{ galene_version }}" + +- name: Compile + ansible.builtin.command: + chdir: /opt/galene + cmd: go build -ldflags='-s -w' + creates: /opt/galene/galene + environment: + CGO_ENABLED: "0" + PATH: /usr/local/go/bin + +- name: Install + ansible.builtin.copy: + remote_src: true + src: /opt/galene/galene + dest: /usr/local/bin/galene + owner: root + group: root + mode: "0755" +# TODO End of install in block + +- name: Create user + ansible.builtin.user: + name: "{{ galene_user }}" + system: true + password: '!' + home: "{{ galene_base_directory }}" + create_home: false + +- name: Create directories + ansible.builtin.file: + path: "{{ item }}" + state: directory + owner: "{{ galene_user }}" + group: "{{ galene_group }}" + mode: "0755" + loop: + - "{{ galene_base_directory }}" + - "{{ galene_data_directory }}" + - "{{ galene_groups_directory }}" + - "{{ galene_recording_directory }}" + - "{{ galene_static_directory }}" + +- name: Copy static directory + ansible.builtin.copy: + src: /opt/galene/static/ + dest: "{{ galene_static_directory }}/" + remote_src: true + mode: "0755" + owner: "{{ galene_user }}" + group: "{{ galene_group }}" + when: galene_static_directory != "/opt/galene/static" + +- name: Configure groups + ansible.builtin.copy: + content: "{{ item.value | to_json }}" + dest: "{{ galene_groups_directory }}/{{ item.key }}.json" + owner: "{{ galene_user }}" + group: "{{ galene_group }}" + mode: "0600" + loop: "{{ galene_groups | dict2items }}" + loop_control: + label: "{{ item.key }}" + notify: Restart galene + +- name: Create global configuration + ansible.builtin.copy: + content: "{{ galene_config | to_json }}" + dest: "{{ galene_data_directory }}/config.json" + owner: "{{ galene_user }}" + group: "{{ galene_group }}" + mode: "0600" + notify: Restart galene + +- name: Configure TLS certificates + when: galene_domain is defined + ansible.builtin.copy: + remote_src: true + src: "{{ item.src }}" + dest: "{{ item.dest }}" + owner: "{{ galene_user }}" + group: "{{ galene_group }}" + loop: + - src: "/etc/letsencrypt/live/{{ galene_domain }}/fullchain.pem" + dest: "{{ galene_data_directory }}/cert.pem" + mode: "0644" + - src: "/etc/letsencrypt/live/{{ galene_domain }}/privkey.pem" + dest: "{{ galene_data_directory }}/key.pem" + mode: "0600" + +- name: Create service + ansible.builtin.template: + src: galene.service.j2 + dest: /etc/systemd/system/galene.service + mode: "0644" + owner: root + group: root + notify: + - Reload systemd + - Restart galene + +- name: Start service + ansible.builtin.service: + name: galene + state: started + enabled: true diff --git a/roles/galene/templates/galene.service.j2 b/roles/galene/templates/galene.service.j2 new file mode 100644 index 0000000..5a90399 --- /dev/null +++ b/roles/galene/templates/galene.service.j2 @@ -0,0 +1,19 @@ +{{ ansible_managed | comment }} + +[Unit] +Description=Galene +After=network.target + +[Service] +Type=simple +WorkingDirectory={{ galene_base_directory }} +User={{ galene_user }} +Group={{ galene_group }} +{% if galene_http_port < 1024 %} +AmbientCapabilities=CAP_NET_BIND_SERVICE +{% endif %} +ExecStart=/usr/local/bin/galene -http :{{ galene_http_port }} -data {{ galene_data_directory }} -groups {{ galene_groups_directory }} -recordings {{ galene_recording_directory }} -static {{ galene_static_directory }} -turn "{{ galene_turn }}" +LimitNOFILE=65536 + +[Install] +WantedBy=multi-user.target diff --git a/roles/golang/defaults/main.yml b/roles/golang/defaults/main.yml new file mode 100644 index 0000000..f969c1d --- /dev/null +++ b/roles/golang/defaults/main.yml @@ -0,0 +1,2 @@ +--- +golang_version: 1.25.4 diff --git a/roles/golang/tasks/main.yml b/roles/golang/tasks/main.yml new file mode 100644 index 0000000..6af3007 --- /dev/null +++ b/roles/golang/tasks/main.yml @@ -0,0 +1,7 @@ +--- +- name: Install + ansible.builtin.unarchive: + src: "https://go.dev/dl/go{{ golang_version }}.linux-amd64.tar.gz" + dest: /usr/local + remote_src: true + creates: /usr/local/go diff --git a/roles/navidrome/.gitignore b/roles/navidrome/.gitignore new file mode 100644 index 0000000..5ceb386 --- /dev/null +++ b/roles/navidrome/.gitignore @@ -0,0 +1 @@ +venv diff --git a/roles/navidrome/README.md b/roles/navidrome/README.md new file mode 100644 index 0000000..d00778c --- /dev/null +++ b/roles/navidrome/README.md @@ -0,0 +1,35 @@ +# Ansible Role Navidrome + +Ansible role to manage a [Navidrome](https://github.com/navidrome/navidrome) instance. + +## Configuration + +See [Variable +precedence](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_variables.html#ansible-variable-precedence) +to find where you should put your own variables. + +See list of [default +variables](https://git.riou.xyz/jriou/ansible-role-navidrome/src/branch/main/defaults/main.yml). + +## Usage + +Example of a basic navidrome.yml playbook: + +```yaml +hosts: + - navidrome + +roles: + - navidrome +``` + +Then run the playbook: + +``` +ansible-playbook navidrome.yml +``` + +## Donate + +As we all love FOSS, you should consider sponsoring the +[Navidrome](https://github.com/navidrome/navidrome) project. diff --git a/roles/navidrome/defaults/main.yml b/roles/navidrome/defaults/main.yml new file mode 100644 index 0000000..478998b --- /dev/null +++ b/roles/navidrome/defaults/main.yml @@ -0,0 +1,14 @@ +--- +navidrome_version: 0.54.5 +navidrome_arch: amd64 +navidrome_user: navidrome +navidrome_group: navidrome +navidrome_music_folder: /opt/navidrome/music +navidrome_data_folder: /var/lib/navidrome +navidrome_cache_folder: "{{ navidrome_data_folder }}/cache" +navidrome_manage_iptables: false +navidrome_allowed_sources: [] +navidrome_address: localhost +navidrome_port: 4533 +navidrome_enable_insights_collector: false +# navidrome_base_url: diff --git a/roles/navidrome/handlers/main.yml b/roles/navidrome/handlers/main.yml new file mode 100644 index 0000000..152799e --- /dev/null +++ b/roles/navidrome/handlers/main.yml @@ -0,0 +1,14 @@ +--- +- name: Reload systemd + ansible.builtin.systemd_service: + daemon_reload: true + +- name: Restart navidrome + ansible.builtin.service: + name: navidrome + state: restarted + +- name: Save iptables + ansible.builtin.command: + cmd: netfilter-persistent save + changed_when: true diff --git a/roles/navidrome/tasks/main.yml b/roles/navidrome/tasks/main.yml new file mode 100644 index 0000000..d575f0e --- /dev/null +++ b/roles/navidrome/tasks/main.yml @@ -0,0 +1,62 @@ +--- +- name: Install package + ansible.builtin.apt: + deb: "https://github.com/navidrome/navidrome/releases/download/v{{ navidrome_version }}/navidrome_{{ navidrome_version }}_linux_{{ navidrome_arch }}.deb" + +- name: Create directories + ansible.builtin.file: + state: directory + path: "{{ item }}" + owner: "{{ navidrome_user }}" + group: "{{ navidrome_group }}" + mode: "0755" + loop: + - "{{ navidrome_music_folder }}" + - "{{ navidrome_data_folder }}" + - "{{ navidrome_cache_folder }}" + +- name: Create configuration file + ansible.builtin.template: + src: navidrome.toml.j2 + dest: /etc/navidrome/navidrome.toml + owner: "{{ navidrome_user }}" + group: "{{ navidrome_group }}" + mode: "0644" + notify: + - Restart navidrome + +- name: Create systemd override directory + ansible.builtin.file: + state: directory + path: /etc/systemd/system/navidrome.service.d + owner: root + group: root + mode: "0755" + +- name: Add systemd override + ansible.builtin.template: + src: override.conf.j2 + dest: /etc/systemd/system/navidrome.service.d/override.conf + owner: root + group: root + mode: "0755" + notify: + - Reload systemd + - Restart navidrome + +- name: Start service + ansible.builtin.service: + name: navidrome + state: started + +- name: Manage iptables + ansible.builtin.iptables: + chain: INPUT + protocol: tcp + source: "{{ item }}" + destination_port: "{{ navidrome_port }}" + jump: ACCEPT + comment: navidrome + loop: "{{ navidrome_allowed_sources }}" + notify: Save iptables + when: navidrome_manage_iptables diff --git a/roles/navidrome/templates/navidrome.toml.j2 b/roles/navidrome/templates/navidrome.toml.j2 new file mode 100644 index 0000000..2b6492b --- /dev/null +++ b/roles/navidrome/templates/navidrome.toml.j2 @@ -0,0 +1,10 @@ +{{ ansible_managed | comment }} +MusicFolder = "{{ navidrome_music_folder }}" +DataFolder = "{{ navidrome_data_folder }}" +CacheFolder = "{{ navidrome_cache_folder }}" +Address = "{{ navidrome_address }}" +Port = "{{ navidrome_port }}" +EnableInsightsCollector = "{{ navidrome_enable_insights_collector }}" +{% if navidrome_base_url is defined %} +BaseUrl = "{{ navidrome_base_url }}" +{% endif %} diff --git a/roles/navidrome/templates/override.conf.j2 b/roles/navidrome/templates/override.conf.j2 new file mode 100644 index 0000000..371ef28 --- /dev/null +++ b/roles/navidrome/templates/override.conf.j2 @@ -0,0 +1,5 @@ +{{ ansible_managed | comment }} +[Service] +User={{ navidrome_user }} +WorkingDirectory={{ navidrome_data_folder }} +ReadWritePaths={{ navidrome_data_folder }}