From a27a157e22d539a8df35ce73532b1acfe4e5199e Mon Sep 17 00:00:00 2001
From: Tobias Reisinger <tobias@msrg.cc>
Date: Fri, 31 Jan 2025 02:48:53 +0100
Subject: [PATCH 1/5] Add webdis service

---
 playbooks/roles/webdis/files/webdis.json | 31 ++++++++++++++++++++++++
 playbooks/roles/webdis/tasks/main.yml    | 20 +++++++++++++++
 playbooks/roles/webdis/vars/main.yml     | 23 ++++++++++++++++++
 services.auto.tfvars                     | 14 +++++++++++
 visualize.py                             |  1 +
 5 files changed, 89 insertions(+)
 create mode 100644 playbooks/roles/webdis/files/webdis.json
 create mode 100644 playbooks/roles/webdis/tasks/main.yml
 create mode 100644 playbooks/roles/webdis/vars/main.yml

diff --git a/playbooks/roles/webdis/files/webdis.json b/playbooks/roles/webdis/files/webdis.json
new file mode 100644
index 0000000..25d95ac
--- /dev/null
+++ b/playbooks/roles/webdis/files/webdis.json
@@ -0,0 +1,31 @@
+{
+    "redis_host":	"redis",
+
+    "redis_port":	6379,
+    "redis_auth":	null,
+
+    "http_host":	"0.0.0.0",
+    "http_port":	7379,
+
+    "threads":	5,
+    "pool_size": 20,
+
+    "daemonize":	false,
+    "websockets":	false,
+
+    "database":	0,
+
+    "acl": [
+        {
+            "disabled":	["DEBUG"]
+        },
+
+        {
+            "http_basic_auth":	"user:password",
+            "enabled":		["DEBUG"]
+        }
+    ],
+
+    "verbosity": 4,
+    "logfile": "/dev/stderr"
+}
diff --git a/playbooks/roles/webdis/tasks/main.yml b/playbooks/roles/webdis/tasks/main.yml
new file mode 100644
index 0000000..fb1561b
--- /dev/null
+++ b/playbooks/roles/webdis/tasks/main.yml
@@ -0,0 +1,20 @@
+---
+- name: Set common facts
+  ansible.builtin.import_tasks: tasks/set-default-facts.yml
+
+- name: Deploy {{ role_name }}
+  vars:
+    svc: "{{ webdis_svc }}"
+    compose: "{{ webdis_compose }}"
+  block:
+    - name: Import prepare tasks for common service
+      ansible.builtin.import_tasks: tasks/prepare-common-service.yml
+
+    - name: Copy the config
+      ansible.builtin.copy:
+        src: webdis.json
+        dest: "{{ (service_path, 'webdis.json') | path_join }}"
+        mode: "0755"
+
+    - name: Import start tasks for common service
+      ansible.builtin.import_tasks: tasks/start-common-service.yml
diff --git a/playbooks/roles/webdis/vars/main.yml b/playbooks/roles/webdis/vars/main.yml
new file mode 100644
index 0000000..6a3ddfb
--- /dev/null
+++ b/playbooks/roles/webdis/vars/main.yml
@@ -0,0 +1,23 @@
+---
+webdis_svc:
+  domain: "{{ all_services | service_get_domain(role_name) }}"
+  port: 7379
+
+webdis_compose:
+  watchtower: update
+  image: nicolas/webdis
+  volumes:
+    - ./webdis.json:/config/webdis.json
+  file:
+    services:
+      app:
+        command: /usr/local/bin/webdis /config/webdis.json
+        depends_on:
+          - redis
+      redis:
+        image: redis:6.2.6
+        restart: always
+        labels:
+          com.centurylinklabs.watchtower.enable: true
+    networks:
+      default:
diff --git a/services.auto.tfvars b/services.auto.tfvars
index c2bb2a7..c506628 100644
--- a/services.auto.tfvars
+++ b/services.auto.tfvars
@@ -681,6 +681,20 @@ services = {
     mail = "watchtower"
   },
 
