diff --git a/roles/caddy/defaults/main.yml b/roles/caddy/defaults/main.yml new file mode 100644 index 0000000..3d9f6ff --- /dev/null +++ b/roles/caddy/defaults/main.yml @@ -0,0 +1,11 @@ +--- +# file: roles/caddy/defaults/main.yml + +# parent directory of vhost document roots +caddy_root_prefix: /var/www + +# Email address to use for the ACME account managing the site's certificates. +# Not sure what Caddy does if this doesn't exist. +caddy_email: foo@example.com + +# vim: set ts=2 sw=2: diff --git a/roles/caddy/handlers/main.yml b/roles/caddy/handlers/main.yml new file mode 100644 index 0000000..fa793bf --- /dev/null +++ b/roles/caddy/handlers/main.yml @@ -0,0 +1,10 @@ +--- +# file: roles/caddy/handlers/main.yml + +# I'm currently not sure when we need to restart versus reload +- name: reload caddy + ansible.builtin.systemd: + name: caddy + state: reloaded + +# vim: set sw=2 ts=2: diff --git a/roles/caddy/tasks/main.yml b/roles/caddy/tasks/main.yml new file mode 100644 index 0000000..dfe43e7 --- /dev/null +++ b/roles/caddy/tasks/main.yml @@ -0,0 +1,83 @@ +--- +# file: roles/caddy/tasks/main.yml +# +# Configure Caddy. + +- name: Check Caddy package signing key + ansible.builtin.stat: + path: /etc/apt/keyrings/caddy-stable-archive-keyring.key + register: caddy_signing_key_stat + tags: + - packages + - caddy + +# See: https://caddyserver.com/docs/install#debian-ubuntu-raspbian +- name: Download Caddy package signing key + ansible.builtin.get_url: + url: https://dl.cloudsmith.io/public/caddy/stable/gpg.key + dest: /etc/apt/keyrings/caddy-stable-archive-keyring.key + owner: root + group: root + mode: 0644 + register: download_caddy_signing_key + when: not caddy_signing_key_stat.stat.exists + tags: + - packages + - caddy + +- name: Add Caddy stable repo + ansible.builtin.apt_repository: + repo: 'deb [signed-by=/etc/apt/keyrings/caddy-stable-archive-keyring.key] https://dl.cloudsmith.io/public/caddy/stable/deb/debian any-version main' + filename: caddy-stable + state: present + register: add_caddy_apt_repository + tags: + - packages + - caddy + +- name: Update apt cache + ansible.builtin.apt: # noqa no-handler + update_cache: true + when: + (download_caddy_signing_key.status_code is defined and download_caddy_signing_key.status_code == 200) or + add_caddy_apt_repository is changed + tags: + - packages + - caddy + +- name: Install Caddy + ansible.builtin.apt: + name: caddy + state: present + install_recommends: false + cache_valid_time: 3600 + tags: + - caddy + - packages + +- name: Create Caddyfile + ansible.builtin.template: + src: etc/caddy/Caddyfile.j2 + dest: /etc/caddy/Caddyfile + mode: 0755 + owner: root + group: root + notify: + - reload caddy + tags: caddy + +- name: Create Caddy conf.d directory + ansible.builtin.file: + path: /etc/caddy/conf.d + state: directory + mode: 0755 + owner: root + group: root + +# TODO: the variable is still named nginx_vhosts +- name: Configure Caddy virtual hosts + ansible.builtin.include_tasks: vhosts.yml + when: nginx_vhosts is defined + tags: caddy + +# vim: set sw=2 ts=2: diff --git a/roles/caddy/tasks/vhosts.yml b/roles/caddy/tasks/vhosts.yml new file mode 100644 index 0000000..baf9303 --- /dev/null +++ b/roles/caddy/tasks/vhosts.yml @@ -0,0 +1,15 @@ +--- + +- name: Configure vhosts + ansible.builtin.template: + src: etc/caddy/conf.d/vhost.j2 + dest: /etc/caddy/conf.d/{{ item.domain_name }} + mode: 0644 + owner: root + group: root + loop: "{{ nginx_vhosts }}" + notify: + - reload caddy + tags: caddy + +# vim: set ts=2 sw=2: diff --git a/roles/caddy/templates/etc/caddy/Caddyfile.j2 b/roles/caddy/templates/etc/caddy/Caddyfile.j2 new file mode 100644 index 0000000..e0a067d --- /dev/null +++ b/roles/caddy/templates/etc/caddy/Caddyfile.j2 @@ -0,0 +1,29 @@ +# Global options +{ + email {{ caddy_email }} +} + +# Common security response headers +(security-headers) { + header { + # disable Google FLoC tracking + Permissions-Policy interest-cohort=() + + # enable HSTS + Strict-Transport-Security max-age=31536000 + + # disable clients from sniffing the media type + X-Content-Type-Options nosniff + + # clickjacking protection: refuse to allow rendering this page + # in a frame, iframe, etc. + X-Frame-Options DENY + + # keep referrer data off of HTTP connections + Referrer-Policy no-referrer-when-downgrade + } +} + +# Import additional caddy config files in /etc/caddy/conf.d/ +# Note: these are imported in lexical sort order! +import /etc/caddy/conf.d/* diff --git a/roles/caddy/templates/etc/caddy/conf.d/vhost.j2 b/roles/caddy/templates/etc/caddy/conf.d/vhost.j2 new file mode 100644 index 0000000..141af67 --- /dev/null +++ b/roles/caddy/templates/etc/caddy/conf.d/vhost.j2 @@ -0,0 +1,17 @@ +{{ ansible_managed | comment }} + +{# helper variables and per-site defaults that we can't set in role defaults #} +{% set domain_name = item.domain_name %} +{% set domain_aliases = item.domain_aliases | default("") %} +{# assume optional features are off unless a vhost explicitly sets them #} +{% set has_wordpress = item.has_wordpress | default(false) %} +{% set needs_php = item.needs_php | default(false) %} +{% set has_gitea = item.has_gitea | default(false) %} + +{{ domain_name }} { + {% if has_gitea %} + reverse_proxy :3000 + {% endif %} + + import security-headers +} diff --git a/web.yml b/web.yml index d542f5d..cda2804 100644 --- a/web.yml +++ b/web.yml @@ -7,7 +7,8 @@ roles: - common - { role: mariadb, when: mariadb_databases is defined} - - nginx + - { role: nginx, when: webserver is defined and webserver == 'nginx' } + - { role: caddy, when: webserver is defined and webserver == 'caddy' } - php-fpm - munin vars_files: