{ name, pkgs, lib, dsl, containers, customPkgs, ... }: let inherit (dsl) mkContainer mkService collectContainers; mkHopperConfig = { routes }: let header = '' listen = "0.0.0.0:25565" [routing.routes] ''; mkRoute = { domain, ip }: '' "${domain}" = { ip = "${ip}" } ''; in header + lib.concatMapStrings mkRoute routes; backends = collectContainers "hopperRegister" containers; mcRoutes = map ({ container, data }: { domain = "${data.hopperSubdomain}.mc.floweytf.com"; ip = "${container.name}:${toString data.hopperPort}"; }) backends; hopperCfg = pkgs.writeText "Config.toml" (mkHopperConfig { routes = mcRoutes; }); in { ${name} = mkContainer { inherit name; net.access = map ({ container, data }: { to = container.name; tcp = [ data.hopperPort ]; }) backends; svc.autoStart = true; net.expose.tcp = [ 25565 ]; net.forward.tcp = [ 25565 ]; resources.fs."/Config.toml" = { hostPath = toString hopperCfg; isReadOnly = true; }; service = _: mkService { description = "Hopper Minecraft reverse proxy"; execStart = lib.getExe' customPkgs.hopper-rs "hopper"; workingDir = "/"; networkOnline = true; serviceConfig = { DynamicUser = true; PrivateTmp = true; PrivateDevices = true; CapabilityBoundingSet = ""; RestrictAddressFamilies = "AF_INET AF_INET6"; }; }; }; _hopperRegister = { hopperSubdomain ? null, hopperPort ? 25565, }: self: { hopperRegister = { hopperSubdomain = if hopperSubdomain == null then self.name else hopperSubdomain; inherit hopperPort; }; }; }