aboutsummaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorsefidel <contact@sefidel.net>2024-02-03 04:07:31 +0900
committersefidel <contact@sefidel.net>2024-02-03 04:11:19 +0900
commit6dfa8b17f424baf833034f344ea39393854b14a3 (patch)
treef099a131c8354540672aaa18d80f6dcd74614fa5 /modules
parent8cdd2eb6ec996d39a0def41a4f9df46e6863734d (diff)
downloadnixrc-6dfa8b17f424baf833034f344ea39393854b14a3.zip
feat(modules): add expose
* This commit adds a module for exposing services to the net securely, by making use of Tailscale and Cloudflare Tunnels.
Diffstat (limited to 'modules')
-rw-r--r--modules/expose.nix67
1 files changed, 67 insertions, 0 deletions
diff --git a/modules/expose.nix b/modules/expose.nix
new file mode 100644
index 0000000..29531c5
--- /dev/null
+++ b/modules/expose.nix
@@ -0,0 +1,67 @@
+{ config, lib, ... }:
+
+with lib;
+let
+ cfg = config.modules.expose;
+in
+{
+ options.modules.expose = {
+ enable = mkEnableOption "expose services to network";
+
+ routes = mkOption {
+ type = types.attrsOf types.str;
+ };
+
+ ssl = {
+ enable = mkEnableOption "SSL on all routes";
+ acmeHost = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ description = "ACMEHost for the certificate";
+ };
+ };
+
+ webmasterEmail = mkOption { type = types.str; description = "Email of the webmaster to be contacted for ACME events"; };
+ tailscaleIp = mkOption { type = types.str; description = "Tailscale IP for this node"; };
+ cloudflareUUID = mkOption { type = types.str; description = "UUID of the Cloudflare Tunnel"; };
+ secrets = {
+ acme-credentials = mkOption { type = types.path; description = "Path to the acme environment file"; };
+ cloudflare-credentials = mkOption { type = types.path; description = "Path to the cloudflare tunnel credentials"; };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ assertions = [
+ {
+ assertion = cfg.ssl.enable -> cfg.ssl.acmeHost != null;
+ message = "ssl.acmeHost must be set when enabling SSL";
+ }
+ ];
+
+ services.nginx.virtualHosts = mapAttrs (_: internal: {
+ locations."/".proxyPass = internal;
+ } // optionalAttrs (cfg.ssl.enable) {
+ forceSSL = true;
+ useACMEHost = cfg.ssl.acmeHost;
+ }) (filterAttrs
+ # Assume that reverse proxy is configured externally
+ (_: v: (!hasSuffix ":80" v) && (!hasSuffix ":443" v))
+ cfg.routes);
+
+ # Discard non-localhost mappings, and replace destination with tailscale IP
+ services.blocky.settings.customDNS.mapping = mapAttrs
+ (_: v: cfg.tailscaleIp)
+ (filterAttrs
+ (_: v: hasInfix "localhost" v)
+ cfg.routes);
+
+ services.cloudflared.tunnels."${cfg.cloudflareUUID}" = {
+ credentialsFile = cfg.secrets.cloudflare-credentials;
+ ingress = cfg.routes;
+ } // optionalAttrs (cfg.ssl.enable) {
+ # TODO: This seems to have no effect. Remove?
+ originRequest.originServerName = "*.${cfg.ssl.acmeHost}";
+ originRequest.caPool = config.security.acme.certs.${cfg.ssl.acmeHost}.directory;
+ };
+ };
+}