aboutsummaryrefslogtreecommitdiff
path: root/services
diff options
context:
space:
mode:
authorAkshay Nair <phenax5@gmail.com>2025-06-14 16:40:48 +0530
committerAkshay Nair <phenax5@gmail.com>2025-06-14 16:40:48 +0530
commit42df69164dbc74e5ddb54f5a7a01fd66260fef57 (patch)
treebc8b19c39df9edf16ca6827005b3d5e1ef564764 /services
parent58519ea7b12e8ad58c0f97d9636d30572a789b41 (diff)
downloadhomeserver-nixos-config-42df69164dbc74e5ddb54f5a7a01fd66260fef57.tar.gz
homeserver-nixos-config-42df69164dbc74e5ddb54f5a7a01fd66260fef57.zip
Switch to coredns + refactor dns hosts mapping into service + more refactor
Diffstat (limited to 'services')
-rw-r--r--services/bacchus-dashboard/bacchus-dashboard.service.nix47
-rw-r--r--services/bacchus-dashboard/dashboard-template.nix136
-rw-r--r--services/bacchus-dns.service.nix39
-rw-r--r--services/service-router.service.nix47
4 files changed, 269 insertions, 0 deletions
diff --git a/services/bacchus-dashboard/bacchus-dashboard.service.nix b/services/bacchus-dashboard/bacchus-dashboard.service.nix
new file mode 100644
index 0000000..8b0fcb9
--- /dev/null
+++ b/services/bacchus-dashboard/bacchus-dashboard.service.nix
@@ -0,0 +1,47 @@
+{ config, lib, pkgs, ... }:
+with lib;
+let
+ cfg = config.services.bacchus-dashboard;
+
+ rootHTML = import ./dashboard-template.nix cfg;
+ indexHTMLFile = pkgs.writeText "index.html" rootHTML;
+
+ pageDir = pkgs.stdenv.mkDerivation {
+ pname = "dashboard-page";
+ version = "0.0.0";
+ unpackPhase = "true"; # no source
+ installPhase = ''
+ mkdir -p $out;
+ cp ${indexHTMLFile} $out/index.html;
+ '';
+ };
+in
+{
+ options.services.bacchus-dashboard = {
+ enable = mkEnableOption "Enable dashboard";
+ title = mkOption { type = types.str; default = "Dashboard"; };
+ links = mkOption {
+ type = types.listOf (types.attrs);
+ default = [];
+ };
+ embedLink = mkOption { type = types.str; };
+ openFirewall = mkEnableOption "Open firewall ports";
+ host = mkOption { type = types.str; default = "_"; };
+ port = mkOption { type = types.int; default = 80; };
+ };
+
+ config = {
+ services.nginx = mkIf cfg.enable {
+ enable = true;
+ virtualHosts.${cfg.host} = {
+ listen = [ { addr = toString cfg.port; } ];
+ locations."/" = {
+ root = pageDir;
+ tryFiles = "$uri /index.html";
+ };
+ };
+ };
+
+ networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ 80 ];
+ };
+}
diff --git a/services/bacchus-dashboard/dashboard-template.nix b/services/bacchus-dashboard/dashboard-template.nix
new file mode 100644
index 0000000..9883a1d
--- /dev/null
+++ b/services/bacchus-dashboard/dashboard-template.nix
@@ -0,0 +1,136 @@
+{ title, links ? [], embedLink ? null, ... }:
+with builtins;
+let
+ withLinkAttr = link: attr: def: value:
+ if hasAttr attr link then value else def;
+
+ linkHTML = link: ''
+ <a href="${link.url}" class="card" style="${withLinkAttr link "color" "" "--color-card-accent: ${link.color}"}">
+ ${link.title} ${if hasAttr "key" link then "(${link.key})" else ""}
+ <div class="card-link">${link.url}</div>
+ ${if hasAttr "altUrl" link then ''<div class="card-link">(Alt: ${link.altUrl})</div>'' else ""}
+ </a>
+ '';
+
+ script = ''
+ window.addEventListener('keydown', (event) => {
+ const noMod = !event.ctrlKey && !event.altKey;
+ ${concatStringsSep "\n" (map (link:
+ withLinkAttr link "key" "" ''
+ if (event.key.toLowerCase() == ${toJSON link.key} && noMod) {
+ event.preventDefault();
+ if (event.shiftKey)
+ window.open(${toJSON link.url});
+ else
+ window.location.href = ${toJSON link.url};
+ return;
+ }
+ ''
+ ) links)}
+ });
+ '';
+
+ styles = ''
+ :root {
+ font-size: 16px;
+ color: #dbe0f9;
+ font-family: JetBrains Mono, monospace;
+ --color-gray: #1a1824;
+ }
+ html, body {
+ background-color: #0f0c19;
+ padding: 0;
+ margin: 0;
+ }
+ body * { box-sizing: border-box; }
+ header {
+ padding: 1rem 2rem;
+ background-color: #000;
+ }
+ .links-container {
+ display: grid;
+ gap: 1rem;
+ grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
+ padding: 0 1rem;
+ width: 100%;
+ margin: 1rem auto 2rem;
+ }
+ .card {
+ --color-card-accent: #8e7ae3;
+ display: block;
+ padding: 1rem 1.5rem;
+ font-size: 1.2rem;
+ color: var(--color-card-accent);
+ text-decoration: none;
+ border: 2px solid var(--color-gray);
+ position: relative;
+ }
+ .card::before {
+ content: " ";
+ position: absolute;
+ left: 0; top: 0;
+ width: 4px; height: 100%;
+ background-color: var(--color-card-accent);
+ }
+ .card:hover {
+ border-color: var(--color-card-accent);
+ background-color: rgba(255,255,255,0.05);
+ }
+ .card:focus {
+ border-color: var(--color-card-accent);
+ outline: none;
+ }
+ .card-link {
+ font-size: 0.5em;
+ padding-top: 1em;
+ color: gray;
+ }
+ button {
+ background: none;
+ padding: 0;
+ text-decoration: underline;
+ color: gray;
+ margin: 0;
+ border: 0;
+ }
+ .stats-container {
+ padding: 1rem;
+ border-top: 1px solid var(--color-gray);
+ }
+ .stats-container iframe {
+ width: 100%;
+ display: block;
+ min-height: 1100px;
+ height: 100%;
+ border: 2px solid var(--color-gray);
+ border-radius: 5px;
+ }
+ '';
+
+ headerHTML = ''
+ <header>${title}</header>
+ '';
+in
+''
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>${title}</title>
+ <style>${styles}</style>
+ </head>
+ <body>
+ ${headerHTML}
+ <section class="links-container">
+ ${concatStringsSep "" (map linkHTML links)}
+ </section>
+ ${if embedLink == null then "" else ''
+ <section class="stats-container">
+ <iframe src="${embedLink}"></iframe>
+ </section>
+ ''}
+ <script>${script}</script>
+ </body>
+</html>
+''
diff --git a/services/bacchus-dns.service.nix b/services/bacchus-dns.service.nix
new file mode 100644
index 0000000..d6f45f9
--- /dev/null
+++ b/services/bacchus-dns.service.nix
@@ -0,0 +1,39 @@
+{ lib, config, ... }:
+with lib;
+let
+ cfg = config.services.bacchus-dns;
+in
+{
+ options.services.bacchus-dns = {
+ enable = mkEnableOption "dns server mappings";
+ port = mkOption { type = types.int; default = 53; };
+ openFirewall = mkEnableOption "open required ports in firewall";
+ ttl = mkOption { type = types.int; default = 3600; };
+ fallback = mkOption { type = types.listOf types.str; default = [ "1.1.1.1" ]; };
+ hosts = mkOption { type = types.attrsOf types.str; default = {}; };
+ };
+
+ config = {
+ services.coredns = mkIf cfg.enable {
+ enable = true;
+ extraArgs = [ "-dns.port=${toString cfg.port}" ];
+ config = ''
+ . {
+ hosts {
+ ${concatStringsSep "\n" (
+ mapAttrsToList (domain: target: "${target} ${domain}") cfg.hosts)}
+ fallthrough
+ }
+ forward . ${concatStringsSep " " cfg.fallback}
+ cache ${toString cfg.ttl}
+ errors
+ }
+ '';
+ };
+
+ networking.firewall = mkIf cfg.openFirewall {
+ allowedTCPPorts = [ cfg.port ];
+ allowedUDPPorts = [ cfg.port ];
+ };
+ };
+}
diff --git a/services/service-router.service.nix b/services/service-router.service.nix
new file mode 100644
index 0000000..e52280f
--- /dev/null
+++ b/services/service-router.service.nix
@@ -0,0 +1,47 @@
+{ config, lib, ... }:
+with lib;
+let
+ cfg = config.services.service-router;
+in {
+ imports = [
+ ./bacchus-dns.service.nix
+ ];
+
+ options.services.service-router = {
+ enable = mkEnableOption "enable router";
+ routes = mkOption {
+ type = types.attrsOf (types.submodule { options = {
+ port = mkOption { type = types.int; };
+ host = mkOption { type = types.str; default = "127.0.0.1"; };
+ protocol = mkOption { type = types.str; default = "http"; };
+ basePath = mkOption { type = types.str; default = ""; };
+ extraNginxOptions = mkOption { type = types.attrs; default = {}; };
+ }; });
+ default = {};
+ };
+ };
+
+ config = lib.mkIf cfg.enable {
+ services.nginx = {
+ enable = true;
+ recommendedOptimisation = true;
+ virtualHosts = lib.mapAttrs (_: val:
+ let
+ opts = if hasAttr "extraNginxOptions" val then val.extraNginxOptions else {};
+ in {
+ locations."/" = {
+ proxyPass =
+ "${val.protocol}://${val.host}:${toString val.port}${val.basePath}";
+ proxyWebsockets = true;
+ } // opts;
+ }
+ ) cfg.routes;
+ };
+
+ # Hostname mapping
+ services.bacchus-dns = {
+ enable = true;
+ hosts = mapAttrs (_: val: val.host) cfg.routes;
+ };
+ };
+}