diff --git a/.DS_Store b/.DS_Store
deleted file mode 100644
index fb6f6b3..0000000
Binary files a/.DS_Store and /dev/null differ
diff --git a/.env.sample b/.env.sample
deleted file mode 100644
index 4c6f97e..0000000
--- a/.env.sample
+++ /dev/null
@@ -1,13 +0,0 @@
-HEADSCALE_PREAUTH_KEY=
-HEADSCALE_OIDC_SECRET=
-
-LLDAP_JWT_SECRET=
-LLDAP_USER_PASS=
-
-PIHOLE_WEBPWD=
-STEP_CA_ROOT_PASSWORD=
-STEP_CA_INTERMEDIATE_PASSWORD=
-OPENVPN_USER=
-
-VAULTWARDEN_ADMIN_TOKEN=
-INFO_FROM_PASSWORD=
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..cce9463
--- /dev/null
+++ b/README.md
@@ -0,0 +1,84 @@
+# liz.coffee infra
+
+A collection of playbooks to deploy the liz.coffee infra
+
+## Prerequisites
+
+- `ansible`
+- `yamllint`
+- `ansible-lint`
+- an ssh key accepted on each line in the `inventory`
+
+## Setup
+
+### Vault
+
+Secrets are managed via `ansible-vault`. Initialize or update your vault
+with new secrets via our custom `./ansible-vault-init.sh` script.
+
+Additionally if you want to only update a single secret, use
+`./ansible-vault-init.sh <secret_name>`.
+
+If you don't want to be prompted to enter your password every time you
+deploy something, put your password as plain text into `secrets.pwd` as
+a single line in the root src directory:
+
+```bash
+echo "<your_password>" > secrets.pwd
+```
+
+Then you can add `--vault-password-file secrets.pwd` each time you run a
+deployment (or you know, use `pass` or something if you're paranoid).
+
+### Pre-commit hooks
+
+1. clone the repo
+
+   ```bash
+   git clone git@git.liz.coffee:liz.coffee/infra
+   cd infra
+   ```
+
+2. add a pre-commit hook
+
+   ```bash
+   cd .git/hooks
+   touch pre-commit
+   ```
+
+3. insert into `pre-commit` the following contents:
+
+   ```bash
+   #!/bin/sh
+
+   set -e
+
+   # lint yaml files
+   echo "running yamllint..."
+   yamllint --strict .
+
+   # follow ansible best-practices
+   echo "running ansible-lint"
+   ansible-lint
+   ```
+
+4. make it executable
+   ```bash
+   chmod +x pre-commit
+   ```
+
+## Running
+
+`ansible-playbook -e @secrets.enc deploy.yml` will run each respectively added playbook in `deploy.yml`
+using the vault intialized in the previous steps.
+
+Though in development, one should be testing individual playbooks, and `deploy.yml`
+should be left for an idea of general order of things, or for a
+full deployment after testing.
+
+NOTE: It is highly advised to run `ansible-playbook` in an `ssh-agent` session to avoid retyping your password over and over. Something along the lines of:
+
+```bash
+ssh-agent $(echo $SHELL)
+ssh-add ~/.ssh/<private-key>
+```
diff --git a/ansible-vault-init.sh b/ansible-vault-init.sh
new file mode 100755
index 0000000..8219ec4
--- /dev/null
+++ b/ansible-vault-init.sh
@@ -0,0 +1,66 @@
+#!/bin/bash
+
+# usage: ./ansible-vault-init.sh <? secret-name-to-update>
+
+# password input
+while true; do
+  read -s -p "Password: " VAULT_PASSWORD
+  echo
+  read -s -p "Confirm password: " confirmationpwd
+  echo
+  [ "$VAULT_PASSWORD" = "$confirmationpwd" ] && break
+  echo "Please try again"
+done
+
+###
+
+SECRETS_KEYS_FILE="secrets.txt"
+# temporary secret store
+TEMP_FILE="temp_secrets.yml"
+VAULT_FILE="secrets.enc"
+
+if [ "$#" -eq 1 ]; then
+  SINGLE_SECRET_MODE=true
+  SECRET_TO_UPDATE=$1
+else
+  SINGLE_SECRET_MODE=false
+fi
+
+
+if [ -f "$VAULT_FILE" ]; then
+  ansible-vault decrypt "$VAULT_FILE" --output="$TEMP_FILE" --vault-password-file <(echo $VAULT_PASSWORD)
+else
+  # create the temporary file
+  > "$TEMP_FILE"
+fi
+
+IFS=$'\n' read -d '' -r -a secrets < "$SECRETS_KEYS_FILE"
+echo "Gathering secrets..."
+for secret_name in "${secrets[@]}"; do
+  if [ "$SINGLE_SECRET_MODE" = true ] && [ "$secret_name" != "$SECRET_TO_UPDATE" ]; then
+    continue
+  fi
+
+  if grep -q "^$secret_name:" "$TEMP_FILE"; then
+    if [ "$SINGLE_SECRET_MODE" = true ]; then
+      # Remove the old value of the secret
+      sed -i "/^$secret_name:/d" "$TEMP_FILE"
+    else
+      echo "Secret $secret_name already exists, skipping."
+      continue
+    fi
+  fi
+
+  echo -n "Enter value for $secret_name: "
+  read secret_value
+  echo "$secret_name: $secret_value" >> "$TEMP_FILE"
+done
+
+echo "Re-encrypting secrets..."
+
+ansible-vault encrypt "$TEMP_FILE" --output="$VAULT_FILE" --vault-password-file <(echo $VAULT_PASSWORD)
+
+# remove the temp secrets file securely
+shred -u "$TEMP_FILE"
+
+echo "Secrets have been encrypted into secrets.enc"
diff --git a/ansible.cfg b/ansible.cfg
index dcb0621..7ce8420 100644
--- a/ansible.cfg
+++ b/ansible.cfg
@@ -1,3 +1,4 @@
 [defaults]
 inventory = inventory
 host_key_checking = False
+
diff --git a/create_service.sh b/create_service.sh
deleted file mode 100755
index febf42a..0000000
--- a/create_service.sh
+++ /dev/null
@@ -1,185 +0,0 @@
-#!/bin/bash
-
-set -e
-
-prompt_with_default() {
-  local prompt_message="$1"
-  local default_value="$2"
-  read -p "$prompt_message [$default_value]: " input
-  echo "${input:-$default_value}"
-}
-
-DNS_ENDPOINT=$(prompt_with_default "Enter DNS endpoint" "https://hatecomputers.club/dns")
-BIND_FILE=$(prompt_with_default "Enter bind file path" "roles/nameservers/templates/db.simponic.xyz.j2")
-
-SERVICE_TITLE=$(prompt_with_default "Enter service title" "whois simponic.")
-SERVICE=$(prompt_with_default "Enter service name" "whois")
-SERVICE_PORT=$(prompt_with_default "Enter service port" "8466")
-SERVICE_REPO=$(prompt_with_default "Enter service repository URL" "git.simponic.xyz/simponic/$SERVICE")
-SERVICE_ORIGIN=$(prompt_with_default "Enter service origin URL" "git@git.simponic.xyz:simponic/$SERVICE")
-INTERNAL=$(prompt_with_default "Is the service internal? (yes/no)" "no")
-SERVICE_HOST=$(prompt_with_default "Enter service host" "ryo")
-PACKAGE_PATH=$(prompt_with_default "Enter package path" "$HOME/git/simponic/$SERVICE")
-HATECOMPUTERS_API_KEY=$(prompt_with_default "Enter hatecomputers API key (paste from clipboard)" "$(wl-paste)")
-
-
-function render_template() {
-  cp -r template $PACKAGE_PATH 
-  grep -rlZ "{{ service }}" $PACKAGE_PATH | xargs -0 sed -i "s/{{ service }}/$SERVICE/g"
-  grep -rlZ "{{ service_host }}" $PACKAGE_PATH | xargs -0 sed -i "s/{{ service_host }}/$SERVICE_HOST/g"
-  grep -rlZ "{{ service_repo }}" $PACKAGE_PATH | xargs -0 sed -i "s/{{ service_repo }}/$(echo $SERVICE_REPO | sed 's/\//\\\//g')/g"
-  grep -rlZ "{{ service_port }}" $PACKAGE_PATH | xargs -0 sed -i "s/{{ service_port }}/$SERVICE_PORT/g"
-  grep -rlZ "{{ service_title }}" $PACKAGE_PATH | xargs -0 sed -i "s/{{ service_title }}/$SERVICE_TITLE/g"
-}
-
-function test_and_commit_code() {
-  cd $PACKAGE_PATH
-
-  go fmt ./...
-  go get
-  go mod tidy
-  go build
-  go test -v ./...
-
-  echo "everything looks good, can you make a repo at https://$SERVICE_REPO (press enter when done)"
-  read
-  echo "cool. now, please sync it with drone (https://drone.internal.simponic.xyz/simponic/$SERVICE). (press enter when done)"
-  read
-
-  git init
-  git add .
-  git commit -m "initial commit by simponic-infra"
-  git checkout -B main
-  git remote add origin $SERVICE_ORIGIN
-  git push -u origin main
-  cd -
-}
-
-function add_dns_records() {
-  if [[ "$INTERNAL" = "yes" ]]; then
-    name="$SERVICE.internal.simponic.xyz."
-    content="$SERVICE_HOST.internal.simponic.xyz."
-    curl -H "Authorization: Bearer $HATECOMPUTERS_API_KEY" \
-      -F "type=CNAME&name=$name&content=$content&ttl=43200&internal=on" \
-      $DNS_ENDPOINT
-  else
-    name="$SERVICE.simponic.xyz."
-    content="$SERVICE_HOST.simponic.xyz."
-    sed -i "s|;; CNAME Records|;; CNAME Records\n$name\t43200\tIN\tCNAME\t$content|" $BIND_FILE
-  fi
-}
-
-function add_nginx_config() {
-  endpoint="$SERVICE.simponic.xyz"
-  destination="roles/webservers/files/$SERVICE_HOST"
-  if [[ $INTERNAL = "yes" ]]; then
-    ednpoint="$SERVICE.internal.simponic.xyz"
-    destination="roles/private/files/$SERVICE_HOST"
-  else
-    mkdir -p $destination
-  
-    echo "server {
-  listen 443 ssl;
-  server_name $endpoint;
-
-  ssl_certificate         /etc/letsencrypt/live/$endpoint/fullchain.pem;
-  ssl_certificate_key     /etc/letsencrypt/live/$endpoint/privkey.pem;
-  ssl_trusted_certificate /etc/letsencrypt/live/$endpoint/fullchain.pem;
-
-  ssl_session_cache shared:SSL:50m;
-  ssl_session_timeout 5m;
-  ssl_stapling on;
-  ssl_stapling_verify on;
-
-  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-  ssl_ciphers \"ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4\";
-
-  ssl_dhparam /etc/nginx/dhparams.pem;
-  ssl_prefer_server_ciphers on;
-
-  location / {
-    proxy_pass http://127.0.0.1:$SERVICE_PORT;
-    proxy_http_version 1.1;
-    proxy_set_header Upgrade \$http_upgrade;
-    proxy_set_header Connection \"upgrade\";
-    proxy_set_header Host \$server_name;
-    proxy_buffering off;
-    proxy_set_header X-Real-IP \$remote_addr;
-    proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto \$http_x_forwarded_proto;
-    add_header Strict-Transport-Security \"max-age=15552000; includeSubDomains\" always;
-  }
-}" > "$destination/https.$endpoint.conf"
-    echo "server {
-  listen 80;
-  server_name $endpoint;
-
-  location /.well-known/acme-challenge {
-    root /var/www/letsencrypt;
-    try_files \$uri \$uri/ =404;
-  }
-
-  location / {
-    rewrite ^ https://$endpoint\$request_uri? permanent;
-  }
-}" > "$destination/http.$endpoint.conf"
-  fi
-}
-
-function create_role() {
-  printf "\n[$SERVICE]\n$SERVICE_HOST ansible_user=root ansible_connection=ssh" >> inventory
-  mkdir -p roles/$SERVICE/tasks
-  mkdir -p roles/$SERVICE/templates
-  cp $PACKAGE_PATH/docker-compose.yml roles/$SERVICE/templates/docker-compose.yml.j2
-  
-  echo "---
-- name: ensure $SERVICE docker/compose exist
-  file:
-    path: /etc/docker/compose/$SERVICE
-    state: directory
-    owner: root
-    group: root
-    mode: 0700
-
-- name: ensure $SERVICE db exist
-  file:
-    path: /etc/docker/compose/$SERVICE/db
-    state: directory
-    owner: root
-    group: root
-    mode: 0777
-
-- name: ensure $SERVICE env exist
-  file:
-    path: /etc/docker/compose/$SERVICE/.env
-    state: file
-    owner: root
-    group: root
-    mode: 0700
-
-- name: build $SERVICE docker-compose.yml.j2
-  template:
-    src: ../templates/docker-compose.yml.j2
-    dest: /etc/docker/compose/$SERVICE/docker-compose.yml
-    owner: root
-    group: root
-    mode: u=rw,g=r,o=r
-
-- name: daemon-reload and enable $SERVICE
-  ansible.builtin.systemd_service:
-    state: restarted
-    enabled: true
-    name: docker-compose@$SERVICE" > roles/$SERVICE/tasks/main.yml
-
-  echo "- name: deploy $SERVICE
-  hosts: $SERVICE
-  roles:
-    - $SERVICE" >  deploy-$SERVICE.yml
-}
-
-render_template
-test_and_commit_code
-
-add_dns_records
-add_nginx_config
-create_role
diff --git a/deploy-authelia.yml b/deploy-authelia.yml
deleted file mode 100644
index 4942330..0000000
--- a/deploy-authelia.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-- name: authelia setup
-  hosts: authelia
-  roles:
-    - authelia
diff --git a/deploy-backup-notifications.yml b/deploy-backup-notifications.yml
deleted file mode 100644
index 587ac62..0000000
--- a/deploy-backup-notifications.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-- name: backup-notifications setup
-  hosts: backup-notifications
-  roles:
-    - backup-notifications
diff --git a/deploy-borg.yml b/deploy-borg.yml
deleted file mode 100644
index 271d77e..0000000
--- a/deploy-borg.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-- name: borg setup
-  hosts: borg
-  roles:
-    - borg
diff --git a/deploy-ca.yml b/deploy-ca.yml
deleted file mode 100644
index 699fc5f..0000000
--- a/deploy-ca.yml
+++ /dev/null
@@ -1,31 +0,0 @@
-- name: add acme CA
-  hosts: ca
-  become: yes
-  roles:
-    - role: maxhoesel.smallstep.step_ca
-  tasks:
-    - name: add an acme provisioner to the ca
-      maxhoesel.smallstep.step_ca_provisioner:
-        name: ACME
-        type: ACME
-      become_user: step-ca
-    - name: restart step-ca
-      ansible.builtin.systemd_service: 
-        name: step-ca
-        state: restarted 
-        enabled: true 
-    - name: allow step-ca port traffic on vpn
-      ufw:
-        rule: allow
-        from: 100.64.0.0/10
-        port: "{{ step_ca_port }}" 
-    - name: restart ufw
-      ansible.builtin.systemd_service: 
-        name: ufw
-        state: restarted 
-        enabled: true 
-
-- name: configure trust to internal ca on all hosts
-  hosts: all
-  roles:
-    - ca
diff --git a/deploy-common.yml b/deploy-common.yml
deleted file mode 100644
index 6b3c6f3..0000000
--- a/deploy-common.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-- name: basic host setup 
-  hosts: all
-  roles:
-    - common
diff --git a/deploy-drone.yml b/deploy-drone.yml
deleted file mode 100644
index 2acfda2..0000000
--- a/deploy-drone.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-- name: drone setup
-  hosts: drone
-  roles:
-    - drone
diff --git a/deploy-gitea.yml b/deploy-gitea.yml
deleted file mode 100644
index 150a618..0000000
--- a/deploy-gitea.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-- name: gitea setup
-  hosts: gitea
-  roles:
-    - gitea
diff --git a/deploy-hatecomputers.yml b/deploy-hatecomputers.yml
deleted file mode 100644
index a011104..0000000
--- a/deploy-hatecomputers.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-- name: hatecomputers setup
-  hosts: hatecomputers
-  roles:
-    - hatecomputers
diff --git a/deploy-lldap.yml b/deploy-lldap.yml
deleted file mode 100644
index d632d92..0000000
--- a/deploy-lldap.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-- name: lldap setup
-  hosts: lldap
-  roles:
-    - lldap
diff --git a/deploy-mail.yml b/deploy-mail.yml
deleted file mode 100644
index dbc6746..0000000
--- a/deploy-mail.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-- name: mail setup
-  hosts: mail
-  roles:
-    - mail
-- name: roundcube setup
-  hosts: roundcube
-  roles:
-    - roundcube
diff --git a/deploy-nameservers.yml b/deploy-nameservers.yml
deleted file mode 100644
index c69e361..0000000
--- a/deploy-nameservers.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-- name: basic host setup 
-  hosts: nameservers
-  roles:
-    - dnscommon
-    - nameservers
diff --git a/deploy-ntfy.yml b/deploy-ntfy.yml
deleted file mode 100644
index 5f117c8..0000000
--- a/deploy-ntfy.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-- name: ntfy setup
-  hosts: ntfy
-  roles:
-    - ntfy
diff --git a/deploy-owncloud.yml b/deploy-owncloud.yml
deleted file mode 100644
index 959833b..0000000
--- a/deploy-owncloud.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-- name: owncloud setup
-  hosts: owncloud
-  roles:
-    - owncloud
diff --git a/deploy-phoneassistant.yml b/deploy-phoneassistant.yml
deleted file mode 100644
index 3f73f95..0000000
--- a/deploy-phoneassistant.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-- name: deploy phoneassistant
-  hosts: phoneassistant
-  roles:
-    - phoneassistant
diff --git a/deploy-phoneof.yml b/deploy-phoneof.yml
deleted file mode 100644
index b1f0f6d..0000000
--- a/deploy-phoneof.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-- name: deploy phoneof
-  hosts: phoneof
-  roles:
-    - phoneof
diff --git a/deploy-pihole.yml b/deploy-pihole.yml
deleted file mode 100644
index 59644ae..0000000
--- a/deploy-pihole.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-- name: pihole setup
-  hosts: pihole
-  roles:
-    - pihole
diff --git a/deploy-private.yml b/deploy-private.yml
deleted file mode 100644
index 4274a21..0000000
--- a/deploy-private.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-- name: private setup
-  hosts: private
-  roles:
-    - private
diff --git a/deploy-rainrainrain.yml b/deploy-rainrainrain.yml
deleted file mode 100644
index deff3fe..0000000
--- a/deploy-rainrainrain.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-- name: rainrainrain setup
-  hosts: rainrainrain
-  roles:
-    - rainrainrain
diff --git a/deploy-roundcube.yml b/deploy-roundcube.yml
deleted file mode 100644
index 10c3973..0000000
--- a/deploy-roundcube.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-- name: roundcube setup
-  hosts: roundcube
-  roles:
-    - roundcube
diff --git a/deploy-scurvy.yml b/deploy-scurvy.yml
deleted file mode 100644
index 93de041..0000000
--- a/deploy-scurvy.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-- name: scurvy setup
-  hosts: scurvy
-  roles:
-    - scurvy
diff --git a/deploy-something.yml b/deploy-something.yml
deleted file mode 100644
index 0f3393c..0000000
--- a/deploy-something.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-- name: deploy something
-  hosts: something
-  roles:
-    - something
diff --git a/deploy-static.yml b/deploy-static.yml
deleted file mode 100644
index a29a37c..0000000
--- a/deploy-static.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-- name: static setup
-  hosts: static
-  roles:
-    - static
diff --git a/deploy-uptime.yml b/deploy-uptime.yml
deleted file mode 100644
index 68a914a..0000000
--- a/deploy-uptime.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-- name: uptime setup
-  hosts: uptime
-  roles:
-    - uptime
diff --git a/deploy-vaultwarden.yml b/deploy-vaultwarden.yml
deleted file mode 100644
index 08923d1..0000000
--- a/deploy-vaultwarden.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-- name: vaultwarden setup
-  hosts: vaultwarden
-  roles:
-    - vaultwarden
diff --git a/deploy-vpn-hosts.yml b/deploy-vpn-hosts.yml
deleted file mode 100644
index 9e281ab..0000000
--- a/deploy-vpn-hosts.yml
+++ /dev/null
@@ -1,23 +0,0 @@
-- name: prod headscale tags
-  hosts: prod
-  tasks:
-    - name: add prod tags to prod servers
-      include_role:
-        name: artis3n.tailscale
-      vars:
-        tailscale_args: "--login-server='https://headscale.simponic.xyz'"
-        tailscale_authkey: "{{ lookup('env', 'HEADSCALE_PREAUTH_KEY') }}"
-        tailscale_tags: 
-          - "prod"
-
-- name: private headscale tags
-  hosts: private
-  tasks:
-    - name: add private tags to private servers
-      include_role:
-        name: artis3n.tailscale
-      vars:
-        tailscale_args: "--login-server='https://headscale.simponic.xyz'"
-        tailscale_authkey: "{{ lookup('env', 'HEADSCALE_PREAUTH_KEY') }}"
-        tailscale_tags: 
-          - "private"
diff --git a/deploy-vpn.yml b/deploy-vpn.yml
deleted file mode 100644
index 9d42769..0000000
--- a/deploy-vpn.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-- name: headscale setup
-  hosts: vpn
-  roles:
-    - vpn
diff --git a/deploy-webservers.yml b/deploy-webservers.yml
deleted file mode 100644
index 432819a..0000000
--- a/deploy-webservers.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-- name: webserver setup
-  hosts: webservers
-  roles:
-    - webservers
diff --git a/deploy-whois.yml b/deploy-whois.yml
deleted file mode 100644
index 35df72b..0000000
--- a/deploy-whois.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-- name: deploy whois
-  hosts: whois
-  roles:
-    - whois
diff --git a/deploy-zigbee.yml b/deploy-zigbee.yml
deleted file mode 100644
index 6861047..0000000
--- a/deploy-zigbee.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-- name: configure trust to internal zigbee on all hosts
-  hosts: zigbee
-  roles:
-    - zigbee
diff --git a/deploy.yml b/deploy.yml
new file mode 100644
index 0000000..fc5a2a3
--- /dev/null
+++ b/deploy.yml
@@ -0,0 +1,14 @@
+---
+
+- name: Common
+  ansible.builtin.import_playbook: playbooks/deploy-common.yml
+
+- name: Docker
+  ansible.builtin.import_playbook: playbooks/deploy-docker.yml
+
+- name: NGINX Proxy
+  ansible.builtin.import_playbook: playbooks/deploy-nginx-proxy.yml
+
+- name: outbound
+  ansible.builtin.import_playbook: playbooks/deploy-outbound.yml
+
diff --git a/group_vars/all.yml b/group_vars/all.yml
index f844d49..e8b9def 100644
--- a/group_vars/all.yml
+++ b/group_vars/all.yml
@@ -1,10 +1,9 @@
 ---
-johan_ip: '100.64.0.5'
-nijika_ip: '100.64.0.2'
 
-nameserver_ip: '10.155.0.1'
+ansible_user: serve
 
-step_bootstrap_fingerprint: '2de0c420e3b6f9f8e47f325de908b2b2d395d3bc7e49ed9b672ce9be89bea1bf'
-step_bootstrap_ca_url: 'ca.internal.simponic.xyz'
-step_acme_cert_contact: 'elizabeth@simponic.xyz'
-step_ca_port: 5239
+rfc1918_cgnat_networks:
+  - 10.0.0.0/8
+  - 172.16.0.0/12
+  - 192.168.0.0/16
+  - 100.64.0.0/10
diff --git a/group_vars/borg.yml b/group_vars/borg.yml
deleted file mode 100644
index 8be7df0..0000000
--- a/group_vars/borg.yml
+++ /dev/null
@@ -1,23 +0,0 @@
-borg_password: "{{ lookup('env', 'BORG_ENCRYPTION_PASSWORD') }}"
-borg_repo: "{{ lookup('env', 'BORG_REPO') }}"
-borg_secret_key: "{{ lookup('env', 'BORG_SECRET_KEY') }}"
-borg_my_user: "root"
-borg_my_group: "root"
-borg_ssh_key: "/root/borg_ssh_key"
-
-backup_topic: "{{ lookup('env', 'BORG_BACKUP_TOPIC') }}"
-
-base_files:
-  - /home
-  - /root
-  - /var
-  - /etc
-  - /boot
-  - /opt
-
-extra_files:
-  europa:
-    - /mnt/ssd-01/owncloud
-    - /mnt/ssd-01/borg/sync.sh
-    - /mnt/ssd-01/borg/.config
-    - /mnt/ssd-01/borg/.ssh
diff --git a/group_vars/ca.yml b/group_vars/ca.yml
deleted file mode 100644
index 5bde372..0000000
--- a/group_vars/ca.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-step_ca_root_password: "{{ lookup('env', 'STEP_CA_ROOT_PASSWORD') }}"
-step_ca_intermediate_password: "{{ lookup('env', 'STEP_CA_INTERMEDIATE_PASSWORD') }}"
-step_ca_dns: "{{ nameserver_ip }}, {{ step_bootstrap_ca_url }}"
-step_ca_name: Simponic Internal CA
-step_ca_address: ":{{ step_ca_port }}"
diff --git a/group_vars/drone.yml b/group_vars/drone.yml
deleted file mode 100644
index 55843ea..0000000
--- a/group_vars/drone.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-drone_gitea_client_id: "{{ lookup('env', 'DRONE_GITEA_CLIENT_ID') }}"
-drone_gitea_client_secret: "{{ lookup('env', 'DRONE_GITEA_CLIENT_SECRET') }}"
-drone_rpc_secret: "{{ lookup('env', 'DRONE_RPC_SECRET') }}"
diff --git a/group_vars/lldap.yml b/group_vars/lldap.yml
deleted file mode 100644
index 2322e7f..0000000
--- a/group_vars/lldap.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-lldap_jwt_secret: "{{ lookup('env', 'LLDAP_JWT_SECRET') }}"
-lldap_user_pass: "{{ lookup('env', 'LLDAP_USER_PASS') }}"
diff --git a/group_vars/mail.yml b/group_vars/mail.yml
deleted file mode 100644
index 56b57b6..0000000
--- a/group_vars/mail.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-domain: mail.simponic.xyz
-certbot_email: elizabeth.hunt@simponic.xyz
-postmaster_email: postmaster@simponic.xyz
-lldap_admin_pass: "{{ lookup('env', 'LLDAP_USER_PASS') }}"
diff --git a/group_vars/nameservers.yml b/group_vars/nameservers.yml
deleted file mode 100644
index db4d959..0000000
--- a/group_vars/nameservers.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-dns_zones:
-  - zone: simponic.xyz
-  - zone: rainrainra.in
-  - zone: rileyandlizzy.wedding
-dns_primary_hostname: ryo
-dns_replica_hostname: nijika
-dns_primary_ip: 107.173.19.33
-dns_replica_ip: 107.172.103.253
diff --git a/group_vars/nginx-proxy.yml b/group_vars/nginx-proxy.yml
new file mode 100644
index 0000000..c8cde32
--- /dev/null
+++ b/group_vars/nginx-proxy.yml
@@ -0,0 +1,10 @@
+---
+
+headscale_host: 'vpn.liz.coffee'
+headscale_url: 'https://{{ headscale_host }}'
+headscale_base_domain: 'vpn.liz.coffee'
+headscale_port: '8080'
+headscale_listen_addr: '127.0.0.1:{{ headscale_port }}'
+
+headscale_dns_for_connected_clients_1: '1.1.1.1'
+headscale_dns_for_connected_clients_2: '1.0.0.1'
diff --git a/group_vars/outbound.yml b/group_vars/outbound.yml
new file mode 100644
index 0000000..c8cde32
--- /dev/null
+++ b/group_vars/outbound.yml
@@ -0,0 +1,10 @@
+---
+
+headscale_host: 'vpn.liz.coffee'
+headscale_url: 'https://{{ headscale_host }}'
+headscale_base_domain: 'vpn.liz.coffee'
+headscale_port: '8080'
+headscale_listen_addr: '127.0.0.1:{{ headscale_port }}'
+
+headscale_dns_for_connected_clients_1: '1.1.1.1'
+headscale_dns_for_connected_clients_2: '1.0.0.1'
diff --git a/group_vars/owncloud.yml b/group_vars/owncloud.yml
deleted file mode 100644
index 7a85800..0000000
--- a/group_vars/owncloud.yml
+++ /dev/null
@@ -1,10 +0,0 @@
----
-owncloud_admin_password: "{{ lookup('env', 'OWNCLOUD_ADMIN_PASSWORD') }}"
-owncloud_domain: "owncloud.internal.simponic.xyz"
-owncloud_version: "10.14.0"
-owncloud_trusted_domains: "owncloud.internal.simponic.xyz,localhost,127.0.0.1"
-owncloud_mount: "/mnt/ssd-01/owncloud"
-owncloud_oidc_secret: "{{ lookup('env', 'OWNCLOUD_OIDC_SECRET') }}"
-owncloud_mail_password: "{{ lookup('env', 'INFO_FROM_PASSWORD') }}"
-owncloud_secret: "{{ lookup('env', 'OWNCLOUD_SECRET') }}"
-owncloud_pwd_salt: "{{ lookup('env', 'OWNCLOUD_PWD_SALT') }}"
diff --git a/group_vars/phoneof.yml b/group_vars/phoneof.yml
deleted file mode 100644
index 9c26738..0000000
--- a/group_vars/phoneof.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-from_phone_number: "{{ lookup('env', 'FROM_PHONE_NUMBER')}}"
-to_phone_number: "{{ lookup('env', 'TO_PHONE_NUMBER')}}"
-httpsms_api_token: "{{ lookup('env', 'HTTPSMS_API_TOKEN')}}"
-httpsms_signing_key: "{{ lookup('env', 'HTTPSMS_SIGNING_KEY')}}"
diff --git a/group_vars/pihole.yml b/group_vars/pihole.yml
deleted file mode 100644
index 354d74c..0000000
--- a/group_vars/pihole.yml
+++ /dev/null
@@ -1,2 +0,0 @@
----
-pihole_webpwd: "{{ lookup('env', 'PIHOLE_WEBPWD') }}"
diff --git a/group_vars/roundcube.yml b/group_vars/roundcube.yml
deleted file mode 100644
index e69de29..0000000
diff --git a/group_vars/scurvy.yml b/group_vars/scurvy.yml
deleted file mode 100644
index 2e9b716..0000000
--- a/group_vars/scurvy.yml
+++ /dev/null
@@ -1,2 +0,0 @@
----
-openvpn_user: "{{ lookup('env', 'OPENVPN_USER') }}"
diff --git a/group_vars/vaultwarden.yml b/group_vars/vaultwarden.yml
deleted file mode 100644
index 6ada896..0000000
--- a/group_vars/vaultwarden.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-vaultwarden_admin_token: "{{ lookup('env', 'VAULTWARDEN_ADMIN_TOKEN') }}"
-email_password: "{{ lookup('env', 'INFO_FROM_PASSWORD') }}"
diff --git a/group_vars/vpn.yml b/group_vars/vpn.yml
deleted file mode 100644
index be91bca..0000000
--- a/group_vars/vpn.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-headscale_oidc_secret: "{{ lookup('env', 'HEADSCALE_OIDC_SECRET') }}"
-headscale_allowed_users:
-  - "elizabeth@simponic.xyz"
-  - "riley@simponic.xyz"
-  - "rain@simponic.xyz"
-  - "lucina@simponic.xyz"
diff --git a/group_vars/webservers.yml b/group_vars/webservers.yml
deleted file mode 100644
index 2eb1ac3..0000000
--- a/group_vars/webservers.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-letsencrypt_email: 'elizabeth@simponic.xyz'
-hatecomputers_api_key: "{{ lookup('env', 'HATECOMPUTERS_API_KEY') }}"
diff --git a/inventory b/inventory
index 8b0da38..1b38d01 100644
--- a/inventory
+++ b/inventory
@@ -1,103 +1,15 @@
-[borg]
-nijika  ansible_user=root ansible_connection=ssh
-ryo  ansible_user=root ansible_connection=ssh
-levi  ansible_user=root ansible_connection=ssh
-mail.simponic.xyz ansible_user=root ansible_connection=ssh
-europa  ansible_user=root ansible_connection=ssh
-johan  ansible_user=root ansible_connection=ssh
-raspberrypi ansible_user=root ansible_connection=ssh
+[docker]
+swarm-one.localdomain  ansible_user=serve ansible_connection=ssh ansible_become_password='{{ swarm_become_password }}'
+swarm-two.localdomain  ansible_user=serve ansible_connection=ssh ansible_become_password='{{ swarm_become_password }}'
+swarm-three.localdomain  ansible_user=serve ansible_connection=ssh ansible_become_password='{{ swarm_become_password }}'
 
-[prod]
-nijika  ansible_user=root ansible_connection=ssh
-ryo  ansible_user=root ansible_connection=ssh
-levi  ansible_user=root ansible_connection=ssh
-mail.simponic.xyz ansible_user=root ansible_connection=ssh
+outbound-one.liz.coffee  ansible_user=serve ansible_connection=ssh ansible_become_password='{{ outbound_one_become_password }}'
+# outbound-two.liz.coffee  ansible_user=serve ansible_connection=ssh ansible_become_password='{{ vpn_become_password }}'
 
-[private]
-johan  ansible_user=root ansible_connection=ssh
-europa  ansible_user=root ansible_connection=ssh
-raspberrypi ansible_user=root ansible_connection=ssh
+[nginx-proxy]
+outbound-one.liz.coffee  ansible_user=serve ansible_connection=ssh ansible_become_password='{{ outbound_one_become_password }}'
+# outbound-two.liz.coffee  ansible_user=serve ansible_connection=ssh ansible_become_password='{{ vpn_become_password }}'
 
-[webservers]
-levi  ansible_user=root ansible_connection=ssh
-nijika  ansible_user=root ansible_connection=ssh
-ryo  ansible_user=root ansible_connection=ssh
-
-[nameservers]
-ryo  ansible_user=root ansible_connection=ssh
-nijika  ansible_user=root ansible_connection=ssh
-
-[dnsprimary]
-ryo  ansible_user=root ansible_connection=ssh
-
-[dnsreplica]
-nijika  ansible_user=root ansible_connection=ssh
-
-[vpn]
-nijika ansible_user=root ansible_connection=ssh
-
-[authelia]
-nijika  ansible_user=root ansible_connection=ssh
-
-[dnsinternal]
-johan ansible_user=root ansible_connection=ssh
-
-[pihole]
-johan  ansible_user=root ansible_connection=ssh
-
-[vaultwarden]
-johan  ansible_user=root ansible_connection=ssh
-
-[lldap]
-johan  ansible_user=root ansible_connection=ssh
-
-[ca]
-johan  ansible_user=root ansible_connection=ssh
-
-[mail]
-mail.simponic.xyz  ansible_user=root ansible_connection=ssh
-
-[roundcube]
-europa  ansible_user=root ansible_connection=ssh
-
-[scurvy]
-europa  ansible_user=root ansible_connection=ssh
-
-[gitea]
-nijika  ansible_user=root ansible_connection=ssh
-
-[static]
-levi  ansible_user=root ansible_connection=ssh
-
-[owncloud]
-europa  ansible_user=root ansible_connection=ssh
-
-[drone]
-europa  ansible_user=root ansible_connection=ssh
-
-[hatecomputers]
-levi  ansible_user=root ansible_connection=ssh
-
-[ntfy]
-johan  ansible_user=root ansible_connection=ssh
-
-[backup-notifications]
-johan  ansible_user=root ansible_connection=ssh
-
-[uptime]
-raspberrypi  ansible_user=root ansible_connection=ssh
-
-[phoneof]
-ryo ansible_user=root ansible_connection=ssh
-
-[something]
-ryo ansible_user=root ansible_connection=ssh
-
-[whois]
-ryo ansible_user=root ansible_connection=ssh
-
-[phoneassistant]
-johan ansible_user=root ansible_connection=ssh
-
-[zigbee]
-raspberrypi ansible_user=root ansible_connection=ssh
+[outbound]
+outbound-one.liz.coffee  ansible_user=serve ansible_connection=ssh ansible_become_password='{{ outbound_one_become_password }}'
+# outbound-two.liz.coffee  ansible_user=serve ansible_connection=ssh ansible_become_password='{{ vpn_become_password }}'
diff --git a/password.txt b/password.txt
new file mode 100644
index 0000000..8e354dc
--- /dev/null
+++ b/password.txt
@@ -0,0 +1 @@
+lKLDS8eet229nvvBppGqzS
diff --git a/playbooks/deploy-common.yml b/playbooks/deploy-common.yml
new file mode 100644
index 0000000..49ba22a
--- /dev/null
+++ b/playbooks/deploy-common.yml
@@ -0,0 +1,7 @@
+---
+
+- name: Common setup
+  hosts: all
+  become: true
+  roles:
+    - common
diff --git a/playbooks/deploy-docker.yml b/playbooks/deploy-docker.yml
new file mode 100644
index 0000000..a355bd3
--- /dev/null
+++ b/playbooks/deploy-docker.yml
@@ -0,0 +1,7 @@
+---
+
+- name: Docker setup
+  hosts: docker
+  become: true
+  roles:
+    - docker
diff --git a/playbooks/deploy-nginx-proxy.yml b/playbooks/deploy-nginx-proxy.yml
new file mode 100644
index 0000000..329f186
--- /dev/null
+++ b/playbooks/deploy-nginx-proxy.yml
@@ -0,0 +1,7 @@
+---
+
+- name: nginx-proxy setup
+  hosts: nginx-proxy
+  become: true
+  roles:
+    - nginx-proxy
diff --git a/playbooks/deploy-outbound.yml b/playbooks/deploy-outbound.yml
new file mode 100644
index 0000000..5867313
--- /dev/null
+++ b/playbooks/deploy-outbound.yml
@@ -0,0 +1,7 @@
+---
+
+- name: outbound setup
+  hosts: outbound
+  become: true
+  roles:
+    - outbound
diff --git a/playbooks/roles/common/handlers/main.yml b/playbooks/roles/common/handlers/main.yml
new file mode 100644
index 0000000..6a06d10
--- /dev/null
+++ b/playbooks/roles/common/handlers/main.yml
@@ -0,0 +1,22 @@
+---
+
+- name: Enable systemd-timesyncd
+  ansible.builtin.service:
+    name: systemd-timesyncd
+    state: restarted
+    enabled: true
+
+- name: Restart sshd
+  ansible.builtin.service:
+    name: sshd
+    state: restarted
+    enabled: true
+
+- name: Enable ufw
+  ansible.builtin.service:
+    enabled: true
+
+- name: Reload ufw
+  ansible.builtin.service:
+    name: ufw
+    state: restarted
diff --git a/playbooks/roles/common/tasks/main.yml b/playbooks/roles/common/tasks/main.yml
new file mode 100644
index 0000000..20c1bed
--- /dev/null
+++ b/playbooks/roles/common/tasks/main.yml
@@ -0,0 +1,66 @@
+---
+
+### Rly base stuff
+
+- name: Apt upgrade, update
+  ansible.builtin.apt:
+    update_cache: true
+    upgrade: "dist"
+
+- name: Install dependencies
+  ansible.builtin.apt:
+    name:
+      - apt-transport-https
+      - ca-certificates
+      - curl
+      - gnupg-agent
+      - software-properties-common
+      - vim
+      - git
+      - rsync
+    state: latest
+    update_cache: true
+
+### Time
+
+- name: Timesyncd
+  ansible.builtin.apt:
+    name:
+      - systemd-timesyncd
+  notify:
+    - Enable systemd-timesyncd
+
+### SSH
+
+- name: Copy sshd_config
+  ansible.builtin.copy:
+    src: files/sshd_config
+    dest: /etc/ssh/sshd_config
+    owner: root
+    group: root
+    mode: u=rw,g=r,o=r
+  notify:
+    - Restart sshd
+
+- name: Copy authorized_keys
+  ansible.builtin.copy:
+    src: files/authorized_keys
+    dest: /home/{{ ansible_user }}/.ssh/authorized_keys
+
+### UFW
+
+- name: Install ufw
+  ansible.builtin.apt:
+    name: ufw
+    state: present
+
+- name: Allow ssh from rfc1918 networks
+  loop: "{{ rfc1918_networks }}"
+  community.general.ufw:
+    rule: allow
+    name: "OpenSSH"
+    from: "{{ item }}"
+    state: "enabled"
+  notify:
+    - Enable ufw
+    - Reload ufw
diff --git a/roles/common/files/docker-compose@.service b/playbooks/roles/docker/files/docker-compose@.service
similarity index 77%
rename from roles/common/files/docker-compose@.service
rename to playbooks/roles/docker/files/docker-compose@.service
index ca157e3..77e8892 100644
--- a/roles/common/files/docker-compose@.service
+++ b/playbooks/roles/docker/files/docker-compose@.service
@@ -4,14 +4,16 @@ Requires=docker.service
 After=docker.service
 
 [Service]
-Type=simple
-Restart=always
-RestartSec=3
 RemainAfterExit=true
 WorkingDirectory=/etc/docker/compose/%i
 ExecStartPre=/bin/bash -c "/usr/bin/docker compose pull || true"
-ExecStart=/usr/bin/docker compose up --detach --remove-orphans
+ExecStart=/usr/bin/docker compose up
 ExecStop=/usr/bin/docker compose down
+Restart=always
+RestartSec=5
+StartLimitInterval=500
+StartLimitBurst=3
 
 [Install]
 WantedBy=multi-user.target
+
diff --git a/playbooks/roles/docker/files/docker-rollout b/playbooks/roles/docker/files/docker-rollout
new file mode 100755
index 0000000..c15d5a8
--- /dev/null
+++ b/playbooks/roles/docker/files/docker-rollout
@@ -0,0 +1,204 @@
+#!/bin/sh
+set -e
+
+# Defaults
+HEALTHCHECK_TIMEOUT=60
+NO_HEALTHCHECK_TIMEOUT=10
+WAIT_AFTER_HEALTHY_DELAY=0
+
+# Print metadata for Docker CLI plugin
+if [ "$1" = "docker-cli-plugin-metadata" ]; then
+  cat <<EOF
+{
+  "SchemaVersion": "0.1.0",
+  "Vendor": "Karol Musur",
+  "Version": "v0.9",
+  "ShortDescription": "Rollout new Compose service version"
+}
+EOF
+  exit
+fi
+
+# Save docker arguments, i.e. arguments before "rollout"
+while [ $# -gt 0 ]; do
+  if [ "$1" = "rollout" ]; then
+    shift
+    break
+  fi
+
+  DOCKER_ARGS="$DOCKER_ARGS $1"
+  shift
+done
+
+# Check if compose v2 is available
+if docker compose >/dev/null 2>&1; then
+  # shellcheck disable=SC2086 # DOCKER_ARGS must be unquoted to allow multiple arguments
+  COMPOSE_COMMAND="docker $DOCKER_ARGS compose"
+elif docker-compose >/dev/null 2>&1; then
+  COMPOSE_COMMAND="docker-compose"
+else
+  echo "docker compose or docker-compose is required"
+  exit 1
+fi
+
+usage() {
+  cat <<EOF
+
+Usage: docker rollout [OPTIONS] SERVICE
+
+Rollout new Compose service version.
+
+Options:
+  -h, --help                  Print usage
+  -f, --file FILE             Compose configuration files
+  -t, --timeout N             Healthcheck timeout (default: $HEALTHCHECK_TIMEOUT seconds)
+  -w, --wait N                When no healthcheck is defined, wait for N seconds
+                              before stopping old container (default: $NO_HEALTHCHECK_TIMEOUT seconds)
+      --wait-after-healthy N  When healthcheck is defined and succeeds, wait for additional N seconds
+                              before stopping the old container (default: 0 seconds)
+      --env-file FILE         Specify an alternate environment file
+
+EOF
+}
+
+exit_with_usage() {
+  usage
+  exit 1
+}
+
+healthcheck() {
+  # shellcheck disable=SC2086 # DOCKER_ARGS must be unquoted to allow multiple arguments
+  docker $DOCKER_ARGS inspect --format='{{json .State.Health.Status}}' "$1" | grep -v "unhealthy" | grep -q "healthy"
+}
+
+scale() {
+  # shellcheck disable=SC2086 # COMPOSE_FILES and ENV_FILES must be unquoted to allow multiple files
+  $COMPOSE_COMMAND $COMPOSE_FILES $ENV_FILES up --detach --scale "$1=$2" --no-recreate "$1"
+}
+
+main() {
+  # shellcheck disable=SC2086 # COMPOSE_FILES and ENV_FILES must be unquoted to allow multiple files
+  if [ -z "$($COMPOSE_COMMAND $COMPOSE_FILES $ENV_FILES ps --quiet "$SERVICE")" ]; then
+    echo "==> Service '$SERVICE' is not running. Starting the service."
+    $COMPOSE_COMMAND $COMPOSE_FILES $ENV_FILES up --detach --no-recreate "$SERVICE"
+    exit 0
+  fi
+
+  # shellcheck disable=SC2086 # COMPOSE_FILES and ENV_FILES must be unquoted to allow multiple files
+  OLD_CONTAINER_IDS_STRING=$($COMPOSE_COMMAND $COMPOSE_FILES $ENV_FILES ps --quiet "$SERVICE" | tr '\n' '|' | sed 's/|$//')
+  OLD_CONTAINER_IDS=$(echo "$OLD_CONTAINER_IDS_STRING" | tr '|' ' ')
+  SCALE=$(echo "$OLD_CONTAINER_IDS" | wc -w | tr -d ' ')
+  SCALE_TIMES_TWO=$((SCALE * 2))
+  echo "==> Scaling '$SERVICE' to '$SCALE_TIMES_TWO' instances"
+  scale "$SERVICE" $SCALE_TIMES_TWO
+
+  # Create a variable that contains the IDs of the new containers, but not the old ones
+  # shellcheck disable=SC2086 # COMPOSE_FILES and ENV_FILES must be unquoted to allow multiple files
+  NEW_CONTAINER_IDS=$($COMPOSE_COMMAND $COMPOSE_FILES $ENV_FILES ps --quiet "$SERVICE" | grep -Ev "$OLD_CONTAINER_IDS_STRING" | tr '\n' ' ')
+
+  # Check if first container has healthcheck
+  # shellcheck disable=SC2086 # DOCKER_ARGS must be unquoted to allow multiple arguments
+  if docker $DOCKER_ARGS inspect --format='{{json .State.Health}}' "$(echo $OLD_CONTAINER_IDS | cut -d\  -f 1)" | grep -q "Status"; then
+    echo "==> Waiting for new containers to be healthy (timeout: $HEALTHCHECK_TIMEOUT seconds)"
+    for _ in $(seq 1 "$HEALTHCHECK_TIMEOUT"); do
+      SUCCESS=0
+
+      for NEW_CONTAINER_ID in $NEW_CONTAINER_IDS; do
+        if healthcheck "$NEW_CONTAINER_ID"; then
+          SUCCESS=$((SUCCESS + 1))
+        fi
+      done
+
+      if [ "$SUCCESS" = "$SCALE" ]; then
+        break
+      fi
+
+      sleep 1
+    done
+
+    SUCCESS=0
+
+    for NEW_CONTAINER_ID in $NEW_CONTAINER_IDS; do
+      if healthcheck "$NEW_CONTAINER_ID"; then
+        SUCCESS=$((SUCCESS + 1))
+      fi
+    done
+
+    if [ "$SUCCESS" != "$SCALE" ]; then
+      echo "==> New containers are not healthy. Rolling back." >&2
+
+      docker $DOCKER_ARGS stop $NEW_CONTAINER_IDS
+      docker $DOCKER_ARGS rm $NEW_CONTAINER_IDS
+
+      exit 1
+    fi
+    
+    if [ "$WAIT_AFTER_HEALTHY_DELAY" != "0" ]; then
+      echo "==> Waiting for healthy containers to settle down ($WAIT_AFTER_HEALTHY_DELAY seconds)"
+      sleep $WAIT_AFTER_HEALTHY_DELAY
+    fi
+  else
+    echo "==> Waiting for new containers to be ready ($NO_HEALTHCHECK_TIMEOUT seconds)"
+    sleep "$NO_HEALTHCHECK_TIMEOUT"
+  fi
+
+  echo "==> Stopping and removing old containers"
+
+  # shellcheck disable=SC2086 # DOCKER_ARGS and OLD_CONTAINER_IDS must be unquoted to allow multiple arguments
+  docker $DOCKER_ARGS stop $OLD_CONTAINER_IDS
+  # shellcheck disable=SC2086 # DOCKER_ARGS and OLD_CONTAINER_IDS must be unquoted to allow multiple arguments
+  docker $DOCKER_ARGS rm $OLD_CONTAINER_IDS
+}
+
+while [ $# -gt 0 ]; do
+  case "$1" in
+  -h | --help)
+    usage
+    exit 0
+    ;;
+  -f | --file)
+    COMPOSE_FILES="$COMPOSE_FILES -f $2"
+    shift 2
+    ;;
+  --env-file)
+    ENV_FILES="$ENV_FILES --env-file $2"
+    shift 2
+    ;;
+  -t | --timeout)
+    HEALTHCHECK_TIMEOUT="$2"
+    shift 2
+    ;;
+  -w | --wait)
+    NO_HEALTHCHECK_TIMEOUT="$2"
+    shift 2
+    ;;
+  --wait-after-healthy)
+    WAIT_AFTER_HEALTHY_DELAY="$2"
+    shift 2
+    ;;
+  -*)
+    echo "Unknown option: $1"
+    exit_with_usage
+    ;;
+  *)
+    if [ -n "$SERVICE" ]; then
+      echo "SERVICE is already set to '$SERVICE'"
+
+      if [ "$SERVICE" != "$1" ]; then
+        exit_with_usage
+      fi
+    fi
+
+    SERVICE="$1"
+    shift
+    ;;
+  esac
+done
+
+# Require SERVICE argument
+if [ -z "$SERVICE" ]; then
+  echo "SERVICE is missing"
+  exit_with_usage
+fi
+
+main
diff --git a/playbooks/roles/docker/handlers/main.yml b/playbooks/roles/docker/handlers/main.yml
new file mode 100644
index 0000000..2db0186
--- /dev/null
+++ b/playbooks/roles/docker/handlers/main.yml
@@ -0,0 +1,8 @@
+---
+
+- name: Enable docker
+  ansible.builtin.service:
+    name: docker
+    state: restarted
+    enabled: true
+
diff --git a/playbooks/roles/docker/tasks/main.yml b/playbooks/roles/docker/tasks/main.yml
new file mode 100644
index 0000000..8b91f6a
--- /dev/null
+++ b/playbooks/roles/docker/tasks/main.yml
@@ -0,0 +1,55 @@
+---
+
+- name: Install dependencies
+  ansible.builtin.apt:
+    name:
+      - apt-transport-https
+      - ca-certificates
+      - curl
+      - gnupg-agent
+      - software-properties-common
+    state: present
+    update_cache: true
+
+- name: Docker GPG key
+  become: true
+  ansible.builtin.apt_key:
+    url: >
+      https://download.docker.com/linux/{{ ansible_distribution | lower }}/gpg      
+    state: present
+
+- name: Repository docker
+  ansible.builtin.apt_repository:
+    repo: >
+      deb https://download.docker.com/linux/{{ ansible_distribution | lower }}
+        {{ ansible_distribution_release }} stable      
+    state: present
+
+- name: Install docker
+  ansible.builtin.apt:
+    name:
+      - docker-ce
+      - docker-ce-cli
+      - containerd.io
+    state: present
+    update_cache: true
+  notify:
+    - Enable docker
+
+- name: Copy docker rollout script
+  ansible.builtin.copy:
+    src: docker-rollout
+    dest: /usr/local/bin/docker-rollout
+    mode: 0755
+
+- name: Copy docker-compose@.service
+  ansible.builtin.copy:
+    src: docker-compose@.service
+    dest: /etc/systemd/system/docker-compose@.service
+
+- name: Ensure /etc/docker/compose exist
+  ansible.builtin.file:
+    path: /etc/docker/compose
+    state: directory
+    mode: 0700
+
diff --git a/playbooks/roles/nginx-proxy/tasks/main.yml b/playbooks/roles/nginx-proxy/tasks/main.yml
new file mode 100644
index 0000000..7c0facc
--- /dev/null
+++ b/playbooks/roles/nginx-proxy/tasks/main.yml
@@ -0,0 +1,21 @@
+---
+- name: Build nginx-proxy compose dirs
+  ansible.builtin.file:
+    state: directory
+    dest: '/etc/docker/compose/nginx-proxy/{{ item.path }}'
+  with_filetree: '../templates'
+  when: item.state == 'directory'
+
+- name: Build nginx-proxy compose files
+  ansible.builtin.template:
+    src: '{{ item.src }}'
+    dest: '/etc/docker/compose/nginx-proxy/{{ item.path }}'
+  with_filetree: '../templates'
+  when: item.state == 'file'
+
+- name: Daemon-reload and enable nginx-proxy
+  ansible.builtin.systemd_service:
+    state: started
+    enabled: true
+    daemon_reload: true
+    name: docker-compose@nginx-proxy
diff --git a/playbooks/roles/nginx-proxy/templates/docker-compose.yml b/playbooks/roles/nginx-proxy/templates/docker-compose.yml
new file mode 100644
index 0000000..93e0859
--- /dev/null
+++ b/playbooks/roles/nginx-proxy/templates/docker-compose.yml
@@ -0,0 +1,32 @@
+---
+
+services:
+  nginx-proxy:
+    image: nginxproxy/nginx-proxy
+    container_name: nginx-proxy
+    ports:
+      - "80:80"
+      - "443:443"
+    volumes:
+      - /var/run/docker.sock:/tmp/docker.sock:ro
+      - ./certs:/etc/nginx/certs
+    networks:
+      - proxy
+
+  nginx-acme-companion:
+    image: nginxproxy/acme-companion
+    volumes:
+      - /var/run/docker.sock:/var/run/docker.sock:ro
+      - acme:/etc/acme.sh
+      - ./certs:/etc/nginx/certs
+    environment:
+      - DEFAULT_EMAIL={{ certs_email }}
+    networks:
+      - proxy
+
+volumes:
+  acme:
+
+networks:
+  proxy:
+    driver: bridge
diff --git a/playbooks/roles/outbound/tasks/main.yml b/playbooks/roles/outbound/tasks/main.yml
new file mode 100644
index 0000000..84070d6
--- /dev/null
+++ b/playbooks/roles/outbound/tasks/main.yml
@@ -0,0 +1,28 @@
+---
+
+- name: Build headscale compose dirs
+  ansible.builtin.file:
+    state: directory
+    dest: '/etc/docker/compose/headscale/{{ item.path }}'
+  with_filetree: '../templates'
+  when: item.state == 'directory'
+
+- name: Build headscale compose files
+  ansible.builtin.template:
+    src: '{{ item.src }}'
+    dest: '/etc/docker/compose/headscale/{{ item.path }}'
+  with_filetree: '../templates'
+  when: item.state == 'file'
+
+- name: Daemon-reload and enable headscale
+  ansible.builtin.systemd_service:
+    state: started
+    enabled: true
+    daemon_reload: true
+    name: docker-compose@headscale
+
+- name: Perform rollout incase daemon already started
+  ansible.builtin.shell:
+    cmd: /usr/local/bin/docker-rollout rollout -f docker-compose.yml headscale
+    chdir: /etc/docker/compose/headscale
+
diff --git a/playbooks/roles/outbound/templates/config/config.yaml b/playbooks/roles/outbound/templates/config/config.yaml
new file mode 100644
index 0000000..6d3fdae
--- /dev/null
+++ b/playbooks/roles/outbound/templates/config/config.yaml
@@ -0,0 +1,387 @@
+---
+
+server_url: '{{ headscale_url }}'
+listen_addr: '{{ headscale_listen_addr }}'
+
+# Address to listen to /metrics, you may want
+# to keep this endpoint private to your internal
+# network
+#
+metrics_listen_addr: 127.0.0.1:9090
+
+# Address to listen for gRPC.
+# gRPC is used for controlling a headscale server
+# remotely with the CLI
+# Note: Remote access _only_ works if you have
+# valid certificates.
+#
+# For production:
+# grpc_listen_addr: 0.0.0.0:50443
+grpc_listen_addr: 127.0.0.1:50443
+
+# Allow the gRPC admin interface to run in INSECURE
+# mode. This is not recommended as the traffic will
+# be unencrypted. Only enable if you know what you
+# are doing.
+grpc_allow_insecure: false
+
+# The Noise section includes specific configuration for the
+# TS2021 Noise protocol
+noise:
+  # The Noise private key is used to encrypt the
+  # traffic between headscale and Tailscale clients when
+  # using the new Noise-based protocol.
+  private_key_path: /var/lib/headscale/noise_private.key
+
+# List of IP prefixes to allocate tailaddresses from.
+# Each prefix consists of either an IPv4 or IPv6 address,
+# and the associated prefix length, delimited by a slash.
+# It must be within IP ranges supported by the Tailscale
+# client - i.e., subnets of 100.64.0.0/10 and fd7a:115c:a1e0::/48.
+# See below:
+# IPv6: https://github.com/tailscale/tailscale/blob/22ebb25e833264f58d7c3f534a8b166894a89536/net/tsaddr/tsaddr.go#LL81C52-L81C71
+# IPv4: https://github.com/tailscale/tailscale/blob/22ebb25e833264f58d7c3f534a8b166894a89536/net/tsaddr/tsaddr.go#L33
+# Any other range is NOT supported, and it will cause unexpected issues.
+prefixes:
+  v4: 100.64.0.0/10
+  v6: fd7a:115c:a1e0::/48
+
+  # Strategy used for allocation of IPs to nodes, available options:
+  # - sequential (default): assigns the next free IP from the previous given IP.
+  # - random: assigns the next free IP from a pseudo-random IP generator (crypto/rand).
+  allocation: sequential
+
+# DERP is a relay system that Tailscale uses when a direct
+# connection cannot be established.
+# https://tailscale.com/blog/how-tailscale-works/#encrypted-tcp-relays-derp
+#
+# headscale needs a list of DERP servers that can be presented
+# to the clients.
+derp:
+  server:
+    # If enabled, runs the embedded DERP server and merges it into the rest of the DERP config
+    # The Headscale server_url defined above MUST be using https, DERP requires TLS to be in place
+    enabled: false
+
+    # Region ID to use for the embedded DERP server.
+    # The local DERP prevails if the region ID collides with other region ID coming from
+    # the regular DERP config.
+    region_id: 999
+
+    # Region code and name are displayed in the Tailscale UI to identify a DERP region
+    region_code: "headscale"
+    region_name: "Headscale Embedded DERP"
+
+    # Listens over UDP at the configured address for STUN connections - to help with NAT traversal.
+    # When the embedded DERP server is enabled stun_listen_addr MUST be defined.
+    #
+    # For more details on how this works, check this great article: https://tailscale.com/blog/how-tailscale-works/
+    stun_listen_addr: "0.0.0.0:3478"
+
+    # Private key used to encrypt the traffic between headscale DERP
+    # and Tailscale clients.
+    # The private key file will be autogenerated if it's missing.
+    #
+    private_key_path: /var/lib/headscale/derp_server_private.key
+
+    # This flag can be used, so the DERP map entry for the embedded DERP server is not written automatically,
+    # it enables the creation of your very own DERP map entry using a locally available file with the parameter DERP.paths
+    # If you enable the DERP server and set this to false, it is required to add the DERP server to the DERP map using DERP.paths
+    automatically_add_embedded_derp_region: true
+
+    # For better connection stability (especially when using an Exit-Node and DNS is not working),
+    # it is possible to optionally add the public IPv4 and IPv6 address to the Derp-Map using:
+    ipv4: 1.2.3.4
+    ipv6: 2001:db8::1
+
+  # List of externally available DERP maps encoded in JSON
+  urls:
+    - https://controlplane.tailscale.com/derpmap/default
+
+  # Locally available DERP map files encoded in YAML
+  #
+  # This option is mostly interesting for people hosting
+  # their own DERP servers:
+  # https://tailscale.com/kb/1118/custom-derp-servers/
+  #
+  # paths:
+  #   - /etc/headscale/derp-example.yaml
+  paths: []
+
+  # If enabled, a worker will be set up to periodically
+  # refresh the given sources and update the derpmap
+  # will be set up.
+  auto_update_enabled: true
+
+  # How often should we check for DERP updates?
+  update_frequency: 24h
+
+# Disables the automatic check for headscale updates on startup
+disable_check_updates: false
+
+# Time before an inactive ephemeral node is deleted?
+ephemeral_node_inactivity_timeout: 30m
+
+database:
+  # Database type. Available options: sqlite, postgres
+  # Please note that using Postgres is highly discouraged as it is only supported for legacy reasons.
+  # All new development, testing and optimisations are done with SQLite in mind.
+  type: sqlite
+
+  # Enable debug mode. This setting requires the log.level to be set to "debug" or "trace".
+  debug: false
+
+  # GORM configuration settings.
+  gorm:
+    # Enable prepared statements.
+    prepare_stmt: true
+
+    # Enable parameterized queries.
+    parameterized_queries: true
+
+    # Skip logging "record not found" errors.
+    skip_err_record_not_found: true
+
+    # Threshold for slow queries in milliseconds.
+    slow_threshold: 1000
+
+  # SQLite config
+  sqlite:
+    path: /var/lib/headscale/db.sqlite
+
+    # Enable WAL mode for SQLite. This is recommended for production environments.
+    # https://www.sqlite.org/wal.html
+    write_ahead_log: true
+
+    # Maximum number of WAL file frames before the WAL file is automatically checkpointed.
+    # https://www.sqlite.org/c3ref/wal_autocheckpoint.html
+    # Set to 0 to disable automatic checkpointing.
+    wal_autocheckpoint: 1000
+
+  # # Postgres config
+  # Please note that using Postgres is highly discouraged as it is only supported for legacy reasons.
+  # See database.type for more information.
+  # postgres:
+  #   # If using a Unix socket to connect to Postgres, set the socket path in the 'host' field and leave 'port' blank.
+  #   host: localhost
+  #   port: 5432
+  #   name: headscale
+  #   user: foo
+  #   pass: bar
+  #   max_open_conns: 10
+  #   max_idle_conns: 10
+  #   conn_max_idle_time_secs: 3600
+
+  #   # If other 'sslmode' is required instead of 'require(true)' and 'disabled(false)', set the 'sslmode' you need
+  #   # in the 'ssl' field. Refers to https://www.postgresql.org/docs/current/libpq-ssl.html Table 34.1.
+  #   ssl: false
+
+### TLS configuration
+#
+## Let's encrypt / ACME
+#
+# headscale supports automatically requesting and setting up
+# TLS for a domain with Let's Encrypt.
+#
+# URL to ACME directory
+acme_url: https://acme-v02.api.letsencrypt.org/directory
+
+# Email to register with ACME provider
+acme_email: ""
+
+# Domain name to request a TLS certificate for:
+tls_letsencrypt_hostname: ""
+
+# Path to store certificates and metadata needed by
+# letsencrypt
+# For production:
+tls_letsencrypt_cache_dir: /var/lib/headscale/cache
+
+# Type of ACME challenge to use, currently supported types:
+# HTTP-01 or TLS-ALPN-01
+# See: docs/ref/tls.md for more information
+tls_letsencrypt_challenge_type: HTTP-01
+# When HTTP-01 challenge is chosen, letsencrypt must set up a
+# verification endpoint, and it will be listening on:
+# :http = port 80
+tls_letsencrypt_listen: ":http"
+
+## Use already defined certificates:
+tls_cert_path: ""
+tls_key_path: ""
+
+log:
+  # Output formatting for logs: text or json
+  format: text
+  level: info
+
+## Policy
+# headscale supports Tailscale's ACL policies.
+# Please have a look to their KB to better
+# understand the concepts: https://tailscale.com/kb/1018/acls/
+policy:
+  # The mode can be "file" or "database" that defines
+  # where the ACL policies are stored and read from.
+  mode: file
+  # If the mode is set to "file", the path to a
+  # HuJSON file containing ACL policies.
+  path: ""
+
+## DNS
+#
+# headscale supports Tailscale's DNS configuration and MagicDNS.
+# Please have a look to their KB to better understand the concepts:
+#
+# - https://tailscale.com/kb/1054/dns/
+# - https://tailscale.com/kb/1081/magicdns/
+# - https://tailscale.com/blog/2021-09-private-dns-with-magicdns/
+#
+# Please note that for the DNS configuration to have any effect,
+# clients must have the `--accept-dns=true` option enabled. This is the
+# default for the Tailscale client. This option is enabled by default
+# in the Tailscale client.
+#
+# Setting _any_ of the configuration and `--accept-dns=true` on the
+# clients will integrate with the DNS manager on the client or
+# overwrite /etc/resolv.conf.
+# https://tailscale.com/kb/1235/resolv-conf
+#
+# If you want stop Headscale from managing the DNS configuration
+# all the fields under `dns` should be set to empty values.
+dns:
+  # Whether to use [MagicDNS](https://tailscale.com/kb/1081/magicdns/).
+  magic_dns: true
+
+  # Defines the base domain to create the hostnames for MagicDNS.
+  # This domain _must_ be different from the server_url domain.
+  # `base_domain` must be a FQDN, without the trailing dot.
+  # The FQDN of the hosts will be
+  # `hostname.base_domain` (e.g., _myhost.example.com_).
+  base_domain: "{{ headscale_base_domain }}"
+
+  # List of DNS servers to expose to clients.
+  nameservers:
+    global:
+      - {{ headscale_dns_for_connected_clients_1 }}
+      - {{ headscale_dns_for_connected_clients_2 }}
+
+      # NextDNS (see https://tailscale.com/kb/1218/nextdns/).
+      # "abc123" is example NextDNS ID, replace with yours.
+      # - https://dns.nextdns.io/abc123
+
+    # Split DNS (see https://tailscale.com/kb/1054/dns/),
+    # a map of domains and which DNS server to use for each.
+    split:
+      {}
+      # foo.bar.com:
+      #   - 1.1.1.1
+      # darp.headscale.net:
+      #   - 1.1.1.1
+      #   - 8.8.8.8
+
+  # Set custom DNS search domains. With MagicDNS enabled,
+  # your tailnet base_domain is always the first search domain.
+  search_domains: []
+
+  # Extra DNS records
+  # so far only A and AAAA records are supported (on the tailscale side)
+  # See: docs/ref/dns.md
+  extra_records: []
+  #   - name: "grafana.myvpn.example.com"
+  #     type: "A"
+  #     value: "100.64.0.3"
+  #
+  #   # you can also put it in one line
+  #   - { name: "prometheus.myvpn.example.com", type: "A", value: "100.64.0.3" }
+  #
+  # Alternatively, extra DNS records can be loaded from a JSON file.
+  # Headscale processes this file on each change.
+  # extra_records_path: /var/lib/headscale/extra-records.json
+
+# Unix socket used for the CLI to connect without authentication
+# Note: for production you will want to set this to something like:
+unix_socket: /var/run/headscale/headscale.sock
+unix_socket_permission: "0770"
+#
+# headscale supports experimental OpenID connect support,
+# it is still being tested and might have some bugs, please
+# help us test it.
+# OpenID Connect
+# oidc:
+#   only_start_if_oidc_is_available: true
+#   issuer: "https://your-oidc.issuer.com/path"
+#   client_id: "your-oidc-client-id"
+#   client_secret: "your-oidc-client-secret"
+#   # Alternatively, set `client_secret_path` to read the secret from the file.
+#   # It resolves environment variables, making integration to systemd's
+#   # `LoadCredential` straightforward:
+#   client_secret_path: "${CREDENTIALS_DIRECTORY}/oidc_client_secret"
+#   # client_secret and client_secret_path are mutually exclusive.
+#
+#   # The amount of time from a node is authenticated with OpenID until it
+#   # expires and needs to reauthenticate.
+#   # Setting the value to "0" will mean no expiry.
+#   expiry: 180d
+#
+#   # Use the expiry from the token received from OpenID when the user logged
+#   # in, this will typically lead to frequent need to reauthenticate and should
+#   # only been enabled if you know what you are doing.
+#   # Note: enabling this will cause `oidc.expiry` to be ignored.
+#   use_expiry_from_token: false
+#
+#   # Customize the scopes used in the OIDC flow, defaults to "openid", "profile" and "email" and add custom query
+#   # parameters to the Authorize Endpoint request. Scopes default to "openid", "profile" and "email".
+#
+#   scope: ["openid", "profile", "email", "custom"]
+#   extra_params:
+#     domain_hint: example.com
+#
+#   # List allowed principal domains and/or users. If an authenticated user's domain is not in this list, the
+#   # authentication request will be rejected.
+#
+#   allowed_domains:
+#     - example.com
+#   # Note: Groups from keycloak have a leading '/'
+#   allowed_groups:
+#     - /headscale
+#   allowed_users:
+#     - alice@example.com
+#
+#   # Optional: PKCE (Proof Key for Code Exchange) configuration
+#   # PKCE adds an additional layer of security to the OAuth 2.0 authorization code flow
+#   # by preventing authorization code interception attacks
+#   # See https://datatracker.ietf.org/doc/html/rfc7636
+#   pkce:
+#     # Enable or disable PKCE support (default: false)
+#     enabled: false
+#     # PKCE method to use:
+#     # - plain: Use plain code verifier
+#     # - S256: Use SHA256 hashed code verifier (default, recommended)
+#     method: S256
+#
+#   # Map legacy users from pre-0.24.0 versions of headscale to the new OIDC users
+#   # by taking the username from the legacy user and matching it with the username
+#   # provided by the OIDC. This is useful when migrating from legacy users to OIDC
+#   # to force them using the unique identifier from the OIDC and to give them a
+#   # proper display name and picture if available.
+#   # Note that this will only work if the username from the legacy user is the same
+#   # and there is a possibility for account takeover should a username have changed
+#   # with the provider.
+#   # When this feature is disabled, it will cause all new logins to be created as new users.
+#   # Note this option will be removed in the future and should be set to false
+#   # on all new installations, or when all users have logged in with OIDC once.
+#   map_legacy_users: false
+
+# Logtail configuration
+# Logtail is Tailscales logging and auditing infrastructure, it allows the control panel
+# to instruct tailscale nodes to log their activity to a remote server.
+logtail:
+  # Enable logtail for this headscales clients.
+  # As there is currently no support for overriding the log server in headscale, this is
+  # disabled by default. Enabling this will make your clients send logs to Tailscale Inc.
+  enabled: false
+
+# Enabling this option makes devices prefer a random port for WireGuard traffic over the
+# default static port 41641. This option is intended as a workaround for some buggy
+# firewall devices. See https://tailscale.com/kb/1181/firewalls/ for more information.
+randomize_client_port: false
diff --git a/roles/webservers/files/levi/.gitkeep b/playbooks/roles/outbound/templates/data/.gitkeep
similarity index 100%
rename from roles/webservers/files/levi/.gitkeep
rename to playbooks/roles/outbound/templates/data/.gitkeep
diff --git a/playbooks/roles/outbound/templates/docker-compose.yml b/playbooks/roles/outbound/templates/docker-compose.yml
new file mode 100644
index 0000000..c644ca4
--- /dev/null
+++ b/playbooks/roles/outbound/templates/docker-compose.yml
@@ -0,0 +1,39 @@
+---
+
+services:
+  headscale:
+    image: headscale/headscale:stable-debug # until something better comes along with wget or i make my own dockerfile...
+    pull_policy: always
+    restart: unless-stopped
+    command: serve
+    volumes:
+      - ./config:/etc/headscale
+      - ./data:/var/lib/headscale
+    networks:
+      - proxy
+    environment:
+      - VIRTUAL_HOST={{ headscale_host }}
+      - VIRTUAL_PORT={{ headscale_port }}
+      - LETSENCRYPT_HOST={{ headscale_host }}
+    healthcheck:
+      test: ["CMD", "wget", "-qO", "-", "http://localhost:8080/health"] 
+      interval: 10s
+      timeout: 5s
+      retries: 3
+
+  headscale-ui:
+    image: ghcr.io/gurucomputing/headscale-ui:latest
+    pull_policy: always
+    restart: unless-stopped
+    networks:
+      - proxy
+    environment:
+      - VIRTUAL_HOST={{ headscale_host }}
+      - VIRTUAL_PORT={{ headscale_port }}
+      - LETSENCRYPT_HOST={{ headscale_host }}
+      - VIRTUAL_PATH=/web/ 
+      - VIRTUAL_DEST=/
+
+networks:
+  proxy:
+    external: true
diff --git a/roles/authelia/files/authelia/.gitignore b/roles/authelia/files/authelia/.gitignore
deleted file mode 100644
index 53c78ad..0000000
--- a/roles/authelia/files/authelia/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-users_database.yml
-configuration.yml
diff --git a/roles/authelia/tasks/main.yml b/roles/authelia/tasks/main.yml
deleted file mode 100644
index c9abe44..0000000
--- a/roles/authelia/tasks/main.yml
+++ /dev/null
@@ -1,30 +0,0 @@
----
-- name: ensure authelia docker/compose exist
-  file:
-    path: /etc/docker/compose/authelia
-    state: directory
-    owner: root
-    group: root
-    mode: 0700
-
-- name: copy authelia config
-  copy:
-    src: ../files/authelia
-    dest: /etc/docker/compose/authelia/
-    owner: root
-    group: root
-    mode: u=rw,g=r,o=r
-
-- name: build authelia docker-compose.yml.j2
-  template:
-    src: ../templates/docker-compose.yml.j2
-    dest: /etc/docker/compose/authelia/docker-compose.yml
-    owner: root
-    group: root
-    mode: u=rw,g=r,o=r
-
-- name: daemon-reload and enable authelia
-  ansible.builtin.systemd_service:
-    state: restarted
-    enabled: true
-    name: docker-compose@authelia
diff --git a/roles/authelia/templates/docker-compose.yml.j2 b/roles/authelia/templates/docker-compose.yml.j2
deleted file mode 100644
index e36296f..0000000
--- a/roles/authelia/templates/docker-compose.yml.j2
+++ /dev/null
@@ -1,19 +0,0 @@
-version: '3.3'
-
-services:
-  authelia:
-    image: authelia/authelia
-    container_name: authelia
-    volumes:
-      - ./authelia:/config
-    ports:
-      - 127.0.0.1:9091:9091
-    restart: unless-stopped
-    dns:
-      - {{ nameserver_ip }}
-  redis:
-    image: redis:alpine
-    container_name: redis
-    volumes:
-      - ./redis:/data
-    restart: unless-stopped
diff --git a/roles/backup-notifications/tasks/main.yml b/roles/backup-notifications/tasks/main.yml
deleted file mode 100644
index c649b2e..0000000
--- a/roles/backup-notifications/tasks/main.yml
+++ /dev/null
@@ -1,22 +0,0 @@
----
-- name: ensure backup-notifications docker/compose exist
-  file:
-    path: /etc/docker/compose/backup-notifications
-    state: directory
-    owner: root
-    group: root
-    mode: 0700
-
-- name: build backup-notifications docker-compose.yml.j2
-  template:
-    src: ../templates/docker-compose.yml.j2
-    dest: /etc/docker/compose/backup-notifications/docker-compose.yml
-    owner: root
-    group: root
-    mode: u=rw,g=r,o=r
-
-- name: daemon-reload and enable backup-notifications
-  ansible.builtin.systemd_service:
-    state: restarted
-    enabled: true
-    name: docker-compose@backup-notifications
diff --git a/roles/backup-notifications/templates/docker-compose.yml.j2 b/roles/backup-notifications/templates/docker-compose.yml.j2
deleted file mode 100644
index e915dd3..0000000
--- a/roles/backup-notifications/templates/docker-compose.yml.j2
+++ /dev/null
@@ -1,15 +0,0 @@
-version: "3"
-
-services:
-  backup-notify:
-    restart: always
-    image: git.simponic.xyz/simponic/backup-notify:latest
-    healthcheck:
-      test: ["CMD", "wget", "--spider", "http://localhost:8080/health"]
-      interval: 5s
-      timeout: 10s
-      retries: 5
-    ports:
-      - "127.0.0.1:31152:8080"
-    volumes:
-      - ./db:/app/db
diff --git a/roles/borg/tasks/main.yml b/roles/borg/tasks/main.yml
deleted file mode 100644
index 694290d..0000000
--- a/roles/borg/tasks/main.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-- name: copy key
-  template:
-    src: ../templates/borg_ssh_key.j2
-    dest: /root/borg_ssh_key
-    owner: root
-    group: root
-    mode: 0600
-
-- name: push borg
-  import_role: 
-    name: borgbase.ansible_role_borgbackup
-  vars:
-    borg_encryption_passphrase: "{{ borg_password }}"
-    borg_repository: "{{ borg_repo }}"
-    borg_user: "{{ borg_my_user }}"
-    borg_group: "{{ borg_my_group }}"
-    borgmatic_timer: cron
-    borg_ssh_command: "ssh -o StrictHostKeyChecking=no -i {{ borg_ssh_key }}"
-    borg_source_directories:
-      "{{ base_files + (extra_files[inventory_hostname] | default([])) }}"
-    borgmatic_relocated_repo_access_is_ok: True
-    borg_retention_policy:
-      keep_hourly: 3
-      keep_daily: 7
-      keep_weekly: 4
-      keep_monthly: 6
-    borgmatic_hooks:
-      after_backup:
-        - "curl -d '{{ inventory_hostname }}' {{ backup_topic }}"
diff --git a/roles/borg/templates/borg_ssh_key.j2 b/roles/borg/templates/borg_ssh_key.j2
deleted file mode 100644
index 70d4cc9..0000000
--- a/roles/borg/templates/borg_ssh_key.j2
+++ /dev/null
@@ -1 +0,0 @@
-{{ borg_secret_key | b64decode }}
diff --git a/roles/ca/tasks/main.yml b/roles/ca/tasks/main.yml
deleted file mode 100644
index 2649686..0000000
--- a/roles/ca/tasks/main.yml
+++ /dev/null
@@ -1,15 +0,0 @@
----
-
-- name: get root CA certificate
-  command: >
-    curl -k -X GET -H "Content-Type:application/json" \
-      "https://{{ step_bootstrap_ca_url }}:{{ step_ca_port }}/root/{{ step_bootstrap_fingerprint }}"
-  register: root_ca_fp
-
-- name: copy to os certificates
-  template:
-    src: "../templates/crt.j2"
-    dest: "/usr/local/share/ca-certificates/{{ step_bootstrap_ca_url }}.crt"
-
-- name: update trusted certs
-  command: "update-ca-certificates"
diff --git a/roles/ca/templates/crt.j2 b/roles/ca/templates/crt.j2
deleted file mode 100644
index f775757..0000000
--- a/roles/ca/templates/crt.j2
+++ /dev/null
@@ -1 +0,0 @@
-{{ (root_ca_fp.stdout | from_json).ca }}
diff --git a/roles/common/files/jail.conf b/roles/common/files/jail.conf
deleted file mode 100644
index 2c37a26..0000000
--- a/roles/common/files/jail.conf
+++ /dev/null
@@ -1,979 +0,0 @@
-#
-# WARNING: heavily refactored in 0.9.0 release.  Please review and
-#          customize settings for your setup.
-#
-# Changes:  in most of the cases you should not modify this
-#           file, but provide customizations in jail.local file,
-#           or separate .conf files under jail.d/ directory, e.g.:
-#
-# HOW TO ACTIVATE JAILS:
-#
-# YOU SHOULD NOT MODIFY THIS FILE.
-#
-# It will probably be overwritten or improved in a distribution update.
-#
-# Provide customizations in a jail.local file or a jail.d/customisation.local.
-# For example to change the default bantime for all jails and to enable the
-# ssh-iptables jail the following (uncommented) would appear in the .local file.
-# See man 5 jail.conf for details.
-#
-# [DEFAULT]
-# bantime = 1h
-#
-#
-# See jail.conf(5) man page for more information
-
-
-
-# Comments: use '#' for comment lines and ';' (following a space) for inline comments
-
-
-[INCLUDES]
-
-#before = paths-distro.conf
-before = paths-debian.conf
-
-# The DEFAULT allows a global definition of the options. They can be overridden
-# in each jail afterwards.
-
-[DEFAULT]
-
-#
-# MISCELLANEOUS OPTIONS
-#
-
-# "bantime.increment" allows to use database for searching of previously banned ip's to increase a 
-# default ban time using special formula, default it is banTime * 1, 2, 4, 8, 16, 32...
-#bantime.increment = true
-
-# "bantime.rndtime" is the max number of seconds using for mixing with random time 
-# to prevent "clever" botnets calculate exact time IP can be unbanned again:
-#bantime.rndtime = 
-
-# "bantime.maxtime" is the max number of seconds using the ban time can reach (doesn't grow further)
-#bantime.maxtime = 
-
-# "bantime.factor" is a coefficient to calculate exponent growing of the formula or common multiplier,
-# default value of factor is 1 and with default value of formula, the ban time 
-# grows by 1, 2, 4, 8, 16 ...
-#bantime.factor = 1
-
-# "bantime.formula" used by default to calculate next value of ban time, default value below,
-# the same ban time growing will be reached by multipliers 1, 2, 4, 8, 16, 32...
-#bantime.formula = ban.Time * (1<<(ban.Count if ban.Count<20 else 20)) * banFactor
-#
-# more aggressive example of formula has the same values only for factor "2.0 / 2.885385" :
-#bantime.formula = ban.Time * math.exp(float(ban.Count+1)*banFactor)/math.exp(1*banFactor)
-
-# "bantime.multipliers" used to calculate next value of ban time instead of formula, corresponding
-# previously ban count and given "bantime.factor" (for multipliers default is 1);
-# following example grows ban time by 1, 2, 4, 8, 16 ... and if last ban count greater as multipliers count, 
-# always used last multiplier (64 in example), for factor '1' and original ban time 600 - 10.6 hours
-#bantime.multipliers = 1 2 4 8 16 32 64
-# following example can be used for small initial ban time (bantime=60) - it grows more aggressive at begin,
-# for bantime=60 the multipliers are minutes and equal: 1 min, 5 min, 30 min, 1 hour, 5 hour, 12 hour, 1 day, 2 day
-#bantime.multipliers = 1 5 30 60 300 720 1440 2880
-
-# "bantime.overalljails" (if true) specifies the search of IP in the database will be executed 
-# cross over all jails, if false (default), only current jail of the ban IP will be searched
-#bantime.overalljails = false
-
-# --------------------
-
-# "ignoreself" specifies whether the local resp. own IP addresses should be ignored
-# (default is true). Fail2ban will not ban a host which matches such addresses.
-#ignoreself = true
-
-# "ignoreip" can be a list of IP addresses, CIDR masks or DNS hosts. Fail2ban
-# will not ban a host which matches an address in this list. Several addresses
-# can be defined using space (and/or comma) separator.
-#ignoreip = 127.0.0.1/8 ::1
-
-# External command that will take an tagged arguments to ignore, e.g. <ip>,
-# and return true if the IP is to be ignored. False otherwise.
-#
-# ignorecommand = /path/to/command <ip>
-ignorecommand =
-
-# "bantime" is the number of seconds that a host is banned.
-bantime  = 10m
-
-# A host is banned if it has generated "maxretry" during the last "findtime"
-# seconds.
-findtime  = 10m
-
-# "maxretry" is the number of failures before a host get banned.
-maxretry = 5
-
-# "maxmatches" is the number of matches stored in ticket (resolvable via tag <matches> in actions).
-maxmatches = %(maxretry)s
-
-# "backend" specifies the backend used to get files modification.
-# Available options are "pyinotify", "gamin", "polling", "systemd" and "auto".
-# This option can be overridden in each jail as well.
-#
-# pyinotify: requires pyinotify (a file alteration monitor) to be installed.
-#              If pyinotify is not installed, Fail2ban will use auto.
-# gamin:     requires Gamin (a file alteration monitor) to be installed.
-#              If Gamin is not installed, Fail2ban will use auto.
-# polling:   uses a polling algorithm which does not require external libraries.
-# systemd:   uses systemd python library to access the systemd journal.
-#              Specifying "logpath" is not valid for this backend.
-#              See "journalmatch" in the jails associated filter config
-# auto:      will try to use the following backends, in order:
-#              pyinotify, gamin, polling.
-#
-# Note: if systemd backend is chosen as the default but you enable a jail
-#       for which logs are present only in its own log files, specify some other
-#       backend for that jail (e.g. polling) and provide empty value for
-#       journalmatch. See https://github.com/fail2ban/fail2ban/issues/959#issuecomment-74901200
-backend = systemd
-
-# "usedns" specifies if jails should trust hostnames in logs,
-#   warn when DNS lookups are performed, or ignore all hostnames in logs
-#
-# yes:   if a hostname is encountered, a DNS lookup will be performed.
-# warn:  if a hostname is encountered, a DNS lookup will be performed,
-#        but it will be logged as a warning.
-# no:    if a hostname is encountered, will not be used for banning,
-#        but it will be logged as info.
-# raw:   use raw value (no hostname), allow use it for no-host filters/actions (example user)
-usedns = warn
-
-# "logencoding" specifies the encoding of the log files handled by the jail
-#   This is used to decode the lines from the log file.
-#   Typical examples:  "ascii", "utf-8"
-#
-#   auto:   will use the system locale setting
-logencoding = auto
-
-# "enabled" enables the jails.
-#  By default all jails are disabled, and it should stay this way.
-#  Enable only relevant to your setup jails in your .local or jail.d/*.conf
-#
-# true:  jail will be enabled and log files will get monitored for changes
-# false: jail is not enabled
-enabled = false
-
-
-# "mode" defines the mode of the filter (see corresponding filter implementation for more info).
-mode = normal
-
-# "filter" defines the filter to use by the jail.
-#  By default jails have names matching their filter name
-#
-filter = %(__name__)s[mode=%(mode)s]
-
-
-#
-# ACTIONS
-#
-
-# Some options used for actions
-
-# Destination email address used solely for the interpolations in
-# jail.{conf,local,d/*} configuration files.
-destemail = root@localhost
-
-# Sender email address used solely for some actions
-sender = root@<fq-hostname>
-
-# E-mail action. Since 0.8.1 Fail2Ban uses sendmail MTA for the
-# mailing. Change mta configuration parameter to mail if you want to
-# revert to conventional 'mail'.
-mta = sendmail
-
-# Default protocol
-protocol = tcp
-
-# Specify chain where jumps would need to be added in ban-actions expecting parameter chain
-chain = <known/chain>
-
-# Ports to be banned
-# Usually should be overridden in a particular jail
-port = 0:65535
-
-# Format of user-agent https://tools.ietf.org/html/rfc7231#section-5.5.3
-fail2ban_agent = Fail2Ban/%(fail2ban_version)s
-
-#
-# Action shortcuts. To be used to define action parameter
-
-# Default banning action (e.g. iptables, iptables-new,
-# iptables-multiport, shorewall, etc) It is used to define
-# action_* variables. Can be overridden globally or per
-# section within jail.local file
-banaction = iptables-multiport
-banaction_allports = iptables-allports
-
-# The simplest action to take: ban only
-action_ = %(banaction)s[port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
-
-# ban & send an e-mail with whois report to the destemail.
-action_mw = %(action_)s
-            %(mta)s-whois[sender="%(sender)s", dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"]
-
-# ban & send an e-mail with whois report and relevant log lines
-# to the destemail.
-action_mwl = %(action_)s
-             %(mta)s-whois-lines[sender="%(sender)s", dest="%(destemail)s", logpath="%(logpath)s", chain="%(chain)s"]
-
-# See the IMPORTANT note in action.d/xarf-login-attack for when to use this action
-#
-# ban & send a xarf e-mail to abuse contact of IP address and include relevant log lines
-# to the destemail.
-action_xarf = %(action_)s
-             xarf-login-attack[service=%(__name__)s, sender="%(sender)s", logpath="%(logpath)s", port="%(port)s"]
-
-# ban & send a notification to one or more of the 50+ services supported by Apprise.
-# See https://github.com/caronc/apprise/wiki for details on what is supported.
-#
-# You may optionally over-ride the default configuration line (containing the Apprise URLs)
-# by using 'apprise[config="/alternate/path/to/apprise.cfg"]' otherwise
-# /etc/fail2ban/apprise.conf is sourced for your supported notification configuration.
-# action = %(action_)s
-#          apprise
-
-# ban IP on CloudFlare & send an e-mail with whois report and relevant log lines
-# to the destemail.
-action_cf_mwl = cloudflare[cfuser="%(cfemail)s", cftoken="%(cfapikey)s"]
-                %(mta)s-whois-lines[sender="%(sender)s", dest="%(destemail)s", logpath="%(logpath)s", chain="%(chain)s"]
-
-# Report block via blocklist.de fail2ban reporting service API
-# 
-# See the IMPORTANT note in action.d/blocklist_de.conf for when to use this action.
-# Specify expected parameters in file action.d/blocklist_de.local or if the interpolation
-# `action_blocklist_de` used for the action, set value of `blocklist_de_apikey`
-# in your `jail.local` globally (section [DEFAULT]) or per specific jail section (resp. in 
-# corresponding jail.d/my-jail.local file).
-#
-action_blocklist_de  = blocklist_de[email="%(sender)s", service="%(__name__)s", apikey="%(blocklist_de_apikey)s", agent="%(fail2ban_agent)s"]
-
-# Report ban via abuseipdb.com.
-#
-# See action.d/abuseipdb.conf for usage example and details.
-#
-action_abuseipdb = abuseipdb
-
-# Choose default action.  To change, just override value of 'action' with the
-# interpolation to the chosen action shortcut (e.g.  action_mw, action_mwl, etc) in jail.local
-# globally (section [DEFAULT]) or per specific section
-action = %(action_)s
-
-
-#
-# JAILS
-#
-
-#
-# SSH servers
-#
-
-[sshd]
-
-# To use more aggressive sshd modes set filter parameter "mode" in jail.local:
-# normal (default), ddos, extra or aggressive (combines all).
-# See "tests/files/logs/sshd" or "filter.d/sshd.conf" for usage example and details.
-mode    = normal
-enabled = true
-port    = ssh
-logpath = %(sshd_log)s
-backend = %(sshd_backend)s
-
-
-[dropbear]
-
-port     = ssh
-logpath  = %(dropbear_log)s
-backend  = %(dropbear_backend)s
-
-
-[selinux-ssh]
-
-port     = ssh
-logpath  = %(auditd_log)s
-
-
-#
-# HTTP servers
-#
-
-[apache-auth]
-
-port     = http,https
-logpath  = %(apache_error_log)s
-
-
-[apache-badbots]
-# Ban hosts which agent identifies spammer robots crawling the web
-# for email addresses. The mail outputs are buffered.
-port     = http,https
-logpath  = %(apache_access_log)s
-bantime  = 48h
-maxretry = 1
-
-
-[apache-noscript]
-
-port     = http,https
-logpath  = %(apache_error_log)s
-
-
-[apache-overflows]
-
-port     = http,https
-logpath  = %(apache_error_log)s
-maxretry = 2
-
-
-[apache-nohome]
-
-port     = http,https
-logpath  = %(apache_error_log)s
-maxretry = 2
-
-
-[apache-botsearch]
-
-port     = http,https
-logpath  = %(apache_error_log)s
-maxretry = 2
-
-
-[apache-fakegooglebot]
-
-port     = http,https
-logpath  = %(apache_access_log)s
-maxretry = 1
-ignorecommand = %(fail2ban_confpath)s/filter.d/ignorecommands/apache-fakegooglebot <ip>
-
-
-[apache-modsecurity]
-
-port     = http,https
-logpath  = %(apache_error_log)s
-maxretry = 2
-
-
-[apache-shellshock]
-
-port    = http,https
-logpath = %(apache_error_log)s
-maxretry = 1
-
-
-[openhab-auth]
-
-filter = openhab
-banaction = %(banaction_allports)s
-logpath = /opt/openhab/logs/request.log
-
-
-# To use more aggressive http-auth modes set filter parameter "mode" in jail.local:
-# normal (default), aggressive (combines all), auth or fallback
-# See "tests/files/logs/nginx-http-auth" or "filter.d/nginx-http-auth.conf" for usage example and details.
-[nginx-http-auth]
-# mode = normal
-port    = http,https
-logpath = %(nginx_error_log)s
-
-# To use 'nginx-limit-req' jail you should have `ngx_http_limit_req_module` 
-# and define `limit_req` and `limit_req_zone` as described in nginx documentation
-# http://nginx.org/en/docs/http/ngx_http_limit_req_module.html
-# or for example see in 'config/filter.d/nginx-limit-req.conf'
-[nginx-limit-req]
-port    = http,https
-logpath = %(nginx_error_log)s
-
-[nginx-botsearch]
-
-port     = http,https
-logpath  = %(nginx_error_log)s
-
-[nginx-bad-request]
-port    = http,https
-logpath = %(nginx_access_log)s
-
-# Ban attackers that try to use PHP's URL-fopen() functionality
-# through GET/POST variables. - Experimental, with more than a year
-# of usage in production environments.
-
-[php-url-fopen]
-
-port    = http,https
-logpath = %(nginx_access_log)s
-          %(apache_access_log)s
-
-
-[suhosin]
-
-port    = http,https
-logpath = %(suhosin_log)s
-
-
-[lighttpd-auth]
-# Same as above for Apache's mod_auth
-# It catches wrong authentifications
-port    = http,https
-logpath = %(lighttpd_error_log)s
-
-
-#
-# Webmail and groupware servers
-#
-
-[roundcube-auth]
-
-port     = http,https
-logpath  = %(roundcube_errors_log)s
-# Use following line in your jail.local if roundcube logs to journal.
-#backend = %(syslog_backend)s
-
-
-[openwebmail]
-
-port     = http,https
-logpath  = /var/log/openwebmail.log
-
-
-[horde]
-
-port     = http,https
-logpath  = /var/log/horde/horde.log
-
-
-[groupoffice]
-
-port     = http,https
-logpath  = /home/groupoffice/log/info.log
-
-
-[sogo-auth]
-# Monitor SOGo groupware server
-# without proxy this would be:
-# port    = 20000
-port     = http,https
-logpath  = /var/log/sogo/sogo.log
-
-
-[tine20]
-
-logpath  = /var/log/tine20/tine20.log
-port     = http,https
-
-
-#
-# Web Applications
-#
-#
-
-[drupal-auth]
-
-port     = http,https
-logpath  = %(syslog_daemon)s
-backend  = %(syslog_backend)s
-
-[guacamole]
-
-port     = http,https
-logpath  = /var/log/tomcat*/catalina.out
-#logpath  = /var/log/guacamole.log
-
-[monit]
-#Ban clients brute-forcing the monit gui login
-port = 2812
-logpath  = /var/log/monit
-           /var/log/monit.log
-
-
-[webmin-auth]
-
-port    = 10000
-logpath = %(syslog_authpriv)s
-backend = %(syslog_backend)s
-
-
-[froxlor-auth]
-
-port    = http,https
-logpath  = %(syslog_authpriv)s
-backend  = %(syslog_backend)s
-
-
-#
-# HTTP Proxy servers
-#
-#
-
-[squid]
-
-port     =  80,443,3128,8080
-logpath = /var/log/squid/access.log
-
-
-[3proxy]
-
-port    = 3128
-logpath = /var/log/3proxy.log
-
-
-#
-# FTP servers
-#
-
-
-[proftpd]
-
-port     = ftp,ftp-data,ftps,ftps-data
-logpath  = %(proftpd_log)s
-backend  = %(proftpd_backend)s
-
-
-[pure-ftpd]
-
-port     = ftp,ftp-data,ftps,ftps-data
-logpath  = %(pureftpd_log)s
-backend  = %(pureftpd_backend)s
-
-
-[gssftpd]
-
-port     = ftp,ftp-data,ftps,ftps-data
-logpath  = %(syslog_daemon)s
-backend  = %(syslog_backend)s
-
-
-[wuftpd]
-
-port     = ftp,ftp-data,ftps,ftps-data
-logpath  = %(wuftpd_log)s
-backend  = %(wuftpd_backend)s
-
-
-[vsftpd]
-# or overwrite it in jails.local to be
-# logpath = %(syslog_authpriv)s
-# if you want to rely on PAM failed login attempts
-# vsftpd's failregex should match both of those formats
-port     = ftp,ftp-data,ftps,ftps-data
-logpath  = %(vsftpd_log)s
-
-
-#
-# Mail servers
-#
-
-# ASSP SMTP Proxy Jail
-[assp]
-
-port     = smtp,465,submission
-logpath  = /root/path/to/assp/logs/maillog.txt
-
-
-[courier-smtp]
-
-port     = smtp,465,submission
-logpath  = %(syslog_mail)s
-backend  = %(syslog_backend)s
-
-
-[postfix]
-# To use another modes set filter parameter "mode" in jail.local:
-mode    = more
-port    = smtp,465,submission
-logpath = %(postfix_log)s
-backend = %(postfix_backend)s
-
-
-[postfix-rbl]
-
-filter   = postfix[mode=rbl]
-port     = smtp,465,submission
-logpath  = %(postfix_log)s
-backend  = %(postfix_backend)s
-maxretry = 1
-
-
-[sendmail-auth]
-
-port    = submission,465,smtp
-logpath = %(syslog_mail)s
-backend = %(syslog_backend)s
-
-
-[sendmail-reject]
-# To use more aggressive modes set filter parameter "mode" in jail.local:
-# normal (default), extra or aggressive
-# See "tests/files/logs/sendmail-reject" or "filter.d/sendmail-reject.conf" for usage example and details.
-#mode    = normal
-port     = smtp,465,submission
-logpath  = %(syslog_mail)s
-backend  = %(syslog_backend)s
-
-
-[qmail-rbl]
-
-filter  = qmail
-port    = smtp,465,submission
-logpath = /service/qmail/log/main/current
-
-
-# dovecot defaults to logging to the mail syslog facility
-# but can be set by syslog_facility in the dovecot configuration.
-[dovecot]
-
-port    = pop3,pop3s,imap,imaps,submission,465,sieve
-logpath = %(dovecot_log)s
-backend = %(dovecot_backend)s
-
-
-[sieve]
-
-port   = smtp,465,submission
-logpath = %(dovecot_log)s
-backend = %(dovecot_backend)s
-
-
-[solid-pop3d]
-
-port    = pop3,pop3s
-logpath = %(solidpop3d_log)s
-
-
-[exim]
-# see filter.d/exim.conf for further modes supported from filter:
-#mode = normal
-port   = smtp,465,submission
-logpath = %(exim_main_log)s
-
-
-[exim-spam]
-
-port   = smtp,465,submission
-logpath = %(exim_main_log)s
-
-
-[kerio]
-
-port    = imap,smtp,imaps,465
-logpath = /opt/kerio/mailserver/store/logs/security.log
-
-
-#
-# Mail servers authenticators: might be used for smtp,ftp,imap servers, so
-# all relevant ports get banned
-#
-
-[courier-auth]
-
-port     = smtp,465,submission,imap,imaps,pop3,pop3s
-logpath  = %(syslog_mail)s
-backend  = %(syslog_backend)s
-
-
-[postfix-sasl]
-
-filter   = postfix[mode=auth]
-port     = smtp,465,submission,imap,imaps,pop3,pop3s
-# You might consider monitoring /var/log/mail.warn instead if you are
-# running postfix since it would provide the same log lines at the
-# "warn" level but overall at the smaller filesize.
-logpath  = %(postfix_log)s
-backend  = %(postfix_backend)s
-
-
-[perdition]
-
-port   = imap,imaps,pop3,pop3s
-logpath = %(syslog_mail)s
-backend = %(syslog_backend)s
-
-
-[squirrelmail]
-
-port = smtp,465,submission,imap,imap2,imaps,pop3,pop3s,http,https,socks
-logpath = /var/lib/squirrelmail/prefs/squirrelmail_access_log
-
-
-[cyrus-imap]
-
-port   = imap,imaps
-logpath = %(syslog_mail)s
-backend = %(syslog_backend)s
-
-
-[uwimap-auth]
-
-port   = imap,imaps
-logpath = %(syslog_mail)s
-backend = %(syslog_backend)s
-
-
-#
-#
-# DNS servers
-#
-
-
-# !!! WARNING !!!
-#   Since UDP is connection-less protocol, spoofing of IP and imitation
-#   of illegal actions is way too simple.  Thus enabling of this filter
-#   might provide an easy way for implementing a DoS against a chosen
-#   victim. See
-#    http://nion.modprobe.de/blog/archives/690-fail2ban-+-dns-fail.html
-#   Please DO NOT USE this jail unless you know what you are doing.
-#
-# IMPORTANT: see filter.d/named-refused for instructions to enable logging
-# This jail blocks UDP traffic for DNS requests.
-# [named-refused-udp]
-#
-# filter   = named-refused
-# port     = domain,953
-# protocol = udp
-# logpath  = /var/log/named/security.log
-
-# IMPORTANT: see filter.d/named-refused for instructions to enable logging
-# This jail blocks TCP traffic for DNS requests.
-
-[named-refused]
-
-port     = domain,953
-logpath  = /var/log/named/security.log
-
-
-[nsd]
-
-port     = 53
-action_  = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
-           %(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
-logpath = /var/log/nsd.log
-
-
-#
-# Miscellaneous
-#
-
-[asterisk]
-
-port     = 5060,5061
-action_  = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
-           %(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
-logpath  = /var/log/asterisk/messages
-maxretry = 10
-
-
-[freeswitch]
-
-port     = 5060,5061
-action_  = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
-           %(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
-logpath  = /var/log/freeswitch.log
-maxretry = 10
-
-
-# enable adminlog; it will log to a file inside znc's directory by default.
-[znc-adminlog]
-
-port     = 6667
-logpath  = /var/lib/znc/moddata/adminlog/znc.log
-
-
-# To log wrong MySQL access attempts add to /etc/my.cnf in [mysqld] or
-# equivalent section:
-# log-warnings = 2
-#
-# for syslog (daemon facility)
-# [mysqld_safe]
-# syslog
-#
-# for own logfile
-# [mysqld]
-# log-error=/var/log/mysqld.log
-[mysqld-auth]
-
-port     = 3306
-logpath  = %(mysql_log)s
-backend  = %(mysql_backend)s
-
-
-[mssql-auth]
-# Default configuration for Microsoft SQL Server for Linux
-# See the 'mssql-conf' manpage how to change logpath or port
-logpath = /var/opt/mssql/log/errorlog
-port = 1433
-filter = mssql-auth
-
-
-# Log wrong MongoDB auth (for details see filter 'filter.d/mongodb-auth.conf')
-[mongodb-auth]
-# change port when running with "--shardsvr" or "--configsvr" runtime operation
-port     = 27017
-logpath  = /var/log/mongodb/mongodb.log
-
-
-# Jail for more extended banning of persistent abusers
-# !!! WARNINGS !!!
-# 1. Make sure that your loglevel specified in fail2ban.conf/.local
-#    is not at DEBUG level -- which might then cause fail2ban to fall into
-#    an infinite loop constantly feeding itself with non-informative lines
-# 2. Increase dbpurgeage defined in fail2ban.conf to e.g. 648000 (7.5 days)
-#    to maintain entries for failed logins for sufficient amount of time
-[recidive]
-
-logpath  = /var/log/fail2ban.log
-banaction = %(banaction_allports)s
-bantime  = 1w
-findtime = 1d
-
-
-# Generic filter for PAM. Has to be used with action which bans all
-# ports such as iptables-allports, shorewall
-
-[pam-generic]
-# pam-generic filter can be customized to monitor specific subset of 'tty's
-banaction = %(banaction_allports)s
-logpath  = %(syslog_authpriv)s
-backend  = %(syslog_backend)s
-
-
-[xinetd-fail]
-
-banaction = iptables-multiport-log
-logpath   = %(syslog_daemon)s
-backend   = %(syslog_backend)s
-maxretry  = 2
-
-
-# stunnel - need to set port for this
-[stunnel]
-
-logpath = /var/log/stunnel4/stunnel.log
-
-
-[ejabberd-auth]
-
-port    = 5222
-logpath = /var/log/ejabberd/ejabberd.log
-
-
-[counter-strike]
-
-logpath = /opt/cstrike/logs/L[0-9]*.log
-tcpport = 27030,27031,27032,27033,27034,27035,27036,27037,27038,27039
-udpport = 1200,27000,27001,27002,27003,27004,27005,27006,27007,27008,27009,27010,27011,27012,27013,27014,27015
-action_  = %(default/action_)s[name=%(__name__)s-tcp, port="%(tcpport)s", protocol="tcp"]
-           %(default/action_)s[name=%(__name__)s-udp, port="%(udpport)s", protocol="udp"]
-
-[softethervpn]
-port     = 500,4500
-protocol = udp
-logpath  = /usr/local/vpnserver/security_log/*/sec.log
-
-[gitlab]
-port    = http,https
-logpath = /var/log/gitlab/gitlab-rails/application.log
-
-[grafana]
-port    = http,https
-logpath = /var/log/grafana/grafana.log
-
-[bitwarden]
-port    = http,https
-logpath = /home/*/bwdata/logs/identity/Identity/log.txt
-
-[centreon]
-port    = http,https
-logpath = /var/log/centreon/login.log
-
-# consider low maxretry and a long bantime
-# nobody except your own Nagios server should ever probe nrpe
-[nagios]
-
-logpath  = %(syslog_daemon)s     ; nrpe.cfg may define a different log_facility
-backend  = %(syslog_backend)s
-maxretry = 1
-
-
-[oracleims]
-# see "oracleims" filter file for configuration requirement for Oracle IMS v6 and above
-logpath = /opt/sun/comms/messaging64/log/mail.log_current
-banaction = %(banaction_allports)s
-
-[directadmin]
-logpath = /var/log/directadmin/login.log
-port = 2222
-
-[portsentry]
-logpath  = /var/lib/portsentry/portsentry.history
-maxretry = 1
-
-[pass2allow-ftp]
-# this pass2allow example allows FTP traffic after successful HTTP authentication
-port         = ftp,ftp-data,ftps,ftps-data
-# knocking_url variable must be overridden to some secret value in jail.local
-knocking_url = /knocking/
-filter       = apache-pass[knocking_url="%(knocking_url)s"]
-# access log of the website with HTTP auth
-logpath      = %(apache_access_log)s
-blocktype    = RETURN
-returntype   = DROP
-action       = %(action_)s[blocktype=%(blocktype)s, returntype=%(returntype)s,
-                        actionstart_on_demand=false, actionrepair_on_unban=true]
-bantime      = 1h
-maxretry     = 1
-findtime     = 1
-
-
-[murmur]
-# AKA mumble-server
-port     = 64738
-action_  = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
-           %(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
-logpath  = /var/log/mumble-server/mumble-server.log
-
-
-[screensharingd]
-# For Mac OS Screen Sharing Service (VNC)
-logpath  = /var/log/system.log
-logencoding = utf-8
-
-[haproxy-http-auth]
-# HAProxy by default doesn't log to file you'll need to set it up to forward
-# logs to a syslog server which would then write them to disk.
-# See "haproxy-http-auth" filter for a brief cautionary note when setting
-# maxretry and findtime.
-logpath  = /var/log/haproxy.log
-
-[slapd]
-port    = ldap,ldaps
-logpath = /var/log/slapd.log
-
-[domino-smtp]
-port    = smtp,ssmtp
-logpath = /home/domino01/data/IBM_TECHNICAL_SUPPORT/console.log
-
-[phpmyadmin-syslog]
-port    = http,https
-logpath = %(syslog_authpriv)s
-backend = %(syslog_backend)s
-
-
-[zoneminder]
-# Zoneminder HTTP/HTTPS web interface auth
-# Logs auth failures to apache2 error log
-port    = http,https
-logpath = %(apache_error_log)s
-
-[traefik-auth]
-# to use 'traefik-auth' filter you have to configure your Traefik instance,
-# see `filter.d/traefik-auth.conf` for details and service example.
-port    = http,https
-logpath = /var/log/traefik/access.log
-
-[scanlogd]
-logpath = %(syslog_local0)s
-banaction = %(banaction_allports)s
-
-[monitorix]
-port	= 8080
-logpath = /var/log/monitorix-httpd
diff --git a/roles/common/files/sshd_config b/roles/common/files/sshd_config
deleted file mode 100644
index fb8efff..0000000
--- a/roles/common/files/sshd_config
+++ /dev/null
@@ -1,24 +0,0 @@
-Include /etc/ssh/sshd_config.d/*.conf
-
-Port 22
-PermitRootLogin yes
-PubkeyAuthentication yes
-PasswordAuthentication no
-
-KbdInteractiveAuthentication no
-
-UsePAM yes
-
-AllowAgentForwarding yes
-X11Forwarding no
-PrintMotd no
-PrintLastLog yes
-TCPKeepAlive yes
-ClientAliveInterval 300
-ClientAliveCountMax 1
-
-# Allow client to pass locale environment variables
-AcceptEnv LANG LC_*
-
-# override default of no subsystems
-Subsystem	sftp	/usr/lib/openssh/sftp-server
diff --git a/roles/common/tasks/main.yml b/roles/common/tasks/main.yml
deleted file mode 100644
index 0250ef3..0000000
--- a/roles/common/tasks/main.yml
+++ /dev/null
@@ -1,123 +0,0 @@
----
-
-# set hostname
-- name: Set a hostname specifying strategy
-  ansible.builtin.hostname:
-    name: "{{ inventory_hostname }}"
-    use: systemd
-
-# docker
-- name: install dependencies
-  apt:
-    name:
-      - apt-transport-https
-      - ca-certificates
-      - curl
-      - gnupg-agent
-      - software-properties-common
-      - sudo
-      - systemd-timesyncd
-    state: latest
-    update_cache: yes
-
-- name: Update and upgrade apt packages
-  become: true
-  apt:
-    upgrade: yes
-    update_cache: yes
-    cache_valid_time: 86400 #One day
-
-- name: enable systemd-timesyncd
-  ansible.builtin.systemd_service: 
-    name: systemd-timesyncd 
-    state: restarted 
-    enabled: true 
-    daemon_reload: true
-
-- name: purge ntp
-  apt:
-    name:
-      - ntp
-    state: absent
-
-- name: docker GPG key
-  apt_key:
-    url: https://download.docker.com/linux/debian/gpg
-    state: present
-
-- name: repository docker
-  apt_repository:
-    repo: deb https://download.docker.com/linux/debian {{ ansible_distribution_release }} stable
-    state: present 
-
-- name: install docker
-  apt:
-    name:
-      - docker-ce
-      - docker-ce-cli
-      - containerd.io
-    state: latest
-    update_cache: yes
-
-- name: enable docker
-  ansible.builtin.systemd_service: 
-    name: docker 
-    state: restarted 
-    enabled: true 
-    daemon_reload: true
-
-- name: copy docker-compose@.service
-  copy:
-    src: ../files/docker-compose@.service
-    dest: /etc/systemd/system/docker-compose@.service
-    owner: root
-    group: root
-    mode: u=rw,g=r,o=r
-
-- name: ensure /etc/docker/compose exist
-  file:
-    path: /etc/docker/compose
-    state: directory
-    owner: root
-    group: root
-    mode: 0700
-
-# SSH
-- name: Copy sshd_config
-  copy:
-    src: ../files/sshd_config
-    dest: /etc/ssh/sshd_config
-    owner: root
-    group: root
-    mode: u=rw,g=r,o=r
-
-- name: restart sshd
-  service: name=sshd state=restarted enabled=yes
-
-# FIREWALL
-- name: install UFW
-  apt: name=ufw state=latest
-
-- name: allow ssh from everywhere and enable
-  ufw:
-    rule: allow
-    name: OpenSSH
-    state: enabled
-
-- name: restart ufw
-  service: name=ufw state=restarted enabled=yes
-
-# FAIL2BAN
-- name: install fail2ban
-  apt: name=fail2ban state=latest
-
-- name: Copy jail.conf
-  copy:
-    src: ../files/jail.conf
-    dest: /etc/fail2ban/jail.conf
-    owner: root
-    group: root
-    mode: u=rw,g=r,o=r
-
-- name: restart fail2ban
-  service: name=fail2ban state=restarted enabled=yes
diff --git a/roles/dnscommon/files/named.conf.options b/roles/dnscommon/files/named.conf.options
deleted file mode 100644
index c788257..0000000
--- a/roles/dnscommon/files/named.conf.options
+++ /dev/null
@@ -1,12 +0,0 @@
-options {
-  directory "/var/cache/bind";
-
-  recursion no;
-  allow-transfer { none; };
-
-  allow-query { any; };
-
-  auth-nxdomain no;    # conform to RFC1035
-
-  listen-on-v6 { any; };
-};
diff --git a/roles/dnscommon/tasks/main.yml b/roles/dnscommon/tasks/main.yml
deleted file mode 100644
index c7547d7..0000000
--- a/roles/dnscommon/tasks/main.yml
+++ /dev/null
@@ -1,30 +0,0 @@
----
-- name: install BIND
-  apt: name=bind9 state=latest
-- name: install BIND-utils
-  apt: name=bind9-utils state=latest
-
-- name: copy named.conf.options
-  copy:
-    src: ../files/named.conf.options
-    dest: /etc/bind/named.conf.options
-    owner: bind
-    group: bind
-    mode: 0644
-
-- name: restart & enable BIND
-  service: name=named state=restarted enabled=yes
-
-- name: allow dns from everywhere via udp
-  ufw:
-    rule: allow
-    port: '53'
-    proto: udp
-- name: allow dns from everywhere via tcp
-  ufw:
-    rule: allow
-    port: '53'
-    proto: tcp
-
-- name: restart ufw
-  service: name=ufw state=restarted enabled=yes
diff --git a/roles/drone/tasks/main.yml b/roles/drone/tasks/main.yml
deleted file mode 100644
index 25f0dbb..0000000
--- a/roles/drone/tasks/main.yml
+++ /dev/null
@@ -1,22 +0,0 @@
----
-- name: ensure drone docker/compose exist
-  file:
-    path: /etc/docker/compose/drone
-    state: directory
-    owner: root
-    group: root
-    mode: 0700
-
-- name: build drone docker-compose.yml.j2
-  template:
-    src: ../templates/docker-compose.yml.j2
-    dest: /etc/docker/compose/drone/docker-compose.yml
-    owner: root
-    group: root
-    mode: u=rw,g=r,o=r
-
-- name: daemon-reload and enable drone
-  ansible.builtin.systemd_service:
-    state: restarted
-    enabled: true
-    name: docker-compose@drone
diff --git a/roles/drone/templates/docker-compose.yml.j2 b/roles/drone/templates/docker-compose.yml.j2
deleted file mode 100644
index 8c5e31e..0000000
--- a/roles/drone/templates/docker-compose.yml.j2
+++ /dev/null
@@ -1,29 +0,0 @@
-version: '3'
-
-services:
-  drone:
-    container_name: drone
-    image: drone/drone:latest
-    volumes:
-      - ./drone:/data
-    ports:
-      - "127.0.0.1:2201:80"
-    environment:
-      - DRONE_GITEA_SERVER=https://git.simponic.xyz
-      - DRONE_GITEA_CLIENT_ID={{ drone_gitea_client_id }}
-      - DRONE_GITEA_CLIENT_SECRET={{ drone_gitea_client_secret }}
-      - DRONE_GIT_ALWAYS_AUTH=true
-      - DRONE_SERVER_PROTO=https
-      - DRONE_SERVER_HOST=drone.internal.simponic.xyz
-      - DRONE_RPC_SECRET={{ drone_rpc_secret }}
-  drone-runner:
-    container_name: drone_runner
-    image: drone/drone-runner-docker:latest
-    userns_mode: 'host' # Needed to get access to docker socket
-    volumes:
-      - /var/run/docker.sock:/var/run/docker.sock
-    environment:
-      - DRONE_RPC_SECRET={{ drone_rpc_secret }}
-      - DRONE_RPC_HOST=drone:80
-      - DRONE_RPC_PROTO=http
-      - DRONE_RUNNER_CAPACITY=4 
diff --git a/roles/gitea/files/.gitignore b/roles/gitea/files/.gitignore
deleted file mode 100644
index 7ac6d1c..0000000
--- a/roles/gitea/files/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-app.ini
diff --git a/roles/gitea/tasks/main.yml b/roles/gitea/tasks/main.yml
deleted file mode 100644
index c18b861..0000000
--- a/roles/gitea/tasks/main.yml
+++ /dev/null
@@ -1,46 +0,0 @@
----
-- name: ensure gitea docker/compose exist
-  file:
-    path: /etc/docker/compose/gitea
-    state: directory
-    owner: root
-    group: root
-    mode: 0700
-
-- name: create gitea docker/compose/data/gitea with set uid/gid
-  file:
-    path: /etc/docker/compose/gitea/data
-    state: directory
-    owner: 1000
-    group: 1000
-    mode: 0700
-
-- name: ensure gitea docker/compose/data/gitea exist
-  file:
-    path: /etc/docker/compose/gitea/data/gitea/conf
-    state: directory
-    owner: 1000
-    group: 1000
-    mode: 0700
-
-- name: copy app.ini
-  copy:
-    src: ../files/app.ini
-    dest: /etc/docker/compose/gitea/data/gitea/conf/app.ini
-    owner: 1000
-    group: 1000
-    mode: 0700
-
-- name: build gitea docker-compose.yml.j2
-  template:
-    src: ../templates/docker-compose.yml.j2
-    dest: /etc/docker/compose/gitea/docker-compose.yml
-    owner: root
-    group: root
-    mode: u=rw,g=r,o=r
-
-- name: daemon-reload and enable gitea
-  ansible.builtin.systemd_service:
-    state: restarted
-    enabled: true
-    name: docker-compose@gitea
diff --git a/roles/gitea/templates/docker-compose.yml.j2 b/roles/gitea/templates/docker-compose.yml.j2
deleted file mode 100644
index b9d410c..0000000
--- a/roles/gitea/templates/docker-compose.yml.j2
+++ /dev/null
@@ -1,22 +0,0 @@
-version: "3"
-
-networks:
-  gitea:
-    external: false
-
-services:
-  server:
-    image: gitea/gitea:latest
-    container_name: gitea
-    restart: always
-    networks:
-      - gitea
-    volumes:
-      - ./data:/data
-      - /etc/timezone:/etc/timezone:ro
-      - /etc/localtime:/etc/localtime:ro
-    ports:
-      - "127.0.0.1:9966:3000"
-      - "{{ nijika_ip }}:222:22"
-    dns:
-      - {{ nameserver_ip }}
diff --git a/roles/hatecomputers/files/.gitignore b/roles/hatecomputers/files/.gitignore
deleted file mode 100644
index 5571ff7..0000000
--- a/roles/hatecomputers/files/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-wireguard.cfg
diff --git a/roles/hatecomputers/tasks/main.yml b/roles/hatecomputers/tasks/main.yml
deleted file mode 100644
index 4e12d32..0000000
--- a/roles/hatecomputers/tasks/main.yml
+++ /dev/null
@@ -1,39 +0,0 @@
-- name: install wireguard
-  apt:
-    name:
-      - wireguard
-    state: latest
-
-- name: stop wireguard and enable on boot
-  systemd:
-    name: wg-quick@hatecomputers
-    enabled: yes
-    state: stopped
-
-- name: copy config
-  ansible.builtin.copy:
-    src: ../files/wireguard.cfg
-    dest: /etc/wireguard/hatecomputers.conf
-    owner: root
-    group: root
-    mode: 0600
-
-- name: enable and persist ip forwarding
-  sysctl:
-    name: net.ipv4.ip_forward
-    value: "1"
-    state: present
-    sysctl_set: yes
-    reload: yes
-
-- name: start wireguard and enable on boot
-  systemd:
-    name: wg-quick@hatecomputers
-    enabled: yes
-    state: restarted
-
-- name: allow wireguard endpoint ufw
-  ufw:
-    rule: allow
-    port: '51820'
-    proto: 'udp'
diff --git a/roles/lldap/tasks/main.yml b/roles/lldap/tasks/main.yml
deleted file mode 100644
index 79b9a86..0000000
--- a/roles/lldap/tasks/main.yml
+++ /dev/null
@@ -1,28 +0,0 @@
----
-- name: ensure lldap docker/compose exist
-  file:
-    path: /etc/docker/compose/lldap
-    state: directory
-    owner: root
-    group: root
-    mode: 0700
-
-- name: build lldap docker-compose.yml.j2
-  template:
-    src: ../templates/docker-compose.yml.j2
-    dest: /etc/docker/compose/lldap/docker-compose.yml
-    owner: root
-    group: root
-    mode: u=rw,g=r,o=r
-
-- name: daemon-reload and enable lldap
-  ansible.builtin.systemd_service:
-    state: restarted
-    enabled: true
-    name: docker-compose@lldap
- 
-- name: allow ldap on vpn
-  ufw:
-    rule: allow
-    port: '3890'
-    from: '100.64.0.0/10'
diff --git a/roles/lldap/templates/docker-compose.yml.j2 b/roles/lldap/templates/docker-compose.yml.j2
deleted file mode 100644
index c4757b2..0000000
--- a/roles/lldap/templates/docker-compose.yml.j2
+++ /dev/null
@@ -1,18 +0,0 @@
-version: "3"
-
-volumes:
-  lldap_data:
-    driver: local
-
-services:
-  lldap:
-    image: lldap/lldap:stable
-    ports:
-      - "{{ johan_ip }}:3890:3890"
-      - "127.0.0.1:17170:17170"
-    volumes:
-      - "lldap_data:/data"
-    environment:
-      - LLDAP_JWT_SECRET="{{ lldap_jwt_secret }}"
-      - LLDAP_LDAP_USER_PASS="{{ lldap_user_pass }}"
-      - LLDAP_LDAP_BASE_DN=dc=simponic,dc=xyz
diff --git a/roles/mail/files/postmaster-main.cf b/roles/mail/files/postmaster-main.cf
deleted file mode 100644
index 1bfb761..0000000
--- a/roles/mail/files/postmaster-main.cf
+++ /dev/null
@@ -1,3 +0,0 @@
-virtual_mailbox_domains = /etc/postfix/vhost
-virtual_mailbox_maps = ldap:/etc/postfix/ldap-users.cf
-virtual_alias_maps =
diff --git a/roles/mail/tasks/main.yml b/roles/mail/tasks/main.yml
deleted file mode 100644
index cef06f5..0000000
--- a/roles/mail/tasks/main.yml
+++ /dev/null
@@ -1,71 +0,0 @@
----
-- name: install letsencrypt
-  apt:
-    name: letsencrypt
-    state: latest
-
-- name: allow 80/tcp ufw
-  ufw:
-    rule: allow
-    port: '80'
-    proto: 'tcp'
-
-- name: allow 443/tcp ufw
-  ufw:
-    rule: allow
-    port: '443'
-    proto: 'tcp'
-
-- name: restart ufw
-  service: name=ufw state=restarted enabled=yes
-
-- name: request certificate
-  shell: >
-    letsencrypt certonly -n --standalone -d "{{ domain }}" \
-      -m "{{ certbot_email }}" --agree-tos
-  args:
-    creates: "/etc/letsencrypt/live/{{ domain }}"
-
-- name: add monthly letsencrypt cronjob for cert renewal
-  cron:
-    name: "letsencrypt_renewal_mail"
-    day: "18"
-    hour: "2"
-    minute: "1"
-    job: "letsencrypt renew --cert-name {{ domain }} -n --standalone --agree-tos -m {{ certbot_email }}"
-
-- name: ensure mail docker/compose exist
-  file:
-    path: /etc/docker/compose/mail
-    state: directory
-    owner: root
-    group: root
-    mode: 0700
-
-- name: ensure mail docker/compose volume exist
-  file:
-    path: /etc/docker/compose/mail/docker-data/dms/config
-    state: directory
-    owner: root
-    group: root
-    mode: 0700
-
-# https://github.com/docker-mailserver/docker-mailserver/issues/1562
-- name: ensure mail docker/compose ldap overrides exist
-  copy:
-    src: ../files/postmaster-main.cf
-    dest: /etc/docker/compose/mail/docker-data/dms/config/postfix-main.cf
-
-- name: build mail docker-compose.yml.j2
-  template:
-    src: ../templates/docker-compose.yml.j2
-    dest: /etc/docker/compose/mail/docker-compose.yml
-    owner: root
-    group: root
-    mode: u=rw,g=r,o=r
-
-- name: daemon-reload and enable mail
-  ansible.builtin.systemd_service:
-    state: restarted
-    enabled: true
-    name: docker-compose@mail
diff --git a/roles/mail/templates/docker-compose.yml.j2 b/roles/mail/templates/docker-compose.yml.j2
deleted file mode 100644
index 5fe8083..0000000
--- a/roles/mail/templates/docker-compose.yml.j2
+++ /dev/null
@@ -1,50 +0,0 @@
-services:
-  mailserver:
-    image: ghcr.io/docker-mailserver/docker-mailserver:latest
-    container_name: mailserver
-    # Provide the FQDN of your mail server here (Your DNS MX record should point to this value)
-    hostname: {{ domain }}
-    ports:
-      - "25:25"
-      - "465:465"
-      - "587:587"
-      - "993:993"
-      - "4190:4190"
-    volumes:
-      - ./docker-data/dms/mail-data/:/var/mail/
-      - ./docker-data/dms/mail-state/:/var/mail-state/
-      - ./docker-data/dms/mail-logs/:/var/log/mail/
-      - ./docker-data/dms/config/:/tmp/docker-mailserver/
-      - /etc/letsencrypt:/etc/letsencrypt
-      - /etc/localtime:/etc/localtime:ro
-    environment:
-      - SSL_TYPE=letsencrypt
-      - ENABLE_CLAMAV=0
-      - ENABLE_AMAVIS=0
-      - ENABLE_MANAGESIEVE=1
-      - ENABLE_FAIL2BAN=1
-      - SPOOF_PROTECTION=1
-      - ACCOUNT_PROVISIONER=LDAP
-      - LDAP_SERVER_HOST=ldap://lldap.internal.simponic.xyz:3890
-      - LDAP_SEARCH_BASE=dc=simponic,dc=xyz
-      - LDAP_BIND_DN=uid=admin,ou=people,dc=simponic,dc=xyz
-      - LDAP_BIND_PW={{ lldap_admin_pass }}
-
-      - LDAP_QUERY_FILTER_USER=(&(objectClass=mailAccount)(|(uid=%u)))
-      - LDAP_QUERY_FILTER_GROUP=(&(cn=mail)(uniquemember=uid=%u,ou=people,dc=simponic,dc=xyz))
-      - LDAP_QUERY_FILTER_ALIAS=(&(objectClass=inetOrgPerson)(|(uid=%u)(mail=%u)))
-      - LDAP_QUERY_FILTER_DOMAIN=(mail=*@%s)
-
-      - DOVECOT_AUTH_BIND=yes
-      - DOVECOT_USER_FILTER=(&(objectClass=inetOrgPerson)(|(uid=%u)(mail=%u)))
-      - DOVECOT_USER_ATTRS==uid=5000,=gid=5000,=home=/var/mail/%Ln,=mail=maildir:~/Maildir
-
-      - ENABLE_SASLAUTHD=1
-      - SASLAUTHD_MECHANISMS=rimap
-      - SASLAUTHD_MECH_OPTIONS=127.0.0.1
-      - POSTMASTER_ADDRESS={{ postmaster_email }}
-    extra_hosts:
-      - "lldap.internal.simponic.xyz:{{ johan_ip }}"
-    dns:
-      - {{ nameserver_ip }}
-    restart: always
diff --git a/roles/nameservers/tasks/main.yml b/roles/nameservers/tasks/main.yml
deleted file mode 100644
index c781ae7..0000000
--- a/roles/nameservers/tasks/main.yml
+++ /dev/null
@@ -1,49 +0,0 @@
----
-
-## PRIMARY
-
-- name: create named.conf.local for primary
-  template:
-    src: ../templates/named.conf.local.primary.j2
-    dest: /etc/bind/named.conf.local
-    owner: bind
-    group: bind
-  when: inventory_hostname in groups['dnsprimary']
-
-- name: create /etc/bind/zones if not exist
-  ansible.builtin.file:
-    path: /etc/bind/zones
-    state: directory
-    owner: bind
-    group: bind
-
-- name: create primary zone files for primary
-  template:
-    src: "../templates/db.{{ item.zone }}.j2"
-    dest: "/etc/bind/zones/db.{{ item.zone }}"
-    owner: bind
-    group: bind
-  with_items: "{{ dns_zones }}"
-  when: inventory_hostname in groups['dnsprimary']
-
-
-## REPLICA
-
-- name: create named.conf.local for replica
-  template:
-    src: ../templates/named.conf.local.replica.j2
-    dest: /etc/bind/named.conf.local
-    owner: bind
-    group: bind
-  when: inventory_hostname in groups['dnsreplica']
-
-- name: flush dns cache on replicas
-  file: path={{ item }} state=absent
-  with_fileglob: "/var/cache/bind/db.*"
-  when: inventory_hostname in groups['dnsreplica']
-
-- name: restart bind9
-  service:
-    name: bind9
-    state: restarted
-    enabled: true
diff --git a/roles/nameservers/templates/db.rainrainra.in.j2 b/roles/nameservers/templates/db.rainrainra.in.j2
deleted file mode 100644
index 42f05c3..0000000
--- a/roles/nameservers/templates/db.rainrainra.in.j2
+++ /dev/null
@@ -1,15 +0,0 @@
-$TTL    604800
-@       IN      SOA     {{ dns_primary_hostname }}.simponic.xyz. admin.simponic.xyz. (
-                              5         ; Serial
-                         604800         ; Refresh
-                          86400         ; Retry
-                        2419200         ; Expire
-                         604800 )       ; Negative Cache TTL
-;
-
-; Name servers
-rainrainra.in.    IN      NS      {{ dns_primary_hostname }}.simponic.xyz.
-rainrainra.in.    IN      NS      {{ dns_replica_hostname }}.simponic.xyz.
-
-; Other A records
-@               IN      A       23.95.214.176
diff --git a/roles/nameservers/templates/db.rileyandlizzy.wedding.j2 b/roles/nameservers/templates/db.rileyandlizzy.wedding.j2
deleted file mode 100644
index e000923..0000000
--- a/roles/nameservers/templates/db.rileyandlizzy.wedding.j2
+++ /dev/null
@@ -1,16 +0,0 @@
-$TTL    604800
-@       IN      SOA     {{ dns_primary_hostname }}.simponic.xyz. admin.simponic.xyz. (
-                              5         ; Serial
-                         604800         ; Refresh
-                          86400         ; Retry
-                        2419200         ; Expire
-                         604800 )       ; Negative Cache TTL
-;
-
-; Name servers
-rileyandlizzy.wedding.    IN      NS      {{ dns_primary_hostname }}.simponic.xyz.
-rileyandlizzy.wedding.    IN      NS      {{ dns_replica_hostname }}.simponic.xyz.
-
-; Other A records
-@               IN      A       129.123.76.14
-www             IN      A       129.123.76.14
diff --git a/roles/nameservers/templates/db.simponic.xyz.j2 b/roles/nameservers/templates/db.simponic.xyz.j2
deleted file mode 100644
index 7494f83..0000000
--- a/roles/nameservers/templates/db.simponic.xyz.j2
+++ /dev/null
@@ -1,63 +0,0 @@
-$TTL    604800
-@       IN      SOA     {{ dns_primary_hostname }}.simponic.xyz. admin.simponic.xyz. (
-                          {{ ansible_date_time.epoch }}         ; Serial
-                          86400         ; Refresh
-                          86400         ; Retry
-                        2419200         ; Expire
-                         604800 )       ; Negative Cache TTL
-;
-
-; Name servers
-simponic.xyz.    IN      NS      {{ dns_primary_hostname }}.simponic.xyz.
-simponic.xyz.    IN      NS      {{ dns_replica_hostname }}.simponic.xyz.
-
-;; A Records
-{{ dns_primary_hostname }}             IN      A      {{ dns_primary_ip }}
-{{ dns_replica_hostname }}             IN      A      {{ dns_replica_ip }}
-
-johan.simponic.xyz. 1 IN  A 23.95.20.192
-osaka.simponic.xyz. 1 IN  A 129.123.76.14
-mcbeta.simponic.xyz.    1   IN  A   24.11.13.69
-
-mail.simponic.xyz.	1	IN	A	192.3.248.205
-
-levi.simponic.xyz.  1 IN  A 23.95.214.176
-simponic.xyz.  1 IN  A 23.95.214.176
-
-chesshbot.simponic.xyz. 1 IN  A 129.123.76.14
-
-;; CNAME Records
-whois.simponic.xyz.	43200	IN	CNAME	ryo.simponic.xyz.
-something.simponic.xyz.	43200	IN	CNAME	ryo.simponic.xyz.
-phoneof.simponic.xyz.	43200	IN	CNAME	ryo.simponic.xyz.
-secure.tunnel.simponic.xyz.	1	IN	CNAME	simponic.xyz.
-tunnel.simponic.xyz.	1	IN	CNAME	simponic.xyz.
-party.simponic.xyz.	1	IN	CNAME	simponic.xyz.
-static.simponic.xyz.	1	IN	CNAME	simponic.xyz.
-www.simponic.xyz.	1	IN	CNAME	simponic.xyz.
-s1._domainkey.simponic.xyz.	1	IN	CNAME	s1.domainkey.u25709709.wl210.sendgrid.net.
-s2._domainkey.simponic.xyz.	1	IN	CNAME	s2.domainkey.u25709709.wl210.sendgrid.net.
-headscale.simponic.xyz.	1	IN	CNAME	nijika.simponic.xyz.
-authelia.simponic.xyz.	1	IN	CNAME	nijika.simponic.xyz.
-git.simponic.xyz. 1 IN  CNAME nijika.simponic.xyz.
-frens.simponic.xyz. 1 IN  CNAME europa.simponic.endpoints.hatecomputers.club.
-
-ormbm2qr5kfynrnlhaezwm454pbwatv7._domainkey.pagelizhunt.simponic.xyz. 1	IN	CNAME	ormbm2qr5kfynrnlhaezwm454pbwatv7.dkim.amazonses.com.
-h4yglqdxrjg2m6akzzcnmtgbif5adbpz._domainkey.pagelizhunt.simponic.xyz.	1	IN	CNAME	h4yglqdxrjg2m6akzzcnmtgbif5adbpz.dkim.amazonses.com.
-re6xagsoccogzbxjrvvvkq6kklb7f43t._domainkey.pagelizhunt.simponic.xyz.	1	IN	CNAME	re6xagsoccogzbxjrvvvkq6kklb7f43t.dkim.amazonses.com.
-
-lab.simponic.xyz.	1	IN	CNAME	simponic.tplinkdns.com.
-
-;; MX Records
-simponic.xyz.	1	IN	MX	10 mail.simponic.xyz.
-
-;; TXT Records
-_atproto.simponic.xyz.  1	IN	TXT	"did=did:plc:krwcprkssroh27ivpmnbpzez"
-_atproto.pressurehooker.simponic.xyz.	1	IN	TXT	"did=did:plc:6frn2g6bbih6s2dqqod6ahks"
-mail._domainkey.simponic.xyz. 1 IN      TXT    ( "v=DKIM1; h=sha256; k=rsa; "
-          "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2ktysbZaewsAo1Uk+FfLvVeL9ii6ejTDxxYE1RoGTxFDulFYXdpvO+MErDq62IvaQ6E4TYTc0RULoqp3BjuVVG6IG85SmhWME9XYSrxLm1pq7yRN1s1b6pBqNC6+yiyxwSjThS7RzH3sxwBL7R8AHRuEV+2UKsvT2wOCyRXAth+lrB7t9S9niWNOB3lvDqe0/oPf9JDrKjpuO6"
-          "lKZ3nglGzPfdJEpfLyXBP4l5UlxqWYUIrCzqHY9bNmyPepb1CJT97AD5jGGngCrnMCmllAdyOKa1ds5uoPjjGaLO8bOoBWXQuacn++hDsdyQ78Y673T2935CN/uGgrLBs9UiA0BQIDAQAB" )  ; ----- DKIM key mail for simponic.xyz 
-_dmarc.simponic.xyz.  1 IN TXT "v=DMARC1; p=quarantine; sp=quarantine; fo=0; adkim=r; aspf=r; pct=100; rf=afrf; ri=86400; rua=mailto:dmarc.report@simponic.xyz; ruf=mailto:dmarc.report@simponic.xyz"
-simponic.xyz.	1	IN	TXT	"v=spf1 mx ip4:192.3.248.205 ~all"
-simponic.xyz.   1   IN  TXT "google-site-verification=iP51S608sxhIkualEX6iODQBGVV8YVe8PY_tij4fdIM"
-_discord.simponic.xyz.	1	IN	TXT	"dh=d80256e712f82be7acb5eb055a8a8cb5f973d9c1"
diff --git a/roles/nameservers/templates/named.conf.local.primary.j2 b/roles/nameservers/templates/named.conf.local.primary.j2
deleted file mode 100644
index 18a0532..0000000
--- a/roles/nameservers/templates/named.conf.local.primary.j2
+++ /dev/null
@@ -1,7 +0,0 @@
-{% for zone in dns_zones %}
-zone "{{ zone.zone }}" {
-    type master;
-    file "/etc/bind/zones/db.{{ zone.zone }}";
-    allow-transfer { {{ dns_replica_ip }}; };
-};
-{% endfor %}
diff --git a/roles/nameservers/templates/named.conf.local.replica.j2 b/roles/nameservers/templates/named.conf.local.replica.j2
deleted file mode 100644
index 1313cba..0000000
--- a/roles/nameservers/templates/named.conf.local.replica.j2
+++ /dev/null
@@ -1,7 +0,0 @@
-{% for zone in dns_zones %}
-zone "{{ zone.zone }}" {
-    type slave;
-    file "db.{{ zone.zone }}";
-    masters { {{ dns_primary_ip }}; };
-};
-{% endfor %}
diff --git a/roles/ntfy/tasks/main.yml b/roles/ntfy/tasks/main.yml
deleted file mode 100644
index 0ee34e3..0000000
--- a/roles/ntfy/tasks/main.yml
+++ /dev/null
@@ -1,22 +0,0 @@
----
-- name: ensure ntfy docker/compose exist
-  file:
-    path: /etc/docker/compose/ntfy
-    state: directory
-    owner: root
-    group: root
-    mode: 0700
-
-- name: build ntfy docker-compose.yml.j2
-  template:
-    src: ../templates/docker-compose.yml.j2
-    dest: /etc/docker/compose/ntfy/docker-compose.yml
-    owner: root
-    group: root
-    mode: u=rw,g=r,o=r
-
-- name: daemon-reload and enable ntfy
-  ansible.builtin.systemd_service:
-    state: restarted
-    enabled: true
-    name: docker-compose@ntfy
diff --git a/roles/ntfy/templates/docker-compose.yml.j2 b/roles/ntfy/templates/docker-compose.yml.j2
deleted file mode 100644
index 4ee982e..0000000
--- a/roles/ntfy/templates/docker-compose.yml.j2
+++ /dev/null
@@ -1,15 +0,0 @@
-version: "2.1"
-services:
-  ntfy:
-    image: binwiederhier/ntfy
-    container_name: ntfy
-    command:
-      - serve
-    environment:
-      - TZ=UTC
-    volumes:
-      - ./cache:/var/cache/ntfy
-      - ./conf:/etc/ntfy
-    ports:
-      - 127.0.0.1:22311:80
-    restart: unless-stopped
diff --git a/roles/owncloud/tasks/main.yml b/roles/owncloud/tasks/main.yml
deleted file mode 100644
index f914619..0000000
--- a/roles/owncloud/tasks/main.yml
+++ /dev/null
@@ -1,37 +0,0 @@
----
-- name: ensure owncloud docker/compose exist
-  file:
-    path: /etc/docker/compose/owncloud
-    state: directory
-    owner: root
-    group: root
-    mode: 0700
-
-- name: build owncloud docker-compose.yml.j2
-  template:
-    src: ../templates/docker-compose.yml.j2
-    dest: /etc/docker/compose/owncloud/docker-compose.yml
-    owner: root
-    group: root
-    mode: u=rw,g=r,o=r
-
-- name: ensure owncloud config volume exist
-  file:
-    path: "{{ owncloud_mount }}/config"
-    state: directory
-    owner: www-data
-    group: root
-
-- name: build owncloud config.php
-  template:
-    src: ../templates/config.php.j2
-    dest: "{{ owncloud_mount }}/config/config.php"
-    owner: www-data
-    group: root
-    mode: 0750
-
-- name: daemon-reload and enable owncloud
-  ansible.builtin.systemd_service:
-    state: restarted
-    enabled: true
-    name: docker-compose@owncloud
diff --git a/roles/owncloud/templates/config.php.j2 b/roles/owncloud/templates/config.php.j2
deleted file mode 100644
index 5924575..0000000
--- a/roles/owncloud/templates/config.php.j2
+++ /dev/null
@@ -1,84 +0,0 @@
-<?php
-$CONFIG = array (
-  'apps_paths' => 
-  array (
-    0 => 
-    array (
-      'path' => '/var/www/owncloud/apps',
-      'url' => '/apps',
-      'writable' => false,
-    ),
-    1 => 
-    array (
-      'path' => '/var/www/owncloud/custom',
-      'url' => '/custom',
-      'writable' => true,
-    ),
-  ),
-  'trusted_domains' => 
-  array (
-    0 => 'owncloud.internal.simponic.xyz',
-    1 => 'localhost',
-    2 => '127.0.0.1',
-  ),
-  'datadirectory' => '/mnt/data/files',
-  'dbtype' => 'mysql',
-  'dbhost' => 'mariadb:3306',
-  'dbname' => 'owncloud',
-  'dbuser' => 'owncloud',
-  'dbpassword' => 'owncloud',
-  'dbtableprefix' => 'oc_',
-  'log_type' => 'owncloud',
-  'supportedDatabases' => 
-  array (
-    0 => 'sqlite',
-    1 => 'mysql',
-    2 => 'pgsql',
-  ),
-  'upgrade.disable-web' => true,
-  'default_language' => 'en',
-  'overwrite.cli.url' => 'https://owncloud.internal.simponic.xyz/',
-  'htaccess.RewriteBase' => '/',
-  'logfile' => '/mnt/data/files/owncloud.log',
-  'memcache.local' => '\\OC\\Memcache\\APCu',
-  'mysql.utf8mb4' => true,
-  'filelocking.enabled' => true,
-  'memcache.distributed' => '\\OC\\Memcache\\Redis',
-  'memcache.locking' => '\\OC\\Memcache\\Redis',
-  'redis' => 
-  array (
-    'host' => 'redis',
-    'port' => '6379',
-  ),
-  'passwordsalt' => '{{ owncloud_pwd_salt }}',
-  'secret' => '{{ owncloud_secret }}',
-  'version' => '10.14.0.3',
-  'dbconnectionstring' => '',
-  'allow_user_to_change_mail_address' => '',
-  'logtimezone' => 'UTC',
-  'installed' => true,
-  'instanceid' => 'oco7aemx06vf',
-  'mail_domain' => 'simponic.xyz',
-  'mail_from_address' => 'info',
-  'mail_smtpmode' => 'smtp',
-  'mail_smtpauth' => 1,
-  'mail_smtpsecure' => 'tls',
-  'mail_smtphost' => 'mail.simponic.xyz',
-  'mail_smtpport' => '587',
-  'mail_smtpname' => 'info',
-  'mail_smtppassword' => '{{ owncloud_mail_password }}',
-  'ldapIgnoreNamingRules' => false,
-  'allow_user_to_change_display_name' => false,
-  'lost_password_link' => 'disabled',
-  'openid-connect' => [
-    'auto-provision' => ['enabled' => true],
-    'autoRedirectOnLoginPage' => false,
-    'client-id' => 'owncloud',
-    'client-secret' => '{{ owncloud_oidc_secret }}',
-    'loginButtonName' => 'Simponic Authelia',
-    'provider-url' => 'https://authelia.simponic.xyz',
-    'redirect-url' => 'https://owncloud.internal.simponic.xyz/apps/openidconnect/redirect'
-  ],
-  'http.cookie.samesite' => 'None',
-  'session_lifetime' => 60 * 60 * 24
-);
diff --git a/roles/owncloud/templates/docker-compose.yml.j2 b/roles/owncloud/templates/docker-compose.yml.j2
deleted file mode 100644
index 3db1284..0000000
--- a/roles/owncloud/templates/docker-compose.yml.j2
+++ /dev/null
@@ -1,80 +0,0 @@
-version: "3"
-
-volumes:
-  mysql:
-    driver: local
-  redis:
-    driver: local
-
-networks:
-  owncloud:
-    external: false
-
-services:
-  owncloud:
-    image: owncloud/server:{{ owncloud_version }}
-    container_name: owncloud_server
-    restart: always
-    ports:
-      - "127.0.0.1:24734:8080"
-    depends_on:
-      - mariadb
-      - redis
-    environment:
-      - OWNCLOUD_DOMAIN={{ owncloud_domain }}
-      - OWNCLOUD_TRUSTED_DOMAINS={{ owncloud_trusted_domains }}
-      - OWNCLOUD_DB_TYPE=mysql
-      - OWNCLOUD_DB_NAME=owncloud
-      - OWNCLOUD_DB_USERNAME=owncloud
-      - OWNCLOUD_DB_PASSWORD=owncloud
-      - OWNCLOUD_DB_HOST=mariadb
-      - OWNCLOUD_ADMIN_USERNAME=admin
-      - OWNCLOUD_ADMIN_PASSWORD={{ owncloud_admin_password }}
-      - OWNCLOUD_MYSQL_UTF8MB4=true
-      - OWNCLOUD_REDIS_ENABLED=true
-      - OWNCLOUD_REDIS_HOST=redis
-    healthcheck:
-      test: ["CMD", "/usr/bin/healthcheck"]
-      interval: 30s
-      timeout: 10s
-      retries: 5
-    volumes:
-      - {{ owncloud_mount }}:/mnt/data:rw
-    networks:
-      - owncloud
-
-  mariadb:
-    image: mariadb:10.11 # minimum required ownCloud version is 10.9
-    container_name: owncloud_mariadb
-    restart: always
-    environment:
-      - MYSQL_ROOT_PASSWORD=owncloud
-      - MYSQL_USER=owncloud
-      - MYSQL_PASSWORD=owncloud
-      - MYSQL_DATABASE=owncloud
-      - MARIADB_AUTO_UPGRADE=1
-    command: ["--max-allowed-packet=128M", "--innodb-log-file-size=64M"]
-    healthcheck:
-      test: ["CMD", "mysqladmin", "ping", "-u", "root", "--password=owncloud"]
-      interval: 10s
-      timeout: 5s
-      retries: 5
-    volumes:
-      - mysql:/var/lib/mysql
-    networks:
-      - owncloud
-
-  redis:
-    image: redis:6
-    container_name: owncloud_redis
-    restart: always
-    command: ["--databases", "1"]
-    healthcheck:
-      test: ["CMD", "redis-cli", "ping"]
-      interval: 10s
-      timeout: 5s
-      retries: 5
-    volumes:
-      - redis:/data
-    networks:
-      - owncloud
diff --git a/roles/phoneassistant/tasks/main.yml b/roles/phoneassistant/tasks/main.yml
deleted file mode 100644
index 2e35377..0000000
--- a/roles/phoneassistant/tasks/main.yml
+++ /dev/null
@@ -1,30 +0,0 @@
----
-- name: ensure phoneassistant docker/compose exist
-  file:
-    path: /etc/docker/compose/phoneassistant
-    state: directory
-    owner: root
-    group: root
-    mode: 0700
-
-- name: ensure phoneassistant db exist
-  file:
-    path: /etc/docker/compose/phoneassistant/db
-    state: directory
-    owner: root
-    group: root
-    mode: 0777
-
-- name: build phoneassistant docker-compose.yml.j2
-  template:
-    src: ../templates/docker-compose.yml.j2
-    dest: /etc/docker/compose/phoneassistant/docker-compose.yml
-    owner: root
-    group: root
-    mode: u=rw,g=r,o=r
-
-- name: daemon-reload and enable phoneassistant
-  ansible.builtin.systemd_service:
-    state: restarted
-    enabled: true
-    name: docker-compose@phoneassistant
diff --git a/roles/phoneassistant/templates/docker-compose.yml.j2 b/roles/phoneassistant/templates/docker-compose.yml.j2
deleted file mode 100644
index 38b6101..0000000
--- a/roles/phoneassistant/templates/docker-compose.yml.j2
+++ /dev/null
@@ -1,16 +0,0 @@
-version: "3"
-
-services:
-  api:
-    restart: always
-    image: git.simponic.xyz/simponic/phoneassistant
-    healthcheck:
-      test: ["CMD", "wget", "--spider", "http://localhost:8080/api/health"]
-      interval: 5s
-      timeout: 10s
-      retries: 5
-    env_file: .env
-    volumes:
-      - ./db:/app/db
-    ports:
-      - "127.0.0.1:9082:8080"
diff --git a/roles/phoneof/tasks/main.yml b/roles/phoneof/tasks/main.yml
deleted file mode 100644
index dcd4720..0000000
--- a/roles/phoneof/tasks/main.yml
+++ /dev/null
@@ -1,35 +0,0 @@
----
-- name: Download internal cert
-  ansible.builtin.get_url:
-    url: https://ca.internal.simponic.xyz/roots.pem
-    validate_certs: false
-    dest: /etc/roots.pem
-    checksum: sha256:12a1d52af6f4073c339946e8c67bdd48fa85590480385fcce7f16b6b60d40831
-
-- name: ensure phoneof docker/compose exist
-  file:
-    path: /etc/docker/compose/phoneof
-    state: directory
-    owner: root
-    group: root
-    mode: 0700
-
-- name: ensure phoneof db exist
-  file:
-    path: /etc/docker/compose/phoneof/db
-    state: directory
-    mode: 0777
-
-- name: build phoneof docker-compose.yml.j2
-  template:
-    src: ../templates/docker-compose.yml.j2
-    dest: /etc/docker/compose/phoneof/docker-compose.yml
-    owner: root
-    group: root
-    mode: u=rw,g=r,o=r
-
-- name: daemon-reload and enable phoneof
-  ansible.builtin.systemd_service:
-    state: restarted
-    enabled: true
-    name: docker-compose@phoneof
diff --git a/roles/phoneof/templates/docker-compose.yml.j2 b/roles/phoneof/templates/docker-compose.yml.j2
deleted file mode 100644
index 58551ae..0000000
--- a/roles/phoneof/templates/docker-compose.yml.j2
+++ /dev/null
@@ -1,24 +0,0 @@
-version: "3"
-
-services:
-  api:
-    restart: always
-    image: git.simponic.xyz/simponic/phoneof
-    healthcheck:
-      test: ["CMD", "wget", "--spider", "http://localhost:8080/api/health"]
-      interval: 5s
-      timeout: 10s
-      retries: 5
-    environment:
-      - FROM_PHONE_NUMBER={{ from_phone_number }}
-      - TO_PHONE_NUMBER={{ to_phone_number }}
-      - HTTPSMS_API_TOKEN={{ httpsms_api_token }}
-      - HTTPSMS_SIGNING_KEY={{ httpsms_signing_key }}
-      - SSL_CERT_DIR=/etc/ssl/
-    volumes:
-      - ./db:/app/db
-      - /etc/roots.pem:/etc/ssl/roots.pem
-    dns:
-      - {{ nameserver_ip }}
-    ports:
-      - "127.0.0.1:19191:8080"
diff --git a/roles/pihole/tasks/main.yml b/roles/pihole/tasks/main.yml
deleted file mode 100644
index 0467b80..0000000
--- a/roles/pihole/tasks/main.yml
+++ /dev/null
@@ -1,36 +0,0 @@
----
-- name: ensure pihole docker/compose exist
-  file:
-    path: /etc/docker/compose/pihole
-    state: directory
-    owner: root
-    group: root
-    mode: 0700
-
-- name: build pihole docker-compose.yml.j2
-  template:
-    src: ../templates/docker-compose.yml.j2
-    dest: /etc/docker/compose/pihole/docker-compose.yml
-    owner: root
-    group: root
-    mode: u=rw,g=r,o=r
-
-- name: daemon-reload and enable pihole
-  ansible.builtin.systemd_service:
-    state: restarted
-    enabled: true
-    name: docker-compose@pihole
-
-- name: allow dns queries in vpn/tcp
-  ufw:
-    rule: allow
-    from: '100.64.0.0/10'
-    port: '53'
-    proto: 'tcp'
-
-- name: allow dns queries in vpn/udp
-  ufw:
-    rule: allow
-    from: '100.64.0.0/10'
-    port: '53'
-    proto: 'udp'
diff --git a/roles/pihole/templates/docker-compose.yml.j2 b/roles/pihole/templates/docker-compose.yml.j2
deleted file mode 100644
index ed98d52..0000000
--- a/roles/pihole/templates/docker-compose.yml.j2
+++ /dev/null
@@ -1,18 +0,0 @@
-version: "3"
-
-services:
-  pihole:
-    container_name: pihole
-    image: pihole/pihole:latest
-    ports:
-      - "{{ johan_ip }}:53:53/tcp"
-      - "{{ johan_ip }}:53:53/udp"
-      - "127.0.0.1:53:53/tcp"
-      - "127.0.0.1:53:53/udp"
-      - "127.0.0.1:9135:80/tcp"
-    environment:
-      WEBPASSWORD: '{{ pihole_webpwd }}'
-    volumes:
-      - './etc-pihole:/etc/pihole'
-      - './etc-dnsmasq.d:/etc/dnsmasq.d'
-    restart: unless-stopped
diff --git a/roles/private/files/europa/http.drone.internal.simponic.xyz.conf b/roles/private/files/europa/http.drone.internal.simponic.xyz.conf
deleted file mode 100644
index db2ea0e..0000000
--- a/roles/private/files/europa/http.drone.internal.simponic.xyz.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-server {
-  listen 80;
-  server_name drone.internal.simponic.xyz;
-
-  location /.well-known/acme-challenge {
-    root /var/www/letsencrypt;
-    try_files $uri $uri/ =404;
-  }
-
-  location / {
-    rewrite ^ https://drone.internal.simponic.xyz$request_uri? permanent;
-  }
-}
diff --git a/roles/private/files/europa/http.jellyfin.internal.simponic.xyz.conf b/roles/private/files/europa/http.jellyfin.internal.simponic.xyz.conf
deleted file mode 100644
index cb50fe3..0000000
--- a/roles/private/files/europa/http.jellyfin.internal.simponic.xyz.conf
+++ /dev/null
@@ -1,22 +0,0 @@
-server {
-  listen 80;
-  server_name jellyfin.internal.simponic.xyz;
-
-  location /.well-known/acme-challenge {
-    root /var/www/letsencrypt;
-    try_files $uri $uri/ =404;
-  }
-
-  location / {
-    proxy_pass http://127.0.0.1:8096;
-    proxy_http_version 1.1;
-    proxy_set_header Upgrade $http_upgrade;
-    proxy_set_header Connection "upgrade";
-    proxy_set_header Host $server_name;
-    proxy_buffering off;
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
-    add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
-  }
-}
diff --git a/roles/private/files/europa/http.owncloud.internal.simponic.xyz.conf b/roles/private/files/europa/http.owncloud.internal.simponic.xyz.conf
deleted file mode 100644
index 9fdc6c3..0000000
--- a/roles/private/files/europa/http.owncloud.internal.simponic.xyz.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-server {
-  listen 80;
-  server_name owncloud.internal.simponic.xyz;
-
-  location /.well-known/acme-challenge {
-    root /var/www/letsencrypt;
-    try_files $uri $uri/ =404;
-  }
-
-  location / {
-    rewrite ^ https://owncloud.internal.simponic.xyz$request_uri? permanent;
-  }
-}
diff --git a/roles/private/files/europa/http.roundcube.internal.simponic.xyz.conf b/roles/private/files/europa/http.roundcube.internal.simponic.xyz.conf
deleted file mode 100644
index 09ce1a6..0000000
--- a/roles/private/files/europa/http.roundcube.internal.simponic.xyz.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-server {
-  listen 80;
-  server_name roundcube.internal.simponic.xyz;
-
-  location /.well-known/acme-challenge {
-    root /var/www/letsencrypt;
-    try_files $uri $uri/ =404;
-  }
-
-  location / {
-    rewrite ^ https://roundcube.internal.simponic.xyz$request_uri? permanent;
-  }
-}
diff --git a/roles/private/files/europa/http.scurvy.internal.simponic.xyz.conf b/roles/private/files/europa/http.scurvy.internal.simponic.xyz.conf
deleted file mode 100644
index 24e9fc1..0000000
--- a/roles/private/files/europa/http.scurvy.internal.simponic.xyz.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-server {
-  listen 80;
-  server_name scurvy.internal.simponic.xyz;
-
-  location /.well-known/acme-challenge {
-    root /var/www/letsencrypt;
-    try_files $uri $uri/ =404;
-  }
-
-  location / {
-    rewrite ^ https://scurvy.internal.simponic.xyz$request_uri? permanent;
-  }
-}
diff --git a/roles/private/files/europa/https.drone.internal.simponic.xyz.conf b/roles/private/files/europa/https.drone.internal.simponic.xyz.conf
deleted file mode 100644
index 06214a6..0000000
--- a/roles/private/files/europa/https.drone.internal.simponic.xyz.conf
+++ /dev/null
@@ -1,32 +0,0 @@
-server {
-  listen 443 ssl;
-  server_name drone.internal.simponic.xyz;
-
-  ssl_certificate         /etc/letsencrypt/live/drone.internal.simponic.xyz/fullchain.pem;
-  ssl_certificate_key     /etc/letsencrypt/live/drone.internal.simponic.xyz/privkey.pem;
-  ssl_trusted_certificate /etc/letsencrypt/live/drone.internal.simponic.xyz/fullchain.pem;
-
-  ssl_session_cache shared:SSL:50m;
-  ssl_session_timeout 5m;
-  ssl_stapling on;
-  ssl_stapling_verify on;
-
-  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-  ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
-
-  ssl_dhparam /etc/nginx/dhparams.pem;
-  ssl_prefer_server_ciphers on;
-
-  location / {
-    proxy_pass http://127.0.0.1:2201;
-    proxy_http_version 1.1;
-    proxy_set_header Upgrade $http_upgrade;
-    proxy_set_header Connection "upgrade";
-    proxy_set_header Host $server_name;
-    proxy_buffering off;
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
-    add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
-  }
-}
diff --git a/roles/private/files/europa/https.jellyfin.internal.simponic.xyz.conf b/roles/private/files/europa/https.jellyfin.internal.simponic.xyz.conf
deleted file mode 100644
index b1823b9..0000000
--- a/roles/private/files/europa/https.jellyfin.internal.simponic.xyz.conf
+++ /dev/null
@@ -1,32 +0,0 @@
-server {
-  listen 443 ssl;
-  server_name jellyfin.internal.simponic.xyz;
-
-  ssl_certificate         /etc/letsencrypt/live/jellyfin.internal.simponic.xyz/fullchain.pem;
-  ssl_certificate_key     /etc/letsencrypt/live/jellyfin.internal.simponic.xyz/privkey.pem;
-  ssl_trusted_certificate /etc/letsencrypt/live/jellyfin.internal.simponic.xyz/fullchain.pem;
-
-  ssl_session_cache shared:SSL:50m;
-  ssl_session_timeout 5m;
-  ssl_stapling on;
-  ssl_stapling_verify on;
-
-  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-  ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
-
-  ssl_dhparam /etc/nginx/dhparams.pem;
-  ssl_prefer_server_ciphers on;
-
-  location / {
-    proxy_pass http://127.0.0.1:8096;
-    proxy_http_version 1.1;
-    proxy_set_header Upgrade $http_upgrade;
-    proxy_set_header Connection "upgrade";
-    proxy_set_header Host $server_name;
-    proxy_buffering off;
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
-    add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
-  }
-}
diff --git a/roles/private/files/europa/https.owncloud.internal.simponic.xyz.conf b/roles/private/files/europa/https.owncloud.internal.simponic.xyz.conf
deleted file mode 100644
index 3ae85b0..0000000
--- a/roles/private/files/europa/https.owncloud.internal.simponic.xyz.conf
+++ /dev/null
@@ -1,46 +0,0 @@
-server {
-  listen 443 ssl;
-  server_name owncloud.internal.simponic.xyz;
-  client_max_body_size 2G;
-
-  ssl_certificate         /etc/letsencrypt/live/owncloud.internal.simponic.xyz/fullchain.pem;
-  ssl_certificate_key     /etc/letsencrypt/live/owncloud.internal.simponic.xyz/privkey.pem;
-  ssl_trusted_certificate /etc/letsencrypt/live/owncloud.internal.simponic.xyz/fullchain.pem;
-
-  ssl_session_cache shared:SSL:50m;
-  ssl_session_timeout 5m;
-  ssl_stapling on;
-  ssl_stapling_verify on;
-
-  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-  ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
-
-  ssl_dhparam /etc/nginx/dhparams.pem;
-  ssl_prefer_server_ciphers on;
-
-  location / {
-    proxy_pass http://127.0.0.1:24734;
-    proxy_http_version 1.1;
-    proxy_set_header Upgrade $http_upgrade;
-    proxy_set_header Connection "upgrade";
-    proxy_set_header Host $server_name;
-    proxy_buffering off;
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
-    add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
-  }
-
-  location /.well-known/openid-configuration {
-    proxy_pass http://127.0.0.1:24734/index.php/apps/openidconnect/config;
-    proxy_http_version 1.1;
-    proxy_set_header Upgrade $http_upgrade;
-    proxy_set_header Connection "upgrade";
-    proxy_set_header Host $server_name;
-    proxy_buffering off;
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
-    add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
-  }
-}
diff --git a/roles/private/files/europa/https.roundcube.internal.simponic.xyz.conf b/roles/private/files/europa/https.roundcube.internal.simponic.xyz.conf
deleted file mode 100644
index f21b186..0000000
--- a/roles/private/files/europa/https.roundcube.internal.simponic.xyz.conf
+++ /dev/null
@@ -1,32 +0,0 @@
-server {
-  listen 443 ssl;
-  server_name roundcube.internal.simponic.xyz;
-
-  ssl_certificate         /etc/letsencrypt/live/roundcube.internal.simponic.xyz/fullchain.pem;
-  ssl_certificate_key     /etc/letsencrypt/live/roundcube.internal.simponic.xyz/privkey.pem;
-  ssl_trusted_certificate /etc/letsencrypt/live/roundcube.internal.simponic.xyz/fullchain.pem;
-
-  ssl_session_cache shared:SSL:50m;
-  ssl_session_timeout 5m;
-  ssl_stapling on;
-  ssl_stapling_verify on;
-
-  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-  ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
-
-  ssl_dhparam /etc/nginx/dhparams.pem;
-  ssl_prefer_server_ciphers on;
-
-  location / {
-    proxy_pass http://127.0.0.1:9002;
-    proxy_http_version 1.1;
-    proxy_set_header Upgrade $http_upgrade;
-    proxy_set_header Connection "upgrade";
-    proxy_set_header Host $server_name;
-    proxy_buffering off;
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
-    add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
-  }
-}
diff --git a/roles/private/files/europa/https.scurvy.internal.simponic.xyz.conf b/roles/private/files/europa/https.scurvy.internal.simponic.xyz.conf
deleted file mode 100644
index 14c7a6b..0000000
--- a/roles/private/files/europa/https.scurvy.internal.simponic.xyz.conf
+++ /dev/null
@@ -1,32 +0,0 @@
-server {
-  listen 443 ssl;
-  server_name scurvy.internal.simponic.xyz;
-
-  ssl_certificate         /etc/letsencrypt/live/scurvy.internal.simponic.xyz/fullchain.pem;
-  ssl_certificate_key     /etc/letsencrypt/live/scurvy.internal.simponic.xyz/privkey.pem;
-  ssl_trusted_certificate /etc/letsencrypt/live/scurvy.internal.simponic.xyz/fullchain.pem;
-
-  ssl_session_cache shared:SSL:50m;
-  ssl_session_timeout 5m;
-  ssl_stapling on;
-  ssl_stapling_verify on;
-
-  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-  ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
-
-  ssl_dhparam /etc/nginx/dhparams.pem;
-  ssl_prefer_server_ciphers on;
-
-  location / {
-    proxy_pass http://127.0.0.1:9000;
-    proxy_http_version 1.1;
-    proxy_set_header Upgrade $http_upgrade;
-    proxy_set_header Connection "upgrade";
-    proxy_set_header Host $server_name;
-    proxy_buffering off;
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
-    add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
-  }
-}
diff --git a/roles/private/files/johan/http.backups.internal.simponic.xyz.conf b/roles/private/files/johan/http.backups.internal.simponic.xyz.conf
deleted file mode 100644
index 47b9ef8..0000000
--- a/roles/private/files/johan/http.backups.internal.simponic.xyz.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-server {
-  listen 80;
-  server_name backups.internal.simponic.xyz;
-
-  location /.well-known/acme-challenge {
-    root /var/www/letsencrypt;
-    try_files $uri $uri/ =404;
-  }
-
-  location / {
-    rewrite ^ https://backups.internal.simponic.xyz$request_uri? permanent;
-  }
-}
diff --git a/roles/private/files/johan/http.ca.internal.simponic.xyz.conf b/roles/private/files/johan/http.ca.internal.simponic.xyz.conf
deleted file mode 100644
index f1cea50..0000000
--- a/roles/private/files/johan/http.ca.internal.simponic.xyz.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-server {
-  listen 80;
-  server_name ca.internal.simponic.xyz;
-
-  location /.well-known/acme-challenge {
-    root /var/www/letsencrypt;
-    try_files $uri $uri/ =404;
-  }
-
-  location / {
-    rewrite ^ https://ca.internal.simponic.xyz$request_uri? permanent;
-  }
-}
diff --git a/roles/private/files/johan/http.httpsms.internal.simponic.xyz.conf b/roles/private/files/johan/http.httpsms.internal.simponic.xyz.conf
deleted file mode 100644
index eb07c2b..0000000
--- a/roles/private/files/johan/http.httpsms.internal.simponic.xyz.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-server {
-  listen 80;
-  server_name httpsms.internal.simponic.xyz;
-
-  location /.well-known/acme-challenge {
-    root /var/www/letsencrypt;
-    try_files $uri $uri/ =404;
-  }
-
-  location / {
-    rewrite ^ https://httpsms.internal.simponic.xyz$request_uri? permanent;
-  }
-}
diff --git a/roles/private/files/johan/http.lldap.internal.simponic.xyz.conf b/roles/private/files/johan/http.lldap.internal.simponic.xyz.conf
deleted file mode 100644
index 8b9efe5..0000000
--- a/roles/private/files/johan/http.lldap.internal.simponic.xyz.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-server {
-  listen 80;
-  server_name lldap.internal.simponic.xyz;
-
-  location /.well-known/acme-challenge {
-    root /var/www/letsencrypt;
-    try_files $uri $uri/ =404;
-  }
-
-  location / {
-    rewrite ^ https://lldap.internal.simponic.xyz$request_uri? permanent;
-  }
-}
diff --git a/roles/private/files/johan/http.ntfy.internal.simponic.xyz.conf b/roles/private/files/johan/http.ntfy.internal.simponic.xyz.conf
deleted file mode 100644
index cdc7839..0000000
--- a/roles/private/files/johan/http.ntfy.internal.simponic.xyz.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-server {
-  listen 80;
-  server_name ntfy.internal.simponic.xyz;
-
-  location /.well-known/acme-challenge {
-    root /var/www/letsencrypt;
-    try_files $uri $uri/ =404;
-  }
-
-  location / {
-    rewrite ^ https://ntfy.internal.simponic.xyz$request_uri? permanent;
-  }
-}
diff --git a/roles/private/files/johan/http.pihole.internal.simponic.xyz.conf b/roles/private/files/johan/http.pihole.internal.simponic.xyz.conf
deleted file mode 100644
index a30ffc3..0000000
--- a/roles/private/files/johan/http.pihole.internal.simponic.xyz.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-server {
-  listen 80;
-  server_name pihole.internal.simponic.xyz;
-
-  location /.well-known/acme-challenge {
-    root /var/www/letsencrypt;
-    try_files $uri $uri/ =404;
-  }
-
-  location / {
-    rewrite ^ https://pihole.internal.simponic.xyz$request_uri? permanent;
-  }
-}
diff --git a/roles/private/files/johan/http.vaultwarden.internal.simponic.xyz.conf b/roles/private/files/johan/http.vaultwarden.internal.simponic.xyz.conf
deleted file mode 100644
index 77f8790..0000000
--- a/roles/private/files/johan/http.vaultwarden.internal.simponic.xyz.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-server {
-  listen 80;
-  server_name vaultwarden.internal.simponic.xyz;
-
-  location /.well-known/acme-challenge {
-    root /var/www/letsencrypt;
-    try_files $uri $uri/ =404;
-  }
-
-  location / {
-    rewrite ^ https://vaultwarden.internal.simponic.xyz$request_uri? permanent;
-  }
-}
diff --git a/roles/private/files/johan/https.backups.internal.simponic.xyz.conf b/roles/private/files/johan/https.backups.internal.simponic.xyz.conf
deleted file mode 100644
index 799b0f7..0000000
--- a/roles/private/files/johan/https.backups.internal.simponic.xyz.conf
+++ /dev/null
@@ -1,32 +0,0 @@
-server {
-  listen 443 ssl;
-  server_name backups.internal.simponic.xyz;
-
-  ssl_certificate         /etc/letsencrypt/live/backups.internal.simponic.xyz/fullchain.pem;
-  ssl_certificate_key     /etc/letsencrypt/live/backups.internal.simponic.xyz/privkey.pem;
-  ssl_trusted_certificate /etc/letsencrypt/live/backups.internal.simponic.xyz/fullchain.pem;
-
-  ssl_session_cache shared:SSL:50m;
-  ssl_session_timeout 5m;
-  ssl_stapling on;
-  ssl_stapling_verify on;
-
-  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-  ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
-
-  ssl_dhparam /etc/nginx/dhparams.pem;
-  ssl_prefer_server_ciphers on;
-
-  location / {
-    proxy_pass http://127.0.0.1:31152;
-    proxy_http_version 1.1;
-    proxy_set_header Upgrade $http_upgrade;
-    proxy_set_header Connection "upgrade";
-    proxy_set_header Host $server_name;
-    proxy_buffering off;
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
-    add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
-  }
-}
diff --git a/roles/private/files/johan/https.ca.internal.simponic.xyz.conf b/roles/private/files/johan/https.ca.internal.simponic.xyz.conf
deleted file mode 100644
index 8d7d190..0000000
--- a/roles/private/files/johan/https.ca.internal.simponic.xyz.conf
+++ /dev/null
@@ -1,32 +0,0 @@
-server {
-  listen 443 ssl;
-  server_name ca.internal.simponic.xyz;
-
-  ssl_certificate         /etc/letsencrypt/live/ca.internal.simponic.xyz/fullchain.pem;
-  ssl_certificate_key     /etc/letsencrypt/live/ca.internal.simponic.xyz/privkey.pem;
-  ssl_trusted_certificate /etc/letsencrypt/live/ca.internal.simponic.xyz/fullchain.pem;
-
-  ssl_session_cache shared:SSL:50m;
-  ssl_session_timeout 5m;
-  ssl_stapling on;
-  ssl_stapling_verify on;
-
-  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-  ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
-
-  ssl_dhparam /etc/nginx/dhparams.pem;
-  ssl_prefer_server_ciphers on;
-
-  location / {
-    proxy_pass https://ca.internal.simponic.xyz:5239;
-    proxy_http_version 1.1;
-    proxy_set_header Upgrade $http_upgrade;
-    proxy_set_header Connection "upgrade";
-    proxy_set_header Host $server_name;
-    proxy_buffering off;
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
-    add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
-  }
-}
diff --git a/roles/private/files/johan/https.httpsms.internal.simponic.xyz.conf b/roles/private/files/johan/https.httpsms.internal.simponic.xyz.conf
deleted file mode 100644
index 380288e..0000000
--- a/roles/private/files/johan/https.httpsms.internal.simponic.xyz.conf
+++ /dev/null
@@ -1,45 +0,0 @@
-server {
-  listen 443 ssl;
-  server_name httpsms.internal.simponic.xyz;
-
-  ssl_certificate         /etc/letsencrypt/live/httpsms.internal.simponic.xyz/fullchain.pem;
-  ssl_certificate_key     /etc/letsencrypt/live/httpsms.internal.simponic.xyz/privkey.pem;
-  ssl_trusted_certificate /etc/letsencrypt/live/httpsms.internal.simponic.xyz/fullchain.pem;
-
-  ssl_session_cache shared:SSL:50m;
-  ssl_session_timeout 5m;
-  ssl_stapling on;
-  ssl_stapling_verify on;
-
-  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-  ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
-
-  ssl_dhparam /etc/nginx/dhparams.pem;
-  ssl_prefer_server_ciphers on;
-
-  location / {
-    proxy_pass http://127.0.0.1:33221;
-    proxy_http_version 1.1;
-    proxy_set_header Upgrade $http_upgrade;
-    proxy_set_header Connection "upgrade";
-    proxy_set_header Host $server_name;
-    proxy_buffering off;
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
-    add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
-  }
-
-  location /v1/ {
-    proxy_pass http://127.0.0.1:33222;
-    proxy_http_version 1.1;
-    proxy_set_header Upgrade $http_upgrade;
-    proxy_set_header Connection "upgrade";
-    proxy_set_header Host $server_name;
-    proxy_buffering off;
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
-    add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
-  }
-}
diff --git a/roles/private/files/johan/https.lldap.internal.simponic.xyz.conf b/roles/private/files/johan/https.lldap.internal.simponic.xyz.conf
deleted file mode 100644
index 98306f5..0000000
--- a/roles/private/files/johan/https.lldap.internal.simponic.xyz.conf
+++ /dev/null
@@ -1,32 +0,0 @@
-server {
-  listen 443 ssl;
-  server_name lldap.internal.simponic.xyz;
-
-  ssl_certificate         /etc/letsencrypt/live/lldap.internal.simponic.xyz/fullchain.pem;
-  ssl_certificate_key     /etc/letsencrypt/live/lldap.internal.simponic.xyz/privkey.pem;
-  ssl_trusted_certificate /etc/letsencrypt/live/lldap.internal.simponic.xyz/fullchain.pem;
-
-  ssl_session_cache shared:SSL:50m;
-  ssl_session_timeout 5m;
-  ssl_stapling on;
-  ssl_stapling_verify on;
-
-  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-  ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
-
-  ssl_dhparam /etc/nginx/dhparams.pem;
-  ssl_prefer_server_ciphers on;
-
-  location / {
-    proxy_pass http://127.0.0.1:17170;
-    proxy_http_version 1.1;
-    proxy_set_header Upgrade $http_upgrade;
-    proxy_set_header Connection "upgrade";
-    proxy_set_header Host $server_name;
-    proxy_buffering off;
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
-    add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
-  }
-}
diff --git a/roles/private/files/johan/https.ntfy.internal.simponic.xyz.conf b/roles/private/files/johan/https.ntfy.internal.simponic.xyz.conf
deleted file mode 100644
index 0ae2e91..0000000
--- a/roles/private/files/johan/https.ntfy.internal.simponic.xyz.conf
+++ /dev/null
@@ -1,32 +0,0 @@
-server {
-  listen 443 ssl;
-  server_name ntfy.internal.simponic.xyz;
-
-  ssl_certificate         /etc/letsencrypt/live/ntfy.internal.simponic.xyz/fullchain.pem;
-  ssl_certificate_key     /etc/letsencrypt/live/ntfy.internal.simponic.xyz/privkey.pem;
-  ssl_trusted_certificate /etc/letsencrypt/live/ntfy.internal.simponic.xyz/fullchain.pem;
-
-  ssl_session_cache shared:SSL:50m;
-  ssl_session_timeout 5m;
-  ssl_stapling on;
-  ssl_stapling_verify on;
-
-  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-  ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
-
-  ssl_dhparam /etc/nginx/dhparams.pem;
-  ssl_prefer_server_ciphers on;
-
-  location / {
-    proxy_pass http://127.0.0.1:22311;
-    proxy_http_version 1.1;
-    proxy_set_header Upgrade $http_upgrade;
-    proxy_set_header Connection "upgrade";
-    proxy_set_header Host $server_name;
-    proxy_buffering off;
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
-    add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
-  }
-}
diff --git a/roles/private/files/johan/https.pihole.internal.simponic.xyz.conf b/roles/private/files/johan/https.pihole.internal.simponic.xyz.conf
deleted file mode 100644
index b231f3f..0000000
--- a/roles/private/files/johan/https.pihole.internal.simponic.xyz.conf
+++ /dev/null
@@ -1,32 +0,0 @@
-server {
-  listen 443 ssl;
-  server_name pihole.internal.simponic.xyz;
-
-  ssl_certificate         /etc/letsencrypt/live/pihole.internal.simponic.xyz/fullchain.pem;
-  ssl_certificate_key     /etc/letsencrypt/live/pihole.internal.simponic.xyz/privkey.pem;
-  ssl_trusted_certificate /etc/letsencrypt/live/pihole.internal.simponic.xyz/fullchain.pem;
-
-  ssl_session_cache shared:SSL:50m;
-  ssl_session_timeout 5m;
-  ssl_stapling on;
-  ssl_stapling_verify on;
-
-  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-  ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
-
-  ssl_dhparam /etc/nginx/dhparams.pem;
-  ssl_prefer_server_ciphers on;
-
-  location / {
-    proxy_pass http://127.0.0.1:9135;
-    proxy_http_version 1.1;
-    proxy_set_header Upgrade $http_upgrade;
-    proxy_set_header Connection "upgrade";
-    proxy_set_header Host $server_name;
-    proxy_buffering off;
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
-    add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
-  }
-}
diff --git a/roles/private/files/johan/https.vaultwarden.internal.simponic.xyz.conf b/roles/private/files/johan/https.vaultwarden.internal.simponic.xyz.conf
deleted file mode 100644
index 4b7ba2c..0000000
--- a/roles/private/files/johan/https.vaultwarden.internal.simponic.xyz.conf
+++ /dev/null
@@ -1,32 +0,0 @@
-server {
-  listen 443 ssl;
-  server_name vaultwarden.internal.simponic.xyz;
-
-  ssl_certificate         /etc/letsencrypt/live/vaultwarden.internal.simponic.xyz/fullchain.pem;
-  ssl_certificate_key     /etc/letsencrypt/live/vaultwarden.internal.simponic.xyz/privkey.pem;
-  ssl_trusted_certificate /etc/letsencrypt/live/vaultwarden.internal.simponic.xyz/fullchain.pem;
-
-  ssl_session_cache shared:SSL:50m;
-  ssl_session_timeout 5m;
-  ssl_stapling on;
-  ssl_stapling_verify on;
-
-  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-  ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
-
-  ssl_dhparam /etc/nginx/dhparams.pem;
-  ssl_prefer_server_ciphers on;
-
-  location / {
-    proxy_pass http://127.0.0.1:8652;
-    proxy_http_version 1.1;
-    proxy_set_header Upgrade $http_upgrade;
-    proxy_set_header Connection "upgrade";
-    proxy_set_header Host $server_name;
-    proxy_buffering off;
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
-    add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
-  }
-}
diff --git a/roles/private/files/nginx.conf b/roles/private/files/nginx.conf
deleted file mode 100644
index 1e04156..0000000
--- a/roles/private/files/nginx.conf
+++ /dev/null
@@ -1,27 +0,0 @@
-user www-data;
-worker_processes 4;
-pid /run/nginx.pid;
-
-events {
-  worker_connections 768;
-}
-
-http {
-  charset utf-8;
-  sendfile on;
-  tcp_nopush on;
-  tcp_nodelay on;
-  keepalive_timeout 65;
-  types_hash_max_size 2048;
-  include /etc/nginx/mime.types;
-  default_type application/octet-stream;
-
-  access_log /var/log/nginx/access.log;
-  error_log /var/log/nginx/error.log;
-
-  gzip on;
-  gzip_disable "msie6";
-
-  include /etc/nginx/conf.d/*.conf;
-  include /etc/nginx/sites-enabled/*;
-}
diff --git a/roles/private/files/raspberrypi/http.uptime.internal.simponic.xyz.conf b/roles/private/files/raspberrypi/http.uptime.internal.simponic.xyz.conf
deleted file mode 100644
index 4fe861c..0000000
--- a/roles/private/files/raspberrypi/http.uptime.internal.simponic.xyz.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-server {
-  listen 80;
-  server_name uptime.internal.simponic.xyz;
-
-  location /.well-known/acme-challenge {
-    root /var/www/letsencrypt;
-    try_files $uri $uri/ =404;
-  }
-
-  location / {
-    rewrite ^ https://uptime.internal.simponic.xyz$request_uri? permanent;
-  }
-}
diff --git a/roles/private/files/raspberrypi/http.uptimeplugins.internal.simponic.xyz.conf b/roles/private/files/raspberrypi/http.uptimeplugins.internal.simponic.xyz.conf
deleted file mode 100644
index b901c7c..0000000
--- a/roles/private/files/raspberrypi/http.uptimeplugins.internal.simponic.xyz.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-server {
-  listen 80;
-  server_name uptimeplugins.internal.simponic.xyz;
-
-  location /.well-known/acme-challenge {
-    root /var/www/letsencrypt;
-    try_files $uri $uri/ =404;
-  }
-
-  location / {
-    rewrite ^ https://uptimeplugins.internal.simponic.xyz$request_uri? permanent;
-  }
-}
diff --git a/roles/private/files/raspberrypi/https.uptime.internal.simponic.xyz.conf b/roles/private/files/raspberrypi/https.uptime.internal.simponic.xyz.conf
deleted file mode 100644
index f002af8..0000000
--- a/roles/private/files/raspberrypi/https.uptime.internal.simponic.xyz.conf
+++ /dev/null
@@ -1,32 +0,0 @@
-server {
-  listen 443 ssl;
-  server_name uptime.internal.simponic.xyz;
-
-  ssl_certificate         /etc/letsencrypt/live/uptime.internal.simponic.xyz/fullchain.pem;
-  ssl_certificate_key     /etc/letsencrypt/live/uptime.internal.simponic.xyz/privkey.pem;
-  ssl_trusted_certificate /etc/letsencrypt/live/uptime.internal.simponic.xyz/fullchain.pem;
-
-  ssl_session_cache shared:SSL:50m;
-  ssl_session_timeout 5m;
-  ssl_stapling on;
-  ssl_stapling_verify on;
-
-  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-  ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
-
-  ssl_dhparam /etc/nginx/dhparams.pem;
-  ssl_prefer_server_ciphers on;
-
-  location / {
-    proxy_pass http://127.0.0.1:9922;
-    proxy_http_version 1.1;
-    proxy_set_header Upgrade $http_upgrade;
-    proxy_set_header Connection "upgrade";
-    proxy_set_header Host $server_name;
-    proxy_buffering off;
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
-    add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
-  }
-}
diff --git a/roles/private/files/raspberrypi/https.uptimeplugins.internal.simponic.xyz.conf b/roles/private/files/raspberrypi/https.uptimeplugins.internal.simponic.xyz.conf
deleted file mode 100644
index 9e13968..0000000
--- a/roles/private/files/raspberrypi/https.uptimeplugins.internal.simponic.xyz.conf
+++ /dev/null
@@ -1,32 +0,0 @@
-server {
-  listen 443 ssl;
-  server_name uptimeplugins.internal.simponic.xyz;
-
-  ssl_certificate         /etc/letsencrypt/live/uptimeplugins.internal.simponic.xyz/fullchain.pem;
-  ssl_certificate_key     /etc/letsencrypt/live/uptimeplugins.internal.simponic.xyz/privkey.pem;
-  ssl_trusted_certificate /etc/letsencrypt/live/uptimeplugins.internal.simponic.xyz/fullchain.pem;
-
-  ssl_session_cache shared:SSL:50m;
-  ssl_session_timeout 5m;
-  ssl_stapling on;
-  ssl_stapling_verify on;
-
-  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-  ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
-
-  ssl_dhparam /etc/nginx/dhparams.pem;
-  ssl_prefer_server_ciphers on;
-
-  location / {
-    proxy_pass http://127.0.0.1:9923;
-    proxy_http_version 1.1;
-    proxy_set_header Upgrade $http_upgrade;
-    proxy_set_header Connection "upgrade";
-    proxy_set_header Host $server_name;
-    proxy_buffering off;
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
-    add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
-  }
-}
diff --git a/roles/private/tasks/main.yml b/roles/private/tasks/main.yml
deleted file mode 100644
index 26c273a..0000000
--- a/roles/private/tasks/main.yml
+++ /dev/null
@@ -1,98 +0,0 @@
----
-- name: allow http from vpn
-  ufw:
-    rule: allow
-    port: '80'
-    proto: tcp
-    from: 100.64.0.0/10
-
-- name: allow https from vpn
-  ufw:
-    rule: allow
-    port: '443'
-    proto: tcp
-    from: 100.64.0.0/10
-
-- name: allow https from docker and other internal stuffs
-  ufw:
-    rule: allow
-    port: '443'
-    proto: tcp
-    from: 172.16.0.0/12
-
-- name: restart ufw
-  service: name=ufw state=restarted enabled=yes
-
-- name: install letsencrypt
-  apt: name=letsencrypt state=latest
-
-- name: create letsencrypt directory
-  file: name=/var/www/letsencrypt state=directory
-
-- name: install nginx
-  apt: name=nginx state=latest
-
-- name: remove default nginx
-  file: name=/etc/nginx/sites-enabled/default state=absent
-
-- name: generate dhparams
-  shell: openssl dhparam -out /etc/nginx/dhparams.pem 2048
-  args:
-    creates: /etc/nginx/dhparams.pem
-
-- name: add system nginx config
-  template:
-    src: ../files/nginx.conf
-    dest: /etc/nginx/nginx.conf
-
-- name: copy http nginx configuration for each domain
-  copy:
-    src: "{{ item }}"
-    dest: "/etc/nginx/sites-enabled/"
-  with_fileglob:
-    - "files/{{ inventory_hostname }}/http.*.conf"
-
-- name: restart nginx to get letsencrypt certificate
-  service: name=nginx state=restarted enabled=yes
-
-- name: find deployed domains
-  ansible.builtin.find:
-    paths: "/etc/nginx/sites-enabled/"
-    patterns: "http.*.conf"
-  register: nginx_conf_files
-  delegate_to: "{{ inventory_hostname }}"
-
-- name: extract domains from deployed nginx configurations
-  shell: |
-    grep -oP 'server_name\s+\K[^;]+' "{{ item.path }}"
-  loop: "{{ nginx_conf_files.files }}"
-  register: extracted_domains
-
-# crt is given from the "ca" role to all hosts; that needs to run first
-- name: request letsencrypt certificate
-  shell: >
-    REQUESTS_CA_BUNDLE="/usr/local/share/ca-certificates/{{ step_bootstrap_ca_url }}.crt" \
-      letsencrypt certonly -n -d {{ item.stdout }} \
-      --server https://{{ step_bootstrap_ca_url }}:{{ step_ca_port }}/acme/ACME/directory \
-      --webroot -w /var/www/letsencrypt \
-      --agree-tos --email {{ step_acme_cert_contact }}
-  args:
-    creates: "/etc/letsencrypt/live/{{ item.stdout }}"
-  loop: "{{ extracted_domains.results }}"
-  when: item.stdout != ""
-
-- name: copy https nginx configuration for each domain
-  copy:
-    src: "{{ item }}"
-    dest: "/etc/nginx/sites-enabled/"
-  with_fileglob:
-    - "files/{{ inventory_hostname }}/https.*.conf"
-
-- name: reload nginx to activate sites
-  service: name=nginx state=restarted
-
-- name: add daily renewal
-  cron:
-    name: "letsencrypt_renewal"
-    special_time: "daily"
-    job: "REQUESTS_CA_BUNDLE=/usr/local/share/ca-certificates/{{ step_bootstrap_ca_url }}.crt letsencrypt renew --force-renewal --non-interactive ; systemctl restart nginx"
diff --git a/roles/rainrainrain/tasks/main.yml b/roles/rainrainrain/tasks/main.yml
deleted file mode 100644
index 87638c8..0000000
--- a/roles/rainrainrain/tasks/main.yml
+++ /dev/null
@@ -1,9 +0,0 @@
----
-
-- name: clone static repo
-  git:
-    repo: https://git.simponic.xyz/simponic/rainrainra.in.git
-    dest: /var/www/html/rainrainra.in
-    recursive: yes
-    clone: yes
-    update: yes
diff --git a/roles/roundcube/tasks/main.yml b/roles/roundcube/tasks/main.yml
deleted file mode 100644
index d838433..0000000
--- a/roles/roundcube/tasks/main.yml
+++ /dev/null
@@ -1,22 +0,0 @@
----
-- name: ensure rouncube docker/compose exist
-  file:
-    path: /etc/docker/compose/roundcube
-    state: directory
-    owner: root
-    group: root
-    mode: 0700
-
-- name: build roundcube docker-compose.yml.j2
-  template:
-    src: ../templates/docker-compose.yml.j2
-    dest: /etc/docker/compose/roundcube/docker-compose.yml
-    owner: root
-    group: root
-    mode: u=rw,g=r,o=r
-
-- name: daemon-reload and enable roundcube
-  ansible.builtin.systemd_service:
-    state: restarted
-    enabled: true
-    name: docker-compose@roundcube
diff --git a/roles/roundcube/templates/docker-compose.yml.j2 b/roles/roundcube/templates/docker-compose.yml.j2
deleted file mode 100644
index 1860459..0000000
--- a/roles/roundcube/templates/docker-compose.yml.j2
+++ /dev/null
@@ -1,23 +0,0 @@
-version: '3'
-
-services:
-  roundcube:
-    image: roundcube/roundcubemail:latest
-    container_name: roundcubemail
-    restart: unless-stopped
-    hostname: roundcube.internal.simponic.xyz
-    volumes:
-      - ./www:/var/www/html
-      - ./db/sqlite:/var/roundcube/db
-    ports:
-      - 127.0.0.1:9002:80
-    dns:
-      - {{ nameserver_ip }}
-    environment:
-      - ROUNDCUBEMAIL_DB_TYPE=sqlite
-      - ROUNDCUBEMAIL_SKIN=elastic
-      - ROUNDCUBEMAIL_DEFAULT_HOST=ssl://mail.simponic.xyz
-      - ROUNDCUBEMAIL_DEFAULT_PORT=993
-      - ROUNDCUBEMAIL_SMTP_SERVER=tls://mail.simponic.xyz
-      - ROUNDCUBEMAIL_PLUGINS=archive,zipdownload,managesieve,markasjunk
-      - ROUNDCUBEMAIL_SMTP_PORT=587
diff --git a/roles/roundcube/templates/sieve.inc.php.j2 b/roles/roundcube/templates/sieve.inc.php.j2
deleted file mode 100644
index 8970ff3..0000000
--- a/roles/roundcube/templates/sieve.inc.php.j2
+++ /dev/null
@@ -1,4 +0,0 @@
-<?php
-
-$config['managesieve_host'] = "tls://mail.simponic.xyz";
-$config['managesieve_auth_type'] = "PLAIN";
diff --git a/roles/scurvy/tasks/main.yml b/roles/scurvy/tasks/main.yml
deleted file mode 100644
index c1d8902..0000000
--- a/roles/scurvy/tasks/main.yml
+++ /dev/null
@@ -1,22 +0,0 @@
----
-- name: ensure scurvy docker/compose exist
-  file:
-    path: /etc/docker/compose/scurvy
-    state: directory
-    owner: root
-    group: root
-    mode: 0700
-
-- name: build scurvy docker-compose.yml.j2
-  template:
-    src: ../templates/docker-compose.yml.j2
-    dest: /etc/docker/compose/scurvy/docker-compose.yml
-    owner: root
-    group: root
-    mode: u=rw,g=r,o=r
-
-- name: daemon-reload and enable scurvy
-  ansible.builtin.systemd_service:
-    state: restarted
-    enabled: true
-    name: docker-compose@scurvy
diff --git a/roles/scurvy/templates/docker-compose.yml.j2 b/roles/scurvy/templates/docker-compose.yml.j2
deleted file mode 100644
index a22ed9b..0000000
--- a/roles/scurvy/templates/docker-compose.yml.j2
+++ /dev/null
@@ -1,61 +0,0 @@
-version: '3'
-services:
-  gluetun:
-    image: qmcgaw/gluetun
-    container_name: gluetun
-    cap_add:
-      - NET_ADMIN
-    devices:
-      - /dev/net/tun:/dev/net/tun
-    ports:
-      - 127.0.0.1:9000:8080/tcp
-      - 127.0.0.1:6881:6881
-      - 127.0.0.1:6881:6881/udp
-    volumes:
-      - /gluetun
-    environment:
-      - VPN_SERVICE_PROVIDER=mullvad
-      - VPN_TYPE=openvpn
-      - OPENVPN_USER={{ openvpn_user }}
-      - SERVER_CITIES=Seattle WA
-
-  qbittorrent:
-    image: hotio/qbittorrent:latest
-    container_name: qbittorrent
-    environment:
-      - PUID=1000
-      - PGID=1000
-    volumes:
-      - qbittorrent_config:/config:rw
-      - type: bind
-        source: /mnt/hdd-01
-        target: /hdd-01
-      - type: bind
-        source: /mnt/ssd-01
-        target: /ssd-01
-    restart: unless-stopped
-    network_mode: "container:gluetun"
-
-  jellyfin:
-    image: lscr.io/linuxserver/jellyfin:latest
-    container_name: jellyfin
-    environment:
-      - JELLYFIN_PublishedServerUrl=https://jellyfin.internal.simponic.xyz
-    ports:
-      - 127.0.0.1:8096:8096
-    devices:
-      - /dev/dri:/dev/dri
-    volumes:
-      - type: bind
-        source: /mnt/hdd-01
-        target: /hdd-01
-      - type: bind
-        source: /mnt/ssd-01
-        target: /ssd-01
-      - jellyfin_config:/config:rw
-      - jellyfin_cache:/cache:rw
-
-volumes:
-  jellyfin_config:
-  jellyfin_cache:
-  qbittorrent_config:
diff --git a/roles/something/tasks/main.yml b/roles/something/tasks/main.yml
deleted file mode 100644
index 0837780..0000000
--- a/roles/something/tasks/main.yml
+++ /dev/null
@@ -1,30 +0,0 @@
----
-- name: ensure something docker/compose exist
-  file:
-    path: /etc/docker/compose/something
-    state: directory
-    owner: root
-    group: root
-    mode: 0700
-
-- name: ensure something db exist
-  file:
-    path: /etc/docker/compose/something/db
-    state: directory
-    owner: root
-    group: root
-    mode: 0777
-
-- name: build something docker-compose.yml.j2
-  template:
-    src: ../templates/docker-compose.yml.j2
-    dest: /etc/docker/compose/something/docker-compose.yml
-    owner: root
-    group: root
-    mode: u=rw,g=r,o=r
-
-- name: daemon-reload and enable something
-  ansible.builtin.systemd_service:
-    state: restarted
-    enabled: true
-    name: docker-compose@something
diff --git a/roles/something/templates/docker-compose.yml.j2 b/roles/something/templates/docker-compose.yml.j2
deleted file mode 100644
index 6704897..0000000
--- a/roles/something/templates/docker-compose.yml.j2
+++ /dev/null
@@ -1,16 +0,0 @@
-version: "3"
-
-services:
-  api:
-    restart: always
-    image: git.simponic.xyz/simponic/something
-    healthcheck:
-      test: ["CMD", "wget", "--spider", "http://localhost:8080/api/health"]
-      interval: 5s
-      timeout: 10s
-      retries: 5
-    env_file: .env
-    volumes:
-      - ./db:/app/db
-    ports:
-      - "127.0.0.1:6363:8080"
diff --git a/roles/static/tasks/main.yml b/roles/static/tasks/main.yml
deleted file mode 100644
index 4e65376..0000000
--- a/roles/static/tasks/main.yml
+++ /dev/null
@@ -1,9 +0,0 @@
----
-
-- name: clone static repo
-  git:
-    repo: https://git.simponic.xyz/simponic/simponic.xyz.git
-    dest: /var/www/html/simponic.xyz
-    recursive: yes
-    clone: yes
-    update: yes
diff --git a/roles/uptime/tasks/main.yml b/roles/uptime/tasks/main.yml
deleted file mode 100644
index b656040..0000000
--- a/roles/uptime/tasks/main.yml
+++ /dev/null
@@ -1,29 +0,0 @@
----
-- name: Download internal cert
-  ansible.builtin.get_url:
-    url: https://ca.internal.simponic.xyz/roots.pem
-    validate_certs: false
-    dest: /etc/roots.pem
-    checksum: sha256:12a1d52af6f4073c339946e8c67bdd48fa85590480385fcce7f16b6b60d40831
-
-- name: ensure uptimekuma docker/compose exist
-  file:
-    path: /etc/docker/compose/uptimekuma
-    state: directory
-    owner: root
-    group: root
-    mode: 0700
-
-- name: build uptimekuma docker-compose.yml.j2
-  template:
-    src: ../templates/docker-compose.yml.j2
-    dest: /etc/docker/compose/uptimekuma/docker-compose.yml
-    owner: root
-    group: root
-    mode: u=rw,g=r,o=r
-
-- name: daemon-reload and enable uptimekuma
-  ansible.builtin.systemd_service:
-    state: restarted
-    enabled: true
-    name: docker-compose@uptimekuma
diff --git a/roles/uptime/templates/docker-compose.yml.j2 b/roles/uptime/templates/docker-compose.yml.j2
deleted file mode 100644
index 0f1cd8e..0000000
--- a/roles/uptime/templates/docker-compose.yml.j2
+++ /dev/null
@@ -1,28 +0,0 @@
-version: '3'
-
-services:
-  uptime-kuma:
-    container_name: uptime-kuma
-    networks:
-      - uptime
-    image: louislam/uptime-kuma:1
-    volumes:
-      - ./data:/app/data
-      - /etc/roots.pem:/roots.pem
-    ports:
-      - 127.0.0.1:9922:3001
-    dns:
-      - {{ nameserver_ip }}
-    restart: unless-stopped
-    environment:
-      - NODE_EXTRA_CA_CERTS=/roots.pem
-  uptime-plugins:
-    container_name: uptime-plugins
-    networks:
-      - uptime
-    image: git.simponic.xyz/simponic/uptime:arm
-    restart: unless-stopped
-    ports:
-      - 127.0.0.1:9923:3000
-networks:
-  uptime:
diff --git a/roles/vaultwarden/tasks/main.yml b/roles/vaultwarden/tasks/main.yml
deleted file mode 100644
index 5c57bb5..0000000
--- a/roles/vaultwarden/tasks/main.yml
+++ /dev/null
@@ -1,22 +0,0 @@
----
-- name: ensure vaultwarden docker/compose exist
-  file:
-    path: /etc/docker/compose/vaultwarden
-    state: directory
-    owner: root
-    group: root
-    mode: 0700
-
-- name: build vaultwarden docker-compose.yml.j2
-  template:
-    src: ../templates/docker-compose.yml.j2
-    dest: /etc/docker/compose/vaultwarden/docker-compose.yml
-    owner: root
-    group: root
-    mode: u=rw,g=r,o=r
-
-- name: daemon-reload and enable vaultwarden
-  ansible.builtin.systemd_service:
-    state: restarted
-    enabled: true
-    name: docker-compose@vaultwarden
diff --git a/roles/vaultwarden/templates/docker-compose.yml.j2 b/roles/vaultwarden/templates/docker-compose.yml.j2
deleted file mode 100644
index 17e5c5b..0000000
--- a/roles/vaultwarden/templates/docker-compose.yml.j2
+++ /dev/null
@@ -1,36 +0,0 @@
-version: '3'
-
-services:
-  vaultwarden:
-    container_name: vaultwarden
-    image: vaultwarden/server:latest
-    restart: unless-stopped
-    volumes:
-      - ./data/:/data/
-    ports:
-      - 127.0.0.1:8652:80
-    environment:
-      - DOMAIN=https://vaultwarden.internal.simponic.xyz
-      - LOGIN_RATELIMIT_MAX_BURST=10
-      - LOGIN_RATELIMIT_SECONDS=60
-      - ADMIN_RATELIMIT_MAX_BURST=10
-      - ADMIN_RATELIMIT_SECONDS=60
-      - ADMIN_TOKEN={{ vaultwarden_admin_token }}
-      - SENDS_ALLOWED=true
-      - EMERGENCY_ACCESS_ALLOWED=true
-      - WEB_VAULT_ENABLED=true
-      
-      - SIGNUPS_ALLOWED=false
-      - SIGNUPS_VERIFY=true
-      - SIGNUPS_VERIFY_RESEND_TIME=3600
-      - SIGNUPS_VERIFY_RESEND_LIMIT=5
-      - SIGNUPS_DOMAINS_WHITELIST=simponic.xyz
-
-      - SMTP_HOST=mail.simponic.xyz
-      - SMTP_FROM=info@simponic.xyz
-      - SMTP_FROM_NAME=VaultWarden
-      - SMTP_SECURITY=starttls
-      - SMTP_PORT=587
-      - SMTP_USERNAME=info@simponic.xyz
-      - SMTP_PASSWORD={{ email_password }}
-      - SMTP_AUTH_MECHANISM="Plain"
diff --git a/roles/vpn/files/config/acl.json b/roles/vpn/files/config/acl.json
deleted file mode 100644
index 9aaf5eb..0000000
--- a/roles/vpn/files/config/acl.json
+++ /dev/null
@@ -1,45 +0,0 @@
-{
-  "groups": {
-    "group:admin": ["elizabeth"],
-    "group:roomates": ["riley", "lucina", "elizabeth"],
-    "group:friends": ["riley", "rain", "lucina"],
-    "group:sys": ["sys"]
-  },
-  "tagOwners": {
-    "tag:prod": ["group:admin"],
-    "tag:private": ["group:admin"],
-    "tag:dev": ["group:admin"]
-  },
-  "acls": [
-    {
-      "action": "accept",
-      "src": ["group:admin"],
-      "dst": [
-        "tag:dev:*",
-        "tag:private:*",
-        "tag:prod:*",
-        "group:sys:*"
-      ]
-    },
-    {
-      "action": "accept",
-      "src": ["group:sys"],
-      "dst": ["group:sys:*", "10.128.0.0/9:*"]
-    },
-    {
-      "action": "accept",
-      "src": ["group:admin"],
-      "dst": ["group:admin:*"]
-    },
-    {
-      "action": "accept",
-      "src": ["group:roomates"],
-      "dst": ["10.0.0.0/8:*", "192.168.86.0/24:*", "192.168.1.0/24:*", "group:roomates:*"]
-    },
-    {
-      "action": "accept",
-      "src": ["group:friends"],
-      "dst": ["group:sys:*"]
-    }
-  ]
-}
diff --git a/roles/vpn/files/docker-compose.yml b/roles/vpn/files/docker-compose.yml
deleted file mode 100644
index 8ea016d..0000000
--- a/roles/vpn/files/docker-compose.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-version: '3.5'
-services:
-  headscale:
-    image: headscale/headscale:0.22.3
-    container_name: headscale
-    volumes:
-      - ./config:/etc/headscale
-      - ./data:/var/lib/headscale
-    ports:
-      - 127.0.0.1:27896:8080
-    command: headscale serve
-    restart: unless-stopped
-  headscale-ui:
-    image: ghcr.io/gurucomputing/headscale-ui:latest
-    restart: unless-stopped
-    container_name: headscale-ui
-    ports:
-      - 127.0.0.1:9443:443
diff --git a/roles/vpn/tasks/main.yml b/roles/vpn/tasks/main.yml
deleted file mode 100644
index b1b5009..0000000
--- a/roles/vpn/tasks/main.yml
+++ /dev/null
@@ -1,46 +0,0 @@
----
-- name: ensure headscale docker/compose exist
-  file:
-    path: /etc/docker/compose/headscale
-    state: directory
-    owner: root
-    group: root
-    mode: 0700
-
-- name: copy headscale docker-compose.yml
-  copy:
-    src: ../files/docker-compose.yml
-    dest: /etc/docker/compose/headscale/docker-compose.yml
-    owner: root
-    group: root
-    mode: u=rw,g=r,o=r
-
-- name: copy headscale config volume
-  copy:
-    src: ../files/config
-    dest: /etc/docker/compose/headscale/
-    owner: root
-    group: root
-    mode: u=rw,g=r,o=r
-
-- name: build headscale config template
-  template:
-    src: ../templates/config.yml.j2
-    dest: /etc/docker/compose/headscale/config/config.yml
-    owner: root
-    group: root
-    mode: u=rw,g=r,o=r
-
-- name: ensure headscale data volume exist
-  file:
-    path: /etc/docker/compose/headscale/data
-    state: directory
-    owner: root
-    group: root
-    mode: 0700
-
-- name: daemon-reload and enable headscale
-  ansible.builtin.systemd_service:
-    state: restarted
-    enabled: true
-    name: docker-compose@headscale
diff --git a/roles/vpn/templates/config.yml.j2 b/roles/vpn/templates/config.yml.j2
deleted file mode 100644
index 24a54c8..0000000
--- a/roles/vpn/templates/config.yml.j2
+++ /dev/null
@@ -1,298 +0,0 @@
----
-# headscale will look for a configuration file named `config.yaml` (or `config.json`) in the following order:
-#
-# - `/etc/headscale`
-# - `~/.headscale`
-# - current working directory
-
-# The url clients will connect to.
-# Typically this will be a domain like:
-#
-# https://myheadscale.example.com:443
-#
-server_url: https://headscale.simponic.xyz:443
-
-# Address to listen to / bind to on the server
-#
-# For production:
-# listen_addr: 0.0.0.0:8080
-listen_addr: 0.0.0.0:8080
-
-# Address to listen to /metrics, you may want
-# to keep this endpoint private to your internal
-# network
-#
-metrics_listen_addr: 127.0.0.1:9090
-
-# Address to listen for gRPC.
-# gRPC is used for controlling a headscale server
-# remotely with the CLI
-# Note: Remote access _only_ works if you have
-# valid certificates.
-#
-# For production:
-# grpc_listen_addr: 0.0.0.0:50443
-grpc_listen_addr: 127.0.0.1:50443
-
-# Allow the gRPC admin interface to run in INSECURE
-# mode. This is not recommended as the traffic will
-# be unencrypted. Only enable if you know what you
-# are doing.
-grpc_allow_insecure: false
-
-# The Noise section includes specific configuration for the
-# TS2021 Noise protocol
-noise:
-  # The Noise private key is used to encrypt the
-  # traffic between headscale and Tailscale clients when
-  # using the new Noise-based protocol.
-  private_key_path: /var/lib/headscale/noise_private.key
-
-private_key_path: /var/lib/headscale/private.key
-
-# List of IP prefixes to allocate tailaddresses from.
-# Each prefix consists of either an IPv4 or IPv6 address,
-# and the associated prefix length, delimited by a slash.
-# It must be within IP ranges supported by the Tailscale
-# client - i.e., subnets of 100.64.0.0/10 and fd7a:115c:a1e0::/48.
-# See below:
-# IPv6: https://github.com/tailscale/tailscale/blob/22ebb25e833264f58d7c3f534a8b166894a89536/net/tsaddr/tsaddr.go#LL81C52-L81C71
-# IPv4: https://github.com/tailscale/tailscale/blob/22ebb25e833264f58d7c3f534a8b166894a89536/net/tsaddr/tsaddr.go#L33
-# Any other range is NOT supported, and it will cause unexpected issues.
-ip_prefixes:
-  - fd7a:115c:a1e0::/48
-  - 100.64.0.0/10
-
-# DERP is a relay system that Tailscale uses when a direct
-# connection cannot be established.
-# https://tailscale.com/blog/how-tailscale-works/#encrypted-tcp-relays-derp
-#
-# headscale needs a list of DERP servers that can be presented
-# to the clients.
-derp:
-  server:
-    # If enabled, runs the embedded DERP server and merges it into the rest of the DERP config
-    # The Headscale server_url defined above MUST be using https, DERP requires TLS to be in place
-    enabled: false
-
-    # Region ID to use for the embedded DERP server.
-    # The local DERP prevails if the region ID collides with other region ID coming from
-    # the regular DERP config.
-    region_id: 999
-
-    # Region code and name are displayed in the Tailscale UI to identify a DERP region
-    region_code: "headscale"
-    region_name: "Headscale Embedded DERP"
-
-    # Listens over UDP at the configured address for STUN connections - to help with NAT traversal.
-    # When the embedded DERP server is enabled stun_listen_addr MUST be defined.
-    #
-    # For more details on how this works, check this great article: https://tailscale.com/blog/how-tailscale-works/
-    stun_listen_addr: "0.0.0.0:3478"
-
-    # Private key used to encrypt the traffic between headscale DERP
-    # and Tailscale clients.
-    # The private key file will be autogenerated if it's missing.
-    #
-    private_key_path: /var/lib/headscale/derp_server_private.key
-
-  # List of externally available DERP maps encoded in JSON
-  urls:
-    - https://controlplane.tailscale.com/derpmap/default
-
-  # Locally available DERP map files encoded in YAML
-  #
-  # This option is mostly interesting for people hosting
-  # their own DERP servers:
-  # https://tailscale.com/kb/1118/custom-derp-servers/
-  #
-  # paths:
-  #   - /etc/headscale/derp-example.yaml
-  paths: []
-
-  # If enabled, a worker will be set up to periodically
-  # refresh the given sources and update the derpmap
-  # will be set up.
-  auto_update_enabled: true
-
-  # How often should we check for DERP updates?
-  update_frequency: 24h
-
-# Disables the automatic check for headscale updates on startup
-disable_check_updates: false
-
-# Time before an inactive ephemeral node is deleted?
-ephemeral_node_inactivity_timeout: 30m
-
-# Period to check for node updates within the tailnet. A value too low will severely affect
-# CPU consumption of Headscale. A value too high (over 60s) will cause problems
-# for the nodes, as they won't get updates or keep alive messages frequently enough.
-# In case of doubts, do not touch the default 10s.
-node_update_check_interval: 10s
-
-# SQLite config
-db_type: sqlite3
-
-# For production:
-db_path: /var/lib/headscale/db.sqlite
-
-# # Postgres config
-# If using a Unix socket to connect to Postgres, set the socket path in the 'host' field and leave 'port' blank.
-# db_type: postgres
-# db_host: localhost
-# db_port: 5432
-# db_name: headscale
-# db_user: foo
-# db_pass: bar
-
-# If other 'sslmode' is required instead of 'require(true)' and 'disabled(false)', set the 'sslmode' you need
-# in the 'db_ssl' field. Refers to https://www.postgresql.org/docs/current/libpq-ssl.html Table 34.1.
-# db_ssl: false
-
-tls_cert_path: ""
-tls_key_path: ""
-
-log:
-  # Output formatting for logs: text or json
-  format: text
-  level: info
-
-# Path to a file containg ACL policies.
-# ACLs can be defined as YAML or HUJSON.
-# https://tailscale.com/kb/1018/acls/
-acl_policy_path: "/etc/headscale/acl.json"
-
-## DNS
-#
-# headscale supports Tailscale's DNS configuration and MagicDNS.
-# Please have a look to their KB to better understand the concepts:
-#
-# - https://tailscale.com/kb/1054/dns/
-# - https://tailscale.com/kb/1081/magicdns/
-# - https://tailscale.com/blog/2021-09-private-dns-with-magicdns/
-#
-dns_config:
-  # Whether to prefer using Headscale provided DNS or use local.
-  override_local_dns: true
-
-  # List of DNS servers to expose to clients.
-  nameservers:
-    - 1.1.1.1
-    - 1.0.0.1
-
-  # NextDNS (see https://tailscale.com/kb/1218/nextdns/).
-  # "abc123" is example NextDNS ID, replace with yours.
-  #
-  # With metadata sharing:
-  # nameservers:
-  #   - https://dns.nextdns.io/abc123
-  #
-  # Without metadata sharing:
-  # nameservers:
-  #   - 2a07:a8c0::ab:c123
-  #   - 2a07:a8c1::ab:c123
-
-  # Split DNS (see https://tailscale.com/kb/1054/dns/),
-  # list of search domains and the DNS to query for each one.
-  #
-  # restricted_nameservers:
-  #   foo.bar.com:
-  #     - 1.1.1.1
-  #   darp.headscale.net:
-  #     - 1.1.1.1
-  #     - 8.8.8.8
-  restricted_nameservers:
-    simponic.xyz:
-      - {{ nameserver_ip }}
-    hatecomputers.club:
-      - {{ nameserver_ip }}
-    mistymountainstherapy.com:
-      - {{ nameserver_ip }}
-    lucina.cloud:
-      - 192.168.1.1
-    ezri.dev:
-      - {{ nameserver_ip }}
-
-  domains: [simponic.xyz', 'internal.simponic.xyz', 'lucina.cloud']
-
-  # Extra DNS records
-  # so far only A-records are supported (on the tailscale side)
-  # See https://github.com/juanfont/headscale/blob/main/docs/dns-records.md#Limitations
-  # extra_records:
-  #   - name: "grafana.myvpn.example.com"
-  #     type: "A"
-  #     value: "100.64.0.3"
-  #
-  #   # you can also put it in one line
-  #   - { name: "prometheus.myvpn.example.com", type: "A", value: "100.64.0.3" }
-
-  # Whether to use [MagicDNS](https://tailscale.com/kb/1081/magicdns/).
-  # Only works if there is at least a nameserver defined.
-  magic_dns: true
-
-  # Defines the base domain to create the hostnames for MagicDNS.
-  # `base_domain` must be a FQDNs, without the trailing dot.
-  # The FQDN of the hosts will be
-  # `hostname.user.base_domain` (e.g., _myhost.myuser.example.com_).
-  base_domain: internal.simponic.xyz
-
-# Unix socket used for the CLI to connect without authentication
-# Note: for production you will want to set this to something like:
-unix_socket: /var/run/headscale/headscale.sock
-unix_socket_permission: "0770"
-#
-# headscale supports experimental OpenID connect support,
-# it is still being tested and might have some bugs, please
-# help us test it.
-# OpenID Connect
-oidc:
-  # Block further startup until the OIDC provider is healthy and available
-  only_start_if_oidc_is_available: false
-  # Specified by your OIDC provider
-  issuer: "https://authelia.simponic.xyz"
-  # Specified/generated by your OIDC provider
-  client_id: "simponicheadscale"
-  client_secret: "{{ headscale_oidc_secret }}"
-  # alternatively, set `client_secret_path` to read the secret from the file.
-  # It resolves environment variables, making integration to systemd's
-  # `LoadCredential` straightforward:
-  #client_secret_path: "${CREDENTIALS_DIRECTORY}/oidc_client_secret"
-
-  # Customize the scopes used in the OIDC flow, defaults to "openid", "profile" and "email" and add custom query
-  # parameters to the Authorize Endpoint request. Scopes default to "openid", "profile" and "email".
-  scope: ["openid", "profile", "email"]
-  # Optional: Passed on to the browser login request – used to tweak behaviour for the OIDC provider
-  extra_params:
-    domain_hint: simponic.xyz
-
-  # Optional: List allowed principal domains and/or users. If an authenticated user's domain is not in this list,
-  # the authentication request will be rejected.
-  allowed_domains:
-    - simponic.xyz 
-  # Optional. Note that groups from Keycloak have a leading '/'.
-  # allowed_groups:
-  #   - /admins
-  #   - admins
-  #   - people
-  # Optional.
-  allowed_users: {{ headscale_allowed_users }}
-
-  # If `strip_email_domain` is set to `true`, the domain part of the username email address will be removed.
-  # This will transform `first-name.last-name@example.com` to the user `first-name.last-name`
-  # If `strip_email_domain` is set to `false` the domain part will NOT be removed resulting to the following
-  # user: `first-name.last-name.example.com`
-  strip_email_domain: true
-
-# Logtail configuration
-# Logtail is Tailscales logging and auditing infrastructure, it allows the control panel
-# to instruct tailscale nodes to log their activity to a remote server.
-logtail:
-  # Enable logtail for this headscales clients.
-  # As there is currently no support for overriding the log server in headscale, this is
-  # disabled by default. Enabling this will make your clients send logs to Tailscale Inc.
-  enabled: false
-
-# Enabling this option makes devices prefer a random port for WireGuard traffic over the
-# default static port 41641. This option is intended as a workaround for some buggy
-# firewall devices. See https://tailscale.com/kb/1181/firewalls/ for more information.
-randomize_client_port: true
diff --git a/roles/webservers/files/levi/http.ntfy.simponic.hatecomputers.club.conf b/roles/webservers/files/levi/http.ntfy.simponic.hatecomputers.club.conf
deleted file mode 100644
index 0306736..0000000
--- a/roles/webservers/files/levi/http.ntfy.simponic.hatecomputers.club.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-server {
-  listen 80;
-  server_name ntfy.simponic.hatecomputers.club;
-
-  location /.well-known/acme-challenge {
-    root /var/www/letsencrypt;
-    try_files $uri $uri/ =404;
-  }
-
-  location / {
-    rewrite ^ https://ntfy.simponic.hatecomputers.club$request_uri? permanent;
-  }
-}
diff --git a/roles/webservers/files/levi/http.party.simponic.xyz.conf b/roles/webservers/files/levi/http.party.simponic.xyz.conf
deleted file mode 100644
index 0bbed95..0000000
--- a/roles/webservers/files/levi/http.party.simponic.xyz.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-server {
-  listen 80;
-  server_name party.simponic.xyz;
-
-  location /.well-known/acme-challenge {
-    root /var/www/letsencrypt;
-    try_files $uri $uri/ =404;
-  }
-
-  location / {
-    rewrite ^ https://party.simponic.xyz$request_uri? permanent;
-  }
-}
diff --git a/roles/webservers/files/levi/http.rainrain.xyz.conf b/roles/webservers/files/levi/http.rainrain.xyz.conf
deleted file mode 100644
index de7a872..0000000
--- a/roles/webservers/files/levi/http.rainrain.xyz.conf
+++ /dev/null
@@ -1,5 +0,0 @@
-server {
-  listen 80;
-  server_name *.rainrain.xyz;
-  return 301 https://$server_name$request_uri?;
-}
diff --git a/roles/webservers/files/levi/http.secure.tunnel.simponic.xyz.conf b/roles/webservers/files/levi/http.secure.tunnel.simponic.xyz.conf
deleted file mode 100644
index 0b50de7..0000000
--- a/roles/webservers/files/levi/http.secure.tunnel.simponic.xyz.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-server {
-  listen 80;
-  server_name secure.tunnel.simponic.xyz;
-
-  location /.well-known/acme-challenge {
-    root /var/www/letsencrypt;
-    try_files $uri $uri/ =404;
-  }
-
-  location / {
-    rewrite ^ https://secure.tunnel.simponic.xyz$request_uri? permanent;
-  }
-}
diff --git a/roles/webservers/files/levi/http.simponic.hatecomputers.club.conf b/roles/webservers/files/levi/http.simponic.hatecomputers.club.conf
deleted file mode 100644
index a58af01..0000000
--- a/roles/webservers/files/levi/http.simponic.hatecomputers.club.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-server {
-  listen 80;
-  server_name simponic.hatecomputers.club;
-
-  location /.well-known/acme-challenge {
-    root /var/www/letsencrypt;
-    try_files $uri $uri/ =404;
-  }
-
-  location / {
-    rewrite ^ https://simponic.hatecomputers.club$request_uri? permanent;
-  }
-}
diff --git a/roles/webservers/files/levi/http.simponic.xyz.conf b/roles/webservers/files/levi/http.simponic.xyz.conf
deleted file mode 100644
index b2686c9..0000000
--- a/roles/webservers/files/levi/http.simponic.xyz.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-server {
-  listen 80;
-  server_name simponic.xyz;
-
-  location /.well-known/acme-challenge {
-    root /var/www/letsencrypt;
-    try_files $uri $uri/ =404;
-  }
-
-  location / {
-    rewrite ^ https://simponic.xyz$request_uri? permanent;
-  }
-}
diff --git a/roles/webservers/files/levi/http.static.simponic.xyz.conf b/roles/webservers/files/levi/http.static.simponic.xyz.conf
deleted file mode 100644
index 648c2db..0000000
--- a/roles/webservers/files/levi/http.static.simponic.xyz.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-server {
-  listen 80;
-  server_name static.simponic.xyz;
-
-  location /.well-known/acme-challenge {
-    root /var/www/letsencrypt;
-    try_files $uri $uri/ =404;
-  }
-
-  location / {
-    rewrite ^ https://simponic.xyz$request_uri? permanent;
-  }
-}
diff --git a/roles/webservers/files/levi/http.tunnel.simponic.xyz.conf b/roles/webservers/files/levi/http.tunnel.simponic.xyz.conf
deleted file mode 100644
index f4a94a3..0000000
--- a/roles/webservers/files/levi/http.tunnel.simponic.xyz.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-server {
-  listen 80;
-  server_name tunnel.simponic.xyz;
-
-  location /.well-known/acme-challenge {
-    root /var/www/letsencrypt;
-    try_files $uri $uri/ =404;
-  }
-
-  location / {
-    rewrite ^ https://tunnel.simponic.xyz$request_uri? permanent;
-  }
-}
diff --git a/roles/webservers/files/levi/https.ntfy.simponic.hatecomputers.club.conf b/roles/webservers/files/levi/https.ntfy.simponic.hatecomputers.club.conf
deleted file mode 100644
index 8c707b4..0000000
--- a/roles/webservers/files/levi/https.ntfy.simponic.hatecomputers.club.conf
+++ /dev/null
@@ -1,36 +0,0 @@
-server {
-  listen 4443 ssl proxy_protocol;
-  real_ip_header proxy_protocol;
-  set_real_ip_from 127.0.0.1;
-
-  allow  10.0.0.0/8;
-  allow  100.64.0.0/12;
-  deny   all;
-
-  server_name ntfy.simponic.hatecomputers.club;
-
-  ssl_certificate         /etc/letsencrypt/live/ntfy.simponic.hatecomputers.club/fullchain.pem;
-  ssl_certificate_key     /etc/letsencrypt/live/ntfy.simponic.hatecomputers.club/privkey.pem;
-  ssl_trusted_certificate /etc/letsencrypt/live/ntfy.simponic.hatecomputers.club/fullchain.pem;
-
-  ssl_session_cache shared:SSL:50m;
-  ssl_session_timeout 5m;
-  ssl_stapling on;
-  ssl_stapling_verify on;
-
-  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-  ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
-
-  ssl_dhparam /etc/nginx/dhparams.pem;
-  ssl_prefer_server_ciphers on;
-
-  location / {
-    proxy_pass https://ntfy.internal.simponic.xyz;
-    proxy_http_version 1.1;
-    proxy_set_header Upgrade $http_upgrade;
-    proxy_set_header Connection "upgrade";
-    proxy_buffering off;
-    proxy_set_header X-Real-IP $remote_addr;
-    add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
-  }
-}
diff --git a/roles/webservers/files/levi/https.party.simponic.xyz.conf b/roles/webservers/files/levi/https.party.simponic.xyz.conf
deleted file mode 100644
index b0f85d7..0000000
--- a/roles/webservers/files/levi/https.party.simponic.xyz.conf
+++ /dev/null
@@ -1,25 +0,0 @@
-server {
-  listen 4443 ssl;
-  server_name party.simponic.xyz;
-
-  ssl_certificate         /etc/letsencrypt/live/party.simponic.xyz/fullchain.pem;
-  ssl_certificate_key     /etc/letsencrypt/live/party.simponic.xyz/privkey.pem;
-  ssl_trusted_certificate /etc/letsencrypt/live/party.simponic.xyz/fullchain.pem;
-
-  ssl_session_cache shared:SSL:50m;
-  ssl_session_timeout 5m;
-  ssl_stapling on;
-  ssl_stapling_verify on;
-
-  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-  ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
-
-  ssl_dhparam /etc/nginx/dhparams.pem;
-  ssl_prefer_server_ciphers on;
-
-  root /var/www/html/party.simponic.xyz;
-
-  location / {
-    try_files $uri $uri/ $uri.html =404;
-  }
-}
diff --git a/roles/webservers/files/levi/https.rainrain.xyz.servconf b/roles/webservers/files/levi/https.rainrain.xyz.servconf
deleted file mode 100644
index 42b2535..0000000
--- a/roles/webservers/files/levi/https.rainrain.xyz.servconf
+++ /dev/null
@@ -1,20 +0,0 @@
-stream {
-  map $ssl_preread_server_name $name {
-    hostnames;
-    .rainrain.xyz  rainrainxyz; default proxy;
-  }
-
-  upstream rainrainxyz {
-    server tailscale.rain.internal.simponic.xyz:443;
-  }
-  upstream proxy {
-    server 127.0.0.1:4443;
-  }
-
-  server {
-    listen 443;
-    proxy_pass $name;
-    proxy_protocol on;
-    ssl_preread on;
-  }
-}
diff --git a/roles/webservers/files/levi/https.secure.tunnel.simponic.xyz.conf b/roles/webservers/files/levi/https.secure.tunnel.simponic.xyz.conf
deleted file mode 100644
index 707f12f..0000000
--- a/roles/webservers/files/levi/https.secure.tunnel.simponic.xyz.conf
+++ /dev/null
@@ -1,39 +0,0 @@
-server {
-  listen 4443 ssl;
-  server_name secure.tunnel.simponic.xyz;
-
-  ssl_certificate         /etc/letsencrypt/live/secure.tunnel.simponic.xyz/fullchain.pem;
-  ssl_certificate_key     /etc/letsencrypt/live/secure.tunnel.simponic.xyz/privkey.pem;
-  ssl_trusted_certificate /etc/letsencrypt/live/secure.tunnel.simponic.xyz/fullchain.pem;
-
-  ssl_session_cache shared:SSL:50m;
-  ssl_session_timeout 5m;
-  ssl_stapling on;
-  ssl_stapling_verify on;
-
-  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-  ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
-
-  ssl_dhparam /etc/nginx/dhparams.pem;
-  ssl_prefer_server_ciphers on;
-
-  location / {
-    proxy_pass https://127.0.0.1:42443;
-
-    client_body_buffer_size 128k;
-
-    proxy_set_header Host $host;
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto $scheme;
-    proxy_set_header X-Forwarded-Host $http_host;
-    proxy_set_header X-Forwarded-Uri $request_uri;
-    proxy_set_header X-Forwarded-Ssl on;
-    proxy_redirect  http://  $scheme://;
-    proxy_http_version 1.1;
-    proxy_set_header Connection "";
-    proxy_cache_bypass $cookie_session;
-    proxy_no_cache $cookie_session;
-    proxy_buffers 64 256k;
-  }
-}
diff --git a/roles/webservers/files/levi/https.simponic.hatecomputers.club.conf b/roles/webservers/files/levi/https.simponic.hatecomputers.club.conf
deleted file mode 100644
index 16f31ed..0000000
--- a/roles/webservers/files/levi/https.simponic.hatecomputers.club.conf
+++ /dev/null
@@ -1,25 +0,0 @@
-server {
-  listen 4443 ssl;
-  server_name simponic.hatecomputers.club;
-
-  ssl_certificate         /etc/letsencrypt/live/simponic.hatecomputers.club/fullchain.pem;
-  ssl_certificate_key     /etc/letsencrypt/live/simponic.hatecomputers.club/privkey.pem;
-  ssl_trusted_certificate /etc/letsencrypt/live/simponic.hatecomputers.club/fullchain.pem;
-
-  ssl_session_cache shared:SSL:50m;
-  ssl_session_timeout 5m;
-  ssl_stapling on;
-  ssl_stapling_verify on;
-
-  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-  ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
-
-  ssl_dhparam /etc/nginx/dhparams.pem;
-  ssl_prefer_server_ciphers on;
-
-  root /var/www/html/simponic.xyz;
-
-  location / {
-    try_files $uri $uri/ $uri.html =404;
-  }
-}
diff --git a/roles/webservers/files/levi/https.simponic.xyz.conf b/roles/webservers/files/levi/https.simponic.xyz.conf
deleted file mode 100644
index e9b32e7..0000000
--- a/roles/webservers/files/levi/https.simponic.xyz.conf
+++ /dev/null
@@ -1,25 +0,0 @@
-server {
-  listen 4443 ssl;
-  server_name simponic.xyz;
-
-  ssl_certificate         /etc/letsencrypt/live/simponic.xyz/fullchain.pem;
-  ssl_certificate_key     /etc/letsencrypt/live/simponic.xyz/privkey.pem;
-  ssl_trusted_certificate /etc/letsencrypt/live/simponic.xyz/fullchain.pem;
-
-  ssl_session_cache shared:SSL:50m;
-  ssl_session_timeout 5m;
-  ssl_stapling on;
-  ssl_stapling_verify on;
-
-  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-  ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
-
-  ssl_dhparam /etc/nginx/dhparams.pem;
-  ssl_prefer_server_ciphers on;
-
-  root /var/www/html/simponic.xyz;
-
-  location / {
-    try_files $uri $uri/ $uri.html =404;
-  }
-}
diff --git a/roles/webservers/files/levi/https.static.simponic.xyz.conf b/roles/webservers/files/levi/https.static.simponic.xyz.conf
deleted file mode 100644
index 01719c0..0000000
--- a/roles/webservers/files/levi/https.static.simponic.xyz.conf
+++ /dev/null
@@ -1,25 +0,0 @@
-server {
-  listen 4443 ssl;
-  server_name static.simponic.xyz;
-
-  ssl_certificate         /etc/letsencrypt/live/static.simponic.xyz/fullchain.pem;
-  ssl_certificate_key     /etc/letsencrypt/live/static.simponic.xyz/privkey.pem;
-  ssl_trusted_certificate /etc/letsencrypt/live/static.simponic.xyz/fullchain.pem;
-
-  ssl_session_cache shared:SSL:50m;
-  ssl_session_timeout 5m;
-  ssl_stapling on;
-  ssl_stapling_verify on;
-
-  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-  ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
-
-  ssl_dhparam /etc/nginx/dhparams.pem;
-  ssl_prefer_server_ciphers on;
-
-  root /var/www/html/simponic.xyz;
-
-  location / {
-    try_files $uri $uri/ $uri.html =404;
-  }
-}
diff --git a/roles/webservers/files/levi/https.tunnel.simponic.xyz.conf b/roles/webservers/files/levi/https.tunnel.simponic.xyz.conf
deleted file mode 100644
index deee0b7..0000000
--- a/roles/webservers/files/levi/https.tunnel.simponic.xyz.conf
+++ /dev/null
@@ -1,39 +0,0 @@
-server {
-  listen 4443 ssl;
-  server_name tunnel.simponic.xyz;
-
-  ssl_certificate         /etc/letsencrypt/live/tunnel.simponic.xyz/fullchain.pem;
-  ssl_certificate_key     /etc/letsencrypt/live/tunnel.simponic.xyz/privkey.pem;
-  ssl_trusted_certificate /etc/letsencrypt/live/tunnel.simponic.xyz/fullchain.pem;
-
-  ssl_session_cache shared:SSL:50m;
-  ssl_session_timeout 5m;
-  ssl_stapling on;
-  ssl_stapling_verify on;
-
-  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-  ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
-
-  ssl_dhparam /etc/nginx/dhparams.pem;
-  ssl_prefer_server_ciphers on;
-
-  location / {
-    proxy_pass http://127.0.0.1:42069;
-
-    client_body_buffer_size 128k;
-
-    proxy_set_header Host $host;
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto $scheme;
-    proxy_set_header X-Forwarded-Host $http_host;
-    proxy_set_header X-Forwarded-Uri $request_uri;
-    proxy_set_header X-Forwarded-Ssl on;
-    proxy_redirect  http://  $scheme://;
-    proxy_http_version 1.1;
-    proxy_set_header Connection "";
-    proxy_cache_bypass $cookie_session;
-    proxy_no_cache $cookie_session;
-    proxy_buffers 64 256k;
-  }
-}
diff --git a/roles/webservers/files/nginx.conf b/roles/webservers/files/nginx.conf
deleted file mode 100644
index e4f4987..0000000
--- a/roles/webservers/files/nginx.conf
+++ /dev/null
@@ -1,30 +0,0 @@
-user www-data;
-worker_processes 4;
-pid /run/nginx.pid;
-# load_module modules/ndk_http_module.so;
-# load_module modules/ngx_http_set_misc_module.so;
-
-events {
-  worker_connections 768;
-}
-
-http {
-  charset utf-8;
-  sendfile on;
-  tcp_nopush on;
-  tcp_nodelay on;
-  keepalive_timeout 65;
-  types_hash_max_size 2048;
-  include /etc/nginx/mime.types;
-  default_type application/octet-stream;
-
-  access_log /var/log/nginx/access.log;
-  error_log /var/log/nginx/error.log;
-
-  gzip on;
-  gzip_disable "msie6";
-
-  include /etc/nginx/conf.d/*.conf;
-  include /etc/nginx/sites-enabled/*.conf;
-}
-include /etc/nginx/sites-enabled/*.servconf;
diff --git a/roles/webservers/files/nijika/http.authelia.simponic.xyz.conf b/roles/webservers/files/nijika/http.authelia.simponic.xyz.conf
deleted file mode 100644
index e57fbc6..0000000
--- a/roles/webservers/files/nijika/http.authelia.simponic.xyz.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-server {
-  listen 80;
-  server_name authelia.simponic.xyz;
-
-  location /.well-known/acme-challenge {
-    root /var/www/letsencrypt;
-    try_files $uri $uri/ =404;
-  }
-
-  location / {
-    rewrite ^ https://authelia.simponic.xyz$request_uri? permanent;
-  }
-}
diff --git a/roles/webservers/files/nijika/http.git.simponic.xyz.conf b/roles/webservers/files/nijika/http.git.simponic.xyz.conf
deleted file mode 100644
index 2a962a1..0000000
--- a/roles/webservers/files/nijika/http.git.simponic.xyz.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-server {
-  listen 80;
-  server_name git.simponic.xyz;
-
-  location /.well-known/acme-challenge {
-    root /var/www/letsencrypt;
-    try_files $uri $uri/ =404;
-  }
-
-  location / {
-    rewrite ^ https://git.simponic.xyz$request_uri? permanent;
-  }
-}
diff --git a/roles/webservers/files/nijika/http.headscale.simponic.xyz.conf b/roles/webservers/files/nijika/http.headscale.simponic.xyz.conf
deleted file mode 100644
index 32b80b0..0000000
--- a/roles/webservers/files/nijika/http.headscale.simponic.xyz.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-server {
-  listen 80;
-  server_name headscale.simponic.xyz;
-
-  location /.well-known/acme-challenge {
-    root /var/www/letsencrypt;
-    try_files $uri $uri/ =404;
-  }
-
-  location / {
-    rewrite ^ https://headscale.simponic.xyz$request_uri? permanent;
-  }
-}
diff --git a/roles/webservers/files/nijika/https.authelia.simponic.xyz.conf b/roles/webservers/files/nijika/https.authelia.simponic.xyz.conf
deleted file mode 100644
index 95c3cf0..0000000
--- a/roles/webservers/files/nijika/https.authelia.simponic.xyz.conf
+++ /dev/null
@@ -1,62 +0,0 @@
-server {
-  listen 443 ssl;
-  server_name authelia.simponic.xyz;
-
-  ssl_certificate         /etc/letsencrypt/live/authelia.simponic.xyz/fullchain.pem;
-  ssl_certificate_key     /etc/letsencrypt/live/authelia.simponic.xyz/privkey.pem;
-  ssl_trusted_certificate /etc/letsencrypt/live/authelia.simponic.xyz/fullchain.pem;
-
-  ssl_session_cache shared:SSL:50m;
-  ssl_session_timeout 5m;
-  ssl_stapling on;
-  ssl_stapling_verify on;
-
-  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-  ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
-
-  ssl_dhparam /etc/nginx/dhparams.pem;
-  ssl_prefer_server_ciphers on;
-
-  location / {
-    if ($args ~* (.*)(prompt=select_account%20consent&)(.*)) {
-      set $args $1$3;
-      rewrite ^(.*)$ $1;
-    }
-
-    proxy_pass http://127.0.0.1:9091;
-
-    client_body_buffer_size 128k;
-
-    #Timeout if the real server is dead
-    proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
-
-    # Advanced Proxy Config
-    send_timeout 5m;
-    proxy_read_timeout 360;
-    proxy_send_timeout 360;
-    proxy_connect_timeout 360;
-
-    # Basic Proxy Config
-    proxy_set_header Host $host;
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto $scheme;
-    proxy_set_header X-Forwarded-Host $http_host;
-    proxy_set_header X-Forwarded-Uri $request_uri;
-    proxy_set_header X-Forwarded-Ssl on;
-    proxy_redirect  http://  $scheme://;
-    proxy_http_version 1.1;
-    proxy_set_header Connection "";
-    proxy_cache_bypass $cookie_session;
-    proxy_no_cache $cookie_session;
-    proxy_buffers 64 256k;
-
-    # If behind reverse proxy, forwards the correct IP
-    set_real_ip_from 10.0.0.0/8;
-    set_real_ip_from 172.0.0.0/8;
-    set_real_ip_from 192.168.0.0/16;
-    set_real_ip_from fc00::/7;
-    real_ip_header X-Forwarded-For;
-    real_ip_recursive on;
-  }
-}
diff --git a/roles/webservers/files/nijika/https.git.simponic.xyz.conf b/roles/webservers/files/nijika/https.git.simponic.xyz.conf
deleted file mode 100644
index df92763..0000000
--- a/roles/webservers/files/nijika/https.git.simponic.xyz.conf
+++ /dev/null
@@ -1,41 +0,0 @@
-server {
-  listen 443 ssl;
-  server_name git.simponic.xyz;
-
-  ssl_certificate         /etc/letsencrypt/live/git.simponic.xyz/fullchain.pem;
-  ssl_certificate_key     /etc/letsencrypt/live/git.simponic.xyz/privkey.pem;
-  ssl_trusted_certificate /etc/letsencrypt/live/git.simponic.xyz/fullchain.pem;
-
-  ssl_session_cache shared:SSL:50m;
-  ssl_session_timeout 5m;
-  ssl_stapling on;
-  ssl_stapling_verify on;
-
-  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-  ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
-
-  ssl_dhparam /etc/nginx/dhparams.pem;
-  ssl_prefer_server_ciphers on;
-
-  
-  location / {
-    proxy_pass http://127.0.0.1:9966;
-
-    client_max_body_size 500M;
-    client_body_buffer_size 128k;
-
-    proxy_set_header Host $host;
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto $scheme;
-    proxy_set_header X-Forwarded-Host $http_host;
-    proxy_set_header X-Forwarded-Uri $request_uri;
-    proxy_set_header X-Forwarded-Ssl on;
-    proxy_redirect  http://  $scheme://;
-    proxy_http_version 1.1;
-    proxy_set_header Connection "";
-    proxy_cache_bypass $cookie_session;
-    proxy_no_cache $cookie_session;
-    proxy_buffers 64 256k;
-  }
-}
diff --git a/roles/webservers/files/nijika/https.headscale.simponic.xyz.conf b/roles/webservers/files/nijika/https.headscale.simponic.xyz.conf
deleted file mode 100644
index b078672..0000000
--- a/roles/webservers/files/nijika/https.headscale.simponic.xyz.conf
+++ /dev/null
@@ -1,46 +0,0 @@
-server {
-  listen 443 ssl;
-  server_name headscale.simponic.xyz;
-
-  ssl_certificate         /etc/letsencrypt/live/headscale.simponic.xyz/fullchain.pem;
-  ssl_certificate_key     /etc/letsencrypt/live/headscale.simponic.xyz/privkey.pem;
-  ssl_trusted_certificate /etc/letsencrypt/live/headscale.simponic.xyz/fullchain.pem;
-
-  ssl_session_cache shared:SSL:50m;
-  ssl_session_timeout 5m;
-  ssl_stapling on;
-  ssl_stapling_verify on;
-
-  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-  ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
-
-  ssl_dhparam /etc/nginx/dhparams.pem;
-  ssl_prefer_server_ciphers on;
-
-  location /web {
-    proxy_pass https://127.0.0.1:9443;
-    proxy_http_version 1.1;
-    proxy_set_header Upgrade $http_upgrade;
-    proxy_set_header Connection "upgrade";
-    proxy_set_header Host $server_name;
-    proxy_redirect http:// https://;
-    proxy_buffering off;
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
-    add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
-  }
-
-  location / {
-    proxy_pass http://127.0.0.1:27896;
-    proxy_http_version 1.1;
-    proxy_set_header Upgrade $http_upgrade;
-    proxy_set_header Connection "upgrade";
-    proxy_set_header Host $server_name;
-    proxy_buffering off;
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
-    add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
-  }
-}
diff --git a/roles/webservers/files/ryo/http.phoneof.simponic.xyz.conf b/roles/webservers/files/ryo/http.phoneof.simponic.xyz.conf
deleted file mode 100644
index c849a26..0000000
--- a/roles/webservers/files/ryo/http.phoneof.simponic.xyz.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-server {
-  listen 80;
-  server_name phoneof.simponic.xyz;
-
-  location /.well-known/acme-challenge {
-    root /var/www/letsencrypt;
-    try_files $uri $uri/ =404;
-  }
-
-  location / {
-    rewrite ^ https://phoneof.simponic.xyz$request_uri? permanent;
-  }
-}
diff --git a/roles/webservers/files/ryo/http.something.simponic.xyz.conf b/roles/webservers/files/ryo/http.something.simponic.xyz.conf
deleted file mode 100644
index d46b6f8..0000000
--- a/roles/webservers/files/ryo/http.something.simponic.xyz.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-server {
-  listen 80;
-  server_name something.simponic.xyz;
-
-  location /.well-known/acme-challenge {
-    root /var/www/letsencrypt;
-    try_files $uri $uri/ =404;
-  }
-
-  location / {
-    rewrite ^ https://something.simponic.xyz$request_uri? permanent;
-  }
-}
diff --git a/roles/webservers/files/ryo/http.whois.simponic.xyz.conf b/roles/webservers/files/ryo/http.whois.simponic.xyz.conf
deleted file mode 100644
index 7dfc7c8..0000000
--- a/roles/webservers/files/ryo/http.whois.simponic.xyz.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-server {
-  listen 80;
-  server_name whois.simponic.xyz;
-
-  location /.well-known/acme-challenge {
-    root /var/www/letsencrypt;
-    try_files $uri $uri/ =404;
-  }
-
-  location / {
-    rewrite ^ https://whois.simponic.xyz$request_uri? permanent;
-  }
-}
diff --git a/roles/webservers/files/ryo/https.phoneof.simponic.xyz.conf b/roles/webservers/files/ryo/https.phoneof.simponic.xyz.conf
deleted file mode 100644
index 61f9647..0000000
--- a/roles/webservers/files/ryo/https.phoneof.simponic.xyz.conf
+++ /dev/null
@@ -1,32 +0,0 @@
-server {
-  listen 443 ssl;
-  server_name phoneof.simponic.xyz;
-
-  ssl_certificate         /etc/letsencrypt/live/phoneof.simponic.xyz/fullchain.pem;
-  ssl_certificate_key     /etc/letsencrypt/live/phoneof.simponic.xyz/privkey.pem;
-  ssl_trusted_certificate /etc/letsencrypt/live/phoneof.simponic.xyz/fullchain.pem;
-
-  ssl_session_cache shared:SSL:50m;
-  ssl_session_timeout 5m;
-  ssl_stapling on;
-  ssl_stapling_verify on;
-
-  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-  ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
-
-  ssl_dhparam /etc/nginx/dhparams.pem;
-  ssl_prefer_server_ciphers on;
-
-  location / {
-    proxy_pass http://127.0.0.1:19191;
-    proxy_http_version 1.1;
-    proxy_set_header Upgrade $http_upgrade;
-    proxy_set_header Connection "upgrade";
-    proxy_set_header Host $server_name;
-    proxy_buffering off;
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
-    add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
-  }
-}
diff --git a/roles/webservers/files/ryo/https.something.simponic.xyz.conf b/roles/webservers/files/ryo/https.something.simponic.xyz.conf
deleted file mode 100644
index 197f470..0000000
--- a/roles/webservers/files/ryo/https.something.simponic.xyz.conf
+++ /dev/null
@@ -1,32 +0,0 @@
-server {
-  listen 443 ssl;
-  server_name something.simponic.xyz;
-
-  ssl_certificate         /etc/letsencrypt/live/something.simponic.xyz/fullchain.pem;
-  ssl_certificate_key     /etc/letsencrypt/live/something.simponic.xyz/privkey.pem;
-  ssl_trusted_certificate /etc/letsencrypt/live/something.simponic.xyz/fullchain.pem;
-
-  ssl_session_cache shared:SSL:50m;
-  ssl_session_timeout 5m;
-  ssl_stapling on;
-  ssl_stapling_verify on;
-
-  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-  ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
-
-  ssl_dhparam /etc/nginx/dhparams.pem;
-  ssl_prefer_server_ciphers on;
-
-  location / {
-    proxy_pass http://127.0.0.1:6363;
-    proxy_http_version 1.1;
-    proxy_set_header Upgrade $http_upgrade;
-    proxy_set_header Connection "upgrade";
-    proxy_set_header Host $server_name;
-    proxy_buffering off;
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
-    add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
-  }
-}
diff --git a/roles/webservers/files/ryo/https.whois.simponic.xyz.conf b/roles/webservers/files/ryo/https.whois.simponic.xyz.conf
deleted file mode 100644
index dfcea26..0000000
--- a/roles/webservers/files/ryo/https.whois.simponic.xyz.conf
+++ /dev/null
@@ -1,45 +0,0 @@
-server {
-  listen 443 ssl;
-  server_name whois.simponic.xyz;
-
-  ssl_certificate         /etc/letsencrypt/live/whois.simponic.xyz/fullchain.pem;
-  ssl_certificate_key     /etc/letsencrypt/live/whois.simponic.xyz/privkey.pem;
-  ssl_trusted_certificate /etc/letsencrypt/live/whois.simponic.xyz/fullchain.pem;
-
-  ssl_session_cache shared:SSL:50m;
-  ssl_session_timeout 5m;
-  ssl_stapling on;
-  ssl_stapling_verify on;
-
-  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-  ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
-
-  ssl_dhparam /etc/nginx/dhparams.pem;
-  ssl_prefer_server_ciphers on;
-
-  location / {
-    proxy_pass http://127.0.0.1:8466;
-    proxy_http_version 1.1;
-    proxy_set_header Upgrade $http_upgrade;
-    proxy_set_header Connection "upgrade";
-    proxy_set_header Host $server_name;
-    proxy_buffering off;
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
-    add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
-  }
-
-  location /api/ {
-    proxy_pass http://127.0.0.1:8467/;
-    proxy_http_version 1.1;
-    proxy_set_header Upgrade $http_upgrade;
-    proxy_set_header Connection "upgrade";
-    proxy_set_header Host $server_name;
-    proxy_buffering off;
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
-    add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
-  }
-}
diff --git a/roles/webservers/tasks/main.yml b/roles/webservers/tasks/main.yml
deleted file mode 100644
index 5355a3e..0000000
--- a/roles/webservers/tasks/main.yml
+++ /dev/null
@@ -1,120 +0,0 @@
----
-- name: allow http
-  ufw:
-    rule: allow
-    port: '80'
-    proto: tcp
-
-- name: allow https
-  ufw:
-    rule: allow
-    port: '443'
-    proto: tcp
-
-- name: restart ufw
-  service: name=ufw state=restarted enabled=yes
-
-- name: install nginx
-  apt: name=nginx state=latest
-
-- name: install letsencrypt
-  apt: name=letsencrypt state=latest
-
-- name: create letsencrypt directory
-  file: name=/var/www/letsencrypt state=directory
-
-- name: remove default nginx
-  file: name=/etc/nginx/sites-enabled/default state=absent
-
-- name: generate dhparams
-  shell: openssl dhparam -out /etc/nginx/dhparams.pem 2048
-  args:
-    creates: /etc/nginx/dhparams.pem
-
-- name: add system nginx config
-  template:
-    src: ../files/nginx.conf
-    dest: /etc/nginx/nginx.conf
-
-- name: copy http nginx configuration for each domain
-  copy:
-    src: "{{ item }}"
-    dest: "/etc/nginx/sites-enabled/"
-  with_fileglob:
-    - "files/{{ inventory_hostname }}/http.*.conf"
-
-- name: restart nginx to get letsencrypt certificate
-  service: name=nginx state=restarted enabled=yes
-
-- name: find deployed domains
-  ansible.builtin.find:
-    paths: "/etc/nginx/sites-enabled/"
-    patterns: "http.*.conf"
-  register: nginx_conf_files
-  delegate_to: "{{ inventory_hostname }}"
-
-- name: extract domains from deployed nginx configurations
-  shell: |
-    grep -oP 'server_name\s+\K[^;]+' "{{ item.path }}"
-  loop: "{{ nginx_conf_files.files }}"
-  register: extracted_domains
-
-# simponic.xyz & others
-- name: request simponic letsencrypt certificates
-  shell: >
-    letsencrypt certonly -n --webroot -w /var/www/letsencrypt -m {{ letsencrypt_email }} \
-      --agree-tos -d {{ item.stdout }}
-  args:
-    creates: "/etc/letsencrypt/live/{{ item.stdout }}"
-  loop: "{{ extracted_domains.results }}"
-  when: 'not "hatecomputers.club" in item.stdout and not "rainrain" in item.stdout'
-
-# hatecomputers.club
-- name: build plugin template
-  template:
-    src: ../templates/plugin.sh.j2
-    dest: /etc/letsencrypt/hcdns.sh
-    mode: 0744
-    owner: root
-    group: root
-
-- name: clone hcdns auth repo
-  ansible.builtin.git:
-    repo: https://git.hatecomputers.club/simponic/hc-cert-dns
-    dest: /root/hc-cert-dns
-
-- name: request hatecomputers letsencrypt certificate
-  shell: >
-    letsencrypt certonly -n \
-      --manual --manual-auth-hook /etc/letsencrypt/hcdns.sh \
-      --preferred-challenges dns \
-      -d {{ item.stdout }} \
-      --email {{ letsencrypt_email }} \
-      --agree-tos \
-      --no-eff-email
-  args:
-    creates: "/etc/letsencrypt/live/{{ item.stdout }}"
-  loop: "{{ extracted_domains.results }}"
-  when: '"hatecomputers.club" in item.stdout'
-
-- name: copy https nginx configuration for each domain
-  copy:
-    src: "{{ item }}"
-    dest: "/etc/nginx/sites-enabled/"
-  with_fileglob:
-    - "files/{{ inventory_hostname }}/https.*.conf"
-    - "files/{{ inventory_hostname }}/https.*.servconf"
-
-- name: reload nginx to activate sites
-  service: name=nginx state=restarted
-
-- name: add monthly letsencrypt cronjob for cert renewal based on hash of domain name to prevent hitting LE rate limits
-  cron:
-    name: "letsencrypt_renewal_{{ item.stdout }}"
-    day: "{{ '%02d' | format(1 + (item.stdout | hash('md5') | int(0, 16) % 27)) }}"
-    hour: "{{ (item.stdout | hash('md5') | int(0, 16) % 24 ) }}"
-    minute: "{{ (item.stdout | hash('md5') | int(0, 16) % 60 ) }}"
-    job: "letsencrypt renew --cert-name {{ item.stdout }} -n --webroot -w /var/www/letsencrypt -m {{ letsencrypt_email }} --agree-tos ; service nginx restart"
-  loop: "{{ extracted_domains.results }}"
-  when: item.stdout != ""
-
diff --git a/roles/webservers/templates/plugin.sh.j2 b/roles/webservers/templates/plugin.sh.j2
deleted file mode 100644
index 796f078..0000000
--- a/roles/webservers/templates/plugin.sh.j2
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/bash
-
-unset REQUESTS_CA_BUNDLE
-
-API_KEY_FILE=$(mktemp)
-echo "{{ hatecomputers_api_key }}" >> $API_KEY_FILE
-
-ENDPOINT=https://hatecomputers.club
-PUBLIC_SUFFIXES=.hatecomputers.club
-
-/root/hc-cert-dns/main.py --certbot \
-          --public-suffixes=$PUBLIC_SUFFIXES \
-          --certbot-domain=$CERTBOT_DOMAIN \
-          --certbot-validation=$CERTBOT_VALIDATION \
-          --endpoint=$ENDPOINT \
-          --api-key-file=$API_KEY_FILE
-
-rm $API_KEY_FILE
diff --git a/roles/whois/tasks/main.yml b/roles/whois/tasks/main.yml
deleted file mode 100644
index 7b5923e..0000000
--- a/roles/whois/tasks/main.yml
+++ /dev/null
@@ -1,30 +0,0 @@
----
-- name: ensure whois docker/compose exist
-  file:
-    path: /etc/docker/compose/whois
-    state: directory
-    owner: root
-    group: root
-    mode: 0700
-
-- name: ensure whois db exist
-  file:
-    path: /etc/docker/compose/whois/db
-    state: directory
-    owner: root
-    group: root
-    mode: 0777
-
-- name: build whois docker-compose.yml.j2
-  template:
-    src: ../templates/docker-compose.yml.j2
-    dest: /etc/docker/compose/whois/docker-compose.yml
-    owner: root
-    group: root
-    mode: u=rw,g=r,o=r
-
-- name: daemon-reload and enable whois
-  ansible.builtin.systemd_service:
-    state: restarted
-    enabled: true
-    name: docker-compose@whois
diff --git a/roles/whois/templates/docker-compose.yml.j2 b/roles/whois/templates/docker-compose.yml.j2
deleted file mode 100644
index 7a15155..0000000
--- a/roles/whois/templates/docker-compose.yml.j2
+++ /dev/null
@@ -1,26 +0,0 @@
-version: "3"
-
-services:
-  api:
-    restart: always
-    image: git.simponic.xyz/simponic/whois
-    healthcheck:
-      test: ["CMD", "wget", "--spider", "http://localhost:8080/health"]
-      interval: 5s
-      timeout: 10s
-      retries: 5
-    env_file: .env
-    volumes:
-      - ./db:/app/db
-    ports:
-      - "127.0.0.1:8467:8080"
-  frontend:
-    restart: always
-    image: git.simponic.xyz/simponic/penguin-new-tab
-    healthcheck:
-      test: ["CMD", "wget", "--spider", "http://localhost:3000"]
-      interval: 5s
-      timeout: 10s
-      retries: 5
-    ports:
-      - "127.0.0.1:8466:3000"
diff --git a/roles/zigbee/files/configuration.yaml b/roles/zigbee/files/configuration.yaml
deleted file mode 100644
index 497d633..0000000
--- a/roles/zigbee/files/configuration.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-version: 4
-mqtt:
-    base_topic: zigbee2mqtt
-    server: mqtt://mqtt
-serial:
-    port: /dev/ttyUSB0
-    adapter: zstack
-advanced:
-    channel: 11
-    network_key: GENERATE
-    pan_id: GENERATE
-    ext_pan_id: GENERATE
-frontend:
-    enabled: true
-homeassistant:
-    enabled: true
diff --git a/roles/zigbee/tasks/main.yml b/roles/zigbee/tasks/main.yml
deleted file mode 100644
index 0c2e3cb..0000000
--- a/roles/zigbee/tasks/main.yml
+++ /dev/null
@@ -1,46 +0,0 @@
----
-- name: ensure zigbee docker/compose exist
-  file:
-    path: /etc/docker/compose/zigbee
-    state: directory
-    owner: root
-    group: root
-    mode: 0700
-
-- name: create zigbee docker/compose/data/zigbee with set uid/gid
-  file:
-    path: /etc/docker/compose/zigbee/data
-    state: directory
-    owner: 1000
-    group: 1000
-    mode: 0700
-
-- name: create zigbee docker/compose/zigbee/-data with set uid/gid
-  file:
-    path: /etc/docker/compose/zigbee/zigbee2mqtt-data
-    state: directory
-    owner: 1000
-    group: 1000
-    mode: 0700
-
-- name: copy zigbee config.yml
-  copy:
-    src: ../files/configuration.yaml
-    dest: /etc/docker/compose/zigbee/zigbee2mqtt-data/configuration.yaml
-    owner: root
-    group: root
-    mode: u=rw,g=r,o=r
-
-- name: build zigbee docker-compose.yml.j2
-  template:
-    src: ../templates/docker-compose.yml.j2
-    dest: /etc/docker/compose/zigbee/docker-compose.yml
-    owner: root
-    group: root
-    mode: u=rw,g=r,o=r
-
-- name: daemon-reload and enable zigbee
-  ansible.builtin.systemd_service:
-    state: restarted
-    enabled: true
-    name: docker-compose@zigbee
diff --git a/roles/zigbee/templates/docker-compose.yml.j2 b/roles/zigbee/templates/docker-compose.yml.j2
deleted file mode 100644
index ea166d9..0000000
--- a/roles/zigbee/templates/docker-compose.yml.j2
+++ /dev/null
@@ -1,25 +0,0 @@
-version: '3.8'
-services:
-    mqtt:
-        image: eclipse-mosquitto:2.0
-        restart: unless-stopped
-        volumes:
-            - './data:/mosquitto'
-        ports:
-            - '1883:1883'
-            - '9001:9001'
-        command: 'mosquitto -c /mosquitto-no-auth.conf'
-
-    zigbee2mqtt:
-        container_name: zigbee2mqtt
-        restart: unless-stopped
-        image: koenkk/zigbee2mqtt
-        volumes:
-            - ./zigbee2mqtt-data:/app/data
-            - /run/udev:/run/udev:ro
-        ports:
-            - 8080:8080
-        environment:
-            - TZ=America/Los_Angeles
-        devices:
-            - /dev/ttyUSB0:/dev/ttyUSB0
diff --git a/secrets.enc b/secrets.enc
new file mode 100644
index 0000000..1073930
--- /dev/null
+++ b/secrets.enc
@@ -0,0 +1,10 @@
+$ANSIBLE_VAULT;1.1;AES256
+62656662386638326363613330333163613334323466323262656564363064616162303135656265
+6130333638333138653462653765666661623531353564350a346263636563363538366666363636
+32376262343434323633623137373638663266646336643136653564386635643338343239323466
+6135333937666161330a663532333832353535663131343234613336663139666436316630343232
+33613338393636653638303866343066636566653236396166616638366463393933633963656130
+61613262383539373735396437623935663433386661666139376330343065636363353635363662
+32343530366262663863346236646664613236643432633130663236386231316464386239663033
+31623336373165396465666536646135373562613364356236323261613437656134326632306134
+3132
diff --git a/secrets.pwd b/secrets.pwd
new file mode 100644
index 0000000..8e354dc
--- /dev/null
+++ b/secrets.pwd
@@ -0,0 +1 @@
+lKLDS8eet229nvvBppGqzS
diff --git a/secrets.txt b/secrets.txt
new file mode 100644
index 0000000..5c28bc0
--- /dev/null
+++ b/secrets.txt
@@ -0,0 +1,2 @@
+swarm_become_password
+outbound_one_become_password
diff --git a/template/.DS_Store b/template/.DS_Store
deleted file mode 100644
index c2ba3f0..0000000
Binary files a/template/.DS_Store and /dev/null differ
diff --git a/template/.dockerignore b/template/.dockerignore
deleted file mode 100644
index 7dddab3..0000000
--- a/template/.dockerignore
+++ /dev/null
@@ -1,5 +0,0 @@
-.env
-{{ service }}
-Dockerfile
-*.db
-.drone.yml
diff --git a/template/.drone.yml b/template/.drone.yml
deleted file mode 100644
index 92378f4..0000000
--- a/template/.drone.yml
+++ /dev/null
@@ -1,49 +0,0 @@
----
-kind: pipeline
-type: docker
-name: build
-
-steps:
-  - name: run tests
-    image: golang
-    commands:
-      - go get
-      - go test -p 1 -v ./...
-
-trigger:
-  event:
-    - pull_request
-
-
----
-kind: pipeline
-type: docker
-name: cicd
-
-steps:
-  - name: ci
-    image: plugins/docker
-    settings:
-      username:
-        from_secret: gitea_packpub_username
-      password:
-        from_secret: gitea_packpub_password
-      registry: git.simponic.xyz
-      repo: {{ service_repo }}
-  - name: ssh
-    image: appleboy/drone-ssh
-    settings:
-      host: {{ service_host }}.simponic.xyz
-      username: root
-      key:
-        from_secret: cd_ssh_key 
-      port: 22
-      command_timeout: 2m
-      script:
-        - systemctl restart docker-compose@{{ service }}
-
-trigger:
-  branch:
-    - main
-  event:
-    - push
diff --git a/template/.gitignore b/template/.gitignore
deleted file mode 100644
index 059b6c1..0000000
--- a/template/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-*.env
-{{ service }}
-*.db
diff --git a/template/.tool-versions b/template/.tool-versions
deleted file mode 100644
index db5d8ee..0000000
--- a/template/.tool-versions
+++ /dev/null
@@ -1 +0,0 @@
-golang 1.23.4
diff --git a/template/Dockerfile b/template/Dockerfile
deleted file mode 100644
index ff39f7c..0000000
--- a/template/Dockerfile
+++ /dev/null
@@ -1,13 +0,0 @@
-FROM golang:1.23
-WORKDIR /app
-
-COPY go.mod go.sum ./
-RUN go mod download
-
-COPY . .
-
-RUN go build -o /app/{{ service }}
-
-EXPOSE 8080
-
-CMD ["/app/{{ service }}", "--server", "--migrate", "--port", "8080", "--template-path", "/app/templates", "--database-path", "/app/db/{{ service }}.db", "--static-path", "/app/static", "--scheduler", "--ntfy-topics", "whois", "--ntfy-endpoint", "https://ntfy.simponic.hatecomputers.club"]
diff --git a/template/README.md b/template/README.md
deleted file mode 100644
index c7477e4..0000000
--- a/template/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## {{ service_title }}
-
-this is a simponic service for {{ service }}
diff --git a/template/api/api.go b/template/api/api.go
deleted file mode 100644
index 4d278da..0000000
--- a/template/api/api.go
+++ /dev/null
@@ -1,91 +0,0 @@
-package api
-
-import (
-	"database/sql"
-	"fmt"
-	"log"
-	"net/http"
-	"time"
-
-	"{{ service_repo }}/api/template"
-	"{{ service_repo }}/api/types"
-	"{{ service_repo }}/args"
-	"{{ service_repo }}/utils"
-)
-
-func LogRequestContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain {
-	return func(success types.Continuation, _failure types.Continuation) types.ContinuationChain {
-		context.Start = time.Now()
-		context.Id = utils.RandomId()
-
-		log.Println(req.Method, req.URL.Path, req.RemoteAddr, context.Id)
-		return success(context, req, resp)
-	}
-}
-
-func LogExecutionTimeContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain {
-	return func(success types.Continuation, _failure types.Continuation) types.ContinuationChain {
-		end := time.Now()
-		log.Println(context.Id, "took", end.Sub(context.Start))
-
-		return success(context, req, resp)
-	}
-}
-
-func HealthCheckContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain {
-	return func(success types.Continuation, _failure types.Continuation) types.ContinuationChain {
-		resp.WriteHeader(200)
-		resp.Write([]byte("healthy"))
-		return success(context, req, resp)
-	}
-}
-
-func FailurePassingContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain {
-	return func(_success types.Continuation, failure types.Continuation) types.ContinuationChain {
-		return failure(context, req, resp)
-	}
-}
-
-func IdContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain {
-	return func(success types.Continuation, _failure types.Continuation) types.ContinuationChain {
-		return success(context, req, resp)
-	}
-}
-
-func CacheControlMiddleware(next http.Handler, maxAge int) http.Handler {
-	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		header := fmt.Sprintf("public, max-age=%d", maxAge)
-		w.Header().Set("Cache-Control", header)
-		next.ServeHTTP(w, r)
-	})
-}
-
-func MakeMux(argv *args.Arguments, dbConn *sql.DB) *http.ServeMux {
-	mux := http.NewServeMux()
-
-	staticFileServer := http.FileServer(http.Dir(argv.StaticPath))
-	mux.Handle("GET /static/", http.StripPrefix("/static/", CacheControlMiddleware(staticFileServer, 3600)))
-
-	makeRequestContext := func() *types.RequestContext {
-		return &types.RequestContext{
-			DBConn:       dbConn,
-			Args:         argv,
-			TemplateData: &map[string]interface{}{},
-		}
-	}
-
-	mux.HandleFunc("GET /health", func(w http.ResponseWriter, r *http.Request) {
-		requestContext := makeRequestContext()
-		LogRequestContinuation(requestContext, r, w)(HealthCheckContinuation, FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation)
-	})
-
-	mux.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) {
-		requestContext := makeRequestContext()
-
-    (*requestContext.TemplateData)["Service"] = "{{ service }}"
-    templateFile := "hello.html"
-    LogRequestContinuation(requestContext, r, w)(template.TemplateContinuation(templateFile, true), FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation)
-	})
-
-  return mux
-}
diff --git a/template/api/api_test.go b/template/api/api_test.go
deleted file mode 100644
index 9ad8f92..0000000
--- a/template/api/api_test.go
+++ /dev/null
@@ -1,89 +0,0 @@
-package api_test
-
-import (
-	"database/sql"
-  "io"
-	"net/http/httptest"
-	"os"
-	"strings"
-	"testing"
-
-	"{{ service_repo }}/api"
-	"{{ service_repo }}/args"
-	"{{ service_repo }}/database"
-	"{{ service_repo }}/utils"
-)
-
-func setup(t *testing.T) (*sql.DB, *httptest.Server) {
-	randomDb := utils.RandomId()
-
-	testDb := database.MakeConn(&randomDb)
-	database.Migrate(testDb)
-
-  arguments := &args.Arguments{
-    TemplatePath: "../templates",
-    StaticPath: "../static",
-  }
-
-  mux := api.MakeMux(arguments, testDb)
-  testServer := httptest.NewServer(mux)
-
-  t.Cleanup(func() {
-		testServer.Close()
-		testDb.Close()
-		os.Remove(randomDb)
-  })
-	return testDb, testServer
-}
-
-func assertResponseCode(t *testing.T, resp *httptest.ResponseRecorder, statusCode int) {
-  if resp.Code != statusCode {
-    t.Errorf("code is unexpected: %d, expected %d", resp.Code, statusCode)
-  }
-}
-
-func assertResponseBody(t *testing.T, resp *httptest.ResponseRecorder, body string) {
-  buf := new(strings.Builder)
-  _, err := io.Copy(buf, resp.Body)
-  if err != nil {
-    panic("could not read response body")
-  }
-  bodyStr := buf.String()
-  if bodyStr != body {
-    t.Errorf("body is unexpected: %s, expected %s", bodyStr, body)
-  }
-}
-
-func TestHealthcheck(t *testing.T) {
-	_, testServer := setup(t)
-
-  req := httptest.NewRequest("GET", "/health", nil)
-  resp := httptest.NewRecorder()
-  testServer.Config.Handler.ServeHTTP(resp, req)
-
-  assertResponseCode(t, resp, 200)
-  assertResponseBody(t, resp, "healthy")
-}
-
-func TestHello(t *testing.T) {
-	_, testServer := setup(t)
-
-  req := httptest.NewRequest("GET", "/", nil)
-  resp := httptest.NewRecorder()
-  testServer.Config.Handler.ServeHTTP(resp, req)
-
-  assertResponseCode(t, resp, 200)
-}
-
-func TestCachingStaticFiles(t *testing.T) {
-	_, testServer := setup(t)
-
-  req := httptest.NewRequest("GET", "/static/css/styles.css", nil)
-  resp := httptest.NewRecorder()
-  testServer.Config.Handler.ServeHTTP(resp, req)
-
-  assertResponseCode(t, resp, 200)
-  if resp.Header().Get("Cache-Control") != "public, max-age=3600" {
-    t.Errorf("client cache will live indefinitely for static files, which is probably not great! %s", resp.Header().Get("Cache-Control"))
-  }
-}
diff --git a/template/api/template/template.go b/template/api/template/template.go
deleted file mode 100644
index a5db3d6..0000000
--- a/template/api/template/template.go
+++ /dev/null
@@ -1,73 +0,0 @@
-package template
-
-import (
-	"bytes"
-	"errors"
-	"html/template"
-	"log"
-	"net/http"
-	"os"
-
-	"{{ service_repo }}/api/types"
-)
-
-func renderTemplate(context *types.RequestContext, templateName string, showBaseHtml bool) (bytes.Buffer, error) {
-	templatePath := context.Args.TemplatePath
-	basePath := templatePath + "/base_empty.html"
-	if showBaseHtml {
-		basePath = templatePath + "/base.html"
-	}
-
-	templateLocation := templatePath + "/" + templateName
-	tmpl, err := template.New("").ParseFiles(templateLocation, basePath)
-	if err != nil {
-		return bytes.Buffer{}, err
-	}
-
-	dataPtr := context.TemplateData
-	if dataPtr == nil {
-		dataPtr = &map[string]interface{}{}
-	}
-
-	data := *dataPtr
-
-	var buffer bytes.Buffer
-	err = tmpl.ExecuteTemplate(&buffer, "base", data)
-
-	if err != nil {
-		return bytes.Buffer{}, err
-	}
-	return buffer, nil
-}
-
-func TemplateContinuation(path string, showBase bool) types.Continuation {
-	return func(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain {
-		return func(success types.Continuation, failure types.Continuation) types.ContinuationChain {
-			html, err := renderTemplate(context, path, showBase)
-			if errors.Is(err, os.ErrNotExist) {
-				resp.WriteHeader(404)
-				html, err = renderTemplate(context, "404.html", true)
-				if err != nil {
-					log.Println("error rendering 404 template", err)
-					resp.WriteHeader(500)
-					return failure(context, req, resp)
-				}
-
-				resp.Header().Set("Content-Type", "text/html")
-				resp.Write(html.Bytes())
-				return failure(context, req, resp)
-			}
-
-			if err != nil {
-				log.Println("error rendering template", err)
-				resp.WriteHeader(500)
-				resp.Write([]byte("error rendering template"))
-				return failure(context, req, resp)
-			}
-
-			resp.Header().Set("Content-Type", "text/html")
-			resp.Write(html.Bytes())
-			return success(context, req, resp)
-		}
-	}
-}
diff --git a/template/api/types/types.go b/template/api/types/types.go
deleted file mode 100644
index d2a91a3..0000000
--- a/template/api/types/types.go
+++ /dev/null
@@ -1,26 +0,0 @@
-package types
-
-import (
-	"database/sql"
-	"net/http"
-	"time"
-
-	"{{ service_repo }}/args"
-)
-
-type RequestContext struct {
-	DBConn *sql.DB
-	Args   *args.Arguments
-
-	Id    string
-	Start time.Time
-
-	TemplateData *map[string]interface{}
-}
-
-type BannerMessages struct {
-	Messages []string
-}
-
-type Continuation func(*RequestContext, *http.Request, http.ResponseWriter) ContinuationChain
-type ContinuationChain func(Continuation, Continuation) ContinuationChain
diff --git a/template/args/args.go b/template/args/args.go
deleted file mode 100644
index dcba9f7..0000000
--- a/template/args/args.go
+++ /dev/null
@@ -1,94 +0,0 @@
-package args
-
-import (
-	"flag"
-  "fmt"
-  "os"
-  "strings"
-  "sync"
-)
-
-type Arguments struct {
-	DatabasePath string
-	TemplatePath string
-	StaticPath   string
-
-	Migrate   bool
-	Scheduler bool
-
-	NtfyEndpoint string
-  NtfyTopics   []string
-  NtfyListener bool
-
-	Port   int
-	Server bool
-}
-
-func isDirectory(path string) (bool, error) {
-	fileInfo, err := os.Stat(path)
-	if err != nil {
-		return false, err
-	}
-
-	return fileInfo.IsDir(), err
-}
-
-func validateArgs(args *Arguments) error {
-  templateIsDir, err := isDirectory(args.TemplatePath)
-  if err != nil || !templateIsDir {
-    return fmt.Errorf("template path is not an accessible directory %s", err)
-  }
-  staticPathIsDir, err := isDirectory(args.StaticPath)
-  if err != nil || !staticPathIsDir {
-    return fmt.Errorf("static path is not an accessible directory %s", err)
-  }
-  return nil
-}
-
-var lock = &sync.Mutex{}
-var args *Arguments
-
-func GetArgs() (*Arguments, error) {
-  lock.Lock()
-  defer lock.Unlock()
-
-  if args != nil {
-    return args, nil
-  }
-
-	databasePath := flag.String("database-path", "./{{ service }}.db", "Path to the SQLite database")
-
-	templatePath := flag.String("template-path", "./templates", "Path to the template directory")
-	staticPath := flag.String("static-path", "./static", "Path to the static directory")
-
-  ntfyEndpoint := flag.String("ntfy-endpoint", "https://ntfy.simponic.hatecomputers.club", "NTFY Endpoint")
-  ntfyTopics := flag.String("ntfy-topics", "testtopic", "Comma-separated NTFY Topics")
-	ntfyListener := flag.Bool("ntfy-listener", false, "Listen to NTFY Topic and propagate messages")
-
-	scheduler := flag.Bool("scheduler", false, "Run scheduled jobs via cron")
-	migrate := flag.Bool("migrate", false, "Run the migrations")
-
-	port := flag.Int("port", 8080, "Port to listen on")
-	server := flag.Bool("server", false, "Run the server")
-
-	flag.Parse()
-
-	args = &Arguments{
-		DatabasePath:     *databasePath,
-		TemplatePath:     *templatePath,
-		StaticPath:       *staticPath,
-		Port:             *port,
-		Server:           *server,
-		Migrate:          *migrate,
-		Scheduler:        *scheduler,
-    NtfyEndpoint:     *ntfyEndpoint,
-    NtfyTopics:       strings.Split(*ntfyTopics, ","),
-    NtfyListener:     *ntfyListener,
-	}
-  err := validateArgs(args)
-  if err != nil {
-    return nil, err
-  }
-
-	return args, nil
-}
diff --git a/template/database/conn.go b/template/database/conn.go
deleted file mode 100644
index be27586..0000000
--- a/template/database/conn.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package database
-
-import (
-	"database/sql"
-	_ "github.com/mattn/go-sqlite3"
-	"log"
-)
-
-func MakeConn(databasePath *string) *sql.DB {
-	log.Println("opening database at", *databasePath, "with foreign keys enabled")
-	dbConn, err := sql.Open("sqlite3", *databasePath+"?_foreign_keys=on")
-	if err != nil {
-		panic(err)
-	}
-
-	return dbConn
-}
diff --git a/template/database/migrate.go b/template/database/migrate.go
deleted file mode 100644
index 64457bc..0000000
--- a/template/database/migrate.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package database
-
-import (
-	"log"
-
-	"database/sql"
-
-	_ "github.com/mattn/go-sqlite3"
-)
-
-type Migrator func(*sql.DB) (*sql.DB, error)
-
-func DoNothing(dbConn *sql.DB) (*sql.DB, error) {
-	log.Println("doing nothing")
-
-	_, err := dbConn.Exec(`SELECT 0;`)
-	if err != nil {
-		return dbConn, err
-	}
-
-	return dbConn, nil
-}
-
-func Migrate(dbConn *sql.DB) (*sql.DB, error) {
-	log.Println("migrating database")
-
-	migrations := []Migrator{
-		DoNothing,
-	}
-
-	for _, migration := range migrations {
-		dbConn, err := migration(dbConn)
-		if err != nil {
-			return dbConn, err
-		}
-	}
-
-	return dbConn, nil
-}
diff --git a/template/docker-compose.yml b/template/docker-compose.yml
deleted file mode 100644
index 2848c09..0000000
--- a/template/docker-compose.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-version: "3"
-
-services:
-  api:
-    restart: always
-    image: {{ service_repo }}
-    healthcheck:
-      test: ["CMD", "wget", "--spider", "http://localhost:8080/health"]
-      interval: 5s
-      timeout: 10s
-      retries: 5
-    env_file: .env
-    volumes:
-      - ./db:/app/db
-    ports:
-      - "127.0.0.1:{{ service_port }}:8080"
diff --git a/template/go.mod b/template/go.mod
deleted file mode 100644
index 006e357..0000000
--- a/template/go.mod
+++ /dev/null
@@ -1,9 +0,0 @@
-module {{ service_repo }}
-
-go 1.23.4
-
-require (
-	github.com/go-co-op/gocron/v2 v2.14.0
-	github.com/joho/godotenv v1.5.1
-	github.com/mattn/go-sqlite3 v1.14.24
-)
diff --git a/template/main.go b/template/main.go
deleted file mode 100644
index 3ddb39c..0000000
--- a/template/main.go
+++ /dev/null
@@ -1,76 +0,0 @@
-package main
-
-import (
-	"fmt"
-	"log"
-	"net/http"
-
-	"{{ service_repo }}/api"
-	"{{ service_repo }}/args"
-	"{{ service_repo }}/database"
-	"{{ service_repo }}/scheduler"
-  "{{ service_repo }}/ntfy"
-	"github.com/joho/godotenv"
-)
-
-func main() {
-	log.SetFlags(log.LstdFlags | log.Lshortfile)
-
-	err := godotenv.Load()
-	if err != nil {
-		log.Println("could not load .env file:", err)
-	}
-
-	argv, err := args.GetArgs()
-	if err != nil {
-		log.Fatal(err)
-	}
-
-	dbConn := database.MakeConn(&argv.DatabasePath)
-	defer dbConn.Close()
-
-	if argv.Migrate {
-		_, err = database.Migrate(dbConn)
-		if err != nil {
-			log.Fatal(err)
-		}
-		log.Println("database migrated successfully")
-	}
-
-	if argv.NtfyListener {
-    ntfy := ntfy.MakeNtfyWatcher(argv.NtfyEndpoint, argv.NtfyTopics)
-    notifications := ntfy.Watch()
-
-    go func() {
-      for notification := range notifications {
-        message := notification.Message
-        log.Println("got message", message)
-      }
-    }()
-	}
-
-	if argv.Scheduler {
-    go func() {
-      scheduler.StartScheduler(dbConn, argv)
-    }()
-	}
-
-	if argv.Server {
-		mux := api.MakeMux(argv, dbConn)
-		log.Println("🚀🚀 {{ service }} API listening on port", argv.Port)
-		go func() {
-      server := &http.Server{
-    		Addr:    ":" + fmt.Sprint(argv.Port),
-    		Handler: mux,
-    	}
-			err = server.ListenAndServe()
-			if err != nil {
-				log.Fatal(err)
-			}
-		}()
-	}
-
-  if argv.Server || argv.Scheduler || argv.NtfyListener {
-    select {} // block forever
-  }
-}
diff --git a/template/ntfy/publisher.go b/template/ntfy/publisher.go
deleted file mode 100644
index 68f8e49..0000000
--- a/template/ntfy/publisher.go
+++ /dev/null
@@ -1,16 +0,0 @@
-package ntfy
-
-import (
-	"net/http"
-	"strings"
-)
-
-func SendMessage(message string, endpoint string, topics []string) error {
-	for _, topic := range topics {
-		_, err := http.Post(endpoint+"/"+topic, "text/plain", strings.NewReader(message))
-		if err != nil {
-			return err
-		}
-	}
-	return nil
-}
diff --git a/template/ntfy/watcher.go b/template/ntfy/watcher.go
deleted file mode 100644
index d8959cd..0000000
--- a/template/ntfy/watcher.go
+++ /dev/null
@@ -1,96 +0,0 @@
-package ntfy
-
-import (
-	"bufio"
-  "encoding/json"
-	"log"
-	"net/http"
-	"net/url"
-	"path"
-	"time"
-)
-
-type Message struct {
-  Id      string `json:"id"`
-  Time    int    `json:"time"`
-  Message string `json:"message"`
-  Event   string `json:"event"`
-}
-
-type NtfyWatcher struct {
-	Endpoint string
-	Topics   []string
-}
-
-func (w *NtfyWatcher) Watch() chan Message {
-	notifications := make(chan Message)
-
-	for _, topic := range w.Topics {
-		log.Println("subscribing to topic:", topic)
-
-		go func() {
-			retryCount := 5
-			retryTime := 5 * time.Second
-			retries := retryCount
-
-			sleepAndDecrementRetry := func() {
-				log.Println("waiting 5 seconds before reconnecting. retries left:", retries, "topic:", topic, "endpoint:", w.Endpoint)
-				time.Sleep(retryTime)
-				retries--
-			}
-
-			for true {
-				if retries == 0 {
-					log.Fatal("too many retries, exiting")
-				}
-
-				endpoint, _ := url.JoinPath(w.Endpoint, path.Join(topic, "json"))
-				resp, err := http.Get(endpoint)
-				if err != nil {
-					log.Println("error connecting to endpoint:", err)
-					sleepAndDecrementRetry()
-					continue
-				}
-
-				defer resp.Body.Close()
-				scanner := bufio.NewScanner(resp.Body)
-				for scanner.Scan() {
-					bytes := scanner.Bytes()
-          var msg Message
-          err := json.Unmarshal(bytes, &msg)
-          if err != nil {
-            log.Println("could not unmarshal message:", err)
-            continue
-          }
-
-          if msg.Event == "keepalive" {
-				  	log.Println("received keepalive message")
-				  	continue
-          }
-          if msg.Event != "message" {
-            log.Println("received unknown event:", msg.Event)
-            continue
-          }
-
-					log.Println("received notification:", msg)
-					notifications <- msg
-					retries = retryCount // reset retries
-				}
-
-				if err := scanner.Err(); err != nil {
-					log.Println("error reading response body:", err)
-					sleepAndDecrementRetry()
-				}
-			}
-		}()
-	}
-
-	return notifications
-}
-
-func MakeNtfyWatcher(endpoint string, topics []string) *NtfyWatcher {
-	return &NtfyWatcher{
-		Endpoint: endpoint,
-		Topics:   topics,
-	}
-}
diff --git a/template/scheduler/scheduler.go b/template/scheduler/scheduler.go
deleted file mode 100644
index 7b4487a..0000000
--- a/template/scheduler/scheduler.go
+++ /dev/null
@@ -1,34 +0,0 @@
-package scheduler
-
-import (
-	"database/sql"
-	"log"
-	"time"
-
-	"{{ service_repo }}/args"
-  "github.com/go-co-op/gocron/v2"
-)
-
-func StartScheduler(_dbConn *sql.DB, argv *args.Arguments) {
-	scheduler, err := gocron.NewScheduler()
-	if err != nil {
-    panic("could not create scheduler")
-	}
-
-	_, err = scheduler.NewJob(
-		gocron.DurationJob(
-			24*time.Hour,
-		),
-		gocron.NewTask(
-			func(msg string) {
-        log.Println(msg)
-			},
-			"it's a beautiful new day!",
-		),
-	)
-  if err != nil {
-    panic("could not create job")
-  }
-
-	scheduler.Start()
-}
diff --git a/template/static/.DS_Store b/template/static/.DS_Store
deleted file mode 100644
index e36d3e1..0000000
Binary files a/template/static/.DS_Store and /dev/null differ
diff --git a/template/static/css/colors.css b/template/static/css/colors.css
deleted file mode 100644
index e40f80c..0000000
--- a/template/static/css/colors.css
+++ /dev/null
@@ -1,55 +0,0 @@
-/* Colors inspired by "day/night-fox" schemes */
-:root {
-  /* Light mode colors */
-  --background-color-light: #f6f2ee; /* base00 */
-  --background-color-light-2: #dbd1dd; /* base01 */
-  --text-color-light: #3d2b5a; /* base05 */
-  --confirm-color-light: #396847; /* base0B */
-  --link-color-light: #6e33ce; /* base0E */
-  --container-bg-light: #f4ece6; /* base07 */
-  --border-color-light: #2848a9; /* base0D */
-  --error-color-light: #a5222f; /* base08 */
-
-  /* Dark mode colors */
-  --background-color-dark: #192330; /* base00 */
-  --background-color-dark-2: #212e3f; /* base01 */
-  --text-color-dark: #cdcecf; /* base05 */
-  --confirm-color-dark: #81b29a; /* base0B */
-  --link-color-dark: #9d79d6; /* base0E */
-  --container-bg-dark: #29394f; /* base02 */
-  --border-color-dark: #719cd6; /* base0D */
-  --error-color-dark: #c94f6d; /* base08 */
-}
-
-
-[data-theme="DARK"] {
-  --background-color: var(--background-color-dark);
-  --background-color-2: var(--background-color-dark-2);
-  --text-color: var(--text-color-dark);
-  --link-color: var(--link-color-dark);
-  --container-bg: var(--container-bg-dark);
-  --border-color: var(--border-color-dark);
-  --error-color: var(--error-color-dark);
-  --confirm-color: var(--confirm-color-dark);
-}
-
-[data-theme="LIGHT"] {
-  --background-color: var(--background-color-light);
-  --background-color-2: var(--background-color-light-2);
-  --text-color: var(--text-color-light);
-  --link-color: var(--link-color-light);
-  --container-bg: var(--container-bg-light);
-  --border-color: var(--border-color-light);
-  --error-color: var(--error-color-light);
-  --confirm-color: var(--confirm-color-light);
-}
-
-.error {
-  background-color: var(--error-color);
-  padding: 1rem;
-}
-
-.success {
-  background-color: var(--confirm-color);
-  padding: 1rem;
-}
diff --git a/template/static/css/form.css b/template/static/css/form.css
deleted file mode 100644
index 7ccd8db..0000000
--- a/template/static/css/form.css
+++ /dev/null
@@ -1,42 +0,0 @@
-.form {
-  max-width: 600px;
-  padding: 1em;
-  background: var(--background-color-2);
-  border: 1px solid #ccc;
-}
-
-label {
-  display: block;
-  margin: 0 0 1em;
-  font-weight: bold;
-}
-
-input {
-  display: block;
-  width: 100%;
-  padding: 0.5em;
-  margin: 0 0 1em;
-  border: 1px solid var(--border-color);
-  background: var(--container-bg);
-}
-
-button,
-input[type="submit"] {
-  padding: 0.5em 1em;
-  background: var(--link-color);
-  color: var(--text-color);
-  border: 0;
-  cursor: pointer;
-}
-
-textarea {
-  display: block;
-  width: 100%;
-  padding: 0.5em;
-  margin: 0 0 1em;
-  border: 1px solid var(--border-color);
-  background: var(--container-bg);
-
-  resize: vertical;
-  min-height: 100px;
-}
diff --git a/template/static/css/styles.css b/template/static/css/styles.css
deleted file mode 100644
index 2ec823a..0000000
--- a/template/static/css/styles.css
+++ /dev/null
@@ -1,60 +0,0 @@
-@import "/static/css/colors.css";
-@import "/static/css/form.css";
-@import "/static/css/table.css";
-@import "/static/css/chat.css";
-
-@font-face {
-    font-family: 'GeistMono';
-    src: url('/static/fonts/GeistMono-Medium.ttf') format('truetype');
-}  
-
-* {
-  box-sizing: border-box;
-  font-family: GeistMono;
-}
-
-html {
-  margin: 0;
-  padding: 0;
-  color: var(--text-color);
-}
-
-body {
-  background-color: var(--background-color);
-  min-height: 100vh;
-}
-
-hr {
-  border: 0;
-  border-top: 1px solid var(--text-color);
-
-  margin: 20px 0;
-}
-
-.container {
-  max-width: 1600px;
-  margin: auto;
-  background-color: var(--container-bg);
-  padding: 1rem;
-}
-
-
-a {
-  color: var(--link-color);
-  text-decoration: none;
-  font-weight: bold;
-}
-a:hover {
-  text-decoration: underline;
-}
-
-.info {
-  margin-bottom: 1rem;
-  max-width: 600px;
-
-  transition: opacity 0.3s;
-}
-
-.info:hover {
-  opacity: 0.8;
-}
diff --git a/template/static/css/table.css b/template/static/css/table.css
deleted file mode 100644
index 16da86d..0000000
--- a/template/static/css/table.css
+++ /dev/null
@@ -1,28 +0,0 @@
-@import "/static/css/colors.css";
-
-table {
-  width: auto;
-  border-collapse: collapse;
-  border: 1px solid var(--border-color);
-}
-
-th,
-td {
-  padding: 12px 20px;
-  text-align: center;
-  border-bottom: 1px solid var(--border-color);
-}
-
-th,
-thead {
-  background-color: var(--background-color-2);
-}
-
-tbody tr:nth-child(odd) {
-  background-color: var(--background-color);
-  color: var(--text-color);
-}
-
-tbody tr {
-  transition: background-color 0.3s ease;
-}
diff --git a/template/static/fonts/.DS_Store b/template/static/fonts/.DS_Store
deleted file mode 100644
index aa99597..0000000
Binary files a/template/static/fonts/.DS_Store and /dev/null differ
diff --git a/template/static/fonts/GeistMono-Medium.ttf b/template/static/fonts/GeistMono-Medium.ttf
deleted file mode 100644
index 4284eb4..0000000
Binary files a/template/static/fonts/GeistMono-Medium.ttf and /dev/null differ
diff --git a/template/static/img/favicon.ico b/template/static/img/favicon.ico
deleted file mode 100644
index 58c53c3..0000000
Binary files a/template/static/img/favicon.ico and /dev/null differ
diff --git a/template/static/js/components/formatDate.js b/template/static/js/components/formatDate.js
deleted file mode 100644
index a12f04f..0000000
--- a/template/static/js/components/formatDate.js
+++ /dev/null
@@ -1,7 +0,0 @@
-const timeElements = document.querySelectorAll(".time");
-timeElements.forEach((timeElement) => {
-  const dateStr = timeElement.textContent.split(" ").slice(0, 3).join(" ");
-  const date = new Date(dateStr);
-
-  timeElement.textContent = date.toLocaleString();
-});
diff --git a/template/static/js/components/infoBanners.js b/template/static/js/components/infoBanners.js
deleted file mode 100644
index 6a19864..0000000
--- a/template/static/js/components/infoBanners.js
+++ /dev/null
@@ -1,6 +0,0 @@
-const infoBanners = document.querySelectorAll(".info");
-Array.from(infoBanners).forEach((infoBanner) => {
-  infoBanner.addEventListener("click", () => {
-    infoBanner.remove();
-  });
-});
diff --git a/template/static/js/components/themeSwitcher.js b/template/static/js/components/themeSwitcher.js
deleted file mode 100644
index e5497f0..0000000
--- a/template/static/js/components/themeSwitcher.js
+++ /dev/null
@@ -1,27 +0,0 @@
-const THEMES = {
-  DARK: "DARK",
-  LIGHT: "LIGHT",
-};
-
-const flipFlopTheme = (theme) =>
-  THEMES[theme] === THEMES.DARK ? THEMES.LIGHT : THEMES.DARK;
-
-const themePickerText = {
-  DARK: "light mode.",
-  LIGHT: "dark mode.",
-};
-
-const themeSwitcher = document.getElementById("theme-switcher");
-
-const setTheme = (theme) => {
-  themeSwitcher.textContent = `${themePickerText[theme]}`;
-
-  document.documentElement.setAttribute("data-theme", theme);
-  localStorage.setItem("theme", theme);
-};
-
-themeSwitcher.addEventListener("click", () =>
-  setTheme(flipFlopTheme(document.documentElement.getAttribute("data-theme"))),
-);
-
-setTheme(localStorage.getItem("theme") || THEMES.LIGHT);
diff --git a/template/static/js/require.js b/template/static/js/require.js
deleted file mode 100644
index a4203f0..0000000
--- a/template/static/js/require.js
+++ /dev/null
@@ -1,5 +0,0 @@
-/** vim: et:ts=4:sw=4:sts=4
- * @license RequireJS 2.3.6 Copyright jQuery Foundation and other contributors.
- * Released under MIT license, https://github.com/requirejs/requirejs/blob/master/LICENSE
- */
-var requirejs,require,define;!function(global,setTimeout){var req,s,head,baseElement,dataMain,src,interactiveScript,currentlyAddingScript,mainScript,subPath,version="2.3.6",commentRegExp=/\/\*[\s\S]*?\*\/|([^:"'=]|^)\/\/.*$/gm,cjsRequireRegExp=/[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,jsSuffixRegExp=/\.js$/,currDirRegExp=/^\.\//,op=Object.prototype,ostring=op.toString,hasOwn=op.hasOwnProperty,isBrowser=!("undefined"==typeof window||"undefined"==typeof navigator||!window.document),isWebWorker=!isBrowser&&"undefined"!=typeof importScripts,readyRegExp=isBrowser&&"PLAYSTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/,defContextName="_",isOpera="undefined"!=typeof opera&&"[object Opera]"===opera.toString(),contexts={},cfg={},globalDefQueue=[],useInteractive=!1;function commentReplace(e,t){return t||""}function isFunction(e){return"[object Function]"===ostring.call(e)}function isArray(e){return"[object Array]"===ostring.call(e)}function each(e,t){var i;if(e)for(i=0;i<e.length&&(!e[i]||!t(e[i],i,e));i+=1);}function eachReverse(e,t){var i;if(e)for(i=e.length-1;-1<i&&(!e[i]||!t(e[i],i,e));i-=1);}function hasProp(e,t){return hasOwn.call(e,t)}function getOwn(e,t){return hasProp(e,t)&&e[t]}function eachProp(e,t){var i;for(i in e)if(hasProp(e,i)&&t(e[i],i))break}function mixin(i,e,r,n){return e&&eachProp(e,function(e,t){!r&&hasProp(i,t)||(!n||"object"!=typeof e||!e||isArray(e)||isFunction(e)||e instanceof RegExp?i[t]=e:(i[t]||(i[t]={}),mixin(i[t],e,r,n)))}),i}function bind(e,t){return function(){return t.apply(e,arguments)}}function scripts(){return document.getElementsByTagName("script")}function defaultOnError(e){throw e}function getGlobal(e){if(!e)return e;var t=global;return each(e.split("."),function(e){t=t[e]}),t}function makeError(e,t,i,r){var n=new Error(t+"\nhttps://requirejs.org/docs/errors.html#"+e);return n.requireType=e,n.requireModules=r,i&&(n.originalError=i),n}if(void 0===define){if(void 0!==requirejs){if(isFunction(requirejs))return;cfg=requirejs,requirejs=void 0}void 0===require||isFunction(require)||(cfg=require,require=void 0),req=requirejs=function(e,t,i,r){var n,o,a=defContextName;return isArray(e)||"string"==typeof e||(o=e,isArray(t)?(e=t,t=i,i=r):e=[]),o&&o.context&&(a=o.context),(n=getOwn(contexts,a))||(n=contexts[a]=req.s.newContext(a)),o&&n.configure(o),n.require(e,t,i)},req.config=function(e){return req(e)},req.nextTick=void 0!==setTimeout?function(e){setTimeout(e,4)}:function(e){e()},require||(require=req),req.version=version,req.jsExtRegExp=/^\/|:|\?|\.js$/,req.isBrowser=isBrowser,s=req.s={contexts:contexts,newContext:newContext},req({}),each(["toUrl","undef","defined","specified"],function(t){req[t]=function(){var e=contexts[defContextName];return e.require[t].apply(e,arguments)}}),isBrowser&&(head=s.head=document.getElementsByTagName("head")[0],baseElement=document.getElementsByTagName("base")[0],baseElement&&(head=s.head=baseElement.parentNode)),req.onError=defaultOnError,req.createNode=function(e,t,i){var r=e.xhtml?document.createElementNS("http://www.w3.org/1999/xhtml","html:script"):document.createElement("script");return r.type=e.scriptType||"text/javascript",r.charset="utf-8",r.async=!0,r},req.load=function(t,i,r){var e,n=t&&t.config||{};if(isBrowser)return(e=req.createNode(n,i,r)).setAttribute("data-requirecontext",t.contextName),e.setAttribute("data-requiremodule",i),!e.attachEvent||e.attachEvent.toString&&e.attachEvent.toString().indexOf("[native code")<0||isOpera?(e.addEventListener("load",t.onScriptLoad,!1),e.addEventListener("error",t.onScriptError,!1)):(useInteractive=!0,e.attachEvent("onreadystatechange",t.onScriptLoad)),e.src=r,n.onNodeCreated&&n.onNodeCreated(e,n,i,r),currentlyAddingScript=e,baseElement?head.insertBefore(e,baseElement):head.appendChild(e),currentlyAddingScript=null,e;if(isWebWorker)try{setTimeout(function(){},0),importScripts(r),t.completeLoad(i)}catch(e){t.onError(makeError("importscripts","importScripts failed for "+i+" at "+r,e,[i]))}},isBrowser&&!cfg.skipDataMain&&eachReverse(scripts(),function(e){if(head||(head=e.parentNode),dataMain=e.getAttribute("data-main"))return mainScript=dataMain,cfg.baseUrl||-1!==mainScript.indexOf("!")||(mainScript=(src=mainScript.split("/")).pop(),subPath=src.length?src.join("/")+"/":"./",cfg.baseUrl=subPath),mainScript=mainScript.replace(jsSuffixRegExp,""),req.jsExtRegExp.test(mainScript)&&(mainScript=dataMain),cfg.deps=cfg.deps?cfg.deps.concat(mainScript):[mainScript],!0}),define=function(e,i,t){var r,n;"string"!=typeof e&&(t=i,i=e,e=null),isArray(i)||(t=i,i=null),!i&&isFunction(t)&&(i=[],t.length&&(t.toString().replace(commentRegExp,commentReplace).replace(cjsRequireRegExp,function(e,t){i.push(t)}),i=(1===t.length?["require"]:["require","exports","module"]).concat(i))),useInteractive&&(r=currentlyAddingScript||getInteractiveScript())&&(e||(e=r.getAttribute("data-requiremodule")),n=contexts[r.getAttribute("data-requirecontext")]),n?(n.defQueue.push([e,i,t]),n.defQueueMap[e]=!0):globalDefQueue.push([e,i,t])},define.amd={jQuery:!0},req.exec=function(text){return eval(text)},req(cfg)}function newContext(u){var i,e,l,c,d,g={waitSeconds:7,baseUrl:"./",paths:{},bundles:{},pkgs:{},shim:{},config:{}},p={},f={},r={},h=[],m={},n={},v={},x=1,b=1;function q(e,t,i){var r,n,o,a,s,u,c,d,p,f,l=t&&t.split("/"),h=g.map,m=h&&h["*"];if(e&&(u=(e=e.split("/")).length-1,g.nodeIdCompat&&jsSuffixRegExp.test(e[u])&&(e[u]=e[u].replace(jsSuffixRegExp,"")),"."===e[0].charAt(0)&&l&&(e=l.slice(0,l.length-1).concat(e)),function(e){var t,i;for(t=0;t<e.length;t++)if("."===(i=e[t]))e.splice(t,1),t-=1;else if(".."===i){if(0===t||1===t&&".."===e[2]||".."===e[t-1])continue;0<t&&(e.splice(t-1,2),t-=2)}}(e),e=e.join("/")),i&&h&&(l||m)){e:for(o=(n=e.split("/")).length;0<o;o-=1){if(s=n.slice(0,o).join("/"),l)for(a=l.length;0<a;a-=1)if((r=getOwn(h,l.slice(0,a).join("/")))&&(r=getOwn(r,s))){c=r,d=o;break e}!p&&m&&getOwn(m,s)&&(p=getOwn(m,s),f=o)}!c&&p&&(c=p,d=f),c&&(n.splice(0,d,c),e=n.join("/"))}return getOwn(g.pkgs,e)||e}function E(t){isBrowser&&each(scripts(),function(e){if(e.getAttribute("data-requiremodule")===t&&e.getAttribute("data-requirecontext")===l.contextName)return e.parentNode.removeChild(e),!0})}function w(e){var t=getOwn(g.paths,e);if(t&&isArray(t)&&1<t.length)return t.shift(),l.require.undef(e),l.makeRequire(null,{skipMap:!0})([e]),!0}function y(e){var t,i=e?e.indexOf("!"):-1;return-1<i&&(t=e.substring(0,i),e=e.substring(i+1,e.length)),[t,e]}function S(e,t,i,r){var n,o,a,s,u=null,c=t?t.name:null,d=e,p=!0,f="";return e||(p=!1,e="_@r"+(x+=1)),u=(s=y(e))[0],e=s[1],u&&(u=q(u,c,r),o=getOwn(m,u)),e&&(u?f=i?e:o&&o.normalize?o.normalize(e,function(e){return q(e,c,r)}):-1===e.indexOf("!")?q(e,c,r):e:(u=(s=y(f=q(e,c,r)))[0],f=s[1],i=!0,n=l.nameToUrl(f))),{prefix:u,name:f,parentMap:t,unnormalized:!!(a=!u||o||i?"":"_unnormalized"+(b+=1)),url:n,originalName:d,isDefine:p,id:(u?u+"!"+f:f)+a}}function k(e){var t=e.id,i=getOwn(p,t);return i||(i=p[t]=new l.Module(e)),i}function M(e,t,i){var r=e.id,n=getOwn(p,r);!hasProp(m,r)||n&&!n.defineEmitComplete?(n=k(e)).error&&"error"===t?i(n.error):n.on(t,i):"defined"===t&&i(m[r])}function O(i,e){var t=i.requireModules,r=!1;e?e(i):(each(t,function(e){var t=getOwn(p,e);t&&(t.error=i,t.events.error&&(r=!0,t.emit("error",i)))}),r||req.onError(i))}function j(){globalDefQueue.length&&(each(globalDefQueue,function(e){var t=e[0];"string"==typeof t&&(l.defQueueMap[t]=!0),h.push(e)}),globalDefQueue=[])}function P(e){delete p[e],delete f[e]}function R(){var e,r,t=1e3*g.waitSeconds,n=t&&l.startTime+t<(new Date).getTime(),o=[],a=[],s=!1,u=!0;if(!i){if(i=!0,eachProp(f,function(e){var t=e.map,i=t.id;if(e.enabled&&(t.isDefine||a.push(e),!e.error))if(!e.inited&&n)w(i)?s=r=!0:(o.push(i),E(i));else if(!e.inited&&e.fetched&&t.isDefine&&(s=!0,!t.prefix))return u=!1}),n&&o.length)return(e=makeError("timeout","Load timeout for modules: "+o,null,o)).contextName=l.contextName,O(e);u&&each(a,function(e){!function n(o,a,s){var e=o.map.id;o.error?o.emit("error",o.error):(a[e]=!0,each(o.depMaps,function(e,t){var i=e.id,r=getOwn(p,i);!r||o.depMatched[t]||s[i]||(getOwn(a,i)?(o.defineDep(t,m[i]),o.check()):n(r,a,s))}),s[e]=!0)}(e,{},{})}),n&&!r||!s||!isBrowser&&!isWebWorker||d||(d=setTimeout(function(){d=0,R()},50)),i=!1}}function a(e){hasProp(m,e[0])||k(S(e[0],null,!0)).init(e[1],e[2])}function o(e,t,i,r){e.detachEvent&&!isOpera?r&&e.detachEvent(r,t):e.removeEventListener(i,t,!1)}function s(e){var t=e.currentTarget||e.srcElement;return o(t,l.onScriptLoad,"load","onreadystatechange"),o(t,l.onScriptError,"error"),{node:t,id:t&&t.getAttribute("data-requiremodule")}}function T(){var e;for(j();h.length;){if(null===(e=h.shift())[0])return O(makeError("mismatch","Mismatched anonymous define() module: "+e[e.length-1]));a(e)}l.defQueueMap={}}return c={require:function(e){return e.require?e.require:e.require=l.makeRequire(e.map)},exports:function(e){if(e.usingExports=!0,e.map.isDefine)return e.exports?m[e.map.id]=e.exports:e.exports=m[e.map.id]={}},module:function(e){return e.module?e.module:e.module={id:e.map.id,uri:e.map.url,config:function(){return getOwn(g.config,e.map.id)||{}},exports:e.exports||(e.exports={})}}},(e=function(e){this.events=getOwn(r,e.id)||{},this.map=e,this.shim=getOwn(g.shim,e.id),this.depExports=[],this.depMaps=[],this.depMatched=[],this.pluginMaps={},this.depCount=0}).prototype={init:function(e,t,i,r){r=r||{},this.inited||(this.factory=t,i?this.on("error",i):this.events.error&&(i=bind(this,function(e){this.emit("error",e)})),this.depMaps=e&&e.slice(0),this.errback=i,this.inited=!0,this.ignore=r.ignore,r.enabled||this.enabled?this.enable():this.check())},defineDep:function(e,t){this.depMatched[e]||(this.depMatched[e]=!0,this.depCount-=1,this.depExports[e]=t)},fetch:function(){if(!this.fetched){this.fetched=!0,l.startTime=(new Date).getTime();var e=this.map;if(!this.shim)return e.prefix?this.callPlugin():this.load();l.makeRequire(this.map,{enableBuildCallback:!0})(this.shim.deps||[],bind(this,function(){return e.prefix?this.callPlugin():this.load()}))}},load:function(){var e=this.map.url;n[e]||(n[e]=!0,l.load(this.map.id,e))},check:function(){if(this.enabled&&!this.enabling){var t,e,i=this.map.id,r=this.depExports,n=this.exports,o=this.factory;if(this.inited){if(this.error)this.emit("error",this.error);else if(!this.defining){if(this.defining=!0,this.depCount<1&&!this.defined){if(isFunction(o)){if(this.events.error&&this.map.isDefine||req.onError!==defaultOnError)try{n=l.execCb(i,o,r,n)}catch(e){t=e}else n=l.execCb(i,o,r,n);if(this.map.isDefine&&void 0===n&&((e=this.module)?n=e.exports:this.usingExports&&(n=this.exports)),t)return t.requireMap=this.map,t.requireModules=this.map.isDefine?[this.map.id]:null,t.requireType=this.map.isDefine?"define":"require",O(this.error=t)}else n=o;if(this.exports=n,this.map.isDefine&&!this.ignore&&(m[i]=n,req.onResourceLoad)){var a=[];each(this.depMaps,function(e){a.push(e.normalizedMap||e)}),req.onResourceLoad(l,this.map,a)}P(i),this.defined=!0}this.defining=!1,this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else hasProp(l.defQueueMap,i)||this.fetch()}},callPlugin:function(){var u=this.map,c=u.id,e=S(u.prefix);this.depMaps.push(e),M(e,"defined",bind(this,function(e){var o,t,i,r=getOwn(v,this.map.id),n=this.map.name,a=this.map.parentMap?this.map.parentMap.name:null,s=l.makeRequire(u.parentMap,{enableBuildCallback:!0});return this.map.unnormalized?(e.normalize&&(n=e.normalize(n,function(e){return q(e,a,!0)})||""),M(t=S(u.prefix+"!"+n,this.map.parentMap,!0),"defined",bind(this,function(e){this.map.normalizedMap=t,this.init([],function(){return e},null,{enabled:!0,ignore:!0})})),void((i=getOwn(p,t.id))&&(this.depMaps.push(t),this.events.error&&i.on("error",bind(this,function(e){this.emit("error",e)})),i.enable()))):r?(this.map.url=l.nameToUrl(r),void this.load()):((o=bind(this,function(e){this.init([],function(){return e},null,{enabled:!0})})).error=bind(this,function(e){this.inited=!0,(this.error=e).requireModules=[c],eachProp(p,function(e){0===e.map.id.indexOf(c+"_unnormalized")&&P(e.map.id)}),O(e)}),o.fromText=bind(this,function(e,t){var i=u.name,r=S(i),n=useInteractive;t&&(e=t),n&&(useInteractive=!1),k(r),hasProp(g.config,c)&&(g.config[i]=g.config[c]);try{req.exec(e)}catch(e){return O(makeError("fromtexteval","fromText eval for "+c+" failed: "+e,e,[c]))}n&&(useInteractive=!0),this.depMaps.push(r),l.completeLoad(i),s([i],o)}),void e.load(u.name,s,o,g))})),l.enable(e,this),this.pluginMaps[e.id]=e},enable:function(){(f[this.map.id]=this).enabled=!0,this.enabling=!0,each(this.depMaps,bind(this,function(e,t){var i,r,n;if("string"==typeof e){if(e=S(e,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap),this.depMaps[t]=e,n=getOwn(c,e.id))return void(this.depExports[t]=n(this));this.depCount+=1,M(e,"defined",bind(this,function(e){this.undefed||(this.defineDep(t,e),this.check())})),this.errback?M(e,"error",bind(this,this.errback)):this.events.error&&M(e,"error",bind(this,function(e){this.emit("error",e)}))}i=e.id,r=p[i],hasProp(c,i)||!r||r.enabled||l.enable(e,this)})),eachProp(this.pluginMaps,bind(this,function(e){var t=getOwn(p,e.id);t&&!t.enabled&&l.enable(e,this)})),this.enabling=!1,this.check()},on:function(e,t){var i=this.events[e];i||(i=this.events[e]=[]),i.push(t)},emit:function(e,t){each(this.events[e],function(e){e(t)}),"error"===e&&delete this.events[e]}},(l={config:g,contextName:u,registry:p,defined:m,urlFetched:n,defQueue:h,defQueueMap:{},Module:e,makeModuleMap:S,nextTick:req.nextTick,onError:O,configure:function(e){if(e.baseUrl&&"/"!==e.baseUrl.charAt(e.baseUrl.length-1)&&(e.baseUrl+="/"),"string"==typeof e.urlArgs){var i=e.urlArgs;e.urlArgs=function(e,t){return(-1===t.indexOf("?")?"?":"&")+i}}var r=g.shim,n={paths:!0,bundles:!0,config:!0,map:!0};eachProp(e,function(e,t){n[t]?(g[t]||(g[t]={}),mixin(g[t],e,!0,!0)):g[t]=e}),e.bundles&&eachProp(e.bundles,function(e,t){each(e,function(e){e!==t&&(v[e]=t)})}),e.shim&&(eachProp(e.shim,function(e,t){isArray(e)&&(e={deps:e}),!e.exports&&!e.init||e.exportsFn||(e.exportsFn=l.makeShimExports(e)),r[t]=e}),g.shim=r),e.packages&&each(e.packages,function(e){var t;t=(e="string"==typeof e?{name:e}:e).name,e.location&&(g.paths[t]=e.location),g.pkgs[t]=e.name+"/"+(e.main||"main").replace(currDirRegExp,"").replace(jsSuffixRegExp,"")}),eachProp(p,function(e,t){e.inited||e.map.unnormalized||(e.map=S(t,null,!0))}),(e.deps||e.callback)&&l.require(e.deps||[],e.callback)},makeShimExports:function(t){return function(){var e;return t.init&&(e=t.init.apply(global,arguments)),e||t.exports&&getGlobal(t.exports)}},makeRequire:function(o,a){function s(e,t,i){var r,n;return a.enableBuildCallback&&t&&isFunction(t)&&(t.__requireJsBuild=!0),"string"==typeof e?isFunction(t)?O(makeError("requireargs","Invalid require call"),i):o&&hasProp(c,e)?c[e](p[o.id]):req.get?req.get(l,e,o,s):(r=S(e,o,!1,!0).id,hasProp(m,r)?m[r]:O(makeError("notloaded",'Module name "'+r+'" has not been loaded yet for context: '+u+(o?"":". Use require([])")))):(T(),l.nextTick(function(){T(),(n=k(S(null,o))).skipMap=a.skipMap,n.init(e,t,i,{enabled:!0}),R()}),s)}return a=a||{},mixin(s,{isBrowser:isBrowser,toUrl:function(e){var t,i=e.lastIndexOf("."),r=e.split("/")[0];return-1!==i&&(!("."===r||".."===r)||1<i)&&(t=e.substring(i,e.length),e=e.substring(0,i)),l.nameToUrl(q(e,o&&o.id,!0),t,!0)},defined:function(e){return hasProp(m,S(e,o,!1,!0).id)},specified:function(e){return e=S(e,o,!1,!0).id,hasProp(m,e)||hasProp(p,e)}}),o||(s.undef=function(i){j();var e=S(i,o,!0),t=getOwn(p,i);t.undefed=!0,E(i),delete m[i],delete n[e.url],delete r[i],eachReverse(h,function(e,t){e[0]===i&&h.splice(t,1)}),delete l.defQueueMap[i],t&&(t.events.defined&&(r[i]=t.events),P(i))}),s},enable:function(e){getOwn(p,e.id)&&k(e).enable()},completeLoad:function(e){var t,i,r,n=getOwn(g.shim,e)||{},o=n.exports;for(j();h.length;){if(null===(i=h.shift())[0]){if(i[0]=e,t)break;t=!0}else i[0]===e&&(t=!0);a(i)}if(l.defQueueMap={},r=getOwn(p,e),!t&&!hasProp(m,e)&&r&&!r.inited){if(!(!g.enforceDefine||o&&getGlobal(o)))return w(e)?void 0:O(makeError("nodefine","No define call for "+e,null,[e]));a([e,n.deps||[],n.exportsFn])}R()},nameToUrl:function(e,t,i){var r,n,o,a,s,u,c=getOwn(g.pkgs,e);if(c&&(e=c),u=getOwn(v,e))return l.nameToUrl(u,t,i);if(req.jsExtRegExp.test(e))a=e+(t||"");else{for(r=g.paths,o=(n=e.split("/")).length;0<o;o-=1)if(s=getOwn(r,n.slice(0,o).join("/"))){isArray(s)&&(s=s[0]),n.splice(0,o,s);break}a=n.join("/"),a=("/"===(a+=t||(/^data\:|^blob\:|\?/.test(a)||i?"":".js")).charAt(0)||a.match(/^[\w\+\.\-]+:/)?"":g.baseUrl)+a}return g.urlArgs&&!/^blob\:/.test(a)?a+g.urlArgs(e,a):a},load:function(e,t){req.load(l,e,t)},execCb:function(e,t,i,r){return t.apply(r,i)},onScriptLoad:function(e){if("load"===e.type||readyRegExp.test((e.currentTarget||e.srcElement).readyState)){interactiveScript=null;var t=s(e);l.completeLoad(t.id)}},onScriptError:function(e){var i=s(e);if(!w(i.id)){var r=[];return eachProp(p,function(e,t){0!==t.indexOf("_@r")&&each(e.depMaps,function(e){if(e.id===i.id)return r.push(t),!0})}),O(makeError("scripterror",'Script error for "'+i.id+(r.length?'", needed by: '+r.join(", "):'"'),e,[i.id]))}}}).require=l.makeRequire(),l}function getInteractiveScript(){return interactiveScript&&"interactive"===interactiveScript.readyState||eachReverse(scripts(),function(e){if("interactive"===e.readyState)return interactiveScript=e}),interactiveScript}}(this,"undefined"==typeof setTimeout?void 0:setTimeout);
\ No newline at end of file
diff --git a/template/static/js/script.js b/template/static/js/script.js
deleted file mode 100644
index b5e6249..0000000
--- a/template/static/js/script.js
+++ /dev/null
@@ -1,6 +0,0 @@
-const scripts = [
-  "/static/js/components/themeSwitcher.js",
-  "/static/js/components/formatDate.js",
-  "/static/js/components/infoBanners.js",
-];
-requirejs(scripts);
diff --git a/template/static/js/util/setThemeBeforeRender.js b/template/static/js/util/setThemeBeforeRender.js
deleted file mode 100644
index b025cce..0000000
--- a/template/static/js/util/setThemeBeforeRender.js
+++ /dev/null
@@ -1,11 +0,0 @@
-const preferredMode = window.matchMedia("(prefers-color-scheme: dark)").matches
-  ? "DARK"
-  : "LIGHT";
-
-// sets theme before rendering & jquery loaded to prevent flashing of uninitialized theme
-// (ugly white background)
-localStorage.setItem("theme", localStorage.getItem("theme") || preferredMode);
-document.documentElement.setAttribute(
-  "data-theme",
-  localStorage.getItem("theme"),
-);
diff --git a/template/templates/404.html b/template/templates/404.html
deleted file mode 100644
index 5210bfb..0000000
--- a/template/templates/404.html
+++ /dev/null
@@ -1,7 +0,0 @@
-{{ define "content" }}
-<h1>page not found</h1>
-<p><em>but hey, at least you found our witty 404 page. that's something, right?</em></p>
-
-<p><a href="/">go back home</a></p>
-
-{{ end }}
diff --git a/template/templates/base.html b/template/templates/base.html
deleted file mode 100644
index 8d6aab2..0000000
--- a/template/templates/base.html
+++ /dev/null
@@ -1,34 +0,0 @@
-{{ define "base" }}
-<!DOCTYPE html>
-<html>
-  <head>
-    <title>{{ service_title }}</title>
-    <meta charset="utf-8">
-    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
-    <link href="/static/img/favicon.ico" rel="icon" type="image/x-icon">
-    <link rel="stylesheet" type="text/css" href="/static/css/styles.css">
-
-    <meta property="og:type" content="website">
-    <meta property="og:url" content="https://{{ service }}.simponic.xyz">
-    <meta property="og:title" content="{{ service_title }}">
-    <meta property="og:description" content="{{ service_title }}">
-    <meta property="og:image:secure_url" content="https://{{ service }}.simponic.xyz/static/img/favicon.ico">
-    <meta property="og:image:secure" content="https://{{ service }}.simponic.xyz/static/img/favicon.ico">
-
-    <script src="/static/js/util/setThemeBeforeRender.js"></script>
-  </head>
-  <body>
-    <div id="content" class="container">
-      <div>
-        <h1>{{ service }}</h1>
-        <a href="/">home.</a>
-        <span> | </span>
-        <a href="javascript:void(0);" id="theme-switcher">light mode.</a>
-      </div>
-      <hr>
-      {{ template "content" . }}
-    </div>
-    <script data-main="/static/js/script.js" src="/static/js/require.js"></script>
-  </body>
-</html>
-{{ end }}
diff --git a/template/templates/base_empty.html b/template/templates/base_empty.html
deleted file mode 100644
index 6191ab9..0000000
--- a/template/templates/base_empty.html
+++ /dev/null
@@ -1,3 +0,0 @@
-{{ define "base" }}
-    {{ template "content" . }}
-{{ end }}
\ No newline at end of file
diff --git a/template/templates/hello.html b/template/templates/hello.html
deleted file mode 100644
index d2311f5..0000000
--- a/template/templates/hello.html
+++ /dev/null
@@ -1,3 +0,0 @@
-{{ define "content" }}
-hello from {{ .Service }}!
-{{ end }}
diff --git a/template/utils/random_id.go b/template/utils/random_id.go
deleted file mode 100644
index 1b03ec8..0000000
--- a/template/utils/random_id.go
+++ /dev/null
@@ -1,16 +0,0 @@
-package utils
-
-import (
-	"crypto/rand"
-	"fmt"
-)
-
-func RandomId() string {
-	id := make([]byte, 16)
-	_, err := rand.Read(id)
-	if err != nil {
-		panic(err)
-	}
-
-	return fmt.Sprintf("%x", id)
-}