+  "webdis" = {
+    host = "node001"
+    dns = [{
+      domain = "webdis.huck.serguzim.me"
+    }]
+    monitoring = {
+      url = "/info"
+      group = "4-services"
+    }
+    auth = false
+    database = false
+    s3 = false
+  },
+
   "wiki_js" = {
     host = "node001"
     dns = [{
diff --git a/visualize.py b/visualize.py
index 62c8a43..a6b8c83 100755
--- a/visualize.py
+++ b/visualize.py
@@ -20,6 +20,7 @@ icon_overrides = {
     "tandoor": "tandoor-recipes",
     "teamspeak_fallback": None,
     "tinytinyrss": "tiny-tiny-rss",
+    "webdis": "redis",
     "wiki_js": "wiki-js",
     "woodpecker": None,
 }

From b20a2a67a52765e52767a5d0c9e09a0e10dd3021 Mon Sep 17 00:00:00 2001
From: Tobias Reisinger <tobias@msrg.cc>
Date: Sat, 1 Feb 2025 02:51:52 +0100
Subject: [PATCH 2/5] Add custom icons to visualize

---
 visualize.py | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/visualize.py b/visualize.py
index a6b8c83..06f78a3 100755
--- a/visualize.py
+++ b/visualize.py
@@ -9,20 +9,16 @@ import hcl2
 icon_overrides = {
     "acme_dns": "lets-encrypt",
     "backup": "restic",
-    "dokku": None,
     "extra_services": None,
-    "factorio": None,
     "forgejo_runner": "forgejo",
     "healthcheck": "healthchecks",
     "lego": "lets-encrypt",
     "mailcowdockerized": "mailcow",
     "reitanlage_oranienburg": "grav",
     "tandoor": "tandoor-recipes",
-    "teamspeak_fallback": None,
     "tinytinyrss": "tiny-tiny-rss",
     "webdis": "redis",
     "wiki_js": "wiki-js",
-    "woodpecker": None,
 }
 
 icon_format = {
@@ -33,10 +29,17 @@ icon_format = {
     "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",
+    "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):
     svc = icon_overrides.get(svc, svc) or 'docker'
     fmt = icon_format.get(svc, 'svg')
-    return f'https://cdn.jsdelivr.net/gh/selfhst/icons/{fmt}/{svc}.{fmt}'
+    return icon_url.get(svc, f'https://cdn.jsdelivr.net/gh/selfhst/icons/{fmt}/{svc}.{fmt}')
 
 def host_key(host, hosts):
     return f"'serguzim.net'.{hosts[host]["provider"]}.{host}"

From 09c153a4e4d31357b1c3f43aa12739a85ff7e490 Mon Sep 17 00:00:00 2001
From: Tobias Reisinger <tobias@msrg.cc>
Date: Sat, 1 Feb 2025 02:53:05 +0100
Subject: [PATCH 3/5] Add new host and move factorio

---
 hosts.auto.tfvars                      |  8 ++++++++
 inventory/serguzim.net.yml             | 14 ++++++++++++++
 playbooks/roles/factorio/vars/main.yml |  4 ----
 services.auto.tfvars                   |  2 +-
 4 files changed, 23 insertions(+), 5 deletions(-)

diff --git a/hosts.auto.tfvars b/hosts.auto.tfvars
index 84504ed..f7334eb 100644
--- a/hosts.auto.tfvars
+++ b/hosts.auto.tfvars
@@ -7,6 +7,14 @@ hosts = {
     server_type = "cx32"
     datacenter = "fsn1-dc14"
   },
+  "node002" = {
+    hostname = "node002"
+    rdns = "node002.serguzim.net"
+    provider = "hetzner"
+    image = "debian-12"
+    server_type = "cx22"
+    datacenter = "fsn1-dc14"
+  },
   "node003" = {
     hostname = "node003"
     rdns = "mail.serguzim.me"
diff --git a/inventory/serguzim.net.yml b/inventory/serguzim.net.yml
index d1b31a1..2133f54 100644
--- a/inventory/serguzim.net.yml
+++ b/inventory/serguzim.net.yml
@@ -3,6 +3,7 @@ all:
     serguzim_net:
       hosts:
         node001:
+        node002:
         node003:
   hosts:
     local-dev:
@@ -21,6 +22,19 @@ all:
         hc_url: "{{ opentofu.healthchecksio.backup.node001.ping_url }}"
         gatus_token: "{{ vault_hosts.node001.backup.gatus_token }}" 
 
+    node002:
+      ansible_host: "{{ opentofu.hosts.node002.fqdn_vpn }}"
+      ansible_port: "{{ vault_hosts.node002.ansible_port }}"
+      ansible_user: "{{ vault_hosts.node002.ansible_user }}"
+      interactive_user: "{{ vault_hosts.node002.interactive_user }}"
+      host_vpn:
+        domain: "{{ opentofu.hosts.node002.fqdn_vpn }}"
+        ip: "{{ opentofu.hosts.node002.ipv4_address_vpn }}"
+      host_backup:
+        hc_uid: "{{ opentofu.healthchecksio.backup.node002.id }}"
+        hc_url: "{{ opentofu.healthchecksio.backup.node002.ping_url }}"
+        gatus_token: "{{ vault_hosts.node002.backup.gatus_token }}" 
+
     node003:
       ansible_host: "{{ opentofu.hosts.node003.fqdn_vpn }}"
       ansible_port: "{{ vault_hosts.node003.ansible_port }}"
diff --git a/playbooks/roles/factorio/vars/main.yml b/playbooks/roles/factorio/vars/main.yml
index 68c4187..d047915 100644
--- a/playbooks/roles/factorio/vars/main.yml
+++ b/playbooks/roles/factorio/vars/main.yml
@@ -3,10 +3,6 @@ factorio_port: 34197
 factorio_uid: 845
 factorio_gid: 845
 
-factorio_svc:
-  domain: "{{ all_services | service_get_domain(role_name) }}"
-  port: "{{ factorio_port }}"
-
 factorio_env:
   PORT: "{{ factorio_port }}"
   USERNAME: "{{ vault_factorio.username }}"
diff --git a/services.auto.tfvars b/services.auto.tfvars
index c506628..c71a035 100644
--- a/services.auto.tfvars
+++ b/services.auto.tfvars
@@ -129,7 +129,7 @@ services = {
   },
 
   "factorio" = {
-    host = "node001"
+    host = "node002"
     dns = [{
       domain = "factorio.serguzim.me"
     }]

From 315a8655eaf82cad1a0d934fd251f8c6671c370a Mon Sep 17 00:00:00 2001
From: Tobias Reisinger <tobias@msrg.cc>
Date: Mon, 10 Feb 2025 16:13:59 +0100
Subject: [PATCH 4/5] Update configs

Use temporary next image for woodpecker
Restrict SPF in mail
Fix factorio IP
---
 dns/default_records.js                   | 1 +
 dnsconfig.js                             | 1 +
 playbooks/roles/woodpecker/vars/main.yml | 4 ++--
 services.auto.tfvars                     | 2 +-
 4 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/dns/default_records.js b/dns/default_records.js
index e2af7b0..f9cf54b 100644
--- a/dns/default_records.js
+++ b/dns/default_records.js
@@ -5,6 +5,7 @@ function mx_default(dkim) {
 		CNAME("autodiscover", "mail.serguzim.me."),
 		SRV("_autodiscover._tcp", 1, 1, 443, "mail.serguzim.me."),
 
+		TXT("*", "v=spf1 -all"),
 		TXT("@", "v=spf1 mx -all"),
 		TXT("mail-ses", "v=spf1 include:amazonses.com -all"),
 
diff --git a/dnsconfig.js b/dnsconfig.js
index 245546b..427fc85 100644
--- a/dnsconfig.js
+++ b/dnsconfig.js
@@ -59,6 +59,7 @@ D("msrg.cc", REG_OVH, DnsProvider(DSP_OVH),
 //               |___/                                        
 D("serguzim.me", REG_OVH, DnsProvider(DSP_OVH),
 	all_defaults("serguzim.me", true),
+	TXT("direct", "v=spf1 mx -all"),
 
 	TLSA("_25._tcp.mail", 3, 1, 1, "e66a608a3ec459bda7fb1f2d500b8abeb78f2910f26641204b6bc454b8aa2a49"),
 
diff --git a/playbooks/roles/woodpecker/vars/main.yml b/playbooks/roles/woodpecker/vars/main.yml
index 81653ca..7fa61a5 100644
--- a/playbooks/roles/woodpecker/vars/main.yml
+++ b/playbooks/roles/woodpecker/vars/main.yml
@@ -33,11 +33,11 @@ woodpecker_env:
 
 woodpecker_compose:
   watchtower: update
-  image: woodpeckerci/woodpecker-server
+  image: woodpeckerci/woodpecker-server:next
   file:
     services:
       agent:
-        image: woodpeckerci/woodpecker-agent:latest
+        image: woodpeckerci/woodpecker-agent:next
         restart: always
         labels:
           com.centurylinklabs.watchtower.enable: true
diff --git a/services.auto.tfvars b/services.auto.tfvars
index c71a035..0b21e39 100644
--- a/services.auto.tfvars
+++ b/services.auto.tfvars
@@ -138,7 +138,7 @@ services = {
       type = "docker"
     }]
     monitoring = {
-      url = "https://multiplayer.factorio.com/get-game-details/49.13.212.188:34197"
+      url = "https://multiplayer.factorio.com/get-game-details/91.107.211.57:34197"
       group = "4-services"
       interval = "5m"
       conditions = [

From dd1267c284fe2a178782f9ecdd3074cbdf41c757 Mon Sep 17 00:00:00 2001
From: Tobias Reisinger <tobias@msrg.cc>
Date: Thu, 13 Mar 2025 17:23:03 +0100
Subject: [PATCH 5/5] Add minecraft_3 service

---
 .terraform.lock.hcl                        | 95 ++++++++--------------
 playbooks/roles/minecraft_3/tasks/main.yml | 11 +++
 playbooks/roles/minecraft_3/vars/main.yml  | 65 +++++++++++++++
 services.auto.tfvars                       | 24 ++++++
 4 files changed, 136 insertions(+), 59 deletions(-)
 create mode 100644 playbooks/roles/minecraft_3/tasks/main.yml
 create mode 100644 playbooks/roles/minecraft_3/vars/main.yml

diff --git a/.terraform.lock.hcl b/.terraform.lock.hcl
index d722e02..dc5f000 100644
--- a/.terraform.lock.hcl
+++ b/.terraform.lock.hcl
@@ -1,29 +1,6 @@
 # This file is maintained automatically by "tofu init".
 # Manual edits may be lost in future updates.
 
-provider "registry.opentofu.org/contabo/contabo" {
-  version     = "0.1.26"
-  constraints = "~> 0.1.26"
-  hashes = [
-    "h1:BfyKQiCyA0w/UY1ZN07u9bKDi3y9tbLaj30AsmwhPS4=",
-    "zh:13599dd31f62369779bcfc937c68a0fa0b3c865e9cfd805f204f78f995bd78b9",
-    "zh:19bcf3660ac7545103cf999e0066442f9d6350db9654e1496726520cef287246",
-    "zh:35d60f0e7f69cf87cca2451cfb7dd5a5a8a49663f08a114895da08fd86394412",
-    "zh:3d993f0dc113982a7b2c2fdb6828bed9738631cf3c1e94cd8ad2a7ecd7a806bd",
-    "zh:4aab2991ef6b81a5e6bc63af8a6711319d8c47cf2d2fde63f161f2cf6df4aea2",
-    "zh:5d01929898c6e04d99264d6dd58424311a6f17415d583c74cdafc52cecc672ce",
-    "zh:607c4619d312d5b76f4350961f3f37811a2b84084f1bc5626e0887110d5f7345",
-    "zh:60d429eadbdab2f4c55a943760a172332c9c095e5f368ed682709146372adbc4",
-    "zh:6e6234f31ba1f023314fe87b008cadae01d53f1fc96061500d1b2aa51276daef",
-    "zh:7438d416c7f15b4484942bbce11b6f06b8c035b2dfd6066abc9fd92b50c655de",
-    "zh:7a077cbcf5761e5ef55cb4202f97399da4ee9dfd2c5c32d05cf93b5351ef8aa9",
-    "zh:91dbe0e31261e055f6af165a79cbf46e5712fcd1c80c24cf2d6ee2dfe60879f7",
-    "zh:d7004852a590acfc299a273d02f22e5e7479ed40682adc65d28d2263a82168a9",
-    "zh:f4b3a98be793845e886a4bbfdbe4d3dc833e151ba58c7807530d9c9fa9d19075",
-    "zh:f69768aa6a33359ed22ad25eb8aca296086b8d65d2eff7e9b211c49aa2583f7d",
-  ]
-}
-
 provider "registry.opentofu.org/cyrilgdn/postgresql" {
   version     = "1.23.0"
   constraints = "~> 1.23"
@@ -69,37 +46,37 @@ provider "registry.opentofu.org/goauthentik/authentik" {
 }
 
 provider "registry.opentofu.org/hashicorp/aws" {
-  version     = "5.73.0"
+  version     = "5.90.1"
   constraints = "~> 5.0"
   hashes = [
-    "h1:pQKtkpKb4hzErmZakSW+HHXeJubUlBKu1/p0C/b1UuI=",
-    "zh:16a345cb7265937b13f999d644a38c68661844462f5ac7fda33b5aa35d3fdb9f",
-    "zh:1a28b36980e55c430faf6dfd93744b42fedd455ec53e5d848d89f503b8f7808e",
-    "zh:4303bc542d832ced373f64f8f154989affebc04704ae55f00b404167a512891d",
-    "zh:6079983b35df36c0980c6a7eabc17e9697e573ed0359bb07dc8004c40341ee5d",
-    "zh:711419826ce136e64fa172faffcdd23c25ad47e05a2b55be5deb5ae663ae399a",
-    "zh:7ac9ddb634dc98040b8db683b9d829c6654bcbd2cb6c15edaa85029780ea9d57",
-    "zh:8ce89e19e7e1ae84fa9eae98f79dd8654d774daabe2cc73e85d05d2dd00fcd08",
-    "zh:be420d05ec4d31a3a393c19831da10664a109a5ad527b7043f7a75059d694008",
-    "zh:c6552f1c4246afd1b8607edc4c29639846a530487c82663c51ddfb998a259eca",
-    "zh:d5a2a931f83625105c9502398f391165add5a886d950f193fc5721ad18dec273",
+    "h1:u//6jTzb1xx7ITJUAT7TkqcVgYNmo63uxpjMlbshKWI=",
+    "zh:090d7544b88d928049094f24d390d3432edc0ad191a096e68dd775500fe0ca1b",
+    "zh:0ce79633dd94ddb6d9789c540140c2afd67f45147367dbe56e01919fad2d1291",
+    "zh:12218248e4efbfa9ad0541acbb27e679e7d90e69c2d84bc8d731706ac6d75abf",
+    "zh:3ffd37af717ae1494c240a51519e3408c755feeb7865220101081f1116140fa9",
+    "zh:41c88889e7075a21e196255056e5d6899fa2ac4b59b1f2e267e5f838945f15f0",
+    "zh:8b4874a7c1d27788c15e83e303097a3235a9b2adc5fa6998bb1bd4770381e0a2",
+    "zh:a3677cee57d18a8ac70361f254366fd5af99d5e25930a14816fa4ab0c2b911db",
+    "zh:b22a4aae3e1b47c3d84cb070036375cd11888c1e678a4dbe263b5458f1d0870d",
+    "zh:c0c7490b6e2d4fe34a1a5e16a72e06e109ae2c75356ca2b559550f6f5b48324e",
+    "zh:edfc1927e0ace6b2520f11cb45672181c63a58218bf7f6a93daf37e0301919b7",
   ]
 }
 
 provider "registry.opentofu.org/hashicorp/random" {
-  version = "3.6.3"
+  version = "3.7.1"
   hashes = [
-    "h1:Ry0Lr0zaoicslZlcUR4rAySPpl/a7QupfMfuAxhW3fw=",
-    "zh:1bfd2e54b4eee8c761a40b6d99d45880b3a71abc18a9a7a5319204da9c8363b2",
-    "zh:21a15ac74adb8ba499aab989a4248321b51946e5431219b56fc827e565776714",
-    "zh:221acfac3f7a5bcd6cb49f79a1fca99da7679bde01017334bad1f951a12d85ba",
-    "zh:3026fcdc0c1258e32ab519df878579160b1050b141d6f7883b39438244e08954",
-    "zh:50d07a7066ea46873b289548000229556908c3be746059969ab0d694e053ee4c",
-    "zh:54280cdac041f2c2986a585f62e102bc59ef412cad5f4ebf7387c2b3a357f6c0",
-    "zh:632adf40f1f63b0c5707182853c10ae23124c00869ffff05f310aef2ed26fcf3",
-    "zh:b8c2876cce9a38501d14880a47e59a5182ee98732ad7e576e9a9ce686a46d8f5",
-    "zh:f27e6995e1e9fe3914a2654791fc8d67cdce44f17bf06e614ead7dfd2b13d3ae",
-    "zh:f423f2b7e5c814799ad7580b5c8ae23359d8d342264902f821c357ff2b3c6d3d",
+    "h1:v8+6umuoWwD1nKm+3tPcPO8rKHthran7ZSbm7J2xQEc=",
+    "zh:1011387a5127d46e2bf0bd5124a8469506272b2110613d9eb80d178f94bd67a9",
+    "zh:28785c36d6dc331d49e8bf6a30d4ba21ae4378f5d98c43c0aeb42f51efb2e42f",
+    "zh:50fc0e52f0255950404681455420344a16263f91622bd481954606e6e3be9eb2",
+    "zh:563f22c53f40e41cfffdcfac32a9292292c10582183c3f1dd85770cf806bfce9",
+    "zh:586a5615898d369374d4bd7d70bc013cffe7553d3e14638f169a3f745665fee1",
+    "zh:6275f6e5697993048ac088715484a9a5e919682651e098a5ac31e567216bf102",
+    "zh:95a44bb3f012da1e036936d60df2d08f5942a96cb912fc23432d2ee050857527",
+    "zh:a5fe6b0e586645a88d98738739fec40fd7ad83dbc63fe66ff6327aee2dc07f11",
+    "zh:ea57886899b6baf466f3ff978f4482d2fd7fa049c42509cc819431375cddd5bd",
+    "zh:f021cfbe23bdb32738f170c1ae736ffb769a2fa3dcafd0f9906155c2e21377e4",
   ]
 }
 
@@ -116,19 +93,19 @@ provider "registry.opentofu.org/hashicorp/template" {
 }
 
 provider "registry.opentofu.org/hashicorp/time" {
-  version = "0.12.1"
+  version = "0.13.0"
   hashes = [
-    "h1:PnOB6IAQJoYi/r3iUH7Hml2c2zFrIzHksQsrK3VPjSI=",
-    "zh:50a9b67d5f5f42adbdb7712f67858aa64b5670070f6710751239b535fb48a4df",
-    "zh:5a846fae035e363aed75b966d64a56f3489a38083e8407aaa656730437f53ed7",
-    "zh:6767f1fc8a679b48eaa4cd114da0d8185fb3546375f3a0fb3728f10fa3dbc551",
-    "zh:85d3da407c828bf057cbc0e86c75ef3d0f9f74a73c4ea1b4aef18e33f41092b1",
-    "zh:9180721325139431112c638f5382a740ff219782f81d6346cdff5bccc418a43f",
-    "zh:9ba9989f905a64db1409a9a57649549c89c7aedfb55ae399a7fa9411aafaadac",
-    "zh:b3d9e7afb6a742e9be0541bc434b00d849fdfab0b4b859ceb0296c26c541af15",
-    "zh:c87da712d718acd9dd03f544b020c320699cb29df197be4f74783e3c3d80fc17",
-    "zh:cb1abe07638ef6d7b41d0e86dfb12d60a513aca3395a5da7191947f7459821dd",
-    "zh:ecff2e823ef49eda03663fa8ee8bdc17d27cd419dbdacbf1719f38812dbf417e",
+    "h1:X8s0NRd/o8QrLCU/60vIgcicBmndwggB4znQrGpOT2E=",
+    "zh:0e0a5f820793f13d8553742fac6c234f76e65bd095703a81f8f9cad38361d6c6",
+    "zh:11f2d5b5076d17814986886164bd4a4ce6448129baa529c21f658e949687f06f",
+    "zh:1a59c8d7da0c8155a86dffb1716bb5f2884b221a13167d5e7bcffb2ac192ba3f",
+    "zh:1e7abd01ef573294c0f2f1e2b30190c05a98afb7815d7a309fc10193bff4b4dd",
+    "zh:3ca53edfae9adffe1ee9c040e83b076fde89d73e7b2e6dc2de19d408e3f52a40",
+    "zh:5beb2cd0abe5376ff5e76d4f93d20c4740b333c1abc5ca72083e1cc85ffb29dd",
+    "zh:a775d153ba932834401eb1d9151f462c1e49d47494152d282d3e6981b3e591c0",
+    "zh:aac6802f60bf708172f09ead7a13177ab6a47f5a3eca458e935f422ed409f4a6",
+    "zh:d4e5ad0041d752b94317093e8063e6b766982f647cfe3cc1a3f4a10930383357",
+    "zh:fef228471c7223a558a1b6054ec7e8837526dc9787ba9da5dc6fbfa1c762cd1b",
   ]
 }
 
diff --git a/playbooks/roles/minecraft_3/tasks/main.yml b/playbooks/roles/minecraft_3/tasks/main.yml
new file mode 100644
index 0000000..f579f11
--- /dev/null
+++ b/playbooks/roles/minecraft_3/tasks/main.yml
@@ -0,0 +1,11 @@
+---
+- name: Set common facts
+  ansible.builtin.import_tasks: tasks/set-default-facts.yml
+
+- name: Deploy {{ role_name }}
+  vars:
+    env: "{{ minecraft_3_env }}"
+    compose: "{{ minecraft_3_compose }}"
+  block:
+    - name: Import tasks to deploy common service
+      ansible.builtin.import_tasks: tasks/deploy-common-service.yml
diff --git a/playbooks/roles/minecraft_3/vars/main.yml b/playbooks/roles/minecraft_3/vars/main.yml
new file mode 100644
index 0000000..9135c22
--- /dev/null
+++ b/playbooks/roles/minecraft_3/vars/main.yml
@@ -0,0 +1,65 @@
+---
+minecraft_3_env:
+  ALLOW_FLIGHT: true
+  ALLOW_NETHER: true
+  ANNOUNCE_PLAYER_ACHIEVEMENTS: true
+  BROADCAST_CONSOLE_TO_OPS: true
+  BROADCAST_RCON_TO_OPS: true
+  CONSOLE: false
+  ENABLE_AUTOPAUSE: true
+  ENABLE_COMMAND_BLOCK: true
+  ENABLE_JMX: false
+  ENABLE_RCON: true
+  ENABLE_STATUS: true
+  ENABLE_WHITELIST: true
+  ENFORCE_WHITELIST: true
+  ENTITY_BROADCAST_RANGE_PERCENTAGE: 100
+  EULA: true
+  FORCE_GAMEMODE: false
+  FUNCTION_PERMISSION_LEVEL: 2
+  GENERATE_STRUCTURES: true
+  HARDCORDE: false
+  ICON:
+  LEVEL_TYPE: DEFAULT
+  MAX_BUILD_HEIGHT: 512
+  MAX_MEMORY: 4G
+  MAX_TICK_TIME: -1
+  MAX_PLAYERS: 64
+  MAX_WORLD_SIZE: 30000000
+  MODE: survival
+  MOTD:
+  NETWORK_COMPRESSION_THRESHOLD: 256
+  PVP: true
+  SERVER_NAME: minecraft.serguzim.me
+  SNOOPER_ENABLED: false
+  SPAWN_ANIMALS: true
+  SPAWN_MONSTERS: true
+  SPAWN_NPCS: true
+  SPAWN_PROTECTION: 0
+  SYNC_CHUNK_WRITES: true
+  TYPE: PAPER
+  ONLINE_MODE: true
+  OP_PERMISSION_LEVEL: 4
+  OPS: "{{ vault_minecraft_3.ops }}"
+  OVERRIDE_ICON: true
+  OVERRIDE_SERVER_PROPERTIES: true
+  PLAYER_IDLE_TIMEOUT: 0
+  PREVENT_PROXY_CONNECTIONS: false
+  SEED: "{{ vault_minecraft_3.seed }}"
+  USE_NATIVE_TRANSPORT: true
+  VERSION: LATEST
+  VIEW_DISTANCE: 10
+  WHITELIST: "{{ vault_minecraft_3.whitelist }}"
+
+minecraft_3_compose:
+  watchtower: false
+  image: itzg/minecraft-server
+  volumes:
+    - data:/data
+  file:
+    services:
+      app:
+        ports:
+          - 25565:25565
+    volumes:
+      data:
diff --git a/services.auto.tfvars b/services.auto.tfvars
index 0b21e39..bbb6c78 100644
--- a/services.auto.tfvars
+++ b/services.auto.tfvars
@@ -397,6 +397,30 @@ services = {
     s3 = false
   },
 
+  "minecraft_3" = {
+    host = "node002"
+    dns = [
+      {
+        domain = "minecraft.serguzim.me"
+      }
+    ]
+    ports = [
+      {
+        description = "Game port for minecraft"
+        port = 25565
+        protocol = "tcp"
+        type = "firewall"
+      }
+    ]
+    backup = [{
+      name = "minecraft_3_data"
+      type = "docker"
+    }]
+    auth = false
+    database = false
+    s3 = false
+  },
+
   "minio" = {
     host = "node001"
     dns = [