From a54a91ea443f1a187413f0c6788b8a168c6f488b Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Sun, 1 Oct 2023 16:25:20 +0100 Subject: [PATCH] Deploy a dokku --- ansible/ansible.cfg | 2 + ansible/galaxy-requirements.yml | 2 + ansible/host_vars/pve-docker/main.yml | 1 + ansible/host_vars/pve-dokku.yml | 1 + ansible/main.yml | 4 ++ ansible/roles/dokku/files/nginx.conf | 29 ++++++++++ ansible/roles/dokku/handlers/main.yml | 5 ++ ansible/roles/dokku/tasks/main.yml | 53 +++++++++++++++++++ ansible/roles/dokku/vars/main.yml | 9 ++++ ansible/roles/traefik/defaults/main.yml | 1 + .../traefik/files/file-provider-dokku.yml | 10 ++++ ansible/roles/traefik/files/traefik.yml | 4 ++ ansible/roles/traefik/tasks/main.yml | 12 +++++ terraform/theorangeone.net.tf | 16 ++++++ 14 files changed, 149 insertions(+) create mode 100644 ansible/host_vars/pve-dokku.yml create mode 100644 ansible/roles/dokku/files/nginx.conf create mode 100644 ansible/roles/dokku/handlers/main.yml create mode 100644 ansible/roles/dokku/tasks/main.yml create mode 100644 ansible/roles/dokku/vars/main.yml create mode 100644 ansible/roles/traefik/files/file-provider-dokku.yml diff --git a/ansible/ansible.cfg b/ansible/ansible.cfg index be908ea..f298ea0 100644 --- a/ansible/ansible.cfg +++ b/ansible/ansible.cfg @@ -7,6 +7,8 @@ collections_path = $PWD/galaxy_collections inventory = ./hosts become_ask_pass = True interpreter_python = auto_silent +# HACK: Force Ansible to find dokku plugins +library = $PWD/galaxy_roles/dokku_bot.ansible_dokku/library [ssh_connection] pipelining = True diff --git a/ansible/galaxy-requirements.yml b/ansible/galaxy-requirements.yml index c122861..5d7ed8e 100644 --- a/ansible/galaxy-requirements.yml +++ b/ansible/galaxy-requirements.yml @@ -16,3 +16,5 @@ roles: - src: chmduquesne.iptables_persistent - src: ironicbadger.snapraid version: 1.0.0 + - src: dokku_bot.ansible_dokku + version: v2022.10.17 diff --git a/ansible/host_vars/pve-docker/main.yml b/ansible/host_vars/pve-docker/main.yml index a56b631..f27a53e 100644 --- a/ansible/host_vars/pve-docker/main.yml +++ b/ansible/host_vars/pve-docker/main.yml @@ -3,6 +3,7 @@ private_ip: "{{ pve_hosts.docker.ip }}" traefik_provider_jellyfin: true traefik_provider_homeassistant: true traefik_provider_grafana: true +traefik_provider_dokku: true with_fail2ban: true diff --git a/ansible/host_vars/pve-dokku.yml b/ansible/host_vars/pve-dokku.yml new file mode 100644 index 0000000..6e9b907 --- /dev/null +++ b/ansible/host_vars/pve-dokku.yml @@ -0,0 +1 @@ +ssh_extra_allowed_users: dokku diff --git a/ansible/main.yml b/ansible/main.yml index d01a11e..30a1ba1 100644 --- a/ansible/main.yml +++ b/ansible/main.yml @@ -127,3 +127,7 @@ - pihole - role: prometheus.prometheus.node_exporter become: true + +- hosts: pve-dokku + roles: + - dokku diff --git a/ansible/roles/dokku/files/nginx.conf b/ansible/roles/dokku/files/nginx.conf new file mode 100644 index 0000000..c55b670 --- /dev/null +++ b/ansible/roles/dokku/files/nginx.conf @@ -0,0 +1,29 @@ +worker_processes auto; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + sendfile on; + + keepalive_timeout 65; + + gzip on; + + # Block requests which don't have an explicit handler + server { + listen 80 default_server; + listen [::]:80 default_server; + + server_name _; + access_log off; + return 418; + } + + # Load configuration files for the default server block. + include /etc/nginx/conf.d/*.conf; +} diff --git a/ansible/roles/dokku/handlers/main.yml b/ansible/roles/dokku/handlers/main.yml new file mode 100644 index 0000000..460c29a --- /dev/null +++ b/ansible/roles/dokku/handlers/main.yml @@ -0,0 +1,5 @@ +- name: restart nginx + service: + name: nginx + state: restarted + become: true diff --git a/ansible/roles/dokku/tasks/main.yml b/ansible/roles/dokku/tasks/main.yml new file mode 100644 index 0000000..47d783c --- /dev/null +++ b/ansible/roles/dokku/tasks/main.yml @@ -0,0 +1,53 @@ +# HACK: Fake include some tasks from `ansible_dokku`, so its library plugins can be used below +- name: Run role without running any tasks + include_role: + name: dokku_bot.ansible_dokku + tasks_from: init.yml + apply: + when: false + +- name: Install Dokku + package: + name: dokku + become: true + +- name: List dokku plugins + command: dokku plugin:list + changed_when: false + register: installed_dokku_plugins + +- name: Install Dokku plugins + command: dokku plugin:install {{ item.url }} --name {{ item.name }} + when: installed_dokku_plugins.stdout.find(item.name) == -1 + loop: "{{ dokku_plugins }}" + loop_control: + label: "{{ item.name }}" + become: true + +- name: Automatically update Dokku plugins + cron: + name: "dokku plugin:update {{ item.name }}" + minute: "0" + hour: "12" + user: "root" + job: "/usr/bin/chronic /usr/bin/dokku plugin:update {{ item.name }}" + cron_file: "dokku-plugin-update-{{ item.name }}" + loop: "{{ dokku_plugins }}" + loop_control: + label: "{{ item.name }}" + become: true + +- name: Set up global domain + dokku_domains: + global: true + domains: d.theorangeone.net + become: true + +- name: Install custom nginx config + template: + src: files/nginx.conf + dest: /etc/nginx/nginx.conf + validate: nginx -t -c %s + mode: "644" + notify: restart nginx + become: true diff --git a/ansible/roles/dokku/vars/main.yml b/ansible/roles/dokku/vars/main.yml new file mode 100644 index 0000000..c3c9836 --- /dev/null +++ b/ansible/roles/dokku/vars/main.yml @@ -0,0 +1,9 @@ +dokku_plugins: + - name: postgres + url: https://github.com/dokku/dokku-postgres.git + - name: redis + url: https://github.com/dokku/dokku-redis.git + - name: redirect + url: https://github.com/dokku/dokku-redirect.git + - name: http-auth + url: https://github.com/dokku/dokku-http-auth.git diff --git a/ansible/roles/traefik/defaults/main.yml b/ansible/roles/traefik/defaults/main.yml index 184e9c8..eb31b28 100644 --- a/ansible/roles/traefik/defaults/main.yml +++ b/ansible/roles/traefik/defaults/main.yml @@ -1,5 +1,6 @@ traefik_provider_jellyfin: false traefik_provider_homeassistant: false traefik_provider_grafana: false +traefik_provider_dokku: false with_fail2ban: false diff --git a/ansible/roles/traefik/files/file-provider-dokku.yml b/ansible/roles/traefik/files/file-provider-dokku.yml new file mode 100644 index 0000000..9112fa7 --- /dev/null +++ b/ansible/roles/traefik/files/file-provider-dokku.yml @@ -0,0 +1,10 @@ +http: + routers: + router-dokku: + rule: HostRegexp(`{subdomain:[a-z]+}.d.theorangeone.net`) + service: service-dokku + services: + service-dokku: + loadBalancer: + servers: + - url: http://{{ pve_hosts.dokku.ip }} diff --git a/ansible/roles/traefik/files/traefik.yml b/ansible/roles/traefik/files/traefik.yml index 1d91361..a19b9d6 100644 --- a/ansible/roles/traefik/files/traefik.yml +++ b/ansible/roles/traefik/files/traefik.yml @@ -26,6 +26,10 @@ entryPoints: sans: "*.jakehoward.tech" - main: 0rng.one sans: "*.0rng.one" + {% if traefik_provider_dokku %} + - main: d.theorangeone.net + sans: "*.d.theorangeone.net" + {% endif %} proxyProtocol: trustedIPs: - "{{ wireguard.cidr }}" diff --git a/ansible/roles/traefik/tasks/main.yml b/ansible/roles/traefik/tasks/main.yml index 273ea55..d62fdcd 100644 --- a/ansible/roles/traefik/tasks/main.yml +++ b/ansible/roles/traefik/tasks/main.yml @@ -47,6 +47,8 @@ dest: /opt/traefik/traefik/traefik.yml mode: "{{ docker_compose_file_mask }}" owner: "{{ docker_user.name }}" + lstrip_blocks: true + trim_blocks: true notify: restart traefik become: true @@ -89,6 +91,16 @@ when: traefik_provider_grafana become: true +- name: Install dokku provider + template: + src: files/file-provider-dokku.yml + dest: /opt/traefik/traefik/conf/dokku.yml + mode: "{{ docker_compose_file_mask }}" + owner: "{{ docker_user.name }}" + notify: restart traefik + when: traefik_provider_dokku + become: true + - name: logrotate config template: src: files/logrotate.conf diff --git a/terraform/theorangeone.net.tf b/terraform/theorangeone.net.tf index 03ed850..7f3a387 100644 --- a/terraform/theorangeone.net.tf +++ b/terraform/theorangeone.net.tf @@ -181,6 +181,22 @@ resource "cloudflare_record" "theorangeonenet_privatebin" { ttl = 1 } +resource "cloudflare_record" "theorangeonenet_dokku" { + zone_id = cloudflare_zone.theorangeonenet.id + name = "d" + value = linode_instance.casey.ip_address + type = "A" + ttl = 1 +} + +resource "cloudflare_record" "theorangeonenet_dokku_wildcard" { + zone_id = cloudflare_zone.theorangeonenet.id + name = "*.d" + value = cloudflare_record.theorangeonenet_dokku.hostname + type = "CNAME" + ttl = 1 +} + resource "cloudflare_record" "theorangeonenet_google_site_verification" { zone_id = cloudflare_zone.theorangeonenet.id name = "@"