diff --git a/hosts/nixedo/configuration.nix b/hosts/nixedo/configuration.nix
index 0ac6886e..2e734bdf 100644
--- a/hosts/nixedo/configuration.nix
+++ b/hosts/nixedo/configuration.nix
@@ -19,7 +19,27 @@
     core.openssh.enable = true;
     cli.podman.enable = true;
     desktop.dconf.enable = true;
-    homelab.immich.enable = true;
+
+    homelab = {
+      enable = true;
+
+      baseDomain = "oliverdavies.uk";
+
+      services = {
+        audiobookshelf.enable = true;
+
+        forgejo = {
+          enable = true;
+
+          cloudflared.tunnelId = "e1514105-327f-4984-974e-e2fbaca76466";
+        };
+
+        immich.enable = true;
+        jellyfin.enable = true;
+        paperless.enable = true;
+        uptime-kuma.enable = true;
+      };
+    };
   };
 
   services.logind.lidSwitchExternalPower = "ignore";
diff --git a/hosts/nixedo/modules/audiobookshelf.nix b/hosts/nixedo/modules/audiobookshelf.nix
index ab549071..a5a6827d 100644
--- a/hosts/nixedo/modules/audiobookshelf.nix
+++ b/hosts/nixedo/modules/audiobookshelf.nix
@@ -1,23 +1,34 @@
-{ config, ... }:
+{ config, lib, ... }:
+
+with lib;
 
 let
