diff --git a/.ansible-lint b/.ansible-lint new file mode 100644 index 0000000..5578e18 --- /dev/null +++ b/.ansible-lint @@ -0,0 +1,117 @@ +--- +# .ansible-lint + +profile: null # min, basic, moderate,safety, shared, production + +# exclude_paths included in this file are parsed relative to this file's location +# and not relative to the CWD of execution. CLI arguments passed to the --exclude +# option are parsed relative to the CWD of execution. +exclude_paths: + - .cache/ # implicit unless exclude_paths is defined in config + - .github/ + - test/fixtures/formatting-before/ + - test/fixtures/formatting-prettier/ +# parseable: true +# quiet: true +# strict: true +# verbosity: 1 + +# Mock modules or roles in order to pass ansible-playbook --syntax-check +mock_modules: + - zuul_return + # note the foo.bar is invalid as being neither a module or a collection + - fake_namespace.fake_collection.fake_module + - fake_namespace.fake_collection.fake_module.fake_submodule +mock_roles: + - mocked_role + - author.role_name # old standalone galaxy role + - fake_namespace.fake_collection.fake_role # role within a collection + +# Enable checking of loop variable prefixes in roles +# loop_var_prefix: "{role}_" + +# Enforce variable names to follow pattern below, in addition to Ansible own +# requirements, like avoiding python identifiers. To disable add `var-naming` +# to skip_list. +# var_naming_pattern: "^[a-z_][a-z0-9_]*$" + +use_default_rules: true +# Load custom rules from this specific folder +# rulesdir: +# - ./rule/directory/ + +# Ansible-lint completely ignores rules or tags listed below +# skip_list: + # - skip_this_tag + +# Ansible-lint does not automatically load rules that have the 'opt-in' tag. +# You must enable opt-in rules by listing each rule 'id' below. +enable_list: + - empty-string-compare # opt-in + - no-log-password # opt-in + - no-same-owner # opt-in + # add yaml here if you want to avoid ignoring yaml checks when yamllint + # library is missing. Normally its absence just skips using that rule. + - yaml +# Report only a subset of tags and fully ignore any others +# tags: +# - jinja[spacing] + +# Ansible-lint does not fail on warnings from the rules or tags listed below +warn_list: + - skip_this_tag + - experimental # experimental is included in the implicit list + # - role-name + # - yaml[document-start] # you can also use sub-rule matches + +skip_list: + - fqcn[action-core] + - fqcn[action] + +# Some rules can transform files to fix (or make it easier to fix) identified +# errors. `ansible-lint --write` will reformat YAML files and run these transforms. +# By default it will run all transforms (effectively `write_list: ["all"]`). +# You can disable running transforms by setting `write_list: ["none"]`. +# Or only enable a subset of rule transforms by listing rules/tags here. +# write_list: +# - all + +# Offline mode disables installation of requirements.yml +offline: false + +# Return success if number of violations compared with previous git +# commit has not increased. This feature works only in git +# repositories. +progressive: false + +# Define required Ansible's variables to satisfy syntax check +extra_vars: + foo: bar + multiline_string_variable: | + line1 + line2 + complex_variable: ":{;\t$()" + +# Uncomment to enforce action validation with tasks, usually is not +# needed as Ansible syntax check also covers it. +# skip_action_validation: false + +# List of additional kind:pattern to be added at the top of the default +# match list, first match determines the file kind. +kinds: + # - playbook: "**/examples/*.{yml,yaml}" + # - galaxy: "**/folder/galaxy.yml" + # - tasks: "**/tasks/*.yml" + # - vars: "**/vars/*.yml" + # - meta: "**/meta/main.yml" + - yaml: "**/*.yaml-too" + +# List of additional collections to allow in only-builtins rule. +# only_builtins_allow_collections: +# - example_ns.example_collection + +# List of additions modules to allow in only-builtins rule. +# only_builtins_allow_modules: +# - example_module + +# vim:ft=yaml diff --git a/roles/docker/defaults/main.yml b/roles/docker/defaults/main.yml index 6d5cdd0..f095654 100644 --- a/roles/docker/defaults/main.yml +++ b/roles/docker/defaults/main.yml @@ -1,16 +1,17 @@ --- base_domain: sapti.me -base_volume_folder: /opt/storage/apps +base_volume: /opt/storage/apps +timezone: Europe/Copenhagen services: caddy: file: caddy.yml - volume: "{{ base_volume_folder }}/caddy" + volume: "{{ base_volume }}/caddy" version: 2-alpine watchtower: file: watchtower.yml - version: latest + version: arm64v8-1.5.1 restic: file: restic.yml @@ -20,7 +21,7 @@ services: nextcloud: file: nextcloud.yml domain: "cloud.{{ base_domain }}" - volume: "{{ base_volume_folder }}/nextcloud" + volume: "{{ base_volume }}/nextcloud" version: 25-apache mariadb_version: 10 redis_version: 7-alpine @@ -28,18 +29,20 @@ services: emby: file: emby.yml domain: "watch.{{ base_domain }}" - volume: "{{ base_volume_folder }}/emby" + volume: "{{ base_volume }}/emby" version: latest monerod: file: monerod.yml domain: "xmr.{{ base_domain }}" - version: latest + version: alpine wireguard: file: wireguard.yml domain: "wg01.vpn.{{ base_domain }}" - version: latest + volume: "{{ base_volume }}/wireguard" + port: 51820 + version: arm64v8-alpine snowflake: file: snowflake.yml diff --git a/roles/docker/tasks/main.yml b/roles/docker/tasks/main.yml index 355e883..b0ca16c 100644 --- a/roles/docker/tasks/main.yml +++ b/roles/docker/tasks/main.yml @@ -9,12 +9,21 @@ apt_repository: repo: 'deb [arch=arm64] https://download.docker.com/linux/ubuntu focal stable' state: present - update_cache: yes + update_cache: true - name: Install Docker apt: - name: docker-ce + name: "{{ item }}" state: present + loop: + - docker-ce + - docker-compose-plugin + +- name: Create docker-compose symlink + file: + src: /usr/libexec/docker/cli-plugins/docker-compose + name: /usr/local/bin/docker-compose + state: link - name: Install Python bindings for Docker Compose pip: @@ -24,7 +33,9 @@ - name: Create base directory for Docker volumes file: - name: "{{ base_volume_folder }}" + name: "{{ base_volume }}" + owner: "{{ ansible_user }}" + mode: u=rwx,g=rx,o=rx state: directory - name: Set up Docker services diff --git a/roles/docker/tasks/services.yml b/roles/docker/tasks/services.yml index 1ddb854..d5dd6fc 100644 --- a/roles/docker/tasks/services.yml +++ b/roles/docker/tasks/services.yml @@ -1,8 +1,4 @@ --- -- name: Create Docker network for services - docker_network: - name: services - - name: Deploy services include_tasks: "services/{{ item.service.file }}" loop: "{{ services | dict2items(value_name='service') }}" diff --git a/roles/docker/tasks/services/caddy.yml b/roles/docker/tasks/services/caddy.yml new file mode 100644 index 0000000..27d2f2d --- /dev/null +++ b/roles/docker/tasks/services/caddy.yml @@ -0,0 +1,33 @@ +--- +- name: Create Caddy volume directories + file: + name: "{{ services.caddy.volume }}/{{ dir }}" + mode: u=rwx,g=rx,o=rx + state: directory + loop: + - config + - data + loop_control: + loop_var: dir + +- name: Copy Caddyfile + template: + src: Caddyfile.j2 + dest: "{{ services.caddy.volume }}/Caddyfile" + mode: u=rw,g=r,o=r + +- name: Deploy Caddy Docker container + docker_container: + name: caddy + image: "caddy:{{ services.caddy.version }}" + restart_policy: unless-stopped + network_mode: host + volumes: + - "{{ services.caddy.volume }}/Caddyfile:/etc/caddy/Caddyfile:ro" + - "{{ services.caddy.volume }}/config:/config:rw" + - "{{ services.caddy.volume }}/data:/data:rw" + capabilities: + - net_bind_service + - dac_override + cap_drop: + - all diff --git a/roles/docker/tasks/services/emby.yml b/roles/docker/tasks/services/emby.yml new file mode 100644 index 0000000..9b4868f --- /dev/null +++ b/roles/docker/tasks/services/emby.yml @@ -0,0 +1,30 @@ +--- +- name: Create Emby volume directories + file: + name: "{{ services.emby.volume }}/{{ dir }}" + owner: "{{ ansible_user }}" + mode: u=rwx,g=rx,o=rx + state: directory + loop: + - programdata + - tvshows + - movies + loop_control: + loop_var: dir + +- name: Deploy Emby Docker container + docker_container: + name: emby + image: "emby/embyserver_arm64v8:{{ services.emby.version }}" + restart_policy: unless-stopped + env: + UID: 1000 + GID: 1000 + volumes: + - "{{ services.emby.volume }}/programdata:/config:rw" + - "{{ services.emby.volume }}/tvshows:/mnt/share1:rw" + - "{{ services.emby.volume }}/movies:/mnt/share2:rw" + published_ports: + - "8096:8096" + devices: + - /dev/vchiq:/dev/vchiq # MMAL/OMX on Raspberry Pi diff --git a/roles/docker/tasks/services/monerod.yml b/roles/docker/tasks/services/monerod.yml new file mode 100644 index 0000000..179e790 --- /dev/null +++ b/roles/docker/tasks/services/monerod.yml @@ -0,0 +1,21 @@ +--- +- name: Create Docker volume for Monero blockchain data + docker_volume: + volume_name: monerod_data + +- name: Deploy Monero node Docker container + docker_container: + name: monerod + image: "sethsimmons/simple-monerod:{{ services.monerod.version }}" + restart_policy: unless-stopped + volumes: + - monerod_data:/home/monero/.bitmonero:rw + command: + - --rpc-restricted-bind-ip=0.0.0.0 + - --rpc-restricted-bind-port=18089 + - --no-igd + - --no-zmq + - --enable-dns-blocklist + published_ports: + - "18080:18080" + - "127.0.0.1:18081:18089" diff --git a/roles/docker/tasks/services/nextcloud.yml b/roles/docker/tasks/services/nextcloud.yml index 6eec0a1..2f87ed6 100644 --- a/roles/docker/tasks/services/nextcloud.yml +++ b/roles/docker/tasks/services/nextcloud.yml @@ -1,19 +1,21 @@ --- - name: Create Nextcloud volume directories file: - name: "{{ services.nextcloud.volume }}/{{ name }}" + name: "{{ services.nextcloud.volume }}/{{ dir }}" + mode: u=rwx,g=rx,o=rx state: directory loop: + - apache2 - data - db - - apache2 loop_control: - loop_var: name + loop_var: dir - name: Copy Apache2 config files copy: src: "nextcloud/apache2/{{ file }}" dest: "{{ services.nextcloud.volume }}/apache2/{{ file }}" + mode: u=rw,g=r,o=r loop: - apache2.conf - remoteip.conf @@ -37,12 +39,12 @@ - --binlog-format=ROW - --innodb_read_only_compressed=OFF environment: - MYSQL_DATABASE: "{{ secrets.nextcloud.mysql.db }}" - MYSQL_USER: "{{ secrets.nextcloud.mysql.user }}" + MYSQL_DATABASE: nextcloud + MYSQL_USER: nextcloud MYSQL_PASSWORD: "{{ secrets.nextcloud.mysql.pw }}" MYSQL_ROOT_PASSWORD: "{{ secrets.nextcloud.mysql.pw }}" volumes: - - "{{ services.nextcloud.volume }}/db:/var/lib/mysql" + - "{{ services.nextcloud.volume }}/db:/var/lib/mysql:rw" redis: image: "redis:{{ services.nextcloud.redis_version }}" @@ -56,7 +58,7 @@ restart: unless-stopped entrypoint: /cron.sh volumes: - - "{{ services.nextcloud.volume }}/data:/var/www/html" + - "{{ services.nextcloud.volume }}/data:/var/www/html:rw" depends_on: - mysql - redis @@ -74,7 +76,7 @@ PHP_MEMORY_LIMIT: 2G PHP_UPLOAD_LIMIT: 16G volumes: - - "{{ services.nextcloud.volume }}/data:/var/www/html" + - "{{ services.nextcloud.volume }}/data:/var/www/html:rw" - "{{ services.nextcloud.volume }}/apache2/apache2.conf:/etc/apache2/apache2.conf:ro" - "{{ services.nextcloud.volume }}/apache2/remoteip.conf:/etc/apache2/conf-enabled/remoteip.conf:ro" ports: diff --git a/roles/docker/tasks/services/restic.yml b/roles/docker/tasks/services/restic.yml index f0beeb8..538b3bb 100644 --- a/roles/docker/tasks/services/restic.yml +++ b/roles/docker/tasks/services/restic.yml @@ -27,12 +27,11 @@ --keep-monthly 12 B2_ACCOUNT_ID: "{{ secrets.restic.b2.id }}" B2_ACCOUNT_KEY: "{{ secrets.restic.b2.key }}" - TZ: Europe/Copenhagen + TZ: "{{ timezone }}" volumes: - - ./caddy:/mnt/volumes/caddy:ro - - ./nextcloud:/mnt/volumes/nextcloud:ro - networks: - restic: + - "{{ services.caddy.volume }}:/mnt/volumes/caddy:ro" + - "{{ services.nextcloud.volume }}:/mnt/volumes/nextcloud:ro" + - "{{ services.emby.volume }}/programdata:/mnt/volumes/emby/programdata:ro" restic_prune: image: "mazzolino/restic:{{ services.restic.version }}" @@ -46,20 +45,18 @@ --verbose B2_ACCOUNT_ID: "{{ secrets.restic.b2.id }}" B2_ACCOUNT_KEY: "{{ secrets.restic.b2.key }}" - TZ: Europe/Copenhagen - networks: - restic: + TZ: "{{ timezone }}" restic_check: image: "mazzolino/restic:{{ services.restic.version }}" restart: unless-stopped environment: RUN_ON_STARTUP: false - CHECK_CRON: '0 15 5 * * *' + CHECK_CRON: '0 30 4 * * *' RESTIC_REPOSITORY: "b2:{{ secrets.restic.b2.bucket }}:{{ services.restic.repo }}" RESTIC_PASSWORD: "{{ secrets.restic.pw }}" RESTIC_CHECK_ARGS: >- --verbose B2_ACCOUNT_ID: "{{ secrets.restic.b2.id }}" B2_ACCOUNT_KEY: "{{ secrets.restic.b2.key }}" - TZ: Europe/Copenhagen + TZ: "{{ timezone }}" diff --git a/roles/docker/tasks/services/snowflake.yml b/roles/docker/tasks/services/snowflake.yml new file mode 100644 index 0000000..d86cdd1 --- /dev/null +++ b/roles/docker/tasks/services/snowflake.yml @@ -0,0 +1,7 @@ +--- +- name: Deploy snowflake-proxy Docker container + docker_container: + name: snowflake-proxy + image: "thetorproject/snowflake-proxy:{{ services.snowflake.version }}" + restart_policy: unless-stopped + network_mode: host diff --git a/roles/docker/tasks/services/watchtower.yml b/roles/docker/tasks/services/watchtower.yml new file mode 100644 index 0000000..ef79d97 --- /dev/null +++ b/roles/docker/tasks/services/watchtower.yml @@ -0,0 +1,10 @@ +--- +- name: Deploy Watchtower Docker container + docker_container: + name: watchtower + image: "containrrr/watchtower:{{ services.watchtower.version }}" + restart_policy: unless-stopped + env: + WATCHTOWER_POLL_INTERVAL: 3600 + volumes: + - /var/run/docker.sock:/var/run/docker.sock:rw diff --git a/roles/docker/tasks/services/wireguard.yml b/roles/docker/tasks/services/wireguard.yml new file mode 100644 index 0000000..d721554 --- /dev/null +++ b/roles/docker/tasks/services/wireguard.yml @@ -0,0 +1,28 @@ +--- +- name: Create Wireguard volume directory + file: + name: "{{ services.wireguard.volume }}" + mode: u=rwx,g=rx,o=rx + state: directory + +- name: Deploy Wireguard Docker container + docker_container: + name: wireguard + image: "linuxserver/wireguard:{{ services.wireguard.version }}" + restart_policy: unless-stopped + env: + SERVERURL: "{{ services.wireguard.domain }}" + SERVERPORT: "{{ services.wireguard.port }}" + PEERS: "{{ secrets.wireguard.peers }}" + PEERDNS: auto + TZ: "{{ timezone }}" + volumes: + - "{{ services.wireguard.volume }}:/config:rw" + - /lib/modules:/lib/modules:rw + published_ports: + - "{{ services.wireguard.port }}:{{ services.wireguard.port }}/udp" + capabilities: + - net_admin + - sys_module + sysctls: + net.ipv4.conf.all.src_valid_mark: 1