diff --git a/ansible/inventory/group_vars/all.yml b/ansible/inventory/group_vars/all.yml index 7e0fdf0..2513cac 100644 --- a/ansible/inventory/group_vars/all.yml +++ b/ansible/inventory/group_vars/all.yml @@ -1,2 +1,36 @@ data_directory_base: /mnt/data git_ssh_port: 56287 + +nfs_shares: + - name: nextcloud_data + path: /mnt/data/nextcloud/data + - name: radicale + path: /mnt/data/radicale + - name: freshrss_data + path: /mnt/data/freshrss/data + - name: freshrss_extensions + path: /mnt/data/freshrss/extensions + - name: pihole_data + path: /mnt/data/pihole/data + - name: pihole_dnsmasq + path: /mnt/data/pihole/dnsmasq + - name: hedgedoc_uploads + path: /mnt/data/hedgedoc/uploads + +database_passwords: + nextcloud: !vault | + $ANSIBLE_VAULT;1.1;AES256 + 66326230303135303930363761316534313439383365376231623661316635393839336431313262 + 3832626365376533646561653863316364313135343366330a356136343938666133356532613263 + 39663037623232363266376335643834353735363431636535386566643763386463353962663930 + 3466343563353162320a376437353933656166323364323166376663323531373338656563653463 + 33346263626430616164613937363836343430383233393061643231346661656539623938333631 + 3632373964346139316637663364646132636636373461613534 + hedgedoc: !vault | + $ANSIBLE_VAULT;1.1;AES256 + 63363464666633663762393135333362613966636338623533393132376338343339653431396465 + 6634643863623163366235393434343662313735363438610a373065363361326565633766633835 + 38383637343230363031636634623930666365333739323162313937656239646166613738393965 + 3533666462303563360a313233306335396234393932396331313238376464363964363839396164 + 66366662356135343035363935616664613831626131376330643133313530636431613266636165 + 6265613666616164373637356235396165383662333561393939 diff --git a/ansible/inventory/hosts.yml b/ansible/inventory/hosts.yml index 983401e..aea4b94 100644 --- a/ansible/inventory/hosts.yml +++ b/ansible/inventory/hosts.yml @@ -2,6 +2,8 @@ all: hosts: manager: ansible_host: maestro.dmz + thecloud: + ansible_host: thecloud.dmz children: workers: hosts: diff --git a/ansible/playbooks/setup.yml b/ansible/playbooks/setup.yml index 258779a..7daa6ba 100644 --- a/ansible/playbooks/setup.yml +++ b/ansible/playbooks/setup.yml @@ -1,12 +1,12 @@ --- - name: Wait for Cloud-init to finish - hosts: all + hosts: manager, workers gather_facts: no roles: - cloudinit_wait - name: Initialize Docker Swarm nodes - hosts: all + hosts: manager, workers pre_tasks: - name: Delete externally managed environment file shell: diff --git a/ansible/playbooks/stacks.yml b/ansible/playbooks/stacks.yml index dad95ac..242c3f7 100644 --- a/ansible/playbooks/stacks.yml +++ b/ansible/playbooks/stacks.yml @@ -17,4 +17,4 @@ - {role: shephard, tags: shephard} - {role: jitsi, tags: jitsi} - {role: pihole, tags: pihole} - - {role: discourse, tags: discourse} + - {role: nextcloud, tags: nextcloud} diff --git a/ansible/playbooks/thecloud.yml b/ansible/playbooks/thecloud.yml new file mode 100644 index 0000000..ca639d1 --- /dev/null +++ b/ansible/playbooks/thecloud.yml @@ -0,0 +1,24 @@ +--- +- name: Create databases and NFS shares + hosts: thecloud + handlers: + - name: reload nfs + systemd: + name: nfs-kernel-server + state: restarted + + tasks: + - name: Create nfs shares + with_items: "{{ nfs_shares }}" + copy: + dest: "/etc/exports.d/{{ item.name }}.exports" + content: "{{ item.path }} *(rw,sync,no_subtree_check,no_root_squash)" + notify: reload nfs + + - name: Create databases + with_items: "{{ database_passwords | dict2items }}" + include_role: + name: database + vars: + database_name: "{{ item.key }}" + database_password: "{{ item.value }}" diff --git a/ansible/roles/database/handlers/main.yml b/ansible/roles/database/handlers/main.yml new file mode 100644 index 0000000..a09812e --- /dev/null +++ b/ansible/roles/database/handlers/main.yml @@ -0,0 +1,4 @@ +- name: restart postgres + systemd: + name: postgresql + state: restarted diff --git a/ansible/roles/database/tasks/main.yml b/ansible/roles/database/tasks/main.yml new file mode 100644 index 0000000..0daddd5 --- /dev/null +++ b/ansible/roles/database/tasks/main.yml @@ -0,0 +1,36 @@ +- name: Create database user + postgresql_user: + name: "{{ database_name }}" + password: "{{ database_password }}" + become: true + become_user: postgres + +- name: Create database + postgresql_db: + name: "{{ database_name }}" + owner: "{{ database_name }}" + become: true + become_user: postgres + +- name: Grant access to database + postgresql_privs: + type: database + database: "{{ database_name }}" + role: "{{ database_name }}" + grant_option: no + privs: all + become: true + become_user: postgres + notify: restart postgres + +- name: Allow remote access to database + postgresql_pg_hba: + dest: /etc/postgresql/15/main/pg_hba.conf + contype: host + databases: "{{ database_name }}" + users: "{{ database_name }}" + address: all + create: true + become: true + become_user: postgres + notify: restart postgres diff --git a/ansible/roles/freshrss/docker-stack.yml.j2 b/ansible/roles/freshrss/docker-stack.yml.j2 index 43cbd85..2a23a77 100644 --- a/ansible/roles/freshrss/docker-stack.yml.j2 +++ b/ansible/roles/freshrss/docker-stack.yml.j2 @@ -5,18 +5,34 @@ networks: traefik: external: true +volumes: + data: + driver_opts: + type: "nfs" + o: "addr=192.168.30.10,nolock,soft,rw" + device: ":/mnt/data/freshrss/data" + extensions: + driver_opts: + type: "nfs" + o: "addr=192.168.30.10,nolock,soft,rw" + device: ":/mnt/data/freshrss/extensions" + services: freshrss: image: freshrss/freshrss:edge networks: - traefik volumes: - - type: bind - source: /mnt/data/freshrss/data + - type: volume + source: data target: /var/www/FreshRSS/data - - type: bind - source: /mnt/data/freshrss/extensions + volume: + nocopy: true + - type: volume + source: extensions target: /var/www/FreshRSS/extensions + volume: + nocopy: true environment: TZ: Europe/Amsterdam CRON_MIN: '2,32' @@ -25,13 +41,10 @@ services: ADMIN_API_PASSWORD: {{ admin_password }} PUBLISHED_PORT: 443 deploy: - placement: - constraints: - - "node.labels.freshrss == true" labels: - traefik.enable=true - traefik.http.routers.freshrss.entrypoints=websecure - - traefik.http.routers.freshrss.rule=Host(`rss.pim.kunis.nl`) + - traefik.http.routers.freshrss.rule=Host(`rss.kun.is`) - traefik.http.routers.freshrss.tls=true - traefik.http.routers.freshrss.tls.certresolver=letsencrypt - traefik.http.routers.freshrss.service=freshrss diff --git a/ansible/roles/hedgedoc/docker-stack.yml.j2 b/ansible/roles/hedgedoc/docker-stack.yml.j2 index c5be6d3..6a03c41 100644 --- a/ansible/roles/hedgedoc/docker-stack.yml.j2 +++ b/ansible/roles/hedgedoc/docker-stack.yml.j2 @@ -4,32 +4,19 @@ version: '3' networks: traefik: external: true - hedgedoc: + +volumes: + uploads: + driver_opts: + type: "nfs" + o: "addr=192.168.30.10,nolock,soft,rw" + device: ":/mnt/data/hedgedoc/uploads" services: - hedgedoc-db: - image: postgres:13.4-alpine - environment: - - POSTGRES_USER=hedgedoc - - POSTGRES_PASSWORD=password - - POSTGRES_DB=hedgedoc - volumes: - - type: bind - source: /mnt/data/hedgedoc/database - target: /var/lib/postgresql/data - networks: - hedgedoc: - aliases: - - database - deploy: - placement: - constraints: - - "node.labels.hedgedoc == true" - hedgedoc-app: image: quay.io/hedgedoc/hedgedoc:1.9.7 environment: - - CMD_DB_URL=postgres://hedgedoc:password@database:5432/hedgedoc + - CMD_DB_URL=postgres://hedgedoc:{{ database_passwords.hedgedoc }}@192.168.30.10:5432/hedgedoc - CMD_DOMAIN=md.pim.kunis.nl - CMD_PORT=3000 - CMD_URL_ADDPORT=false @@ -38,18 +25,14 @@ services: - CMD_PROTOCOL_USESSL=true - CMD_SESSION_SECRET={{ session_secret }} volumes: - - type: bind - source: /mnt/data/hedgedoc/uploads + - type: volume + source: uploads target: /hedgedoc/public/uploads - depends_on: - - hedgedoc-db + volume: + nocopy: true networks: - traefik - - hedgedoc deploy: - placement: - constraints: - - "node.labels.hedgedoc == true" labels: - traefik.enable=true - traefik.http.routers.hedgedoc.entrypoints=websecure diff --git a/ansible/roles/hedgedoc/tasks/main.yml b/ansible/roles/hedgedoc/tasks/main.yml index e3ca514..10c8f08 100644 --- a/ansible/roles/hedgedoc/tasks/main.yml +++ b/ansible/roles/hedgedoc/tasks/main.yml @@ -1,3 +1,6 @@ +- name: asdfasdf + debug: + msg: "{{ lookup('template', '{{ role_path }}/docker-stack.yml.j2') | from_yaml }}" - name: Deploy Docker stack docker_stack: name: hedgedoc diff --git a/ansible/roles/nextcloud/docker-stack.yml.j2 b/ansible/roles/nextcloud/docker-stack.yml.j2 new file mode 100644 index 0000000..395556c --- /dev/null +++ b/ansible/roles/nextcloud/docker-stack.yml.j2 @@ -0,0 +1,40 @@ +# vi: ft=yaml +version: '3.8' + +networks: + traefik: + external: true + +volumes: + data: + driver_opts: + type: "nfs" + o: "addr=192.168.30.10,nolock,soft,rw" + device: ":/mnt/data/nextcloud/data" + +services: + app: + image: nextcloud:26 + volumes: + - type: volume + source: data + target: /var/www/html + volume: + nocopy: true + environment: + - POSTGRES_USER=swarm + - POSTGRES_DB=nextcloud + - POSTGRES_PASSWORD={{ database_passwords.nextcloud }} + - POSTGRES_HOST=192.168.30.10 + networks: + - traefik + deploy: + labels: + - traefik.enable=true + - traefik.http.routers.nextcloud.entrypoints=websecure + - traefik.http.routers.nextcloud.rule=Host(`cloud.kun.is`) + - traefik.http.routers.nextcloud.tls=true + - traefik.http.routers.nextcloud.tls.certresolver=letsencrypt + - traefik.http.routers.nextcloud.service=nextcloud + - traefik.http.services.nextcloud.loadbalancer.server.port=80 + - traefik.docker.network=traefik diff --git a/ansible/roles/nextcloud/tasks/main.yml b/ansible/roles/nextcloud/tasks/main.yml new file mode 100644 index 0000000..9b3430e --- /dev/null +++ b/ansible/roles/nextcloud/tasks/main.yml @@ -0,0 +1,5 @@ +- name: Deploy Docker stack + docker_stack: + name: nextcloud + compose: + - "{{ lookup('template', '{{ role_path }}/docker-stack.yml.j2') | from_yaml }}" diff --git a/ansible/roles/overleaf/docker-stack.yml.j2 b/ansible/roles/overleaf/docker-stack.yml.j2 index 293cb04..020dc99 100644 --- a/ansible/roles/overleaf/docker-stack.yml.j2 +++ b/ansible/roles/overleaf/docker-stack.yml.j2 @@ -7,7 +7,7 @@ networks: services: sharelatex: - image: sharelatex/sharelatex + image: sharelatex/sharelatex:3 networks: - traefik - overleaf diff --git a/ansible/roles/pihole/docker-stack.yml.j2 b/ansible/roles/pihole/docker-stack.yml.j2 index 637eb78..b9f82fc 100644 --- a/ansible/roles/pihole/docker-stack.yml.j2 +++ b/ansible/roles/pihole/docker-stack.yml.j2 @@ -1,11 +1,23 @@ # vi: ft=yaml -version: "3" +version: "3.8" networks: traefik: external: true pihole: +volumes: + data: + driver_opts: + type: "nfs" + o: "addr=192.168.30.10,nolock,soft,rw" + device: ":/mnt/data/pihole/data" + dnsmasq: + driver_opts: + type: "nfs" + o: "addr=192.168.30.10,nolock,soft,rw" + device: ":/mnt/data/pihole/dnsmasq" + services: pihole: image: pihole/pihole:latest @@ -18,18 +30,19 @@ services: WEBPASSWORD: {{ pihole_password }} PIHOLE_DNS_: '192.168.30.1' volumes: - - type: bind - source: /mnt/data/pihole/data + - type: volume + source: data target: /etc/pihole - - type: bind - source: /mnt/data/pihole/dnsmasq + volume: + nocopy: true + - type: volume + source: dnsmasq target: /etc/dnsmasq.d + volume: + nocopy: true networks: - traefik deploy: - placement: - constraints: - - "node.labels.pihole == true" labels: - traefik.enable=true - traefik.http.routers.pihole.entrypoints=localsecure diff --git a/ansible/roles/radicale/docker-stack.yml.j2 b/ansible/roles/radicale/docker-stack.yml.j2 index 794e52d..61fba13 100644 --- a/ansible/roles/radicale/docker-stack.yml.j2 +++ b/ansible/roles/radicale/docker-stack.yml.j2 @@ -13,6 +13,13 @@ configs: external: true name: "{{ users.config_name }}" +volumes: + data: + driver_opts: + type: "nfs" + o: "addr=192.168.30.10,nolock,soft,rw" + device: ":/mnt/data/radicale" + services: radicale: image: tomsquest/docker-radicale @@ -30,19 +37,18 @@ services: interval: 30s retries: 3 volumes: - - type: bind - source: /mnt/data/radicale + - type: volume + source: data target: /data + volume: + nocopy: true networks: - traefik deploy: - placement: - constraints: - - "node.labels.radicale == true" labels: - traefik.enable=true - traefik.http.routers.radicale.entrypoints=websecure - - traefik.http.routers.radicale.rule=Host(`dav.pim.kunis.nl`) + - traefik.http.routers.radicale.rule=Host(`dav.kun.is`) - traefik.http.routers.radicale.tls=true - traefik.http.routers.radicale.tls.certresolver=letsencrypt - traefik.http.routers.radicale.service=radicale diff --git a/ansible/roles/traefik/docker-stack.yml.j2 b/ansible/roles/traefik/docker-stack.yml.j2 index ed0bec3..a540c80 100644 --- a/ansible/roles/traefik/docker-stack.yml.j2 +++ b/ansible/roles/traefik/docker-stack.yml.j2 @@ -39,12 +39,6 @@ services: - traefik.http.routers.esrom.tls=true - traefik.http.routers.esrom.tls.certresolver=letsencrypt - - traefik.http.routers.nextcloud.entrypoints=websecure - - traefik.http.routers.nextcloud.service=nextcloud@file - - traefik.http.routers.nextcloud.rule=Host(`cloud.pim.kunis.nl`) - - traefik.http.routers.nextcloud.tls=true - - traefik.http.routers.nextcloud.tls.certresolver=letsencrypt - - traefik.http.routers.uptime.entrypoints=localsecure - traefik.http.routers.uptime.rule=Host(`uptime.pim.kunis.nl`) - traefik.http.routers.uptime.service=uptime@file diff --git a/ansible/roles/traefik/services.yml b/ansible/roles/traefik/services.yml index 9e5906f..206bec4 100644 --- a/ansible/roles/traefik/services.yml +++ b/ansible/roles/traefik/services.yml @@ -4,10 +4,6 @@ http: loadBalancer: servers: - url: http://esrom.dmz:80/ - nextcloud: - loadBalancer: - servers: - - url: http://nextcloud.dmz:80/ uptime: loadBalancer: servers: diff --git a/terraform/dns.tf b/terraform/dns.tf new file mode 100644 index 0000000..7b722c6 --- /dev/null +++ b/terraform/dns.tf @@ -0,0 +1,73 @@ +data "external" "secrets" { + program = ["cat", pathexpand("~/.tfvars.json")] +} + +provider "powerdns" { + server_url = "http://192.168.30.108:3000" + api_key = data.external.secrets.result.powerdns_api_key +} + +resource "powerdns_record" "subdomain_pim" { + for_each = toset(["dav", "git", "meet", "rss", "latex", "md", "swarm", "traefik", "syncthing", "cloud", "pihole", "ntfy", "apprise", "uptime", "concourse", "discourse"]) + zone = "pim.kunis.nl." + name = "${each.key}.pim.kunis.nl." + type = "CNAME" + records = ["www.pim.kunis.nl."] + ttl = 60 +} + +resource "powerdns_record" "social_pim_kunis_nl_a" { + zone = "pim.kunis.nl." + name = "social.pim.kunis.nl." + type = "A" + records = ["84.245.14.149"] + ttl = 60 +} + +resource "powerdns_record" "kms_geokunis2_nl_a" { + zone = "geokunis2.nl." + name = "kms.geokunis2.nl." + type = "A" + records = ["84.245.14.149"] + ttl = 60 +} + +resource "powerdns_record" "files_geokunis2_nl_a" { + zone = "geokunis2.nl." + name = "files.geokunis2.nl." + type = "A" + records = ["84.245.14.149"] + ttl = 60 +} + +resource "powerdns_record" "files_geokunis2_nl_aaaa" { + zone = "geokunis2.nl." + name = "files.geokunis2.nl." + type = "AAAA" + records = ["2a02:58:19a:f730:b62e:99ff:fe77:1bda"] + ttl = 60 +} + +resource "powerdns_record" "cyberchef_geokunis2_nl_a" { + zone = "geokunis2.nl." + name = "cyberchef.geokunis2.nl." + type = "A" + records = ["84.245.14.149"] + ttl = 60 +} + +resource "powerdns_record" "cyberchef_geokunis2_nl_aaaa" { + zone = "geokunis2.nl." + name = "cyberchef.geokunis2.nl." + type = "AAAA" + records = ["2a02:58:19a:f730:c8fe:c0ff:feff:ee03"] + ttl = 60 +} + +resource "powerdns_record" "inbucket_geokunis2_nl_a" { + zone = "geokunis2.nl." + name = "inbucket.geokunis2.nl." + type = "A" + records = ["84.245.14.149"] + ttl = 60 +} diff --git a/terraform/main.tf b/terraform/main.tf index 73028ad..2312a39 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -8,6 +8,11 @@ terraform { libvirt = { source = "dmacvicar/libvirt" } + + powerdns = { + source = "pan-net/powerdns" + version = "1.5.0" + } } }