From 886e83baa86c6eedfb6b9b9e41fc55cf4f34c360 Mon Sep 17 00:00:00 2001 From: Saibotk Date: Thu, 12 Sep 2024 22:51:50 +0200 Subject: [PATCH] feat(caddy): add role Copied from Histalek <3 Based on https://git.histalek.de/histalek-de/infrastructure/-/tree/b17a8f117bd2ce6e7b9c64dcffb2f24294306519/roles/caddy --- playbooks/caddy.yml | 12 +++ roles/caddy/defaults/main.yml | 18 ++++ roles/caddy/handlers/main.yml | 19 ++++ roles/caddy/meta/main.yml | 18 ++++ roles/caddy/tasks/main.yml | 109 +++++++++++++++++++++++ roles/caddy/templates/Caddyfile.j2 | 21 +++++ roles/caddy/templates/caddy.container.j2 | 50 +++++++++++ roles/caddy/templates/caddy.network.j2 | 6 ++ 8 files changed, 253 insertions(+) create mode 100644 playbooks/caddy.yml create mode 100644 roles/caddy/defaults/main.yml create mode 100644 roles/caddy/handlers/main.yml create mode 100644 roles/caddy/meta/main.yml create mode 100644 roles/caddy/tasks/main.yml create mode 100644 roles/caddy/templates/Caddyfile.j2 create mode 100644 roles/caddy/templates/caddy.container.j2 create mode 100644 roles/caddy/templates/caddy.network.j2 diff --git a/playbooks/caddy.yml b/playbooks/caddy.yml new file mode 100644 index 0000000..00b0555 --- /dev/null +++ b/playbooks/caddy.yml @@ -0,0 +1,12 @@ +- name: Install Caddy. + + hosts: caddy + + roles: + - role: podman + become: true + tags: + - always + - podman + - role: caddy + become: true diff --git a/roles/caddy/defaults/main.yml b/roles/caddy/defaults/main.yml new file mode 100644 index 0000000..14d6940 --- /dev/null +++ b/roles/caddy/defaults/main.yml @@ -0,0 +1,18 @@ +caddy_install_dir: /opt/caddy + +caddy_container_image: docker.io/library/caddy +# renovate: depName=docker.io/library/caddy +caddy_image_tag: "2.8.4-alpine" + +caddy_selinux_level: "{{ omit }}" + +caddy_memory_high: 0 +caddy_memory_low: 128m +caddy_swap_max: -1 + +caddy_letsencrypt_email: no-reply@example.com +# possible values: ed25519|p256|p384|rsa2048|rsa4096 +caddy_letsencrypt_key_type: rsa4096 +caddy_letsencrypt_ca_server: https://acme-staging-v02.api.letsencrypt.org/directory + +caddy_log_level: warn diff --git a/roles/caddy/handlers/main.yml b/roles/caddy/handlers/main.yml new file mode 100644 index 0000000..c895c3d --- /dev/null +++ b/roles/caddy/handlers/main.yml @@ -0,0 +1,19 @@ +- name: Apply new SELinux file context to filesystem. + ansible.builtin.command: "restorecon -irF {{ caddy_install_dir }}" + become: true + listen: "caddy selinux context changed" + +- name: Restart caddy service. + ansible.builtin.systemd: + state: restarted + name: "caddy" + daemon_reload: true + become: true + listen: "caddy service changed" + +- name: Reload caddy service. + ansible.builtin.systemd: + state: reloaded + name: "caddy" + become: true + listen: "caddy config changed" diff --git a/roles/caddy/meta/main.yml b/roles/caddy/meta/main.yml new file mode 100644 index 0000000..ea68d9e --- /dev/null +++ b/roles/caddy/meta/main.yml @@ -0,0 +1,18 @@ +galaxy_info: + author: histalek + description: Deploy Caddy with podman and systemd. + + issue_tracker_url: https://git.histalek.de/histalek-de/infrastructure/-/issues + + license: GPL-3.0-only + + min_ansible_version: "2.14" + + platforms: + - name: Fedora + versions: + - "38" + - "39" + - "40" + + standalone: true diff --git a/roles/caddy/tasks/main.yml b/roles/caddy/tasks/main.yml new file mode 100644 index 0000000..4bdf8c3 --- /dev/null +++ b/roles/caddy/tasks/main.yml @@ -0,0 +1,109 @@ +- name: Update default SELinux contexts. + community.general.sefcontext: + target: "{{ item }}(/.*)?" + setype: "container_file_t" + selevel: "{{ caddy_selinux_level }}" + state: present + loop: + - "{{ caddy_install_dir }}/config" + - "{{ caddy_install_dir }}/data" + - "{{ caddy_install_dir }}/srv" + become: true + notify: "caddy selinux context changed" + +- name: Create caddy directories. + ansible.builtin.file: + path: "{{ caddy_install_dir }}" + state: directory + mode: "0700" + owner: "root" + group: "root" + become: true + +- name: Ensure caddy directories and configs exist. + block: + - name: Stat caddy config directory. + ansible.builtin.stat: + path: "{{ caddy_install_dir }}/config" + become: true + register: caddy_stat_config_dir + + - name: Create caddy directories. + ansible.builtin.file: + path: "{{ item.path }}" + state: directory + owner: "{{ caddy_stat_config_dir.stat.uid | default('root') }}" + group: "{{ caddy_stat_config_dir.stat.gid | default('root') }}" + mode: "0700" + loop: + - path: "{{ caddy_install_dir }}/config" + - path: "{{ caddy_install_dir }}/data" + - path: "{{ caddy_install_dir }}/srv" + become: true + + - name: Deploy caddy configs. + ansible.builtin.template: + src: Caddyfile.j2 + dest: "{{ caddy_install_dir }}/config/Caddyfile" + mode: "0600" + owner: "{{ caddy_stat_config_dir.stat.uid | default('root') }}" + group: "{{ caddy_stat_config_dir.stat.gid | default('root') }}" + become: true + notify: "caddy config changed" + +- name: Ensure container image is present on the host. + containers.podman.podman_image: + name: "{{ caddy_container_image }}" + state: present + tag: "{{ caddy_image_tag }}" + become: true + +- name: Allow http and https. + ansible.posix.firewalld: + service: "{{ item }}" + zone: public + permanent: true + immediate: true + state: enabled + loop: + - http + - https + become: true + +# Ref: https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes +- name: Set maximum udp send/receive buffer size to around 2,5MB for quic. + ansible.posix.sysctl: + name: "{{ item.name }}" + value: 2500000 + sysctl_set: true + state: present + reload: true + loop: + - name: net.core.rmem_max + - name: net.core.wmem_max + become: true + +- name: Create caddy container / network file. + ansible.builtin.template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + owner: "root" + group: "root" + mode: "0644" + loop: + - src: caddy.container.j2 + dest: /etc/containers/systemd/caddy.container + - src: caddy.network.j2 + dest: /etc/containers/systemd/caddy.network + become: true + notify: "caddy service changed" + +- name: Flush handlers. + ansible.builtin.meta: flush_handlers + +- name: Start and enable caddy service. + ansible.builtin.systemd: + state: started + enabled: true + name: "caddy" + become: true diff --git a/roles/caddy/templates/Caddyfile.j2 b/roles/caddy/templates/Caddyfile.j2 new file mode 100644 index 0000000..bbd5c80 --- /dev/null +++ b/roles/caddy/templates/Caddyfile.j2 @@ -0,0 +1,21 @@ +{ + admin + persist_config off + log { + output stdout + format console + level warn + } + + email {{ caddy_letsencrypt_email }} + skip_install_trust + acme_ca {{ caddy_letsencrypt_ca_server }} + key_type {{ caddy_letsencrypt_key_type }} + + servers { + # metrics + strict_sni_host + } +} + +import /config/*.caddy diff --git a/roles/caddy/templates/caddy.container.j2 b/roles/caddy/templates/caddy.container.j2 new file mode 100644 index 0000000..3f903b1 --- /dev/null +++ b/roles/caddy/templates/caddy.container.j2 @@ -0,0 +1,50 @@ +{{ ansible_managed | comment }} + +[Unit] +Description=Caddy reverse proxy + +[Service] +Restart=always +RestartSec=5s + +ExecReload=/usr/bin/podman exec \ + -w /config \ + caddy \ + caddy reload + +[Container] +Image={{ caddy_container_image }}:{{ caddy_image_tag }} +ContainerName=caddy + +Exec=caddy run \ + --config /config/Caddyfile \ + --adapter caddyfile + +AutoUpdate=registry +LogDriver=journald + +NoNewPrivileges=true +ReadOnly=true +DropCapability=all +AddCapability=CAP_NET_BIND_SERVICE +UserNS=auto:size=65535 +{% if caddy_selinux_level != omit %} +SecurityLabelLevel={{ caddy_selinux_level }} +{% endif %} + +Network=caddy.network + +PublishPort=80:80/tcp +PublishPort=443:443/tcp +PublishPort=443:443/udp + +Volume={{ caddy_install_dir }}/config:/config:ro,U +Volume={{ caddy_install_dir }}/data:/data:U +Volume={{ caddy_install_dir }}/srv:/srv:U + +PodmanArgs=--memory={{ caddy_memory_high }} +PodmanArgs=--memory-swap={{ caddy_swap_max }} +PodmanArgs=--memory-reservation={{ caddy_memory_low }} + +[Install] +WantedBy=default.target diff --git a/roles/caddy/templates/caddy.network.j2 b/roles/caddy/templates/caddy.network.j2 new file mode 100644 index 0000000..c8fcd68 --- /dev/null +++ b/roles/caddy/templates/caddy.network.j2 @@ -0,0 +1,6 @@ +{{ ansible_managed | comment }} + +[Network] +NetworkName=caddy_reverseproxy +Driver=bridge +IPv6=true