diff --git a/modules/infrastructure/hcloud.tf b/modules/infrastructure/hcloud.tf
index 079cc49..bd67ac8 100644
--- a/modules/infrastructure/hcloud.tf
+++ b/modules/infrastructure/hcloud.tf
@@ -49,6 +49,11 @@ resource "hcloud_server" "nodes" {
     ipv4 = hcloud_primary_ip.node_ipv4_addresses[each.key].id
     ipv6 = hcloud_primary_ip.node_ipv6_addresses[each.key].id
   }
+  labels = merge({
+    "serguzim.net" = ""
+  },
+    { for k, v in var.services : "service/${k}" => "" if (v.host == each.key || v.host == "*") }
+  )
   lifecycle {
     ignore_changes = [
       ssh_keys,
@@ -64,3 +69,39 @@ resource "hcloud_rdns" "nodes_rdns" {
   ip_address = hcloud_server.nodes[each.key].ipv4_address
   dns_ptr    = each.value.rdns
 }
+
+locals {
+  default_firewall_source_ips = [ "0.0.0.0/0", "::/0" ]
+}
+
+# Create firewalls
+resource "hcloud_firewall" "always" {
+  name = "always"
+  apply_to {
+    label_selector = "serguzim.net"
+  }
+
+  rule {
+    direction = "in"
+    protocol  = "icmp"
+    source_ips = local.default_firewall_source_ips
+  }
+}
+
+resource "hcloud_firewall" "services" {
+  for_each = { for k, v in var.services : k => v.ports if v.ports != null }
+  name = each.key
+  apply_to {
+    label_selector = "service/${each.key}"
+  }
+
+  dynamic "rule" {
+    for_each = each.value
+    content {
+      direction   = "in"
+      protocol    = rule.value.protocol
+      port        = rule.value.port
+      source_ips  = local.default_firewall_source_ips
+    }
+  }
+}  
diff --git a/modules/infrastructure/variables.tf b/modules/infrastructure/variables.tf
index a13813a..ba6ffe6 100644
--- a/modules/infrastructure/variables.tf
+++ b/modules/infrastructure/variables.tf
@@ -22,6 +22,11 @@ variable "services" {
       name = string
       type = string
     })))
+    ports = optional(list(object({
+      port = number
+      protocol = string
+      type = string
+    })))
     auth = bool
     auth_cert = optional(string)
     auth_redirects = optional(list(string))
diff --git a/services.auto.tfvars b/services.auto.tfvars
index 8862d15..121bd6e 100644
--- a/services.auto.tfvars
+++ b/services.auto.tfvars
@@ -8,6 +8,18 @@ services = {
       url = "/health"
       group = "7-support"
     }
+    ports = [
+      {
+        port = 53
+        protocol = "tcp"
+        type = "firewall"
+      },
+      {
+        port = 53
+        protocol = "udp"
+        type = "firewall"
+      }
+    ]
     auth = false
     database = true
     s3 = false
@@ -51,7 +63,7 @@ services = {
       },
       {
         port = 443
-        protocol = "tcp"
+        protocol = "udp"
         type = "reverse_proxy"
       },
       #"2019:2019",
@@ -91,6 +103,13 @@ services = {
     monitoring = {
       group = "7-support"
     }
+    ports = [
+      {
+        port = 3022
+        protocol = "tcp"
+        type = "firewall"
+      }
+    ]
     auth = false
     database = false
     s3 = false
@@ -116,6 +135,13 @@ services = {
       url = "/api/v1/version"
       group = "4-services"
     }
+    ports = [
+      {
+        port = 22
+        protocol = "tcp"
+        type = "firewall"
+      }
+    ]
     auth = true
     auth_redirects = ["https://git.serguzim.me/user/oauth2/auth.serguzim.me/callback"]
     database = true
@@ -285,6 +311,38 @@ services = {
     monitoring = {
       group = "4-services"
     }
+    ports = [
+      {
+        port = 25 # SMTP
+        protocol = "tcp"
+        type = "firewall"
+      },
+      {
+        port = 465 # SMTP TLS
+        protocol = "tcp"
+        type = "firewall"
+      },
+      {
+        port = 587 # SMTP StartTLS
+        protocol = "tcp"
+        type = "firewall"
+      },
+      {
+        port = 993 # IMAPS
+        protocol = "tcp"
+        type = "firewall"
+      },
+      {
+        port = 995 # POPS
+        protocol = "tcp"
+        type = "firewall"
+      },
+      {
+        port = 4190 # Sieve
+        protocol = "tcp"
+        type = "firewall"
+      }
+    ]
     auth = false
     database = false
     s3 = false