diff --git a/docker-network/inputs.tf b/docker/network/inputs.tf
similarity index 100%
rename from docker-network/inputs.tf
rename to docker/network/inputs.tf
diff --git a/docker-network/network.tf b/docker/network/network.tf
similarity index 100%
rename from docker-network/network.tf
rename to docker/network/network.tf
diff --git a/docker-network/outputs.tf b/docker/network/outputs.tf
similarity index 100%
rename from docker-network/outputs.tf
rename to docker/network/outputs.tf
diff --git a/docker-apt-caching-proxy/terraform.tf b/docker/network/terraform.tf
similarity index 100%
rename from docker-apt-caching-proxy/terraform.tf
rename to docker/network/terraform.tf
diff --git a/docker-service/inputs.tf b/docker/service/inputs.tf
similarity index 100%
rename from docker-service/inputs.tf
rename to docker/service/inputs.tf
diff --git a/docker-service/outputs.tf b/docker/service/outputs.tf
similarity index 100%
rename from docker-service/outputs.tf
rename to docker/service/outputs.tf
diff --git a/docker-service/service.tf b/docker/service/service.tf
similarity index 100%
rename from docker-service/service.tf
rename to docker/service/service.tf
diff --git a/docker-service/terraform.tf b/docker/service/terraform.tf
similarity index 100%
rename from docker-service/terraform.tf
rename to docker/service/terraform.tf
diff --git a/dockerd-socket-proxy/inputs.tf b/docker/socket-proxy/inputs.tf
similarity index 100%
rename from dockerd-socket-proxy/inputs.tf
rename to docker/socket-proxy/inputs.tf
diff --git a/dockerd-socket-proxy/socket-proxy.tf b/docker/socket-proxy/socket-proxy.tf
similarity index 91%
rename from dockerd-socket-proxy/socket-proxy.tf
rename to docker/socket-proxy/socket-proxy.tf
index b73659f..55f8680 100644
--- a/dockerd-socket-proxy/socket-proxy.tf
+++ b/docker/socket-proxy/socket-proxy.tf
@@ -1,10 +1,10 @@
 module "network" {
-  source     = "../docker-network"
+  source     = "../network"
   name       = "docker-socket-proxy"
   stack_name = var.stack_name
 }
 module "service" {
-  source       = "../docker-service"
+  source       = "../service"
   image        = "${var.docker_socket_proxy_image}:${var.docker_socket_proxy_version}"
   command      = ["/docker-entrypoint.sh", "sockd-username"]
   stack_name   = var.stack_name
diff --git a/dockerd-socket-proxy/terraform.tf b/docker/socket-proxy/terraform.tf
similarity index 100%
rename from dockerd-socket-proxy/terraform.tf
rename to docker/socket-proxy/terraform.tf
diff --git a/docker-apt-caching-proxy/apt-caching-proxy.tf b/products/apt-caching-proxy/apt-caching-proxy.tf
similarity index 85%
rename from docker-apt-caching-proxy/apt-caching-proxy.tf
rename to products/apt-caching-proxy/apt-caching-proxy.tf
index 6506a7b..3a4d232 100644
--- a/docker-apt-caching-proxy/apt-caching-proxy.tf
+++ b/products/apt-caching-proxy/apt-caching-proxy.tf
@@ -1,5 +1,5 @@
 module "ap" {
-  source                = "../docker-service"
+  source                = "../../docker/service"
   image                 = "sameersbn/apt-cacher-ng"
   stack_name            = "apt-caching-proxy"
   service_name          = "apt-caching-proxy"
diff --git a/docker-apt-caching-proxy/inputs.tf b/products/apt-caching-proxy/inputs.tf
similarity index 100%
rename from docker-apt-caching-proxy/inputs.tf
rename to products/apt-caching-proxy/inputs.tf
diff --git a/docker-archiveteam-warrior/terraform.tf b/products/apt-caching-proxy/terraform.tf
similarity index 100%
rename from docker-archiveteam-warrior/terraform.tf
rename to products/apt-caching-proxy/terraform.tf
diff --git a/docker-archiveteam-warrior/inputs.tf b/products/archiveteam/warrior/inputs.tf
similarity index 100%
rename from docker-archiveteam-warrior/inputs.tf
rename to products/archiveteam/warrior/inputs.tf
diff --git a/docker-archiveteam-warrior/locals.tf b/products/archiveteam/warrior/locals.tf
similarity index 100%
rename from docker-archiveteam-warrior/locals.tf
rename to products/archiveteam/warrior/locals.tf
diff --git a/docker-archiveteam-warrior/outputs.tf b/products/archiveteam/warrior/outputs.tf
similarity index 100%
rename from docker-archiveteam-warrior/outputs.tf
rename to products/archiveteam/warrior/outputs.tf
diff --git a/docker-forgejo-actions-runner/terraform.tf b/products/archiveteam/warrior/terraform.tf
similarity index 100%
rename from docker-forgejo-actions-runner/terraform.tf
rename to products/archiveteam/warrior/terraform.tf
diff --git a/docker-archiveteam-warrior/warrior.tf b/products/archiveteam/warrior/warrior.tf
similarity index 93%
rename from docker-archiveteam-warrior/warrior.tf
rename to products/archiveteam/warrior/warrior.tf
index 73d6550..7fcddfe 100644
--- a/docker-archiveteam-warrior/warrior.tf
+++ b/products/archiveteam/warrior/warrior.tf
@@ -1,5 +1,5 @@
 module "warrior" {
-  source                = "../docker-service"
+  source                = "../../../docker/service"
   image                 = "atdr.meo.ws/archiveteam/warrior-dockerfile"
   stack_name            = "archiveteam"
   service_name          = var.service_name
diff --git a/docker-forgejo-actions-runner/forgejo-runner.tf b/products/forgejo/actions-runner/forgejo-runner.tf
similarity index 97%
rename from docker-forgejo-actions-runner/forgejo-runner.tf
rename to products/forgejo/actions-runner/forgejo-runner.tf
index 0f1e24a..a3e0ad2 100644
--- a/docker-forgejo-actions-runner/forgejo-runner.tf
+++ b/products/forgejo/actions-runner/forgejo-runner.tf
@@ -1,5 +1,5 @@
 module "forgejo_actions_runner" {
-  source                = "../docker-service"
+  source                = "../../../docker/service"
   service_name          = var.service_name
   stack_name            = var.stack_name
   placement_constraints = var.placement_constraints
diff --git a/docker-forgejo-actions-runner/inputs.tf b/products/forgejo/actions-runner/inputs.tf
similarity index 100%
rename from docker-forgejo-actions-runner/inputs.tf
rename to products/forgejo/actions-runner/inputs.tf
diff --git a/docker-gitea-actions-runner/terraform.tf b/products/forgejo/actions-runner/terraform.tf
similarity index 100%
rename from docker-gitea-actions-runner/terraform.tf
rename to products/forgejo/actions-runner/terraform.tf
diff --git a/docker-gitea-actions-runner/gitea-runner.tf b/products/gitea/actions-runner/gitea-runner.tf
similarity index 97%
rename from docker-gitea-actions-runner/gitea-runner.tf
rename to products/gitea/actions-runner/gitea-runner.tf
index efa7043..f472446 100644
--- a/docker-gitea-actions-runner/gitea-runner.tf
+++ b/products/gitea/actions-runner/gitea-runner.tf
@@ -1,5 +1,5 @@
 module "gitea_actions_runner" {
-  source                = "../docker-service"
+  source                = "./../../../docker/service"
   service_name          = var.service_name
   stack_name            = var.stack_name
   placement_constraints = var.placement_constraints
diff --git a/docker-gitea-actions-runner/inputs.tf b/products/gitea/actions-runner/inputs.tf
similarity index 100%
rename from docker-gitea-actions-runner/inputs.tf
rename to products/gitea/actions-runner/inputs.tf
diff --git a/docker-github-actions-runner/terraform.tf b/products/gitea/actions-runner/terraform.tf
similarity index 100%
rename from docker-github-actions-runner/terraform.tf
rename to products/gitea/actions-runner/terraform.tf
diff --git a/docker-github-actions-runner/gha-runner.tf b/products/github/actions-runner/gha-runner.tf
similarity index 93%
rename from docker-github-actions-runner/gha-runner.tf
rename to products/github/actions-runner/gha-runner.tf
index 0ed208a..9ef6057 100644
--- a/docker-github-actions-runner/gha-runner.tf
+++ b/products/github/actions-runner/gha-runner.tf
@@ -1,5 +1,5 @@
 module "github_actions_runner" {
-  source                = "../docker-service"
+  source                = "../../../docker/service"
   service_name          = var.service_name
   stack_name            = var.stack_name
   placement_constraints = var.placement_constraints
diff --git a/docker-github-actions-runner/inputs.tf b/products/github/actions-runner/inputs.tf
similarity index 100%
rename from docker-github-actions-runner/inputs.tf
rename to products/github/actions-runner/inputs.tf
diff --git a/docker-network/terraform.tf b/products/github/actions-runner/terraform.tf
similarity index 100%
rename from docker-network/terraform.tf
rename to products/github/actions-runner/terraform.tf
diff --git a/nginx/.gitignore b/products/nginx/.gitignore
similarity index 100%
rename from nginx/.gitignore
rename to products/nginx/.gitignore
diff --git a/nginx/default.conf b/products/nginx/default.conf
similarity index 100%
rename from nginx/default.conf
rename to products/nginx/default.conf
diff --git a/nginx/default_page.tf b/products/nginx/default_page.tf
similarity index 100%
rename from nginx/default_page.tf
rename to products/nginx/default_page.tf
diff --git a/nginx/inputs.tf b/products/nginx/inputs.tf
similarity index 100%
rename from nginx/inputs.tf
rename to products/nginx/inputs.tf
diff --git a/nginx/nginx.tf b/products/nginx/nginx.tf
similarity index 100%
rename from nginx/nginx.tf
rename to products/nginx/nginx.tf
diff --git a/nginx/nginx-site-available/basic-auth.tf b/products/nginx/site-available/basic-auth.tf
similarity index 100%
rename from nginx/nginx-site-available/basic-auth.tf
rename to products/nginx/site-available/basic-auth.tf
diff --git a/nginx/nginx-site-available/cert.tf b/products/nginx/site-available/cert.tf
similarity index 100%
rename from nginx/nginx-site-available/cert.tf
rename to products/nginx/site-available/cert.tf
diff --git a/nginx/nginx-site-available/config.tf b/products/nginx/site-available/config.tf
similarity index 100%
rename from nginx/nginx-site-available/config.tf
rename to products/nginx/site-available/config.tf
diff --git a/nginx/nginx-site-available/inputs.tf b/products/nginx/site-available/inputs.tf
similarity index 100%
rename from nginx/nginx-site-available/inputs.tf
rename to products/nginx/site-available/inputs.tf
diff --git a/nginx/nginx-site-available/nginx_template.conf b/products/nginx/site-available/nginx_template.conf
similarity index 100%
rename from nginx/nginx-site-available/nginx_template.conf
rename to products/nginx/site-available/nginx_template.conf
diff --git a/nginx/nginx-site-available/outputs.tf b/products/nginx/site-available/outputs.tf
similarity index 100%
rename from nginx/nginx-site-available/outputs.tf
rename to products/nginx/site-available/outputs.tf
diff --git a/nginx/nginx-site-available/terraform.tf b/products/nginx/site-available/terraform.tf
similarity index 100%
rename from nginx/nginx-site-available/terraform.tf
rename to products/nginx/site-available/terraform.tf
diff --git a/nginx/terraform.tf b/products/nginx/terraform.tf
similarity index 100%
rename from nginx/terraform.tf
rename to products/nginx/terraform.tf
diff --git a/docker-pgbackweb/inputs.tf b/products/pgbackweb/inputs.tf
similarity index 100%
rename from docker-pgbackweb/inputs.tf
rename to products/pgbackweb/inputs.tf
diff --git a/docker-pgbackweb/nginx.tf b/products/pgbackweb/nginx.tf
similarity index 93%
rename from docker-pgbackweb/nginx.tf
rename to products/pgbackweb/nginx.tf
index d110cf6..ecec129 100644
--- a/docker-pgbackweb/nginx.tf
+++ b/products/pgbackweb/nginx.tf
@@ -13,7 +13,7 @@ variable "acme_certificate" {
 
 module "nginx_config" {
   count         = var.nginx_hostname != null ? 1 : 0
-  source        = "../nginx/nginx-site-available"
+  source        = "../nginx/site-available"
   service_name  = module.pgbackweb.service_name
   hostname      = var.nginx_hostname
   upstream_host = "${module.pgbackweb.service_name}:8085"
diff --git a/docker-pgbackweb/pgbackweb.tf b/products/pgbackweb/pgbackweb.tf
similarity index 90%
rename from docker-pgbackweb/pgbackweb.tf
rename to products/pgbackweb/pgbackweb.tf
index 9c8c026..3e0a6ee 100644
--- a/docker-pgbackweb/pgbackweb.tf
+++ b/products/pgbackweb/pgbackweb.tf
@@ -1,5 +1,5 @@
 module "network" {
-  source     = "../docker-network"
+  source     = "../../docker/network"
   stack_name = var.stack_name
 }
 resource "random_password" "encryption_key" {
@@ -7,7 +7,7 @@ resource "random_password" "encryption_key" {
   special = false
 }
 module "pgbackweb" {
-  source = "../docker-service"
+  source = "../../docker/service"
   image  = "${var.pgbackweb_image}:${var.pgbackweb_version}"
   environment_variables = {
     PBW_ENCRYPTION_KEY       = nonsensitive(random_password.encryption_key.result)
@@ -19,7 +19,7 @@ module "pgbackweb" {
   placement_constraints = var.placement_constraints
 }
 module "postgres" {
-  source                = "../docker-postgres"
+  source                = "../postgres"
   postgres_version      = "16"
   stack_name            = var.stack_name
   networks              = [module.network.network]
diff --git a/docker-http-proxy/terraform.tf b/products/pgbackweb/terraform.tf
similarity index 100%
rename from docker-http-proxy/terraform.tf
rename to products/pgbackweb/terraform.tf
diff --git a/docker-portainer/docker-portainer-edge-agent/agent.tf b/products/portainer/edge-agent/agent.tf
similarity index 100%
rename from docker-portainer/docker-portainer-edge-agent/agent.tf
rename to products/portainer/edge-agent/agent.tf
diff --git a/docker-portainer/docker-portainer-edge-agent/input.tf b/products/portainer/edge-agent/input.tf
similarity index 100%
rename from docker-portainer/docker-portainer-edge-agent/input.tf
rename to products/portainer/edge-agent/input.tf
diff --git a/docker-portainer/docker-portainer-edge-agent/terraform.tf b/products/portainer/edge-agent/terraform.tf
similarity index 100%
rename from docker-portainer/docker-portainer-edge-agent/terraform.tf
rename to products/portainer/edge-agent/terraform.tf
diff --git a/docker-portainer/docker-portainer-ui/inputs.tf b/products/portainer/ui/inputs.tf
similarity index 100%
rename from docker-portainer/docker-portainer-ui/inputs.tf
rename to products/portainer/ui/inputs.tf
diff --git a/docker-portainer/docker-portainer-ui/output.tf b/products/portainer/ui/output.tf
similarity index 100%
rename from docker-portainer/docker-portainer-ui/output.tf
rename to products/portainer/ui/output.tf
diff --git a/docker-portainer/docker-portainer-ui/terraform.tf b/products/portainer/ui/terraform.tf
similarity index 100%
rename from docker-portainer/docker-portainer-ui/terraform.tf
rename to products/portainer/ui/terraform.tf
diff --git a/docker-portainer/docker-portainer-ui/ui.tf b/products/portainer/ui/ui.tf
similarity index 100%
rename from docker-portainer/docker-portainer-ui/ui.tf
rename to products/portainer/ui/ui.tf
diff --git a/docker-postgres/credentials.tf b/products/postgres/credentials.tf
similarity index 100%
rename from docker-postgres/credentials.tf
rename to products/postgres/credentials.tf
diff --git a/docker-postgres/inputs.tf b/products/postgres/inputs.tf
similarity index 100%
rename from docker-postgres/inputs.tf
rename to products/postgres/inputs.tf
diff --git a/docker-postgres/outputs.tf b/products/postgres/outputs.tf
similarity index 100%
rename from docker-postgres/outputs.tf
rename to products/postgres/outputs.tf
diff --git a/docker-postgres/postgres.tf b/products/postgres/postgres.tf
similarity index 93%
rename from docker-postgres/postgres.tf
rename to products/postgres/postgres.tf
index 23d9bef..fb83dba 100644
--- a/docker-postgres/postgres.tf
+++ b/products/postgres/postgres.tf
@@ -1,5 +1,5 @@
 module "service" {
-  source       = "../docker-service"
+  source       = "../../docker/service"
   image        = "${var.postgres_image}:${var.postgres_version}"
   stack_name   = var.stack_name
   service_name = "postgres"
diff --git a/docker-postgres/terraform.tf b/products/postgres/terraform.tf
similarity index 100%
rename from docker-postgres/terraform.tf
rename to products/postgres/terraform.tf
diff --git a/docker-quassel/inputs.tf b/products/quassel/inputs.tf
similarity index 100%
rename from docker-quassel/inputs.tf
rename to products/quassel/inputs.tf
diff --git a/docker-quassel/outputs.tf b/products/quassel/outputs.tf
similarity index 100%
rename from docker-quassel/outputs.tf
rename to products/quassel/outputs.tf
diff --git a/docker-quassel/quassel.tf b/products/quassel/quassel.tf
similarity index 90%
rename from docker-quassel/quassel.tf
rename to products/quassel/quassel.tf
index e3c8b38..2d89fc1 100644
--- a/docker-quassel/quassel.tf
+++ b/products/quassel/quassel.tf
@@ -1,9 +1,9 @@
 module "network" {
-  source     = "../docker-network"
+  source     = "../../docker/network"
   stack_name = var.stack_name
 }
 module "postgres" {
-  source                = "../docker-postgres"
+  source                = "../postgres"
   postgres_version      = "16"
   stack_name            = var.stack_name
   networks              = [module.network.network]
@@ -13,7 +13,7 @@ module "postgres" {
   ports                 = [{ container = 5432, host = 65432 }]
 }
 module "service" {
-  source       = "../docker-service"
+  source       = "../../docker/service"
   image        = "${var.quassel_image}:${var.quassel_version}"
   stack_name   = var.stack_name
   service_name = "quassel"
diff --git a/docker-quassel/terraform.tf b/products/quassel/terraform.tf
similarity index 100%
rename from docker-quassel/terraform.tf
rename to products/quassel/terraform.tf
diff --git a/docker-redis/credentials.tf b/products/redis/credentials.tf
similarity index 100%
rename from docker-redis/credentials.tf
rename to products/redis/credentials.tf
diff --git a/docker-redis/inputs.tf b/products/redis/inputs.tf
similarity index 100%
rename from docker-redis/inputs.tf
rename to products/redis/inputs.tf
diff --git a/docker-redis/outputs.tf b/products/redis/outputs.tf
similarity index 100%
rename from docker-redis/outputs.tf
rename to products/redis/outputs.tf
diff --git a/docker-redis/postgres.tf b/products/redis/postgres.tf
similarity index 91%
rename from docker-redis/postgres.tf
rename to products/redis/postgres.tf
index ee280ef..aa0d9c6 100644
--- a/docker-redis/postgres.tf
+++ b/products/redis/postgres.tf
@@ -1,5 +1,5 @@
 module "service" {
-  source       = "../docker-service"
+  source       = "../../docker/service"
   image        = "${var.redis_image}:${var.redis_version}"
   command      = ["redis-server", "--requirepass", local.auth, "--appendonly", "yes", "--save", 60, 1, "--loglevel", "warning"]
   stack_name   = var.stack_name
diff --git a/docker-redis/terraform.tf b/products/redis/terraform.tf
similarity index 100%
rename from docker-redis/terraform.tf
rename to products/redis/terraform.tf
diff --git a/docker-statping/inputs.tf b/products/statping/inputs.tf
similarity index 100%
rename from docker-statping/inputs.tf
rename to products/statping/inputs.tf
diff --git a/docker-statping/nginx.tf b/products/statping/nginx.tf
similarity index 92%
rename from docker-statping/nginx.tf
rename to products/statping/nginx.tf
index 08fae51..64ce7cd 100644
--- a/docker-statping/nginx.tf
+++ b/products/statping/nginx.tf
@@ -12,7 +12,7 @@ variable "acme_certificate" {
 }
 module "nginx_config" {
   count         = var.nginx_hostname != null ? 1 : 0
-  source        = "../nginx/nginx-site-available"
+  source        = "../nginx/site-available"
   service_name  = module.service.service_name
   hostname      = var.nginx_hostname
   upstream_host = "${module.service.service_name}:8080"
diff --git a/docker-statping/outputs.tf b/products/statping/outputs.tf
similarity index 100%
rename from docker-statping/outputs.tf
rename to products/statping/outputs.tf
diff --git a/docker-statping/statping.tf b/products/statping/statping.tf
similarity index 88%
rename from docker-statping/statping.tf
rename to products/statping/statping.tf
index 03cc276..dd7ce47 100644
--- a/docker-statping/statping.tf
+++ b/products/statping/statping.tf
@@ -1,9 +1,9 @@
 module "network" {
-  source     = "../docker-network"
+  source     = "../../docker/network"
   stack_name = var.stack_name
 }
 module "postgres" {
-  source                = "../docker-postgres"
+  source                = "../../products/postgres"
   postgres_version      = "16"
   stack_name            = var.stack_name
   networks              = [module.network.network]
@@ -11,7 +11,7 @@ module "postgres" {
   ports                 = [{ container = 5432, host = 65200 }]
 }
 module "service" {
-  source       = "../docker-service"
+  source       = "../../docker/service"
   image        = "${var.statping_image}:${var.statping_version}"
   stack_name   = var.stack_name
   service_name = "statping"
diff --git a/docker-statping/terraform.tf b/products/statping/terraform.tf
similarity index 100%
rename from docker-statping/terraform.tf
rename to products/statping/terraform.tf
diff --git a/docker-http-proxy/inputs.tf b/products/threeproxy/inputs.tf
similarity index 100%
rename from docker-http-proxy/inputs.tf
rename to products/threeproxy/inputs.tf
diff --git a/docker-http-proxy/outputs.tf b/products/threeproxy/outputs.tf
similarity index 100%
rename from docker-http-proxy/outputs.tf
rename to products/threeproxy/outputs.tf
diff --git a/docker-http-proxy/proxy.tf b/products/threeproxy/proxy.tf
similarity index 96%
rename from docker-http-proxy/proxy.tf
rename to products/threeproxy/proxy.tf
index 9598cbe..6779dae 100644
--- a/docker-http-proxy/proxy.tf
+++ b/products/threeproxy/proxy.tf
@@ -12,7 +12,7 @@ locals {
   http_endpoint  = "http://${local.username}:${local.password}@${var.endpoint}:${var.http_proxy_port}"
 }
 module "service" {
-  source       = "../docker-service"
+  source       = "../../docker/service"
   image        = "${var.threeproxy_image}:${var.threeproxy_version}"
   stack_name   = var.stack_name
   service_name = var.service_name
diff --git a/docker-pgbackweb/terraform.tf b/products/threeproxy/terraform.tf
similarity index 100%
rename from docker-pgbackweb/terraform.tf
rename to products/threeproxy/terraform.tf
diff --git a/products/unifi/magic-forward/input.tf b/products/unifi/magic-forward/input.tf
new file mode 100644
index 0000000..2d8b2a5
--- /dev/null
+++ b/products/unifi/magic-forward/input.tf
@@ -0,0 +1,45 @@
+variable "enabled" {
+  default     = true
+  description = "Whether the port forward should be enabled"
+  type        = bool
+}
+variable "label" {
+  description = "The label of the port forward"
+  type        = string
+}
+variable "docker_service" {
+  description = "The Docker Service to forward to"
+  type = object({
+    name = string
+    endpoint_spec = list(object({
+      protocol       = optional(string)
+      target_port    = optional(number)
+      published_port = number
+    }))
+  })
+}
+variable "target" {
+  description = "The Target Host to forward traffic to"
+  type = object({
+    mac              = string
+    name             = string
+    fixed_ip         = string
+    local_dns_record = optional(string)
+    dev_id_override  = optional(string)
+  })
+}
+variable "protocol" {
+  default     = "tcp"
+  description = "The protocol to use for the port forward"
+  type        = string
+  validation {
+    condition     = var.protocol == "tcp" || var.protocol == "udp" || var.protocol == "any"
+    error_message = "Protocol must be either tcp or udp or any!"
+  }
+}
+
+variable "port" {
+  description = "Override the detected port to forward"
+  type        = number
+  default     = null
+}
\ No newline at end of file
diff --git a/products/unifi/magic-forward/magic_forward.tf b/products/unifi/magic-forward/magic_forward.tf
new file mode 100644
index 0000000..9f0d4bb
--- /dev/null
+++ b/products/unifi/magic-forward/magic_forward.tf
@@ -0,0 +1,7 @@
+module "port_forward" {
+  source  = "../port-forward"
+  enabled = var.enabled
+  label   = var.label
+  port_to = var.port != null ? var.port : var.docker_service.endpoint_spec[0].ports[0].published_port
+  ip      = var.target.fixed_ip
+}
\ No newline at end of file
diff --git a/products/unifi/magic-forward/terraform.tf b/products/unifi/magic-forward/terraform.tf
new file mode 100644
index 0000000..e780cbe
--- /dev/null
+++ b/products/unifi/magic-forward/terraform.tf
@@ -0,0 +1,3 @@
+terraform {
+  required_version = "~> 1.6"
+}
diff --git a/products/unifi/port-forward/input.tf b/products/unifi/port-forward/input.tf
new file mode 100644
index 0000000..c51fc94
--- /dev/null
+++ b/products/unifi/port-forward/input.tf
@@ -0,0 +1,43 @@
+variable "enabled" {
+  default     = true
+  description = "Whether the port forward should be enabled"
+  type        = bool
+}
+variable "label" {
+  description = "The label of the port forward"
+  type        = string
+}
+variable "ip" {
+  description = "The target IP address to forward to"
+  type        = string
+  validation {
+    condition     = can(cidrnetmask(var.ip))
+    error_message = "Must be a valid IPv4 CIDR block address."
+  }
+}
+variable "port" {
+  description = "The port to forward"
+  type        = number
+  default     = null
+}
+variable "port_from" {
+  description = "The port to forward from"
+  type        = number
+  default     = null
+}
+variable "port_to" {
+  description = "The port to forward to"
+  type        = number
+  default     = null
+}
+
+variable "protocol" {
+  default     = "tcp"
+  description = "The protocol to use for the port forward"
+  type        = string
+  validation {
+    condition     = var.protocol == "tcp" || var.protocol == "udp" || var.protocol == "any"
+    error_message = "Protocol must be either tcp or udp or any!"
+  }
+}
+
diff --git a/products/unifi/port-forward/port_forward.tf b/products/unifi/port-forward/port_forward.tf
new file mode 100644
index 0000000..df45f32
--- /dev/null
+++ b/products/unifi/port-forward/port_forward.tf
@@ -0,0 +1,8 @@
+resource "unifi_port_forward" "port_forward" {
+  count    = var.enabled ? 1 : 0
+  name     = var.label
+  dst_port = var.port_to != null ? var.port_to : var.port
+  fwd_port = var.port_from != null ? var.port_from : var.port
+  protocol = var.protocol
+  fwd_ip   = var.ip
+}
\ No newline at end of file
diff --git a/products/unifi/port-forward/terraform.tf b/products/unifi/port-forward/terraform.tf
new file mode 100644
index 0000000..05ad241
--- /dev/null
+++ b/products/unifi/port-forward/terraform.tf
@@ -0,0 +1,9 @@
+terraform {
+  required_version = "~> 1.6"
+  required_providers {
+    unifi = {
+      source  = "paultyng/unifi"
+      version = "0.41.0"
+    }
+  }
+}
diff --git a/docker-watchtower/inputs.tf b/products/watchtower/inputs.tf
similarity index 100%
rename from docker-watchtower/inputs.tf
rename to products/watchtower/inputs.tf
diff --git a/docker-watchtower/terraform.tf b/products/watchtower/terraform.tf
similarity index 100%
rename from docker-watchtower/terraform.tf
rename to products/watchtower/terraform.tf
diff --git a/docker-watchtower/watchtower.tf b/products/watchtower/watchtower.tf
similarity index 90%
rename from docker-watchtower/watchtower.tf
rename to products/watchtower/watchtower.tf
index a80b041..31ca443 100644
--- a/docker-watchtower/watchtower.tf
+++ b/products/watchtower/watchtower.tf
@@ -1,5 +1,5 @@
 module "watchtower" {
-  source                = "../docker-service"
+  source                = "../../docker/service"
   image                 = "containrrr/watchtower:latest"
   stack_name            = "watchtower"
   service_name          = "watchtower"