diff --git a/Makefile b/Makefile
index 79a5ac5..493533d 100644
--- a/Makefile
+++ b/Makefile
@@ -62,5 +62,7 @@ all:
 	$(MAKE) visualize
 
 visualize:
-	./visualize.py | d2 - infrastructure.svg
+	./scripts/visualize.py | d2 - infrastructure.svg
 
+new_role:
+	./scripts/new_role.sh
diff --git a/modules/infrastructure/main.tf b/modules/infrastructure/main.tf
index 2767415..0858f81 100644
--- a/modules/infrastructure/main.tf
+++ b/modules/infrastructure/main.tf
@@ -31,7 +31,8 @@ terraform {
 locals {
   services_auth = {for key, val in var.services : key => val if val.auth}
   services_database = {for key, val in var.services : key => val if val.database}
-  services_s3 = {for key, val in var.services : key => val if val.s3}
+  services_s3 = {for key, val in var.services : key => (val.s3_buckets != null) ? val.s3_buckets : [key] if val.s3}
+  buckets_s3 = merge([for key, val in local.services_s3 : {for bucket in val : bucket => key}]...)
 
   hetzner_hosts = {for key, val in var.hosts : key => val if val.provider == "hetzner"}
 }
diff --git a/modules/infrastructure/output.tf b/modules/infrastructure/output.tf
index 3307db5..be18002 100644
--- a/modules/infrastructure/output.tf
+++ b/modules/infrastructure/output.tf
@@ -51,9 +51,9 @@ output "healthchecksio" {
 
 output "scaleway_data" {
   value = {
-    for key in keys(scaleway_iam_application.service_applications) : key => {
-      "access_key"   = scaleway_iam_api_key.service_keys[key].access_key
-      "secret_key"   = scaleway_iam_api_key.service_keys[key].secret_key
+    for key, val in local.buckets_s3 : key => {
+      "access_key"   = scaleway_iam_api_key.service_keys[val].access_key
+      "secret_key"   = scaleway_iam_api_key.service_keys[val].secret_key
       "name"         = scaleway_object_bucket.service_buckets[key].name
       "region"       = scaleway_object_bucket.service_buckets[key].region
       "endpoint"     = scaleway_object_bucket.service_buckets[key].endpoint
diff --git a/modules/infrastructure/scaleway.tf b/modules/infrastructure/scaleway.tf
index f017a11..1a27d44 100644
--- a/modules/infrastructure/scaleway.tf
+++ b/modules/infrastructure/scaleway.tf
@@ -27,15 +27,15 @@ resource "scaleway_iam_policy" "service_storage_policies" {
 }
 
 resource "scaleway_object_bucket" "service_buckets" {
-  for_each = local.services_s3
-  name = "${each.key}.serguzim.me"
+  for_each = local.buckets_s3
+  name = replace("${each.key}.serguzim.me", "_", "-")
   lifecycle {
    prevent_destroy = true
  }
 }
 
 resource "scaleway_object_bucket_policy" "service_bucket_policies" {
-  for_each = local.services_s3
+  for_each = local.buckets_s3
   bucket = scaleway_object_bucket.service_buckets[each.key].id
   policy = jsonencode({
     Version = "2023-04-17",
@@ -58,7 +58,7 @@ resource "scaleway_object_bucket_policy" "service_bucket_policies" {
         Effect = "Allow"
         Action = "*"
         Principal = {
-          SCW = "application_id:${scaleway_iam_application.service_applications[each.key].id}"
+          SCW = "application_id:${scaleway_iam_application.service_applications[each.value].id}"
         }
         Resource = [
           "${scaleway_object_bucket.service_buckets[each.key].name}",
diff --git a/modules/infrastructure/variables.tf b/modules/infrastructure/variables.tf
index 4f5918d..f5339ee 100644
--- a/modules/infrastructure/variables.tf
+++ b/modules/infrastructure/variables.tf
@@ -32,6 +32,7 @@ variable "services" {
     auth_cert = optional(string)
     auth_redirects = optional(list(string))
     s3 = bool
+    s3_buckets = optional(list(string))
     database = bool
   }))
 }
diff --git a/playbooks/roles/forgejo/vars/main.yml b/playbooks/roles/forgejo/vars/main.yml
index 6257dc8..3e8b86c 100644
--- a/playbooks/roles/forgejo/vars/main.yml
+++ b/playbooks/roles/forgejo/vars/main.yml
@@ -82,7 +82,7 @@ forgejo_env:
 
 forgejo_compose:
   watchtower: update
-  image: codeberg.org/forgejo/forgejo:9
+  image: codeberg.org/forgejo/forgejo:11
   volumes:
     - data:/data
     - ./templates:/data/gitea/templates
diff --git a/playbooks/roles/software/files/systemd-resolved.conf b/playbooks/roles/software/files/systemd-resolved.conf
new file mode 100644
index 0000000..6f48c7f
--- /dev/null
+++ b/playbooks/roles/software/files/systemd-resolved.conf
@@ -0,0 +1,3 @@
+[Resolve]
+DNSOverTLS=opportunistic
+DNSStubListenerExtra=172.17.0.1
diff --git a/playbooks/roles/software/tasks/systemd-resolved.yml b/playbooks/roles/software/tasks/systemd-resolved.yml
index eb4fcca..0c94efe 100644
--- a/playbooks/roles/software/tasks/systemd-resolved.yml
+++ b/playbooks/roles/software/tasks/systemd-resolved.yml
@@ -6,10 +6,20 @@
     update_cache: true
   become: true
 
-- name: Enable systemd-resolved
+- name: Copy systemd config
+  ansible.builtin.copy:
+    src: systemd-resolved.conf
+    dest: /etc/systemd/resolved.conf
+    mode: "0644"
+    owner: "root"
+    group: "root"
+  become: true
+  register: systemd_resolved_config
+
+- name: Enable systemd-resolved and (re)start
   ansible.builtin.systemd_service:
     name: systemd-resolved.service
-    state: started
+    state: "{{ 'restarted' if systemd_resolved_config.changed else 'started' }}"
     enabled: true
     daemon_reload: true
   become: true
diff --git a/scripts/new_role.sh b/scripts/new_role.sh
new file mode 100755
index 0000000..bad2558
--- /dev/null
+++ b/scripts/new_role.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+
+roles_dir="./playbooks/roles"
+
+read -p "Enter the new role name: " new_role
+
+if [ -z "$new_role" ]; then
+  echo "Usage: $0 <role_name>"
+  exit 1
+fi
+
+if [ -d "$roles_dir/$new_role" ]; then
+  echo "Role $new_role already exists."
+  exit 1
+fi
+
+cp -r "$roles_dir/_TEMPLATE" "$roles_dir/$new_role"
+
+sed -i "s/NAME_/${new_role}_/g" "$roles_dir/$new_role"/**/*.yml
diff --git a/visualize.py b/scripts/visualize.py
similarity index 94%
rename from visualize.py
rename to scripts/visualize.py
index 06f78a3..3f4cddd 100755
--- a/visualize.py
+++ b/scripts/visualize.py
@@ -14,11 +14,13 @@ icon_overrides = {
     "healthcheck": "healthchecks",
     "lego": "lets-encrypt",
     "mailcowdockerized": "mailcow",
+    "minecraft_3": "minecraft",
     "reitanlage_oranienburg": "grav",
     "tandoor": "tandoor-recipes",
     "tinytinyrss": "tiny-tiny-rss",
     "webdis": "redis",
     "wiki_js": "wiki-js",
+    "woodpecker": "woodpecker-ci"
 }
 
 icon_format = {
@@ -26,14 +28,12 @@ icon_format = {
     "linkwarden": "webp",
     "telegraf": "webp",
     "tiny-tiny-rss": "webp",
-    "watchtower": "webp", # TODO revert when icon is fixed
 }
 
 icon_url = {
-    "dokku": "https://avatars.githubusercontent.com/u/13455795?s=200&v=4",
     "factorio": "https://avatars.githubusercontent.com/u/50074624?s=200&v=4",
+    "mimir": "https://raw.githubusercontent.com/grafana/mimir/refs/heads/main/images/logo.png",
     "teamspeak_fallback": "https://avatars.githubusercontent.com/u/136759148?s=200&v=4",
-    "woodpecker": "https://avatars.githubusercontent.com/u/84780935?s=200&v=4",
 }
 
 def get_icon(svc):
diff --git a/services.auto.tfvars b/services.auto.tfvars
index 2f98cb2..69b4b94 100644
--- a/services.auto.tfvars
+++ b/services.auto.tfvars
@@ -1,3 +1,11 @@
+# Groups:
+## 1-hosts
+## 3-services
+## 4-websites
+## 7-support
+## 8-backup
+## 9-external
+
 services = {
   "acme_dns" = {
     host = "node001"
@@ -34,7 +42,7 @@ services = {
     }]
     monitoring = {
       url = "/-/health/live/"
-      group = "4-services"
+      group = "3-services"
     }
     certificates = ["auth.serguzim.me"]
     auth = false
@@ -57,7 +65,7 @@ services = {
     }]
     monitoring = {
       url = "/"
-      group = "4-services"
+      group = "3-services"
     }
     auth = false
     database = false
@@ -142,42 +150,42 @@ services = {
     s3 = false
   },
 
-  "factorio" = {
-    host = "node002"
-    dns = [{
-      domain = "factorio.serguzim.me"
-    }]
-    backup = [{
-      name = "factorio_data"
-      type = "docker"
-    }]
-    monitoring = {
-      url = "https://multiplayer.factorio.com/get-game-details/91.107.211.57:34197"
-      group = "4-services"
-      interval = "5m"
-      conditions = [
-        "DEFAULT",
-        "[BODY].name == StammtischOnAutomation"
-      ]
-    }
-    ports = [
-      {
-        description = "Game port for factorio"
-        port = 34197
-        protocol = "udp"
-        type = "firewall"
-      },
-      {
-        description = "RCON port for factorio"
-        port = 27015
-        protocol = "tcp"
-        type = "firewall"
-      }
-    ]
-    auth = false
-    database = false
-    s3 = false
-  }
+  #"factorio" = {
+  #  host = "node002"
+  #  dns = [{
+  #    domain = "factorio.serguzim.me"
+  #  }]
+  #  backup = [{
+  #    name = "factorio_data"
+  #    type = "docker"
+  #  }]
+  #  monitoring = {
+  #    url = "https://multiplayer.factorio.com/get-game-details/91.107.211.57:34197"
+  #    group = "3-services"
+  #    interval = "5m"
+  #    conditions = [
+  #      "DEFAULT",
+  #      "[BODY].name == StammtischOnAutomation"
+  #    ]
+  #  }
+  #  ports = [
+  #    {
+  #      description = "Game port for factorio"
+  #      port = 34197
+  #      protocol = "udp"
+  #      type = "firewall"
+  #    },
+  #    {
+  #      description = "RCON port for factorio"
+  #      port = 27015
+  #      protocol = "tcp"
+  #      type = "firewall"
+  #    }
+  #  ]
+  #  auth = false
+  #  database = false
+  #  s3 = false
+  #}
 
   "forgejo" = {
     host = "node001"
@@ -190,7 +198,7 @@ services = {
     }]
     monitoring = {
       url = "/api/v1/version"
-      group = "4-services"
+      group = "3-services"
     }
     ports = [
       {
@@ -247,7 +255,7 @@ services = {
     }]
     monitoring = {
       url = "/api/v1/status"
-      group = "4-services"
+      group = "3-services"
       conditions = [
         "DEFAULT",
         "[BODY].health == true"
@@ -275,7 +283,7 @@ services = {
       }
     ]
     monitoring = {
-      group = "4-services"
+      group = "3-services"
     }
     auth = true
     auth_redirects = ["https://gallery.serguzim.me/auth/login"]
@@ -294,7 +302,7 @@ services = {
     }]
     monitoring = {
       url = "/health"
-      group = "4-services"
+      group = "3-services"
       conditions = [
         "DEFAULT",
         "[BODY].status == pass"
@@ -322,7 +330,7 @@ services = {
     ]
     monitoring = {
       url = "/health"
-      group = "4-services"
+      group = "3-services"
       conditions = [
         "DEFAULT",
         "[BODY] == Healthy"
@@ -347,7 +355,7 @@ services = {
     }]
     monitoring = {
       url = "/api/v1/logins"
-      group = "4-services"
+      group = "3-services"
     }
     auth = true
     auth_cert = "rsa"
@@ -366,7 +374,7 @@ services = {
       type = "hook"
     }]
     monitoring = {
-      group = "4-services"
+      group = "3-services"
     }
     ports = [
       {
@@ -428,7 +436,7 @@ services = {
     ]
     monitoring = {
       url = "tcp://minecraft.serguzim.me:25565"
-      group = "4-services"
+      group = "3-services"
       conditions = [
         "[CONNECTED] == true"
       ]
@@ -479,7 +487,7 @@ services = {
     }]
     monitoring = {
       url = "/v1/health"
-      group = "4-services"
+      group = "3-services"
       conditions = [
         "DEFAULT",
         "[BODY].healthy == true"
@@ -529,7 +537,7 @@ services = {
       type = "docker"
     }]
     monitoring = {
-      group = "5-websites"
+      group = "4-websites"
     }
     auth = false
     database = false
@@ -555,7 +563,7 @@ services = {
     ]
     monitoring = {
       url = "/rest/health"
-      group = "4-services"
+      group = "3-services"
       conditions = [
         "DEFAULT",
         "[BODY].status == pass"
@@ -584,7 +592,7 @@ services = {
     }]
     monitoring = {
       url = "/_matrix/client/versions"
-      group = "4-services"
+      group = "3-services"
     }
     ports = [
       {
@@ -612,7 +620,7 @@ services = {
     }]
     monitoring = {
       url = "/accounts/login/"
-      group = "4-services"
+      group = "3-services"
     }
     auth = false
     database = true
@@ -677,7 +685,7 @@ services = {
     }]
     monitoring = {
       url = "/tt-rss/"
-      group = "4-services"
+      group = "3-services"
     }
     auth = false
     database = true
@@ -691,7 +699,7 @@ services = {
     }]
     monitoring = {
       url = "/api/heartbeat"
-      group = "4-services"
+      group = "3-services"
     }
     auth = false
     database = true
@@ -709,7 +717,7 @@ services = {
     }]
     monitoring = {
       url = "/api/v1/info"
-      group = "4-services"
+      group = "3-services"
     }
     auth = true
     auth_redirects = ["https://todo.serguzim.me/auth/openid/authserguzimme"]
@@ -733,7 +741,7 @@ services = {
     }]
     monitoring = {
       url = "/info"
-      group = "4-services"
+      group = "3-services"
     }
     auth = false
     database = false
@@ -746,7 +754,7 @@ services = {
       domain = "wiki.serguzim.me"
     }]
     monitoring = {
-      group = "4-services"
+      group = "3-services"
     }
     auth = true
     auth_redirects = ["https://wiki.serguzim.me/login/f792bc7d-1a25-4437-944e-55eaf0111102/callback"]
@@ -769,7 +777,7 @@ services = {
     ]
     monitoring = {
       url = "/healthz"
-      group = "4-services"
+      group = "3-services"
     }
     auth = false
     database = true
diff --git a/variables.tf b/variables.tf
index e25622f..a28d5af 100644
--- a/variables.tf
+++ b/variables.tf
@@ -162,6 +162,7 @@ variable "services" {
     auth_cert = optional(string)
     auth_redirects = optional(list(string))
     s3 = bool
+    s3_buckets = optional(list(string))
     database = bool
     mail = optional(string)
   }))