-  cfg = config.services.audiobookshelf;
+  cfg = homelab.services.${service};
+  homelab = config.nixosModules.homelab;
+  service = "audiobookshelf";
 in
 {
-  services = {
-    audiobookshelf = {
-      enable = true;
+  options.nixosModules.homelab.services.${service} = {
+    enable = mkEnableOption "Enable ${service}";
 
-      port = 4001;
+    url = mkOption {
+      default = "audiobookshelf.${homelab.baseDomain}";
+      type = types.str;
     };
+  };
 
-    nginx.virtualHosts."audiobookshelf.oliverdavies.uk" = {
-      forceSSL = true;
-      useACMEHost = "oliverdavies.uk";
+  config = mkIf cfg.enable {
+    services = {
+      ${service}.enable = true;
 
-      locations."/" = {
-        proxyPass = "http://localhost:${toString cfg.port}";
-        recommendedProxySettings = true;
+      nginx.virtualHosts.${cfg.url} = {
+        forceSSL = true;
+        useACMEHost = homelab.baseDomain;
+
+        locations."/" = {
+          proxyPass = "http://localhost:${toString cfg.port}";
+          recommendedProxySettings = true;
+        };
       };
     };
   };
diff --git a/hosts/nixedo/modules/default.nix b/hosts/nixedo/modules/default.nix
index c7553e34..8f0dae44 100644
--- a/hosts/nixedo/modules/default.nix
+++ b/hosts/nixedo/modules/default.nix
@@ -1,4 +1,17 @@
+{ lib, ... }:
+
+with lib;
+
 {
+  options.nixosModules.homelab = {
+    enable = mkEnableOption "Enable homelab services and configuration";
+
+    baseDomain = mkOption {
+      description = "The base domain to use for this homelab.";
+      type = types.str;
+    };
+  };
+
   imports = [
     ./acme.nix
     ./audiobookshelf.nix
diff --git a/hosts/nixedo/modules/forgejo.nix b/hosts/nixedo/modules/forgejo.nix
index 501b6147..f1c117dd 100644
--- a/hosts/nixedo/modules/forgejo.nix
+++ b/hosts/nixedo/modules/forgejo.nix
@@ -1,26 +1,42 @@
-{ config, ... }:
+{ config, lib, ... }:
 
+with lib;
+
+let
+  cfg = homelab.services.${service};
+  homelab = config.nixosModules.homelab;
+  service = "forgejo";
+in
 {
-  services = {
-    forgejo = {
-      enable = true;
-      stateDir = "/var/www/forgejo";
+  options.nixosModules.homelab.services.${service} = {
+    enable = mkEnableOption "Enable ${service}";
 
-      settings = {
-        server = {
-          DOMAIN = "code.oliverdavies.uk";
-          HTTP_PORT = 2223;
-        };
-
-        service = {
-          DISABLE_REGISTRATION = true;
-        };
-      };
+    cloudflared.tunnelId = mkOption {
+      example = "00000000-0000-0000-0000-000000000000";
+      type = types.str;
     };
 
-    cloudflared.tunnels."e1514105-327f-4984-974e-e2fbaca76466".ingress = {
-      "code.oliverdavies.uk" =
-        "http://localhost:${toString config.services.forgejo.settings.server.HTTP_PORT}";
+    url = mkOption {
+      default = "code.${homelab.baseDomain}";
+      type = types.str;
+    };
+  };
+
+  config = mkIf cfg.enable {
+    services = {
+      ${service} = {
+        enable = true;
+        stateDir = "/var/www/${service}";
+
+        settings = {
+          server.DOMAIN = cfg.url;
+          service.DISABLE_REGISTRATION = true;
+        };
+      };
+
+      cloudflared.tunnels.${cfg.cloudflared.tunnelId}.ingress = {
+        ${cfg.url} = "http://localhost:${toString config.services.${service}.settings.server.HTTP_PORT}";
+      };
     };
   };
 }
diff --git a/hosts/nixedo/modules/immich.nix b/hosts/nixedo/modules/immich.nix
index 011943ac..1243efd7 100644
--- a/hosts/nixedo/modules/immich.nix
+++ b/hosts/nixedo/modules/immich.nix
@@ -8,24 +8,31 @@
 with lib;
 
 let
-  cfg = config.nixosModules.homelab.immich;
+  cfg = homelab.services.${service};
+  homelab = config.nixosModules.homelab;
+  service = "immich";
 in
 {
-  options.nixosModules.homelab.immich = {
-    enable = mkEnableOption "Enable immich";
+  options.nixosModules.homelab.services.${service} = {
+    enable = mkEnableOption "Enable ${service}";
+
+    url = mkOption {
+      default = "photos.${homelab.baseDomain}";
+      type = types.str;
+    };
   };
 
   config = mkIf cfg.enable {
     services = {
-      immich = {
+      ${service} = {
         enable = true;
         group = "media";
-        mediaLocation = "/mnt/media/immich";
+        mediaLocation = "/mnt/media/${service}";
       };
 
-      nginx.virtualHosts."photos.oliverdavies.uk" = {
+      nginx.virtualHosts."${cfg.url}" = {
         forceSSL = true;
-        useACMEHost = "oliverdavies.uk";
+        useACMEHost = homelab.baseDomain;
 
         locations."/" = {
           proxyPass = "http://localhost:${toString config.services.immich.port}";
diff --git a/hosts/nixedo/modules/jellyfin.nix b/hosts/nixedo/modules/jellyfin.nix
index d78c3c95..74d482c3 100644
--- a/hosts/nixedo/modules/jellyfin.nix
+++ b/hosts/nixedo/modules/jellyfin.nix
@@ -1,22 +1,38 @@
+{ config, lib, ... }:
+
+with lib;
+
+let
+  cfg = homelab.services.${service};
+  homelab = config.nixosModules.homelab;
+  service = "jellyfin";
+in
 {
-  services =
-    let
-      port = 8096;
-    in
-    {
-      jellyfin = {
+  options.nixosModules.homelab.services.${service} = {
+    enable = mkEnableOption "Enable ${service}";
+
+    url = mkOption {
+      default = "${service}.${homelab.baseDomain}";
+      type = types.str;
+    };
+  };
+
+  config = mkIf cfg.enable {
+    services = {
+      ${service} = {
         enable = true;
-        openFirewall = true;
+
+        configDir = "/mnt/media/${service}";
         group = "media";
-        configDir = "/mnt/media/jellyfin";
+        openFirewall = true;
       };
 
-      nginx.virtualHosts."jellyfin.oliverdavies.uk" = {
+      nginx.virtualHosts."${cfg.url}" = {
         forceSSL = true;
-        useACMEHost = "oliverdavies.uk";
+        useACMEHost = homelab.baseDomain;
 
         locations."/" = {
-          proxyPass = "http://localhost:${toString port}";
+          proxyPass = "http://localhost:8096";
           recommendedProxySettings = true;
 
           extraConfig = ''
@@ -25,4 +41,5 @@
         };
       };
     };
+  };
 }
diff --git a/hosts/nixedo/modules/paperless.nix b/hosts/nixedo/modules/paperless.nix
index 4d5ace69..ee82ea1a 100644
--- a/hosts/nixedo/modules/paperless.nix
+++ b/hosts/nixedo/modules/paperless.nix
@@ -1,30 +1,43 @@
-{ config, ... }:
+{ config, lib, ... }:
 
+with lib;
+
+let
+  cfg = homelab.services.paperless;
+  homelab = config.nixosModules.homelab;
+  service = "paperless";
+in
 {
-  services =
-    let
-      cfg = config.services.paperless;
-      hostname = "paperless.oliverdavies.uk";
-    in
-    {
-      paperless = {
+  options.nixosModules.homelab.services.${service} = {
+    enable = mkEnableOption "Enable ${service}";
+
+    url = mkOption {
+      default = "${service}.${homelab.baseDomain}";
+      type = types.str;
+    };
+  };
+
+  config = mkIf cfg.enable {
+    services = {
+      ${service} = {
         enable = true;
 
-        dataDir = "/mnt/media/paperless";
+        dataDir = "/mnt/media/${service}";
 
         settings = {
-          PAPERLESS_URL = "https://${hostname}";
+          PAPERLESS_URL = "https://${cfg.url}";
         };
       };
 
-      nginx.virtualHosts."${hostname}" = {
+      nginx.virtualHosts."${cfg.url}" = {
         forceSSL = true;
-        useACMEHost = "oliverdavies.uk";
+        useACMEHost = homelab.baseDomain;
 
         locations."/" = {
-          proxyPass = "http://localhost:${toString cfg.port}";
+          proxyPass = "http://localhost:${toString config.services.${service}.port}";
           recommendedProxySettings = true;
         };
       };
     };
+  };
 }
diff --git a/hosts/nixedo/services/homepage/default.nix b/hosts/nixedo/services/homepage/default.nix
index 691b9021..e70475c6 100644
--- a/hosts/nixedo/services/homepage/default.nix
+++ b/hosts/nixedo/services/homepage/default.nix
@@ -1,25 +1,51 @@
-{ config, ... }:
-
 {
-  services =
-    let
-      cfg = config.services.homepage-dashboard;
-    in
-    {
-      homepage-dashboard = {
+  config,
+  lib,
+  options,
+  ...
+}:
+
+with lib;
+
+let
+  cfg = homelab.services.${service};
+  homelab = config.homelab;
+  opts = options.services.${service};
+  service = "homepage-dashboard";
+in
+{
+  options.homelab.services.${service} = {
+    enable = mkEnableOption "Enable ${service}";
+
+    port = mkOption {
+      default = opts.listenPort.default;
+      type = types.port;
+    };
+
+    url = mkOption {
+      default = "${config.networking.hostName}.${homelab.baseDomain}";
+      type = types.str;
+    };
+  };
+
+  config = mkIf cfg.enable {
+    services = {
+      ${service} = {
         enable = true;
-        listenPort = 8097;
+        listenPort = cfg.port;
         openFirewall = true;
 
         services = (import ./services.nix { inherit config; });
         widgets = import ./widgets.nix;
       };
 
-      nginx.virtualHosts."nixedo.oliverdavies.uk" = {
+      nginx.virtualHosts.${cfg.url} = {
         forceSSL = true;
-        useACMEHost = "oliverdavies.uk";
+        useACMEHost = homelab.baseDomain;
 
-        locations."/".proxyPass = "http://localhost:${toString cfg.listenPort}";
+        locations."/".proxyPass =
+          "http://localhost:${toString config.services.homepage-dashboard.listenPort}";
       };
     };
+  };
 }
diff --git a/hosts/nixedo/services/uptime-kuma.nix b/hosts/nixedo/services/uptime-kuma.nix
index 6d022d2d..49403794 100644
--- a/hosts/nixedo/services/uptime-kuma.nix
+++ b/hosts/nixedo/services/uptime-kuma.nix
@@ -1,16 +1,34 @@
-{ config, ... }:
+{ config, lib, ... }:
 
+with lib;
+
+let
+  cfg = homelab.services.${service};
+  homelab = config.nixosModules.homelab;
+  service = "uptime-kuma";
+in
 {
-  services = {
-    uptime-kuma.enable = true;
+  options.nixosModules.homelab.services.${service} = {
+    enable = mkEnableOption "Enable ${service}";
 
-    nginx.virtualHosts."uptime.oliverdavies.uk" = {
-      forceSSL = true;
-      useACMEHost = "oliverdavies.uk";
+    url = mkOption {
+      default = "uptime.${homelab.baseDomain}";
+      type = types.str;
+    };
+  };
 
-      locations."/" = {
-        proxyPass = "http://localhost:${toString config.services.uptime-kuma.settings.PORT}";
-        recommendedProxySettings = true;
+  config = mkIf cfg.enable {
+    services = {
+      ${service}.enable = true;
+
+      nginx.virtualHosts.${cfg.url} = {
+        forceSSL = true;
+        useACMEHost = homelab.baseDomain;
+
+        locations."/" = {
+          proxyPass = "http://localhost:${toString config.services.${service}.settings.PORT}";
+          recommendedProxySettings = true;
+        };
       };
     };
   };