From e924b339c8dfcbdf7b28513e5cb1b4409c25b7c6 Mon Sep 17 00:00:00 2001 From: prescientmoon Date: Thu, 13 Jun 2024 15:47:36 +0200 Subject: [PATCH] Attempt to set up guacamole --- common/icons/guacamole.png | Bin 0 -> 37035 bytes common/icons/jupyter.png | Bin 0 -> 17756 bytes docs/ports.md | 26 -- hosts/nixos/common/global/default.nix | 1 + hosts/nixos/common/global/ports.nix | 26 ++ .../nixos/common/optional/services/nginx.nix | 1 + hosts/nixos/lapetus/default.nix | 44 ++- hosts/nixos/lapetus/secrets.yaml | 5 +- hosts/nixos/lapetus/services/actual.nix | 14 +- hosts/nixos/lapetus/services/commafeed.nix | 13 +- hosts/nixos/lapetus/services/ddclient.nix | 2 - hosts/nixos/lapetus/services/diptime.nix | 15 +- hosts/nixos/lapetus/services/forgejo.nix | 2 +- hosts/nixos/lapetus/services/grafana.nix | 13 +- .../lapetus/services/guacamole/default.nix | 14 + .../lapetus/services/guacamole/ed25519.pub | 1 + hosts/nixos/lapetus/services/homer.nix | 363 +++++++++--------- hosts/nixos/lapetus/services/intray.nix | 16 +- hosts/nixos/lapetus/services/invidious.nix | 12 +- hosts/nixos/lapetus/services/jellyfin.nix | 7 +- hosts/nixos/lapetus/services/jupyter.nix | 2 +- hosts/nixos/lapetus/services/microbin.nix | 4 +- hosts/nixos/lapetus/services/prometheus.nix | 16 +- hosts/nixos/lapetus/services/qbittorrent.nix | 19 +- hosts/nixos/lapetus/services/radicale.nix | 6 +- hosts/nixos/lapetus/services/redlib.nix | 8 +- hosts/nixos/lapetus/services/smos.nix | 45 +-- hosts/nixos/lapetus/services/syncthing.nix | 7 +- hosts/nixos/lapetus/services/vaultwarden.nix | 15 +- hosts/nixos/lapetus/services/whoogle.nix | 39 +- modules/README.md | 3 +- modules/nixos/default.nix | 1 + modules/nixos/nginx.nix | 100 ++++- modules/nixos/ports.nix | 9 + scripts/dns/dns.txt | 3 +- scripts/rebuild.sh | 2 +- scripts/repl.sh | 2 + 37 files changed, 434 insertions(+), 422 deletions(-) create mode 100644 common/icons/guacamole.png create mode 100644 common/icons/jupyter.png delete mode 100644 docs/ports.md create mode 100644 hosts/nixos/common/global/ports.nix create mode 100644 hosts/nixos/lapetus/services/guacamole/default.nix create mode 100644 hosts/nixos/lapetus/services/guacamole/ed25519.pub create mode 100644 modules/nixos/ports.nix create mode 100755 scripts/repl.sh diff --git a/common/icons/guacamole.png b/common/icons/guacamole.png new file mode 100644 index 0000000000000000000000000000000000000000..2fb3f9dd497cd383e0c508731653865775d7d39d GIT binary patch literal 37035 zcmXt91ys~uu-;v|r9oI4MLLvNT0l?<3F&U6yGs;S8tF!nlJ16;RFD#-8|iM4dYAuu z&vW+R?r-ovOEFqeOw3xLhxKcRt*Ay1>L={F~KMJ13#F-A9UBJ&o!{Y zKR;}9BzTYGq@d#pzE5-ag32h(o`4Uj-Q=|0)EzC|JWX6IAfBF{+%^uju4X1q7Tk_5 zR_VK9_aP7l$a7g~4X=#tSx>(|e->{K#s>zn%!y&a?^=@?WTep1F&=6=zwREH8hc&a zsapG{Rx)DDVEPTYJcp46EnB#phLqgo%Z@o_DGC6!;Kz;@N?v$jz-XdebM2cN8Z=$!CZJj~biEaypzm;$OYn73L z#u9ByZuZ9A`VSA?O32Dyb(kT7kna+B8SuVCb8rHBt662*Ray+1{_wl*g9F4a0(>-}p?Av5w0v%oom^PjS$amKkY zHYNgcs2gUJNn%qjo}u6vN%6T6Mnxh$Mdtv@6Qx@Md&H#1!yd$>mYgKTle4y%?F%(< zy8UHWQH1UiOdb|kB6fAe9sfzTt5E|Yht5E_K1kGWs8X`F-_?3}(S}cV;r-;*8~y}j zN&$?G#D^qE8fBa#q&aCDRx2&@)`+VDrx>3bs|}MP2j0)bD2MTi<-8UeN_&#~aN$Xs zLPkEOZRmb~Zh)OYnu09s1$f-xRcUz=&F!c2jP!%v&O+FGClO6mvN(nu7~7J=2krhw z`MxhB| zuq7UU1)jI9qI9(1JK|5JattOA`MrIOZ3Xom=pl}4Dujd!$57hpoPFnu5YoyQ zMm*qG8Fm<J`&ycu#Vg+-8X^k;etrX{~T!xuT39BR;u@!N3h1i`a)u+(!E+mh6_ z5875IACQ555l=XT2__tbBNSeNP1>Z%F1RePm*nald%j?C^3#^@Yr(z3nw4exW$jZ< zVv`|_8mdV0TE@2`#*xd@e%ZxiocNU320|_s_wOZUSr>bNICvDdSK7h;w%jCBgpKLp zCm5THOMzKpTQ+1Qv>N&SLn4}^N#eIg@PFYn+??+Rc~C7g^7cXSUZJzJ8~hG(Nnl0n z42(2x&pRkiJI_(5zMZ|->O|zQptY1Hgy&DF-9ZlN`=Z4(Y z<5gFp2Bf=msWNM?8BGBwRQ9O~<5<f zTR29W^bl6K344&~N2~@+FCr?ucj-~gOeC)sQM?PfCDXD=;O!^HAxQWmnaZrAEh_{P ziDZnZ%p%HgL?GYMiKDT3*rF+7tbRIt$n>d{er&v>NZW`;&MueLxbh|KSRD7QG>w?7 zZ1fn~)&SWlo$?M6&8k2^T8|t#bmnzNrH=mgctB~ zdhBSOVFM6cDXoS1b#@`*IOBS<2AH-P0-2Jh#NdKfL6s;;9QSINa?AFH0Bl4j4T^6t zqTS!Bm43I>XDzTR7@H7WcDn#ZmF5z(VLhfI%krBG;{ikuNG;t4NBB77eUhJ?Y?q7q z^K;Ho=`O=53|fR3iav-kSo^=Vh?oZTSC+-318<#>eTn+Sh~q^rJnwc7SVYZPWpv~t zU@EYe7`*2vD4)4yuVjWGm@#}PKaCq8yxXdZIkTP=LZ+KfR*;ZRcNC4bmB
M{3fM1cA*4x*Y)o#ho&Rp?r-QsD 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 literal 0 HcmV?d00001 diff --git a/docs/ports.md b/docs/ports.md deleted file mode 100644 index a412faa..0000000 --- a/docs/ports.md +++ /dev/null @@ -1,26 +0,0 @@ -# Ports - -The idea is to always use consecutive ports, but never go back and try to recycle older no longer used ports (for the sake of keeping things clean). - -| Port | Description | -| ---- | --------------------------------------------------------------------------- | -| 8401 | [whoogle](../hosts/nixos/lapetus/services/whoogle.nix) | -| 8402 | [intray api](../hosts/nixos/lapetus/services/intray.nix) | -| 8403 | [intray](../hosts/nixos/lapetus/services/intray.nix) | -| 8404 | [smos](../hosts/nixos/lapetus/services/smos.nix) | -| 8405 | [smos docs](../hosts/nixos/lapetus/services/smos.nix) | -| 8406 | [smos api](../hosts/nixos/lapetus/services/smos.nix) | -| 8407 | [whoogle](../hosts/nixos/lapetus/services/whoogle.nix) | -| 8408 | [vaultwarden](../hosts/nixos/lapetus/services/vaultwarden.nix) | -| 8409 | [grafana](../hosts/nixos/lapetus/services/grafana.nix) | -| 8410 | [prometheus](../hosts/nixos/lapetus/services/prometheus.nix) | -| 8411 | [prometheus node exporter](../hosts/nixos/lapetus/services/prometheus.nix) | -| 8412 | [prometheus nginx exporter](../hosts/nixos/lapetus/services/prometheus.nix) | -| 8413 | [commafeed](../hosts/nixos/lapetus/services/commafeed.nix) | -| 8414 | [invidious](../hosts/nixos/lapetus/services/invidious.nix) | -| 8415 | [radicale](../hosts/nixos/lapetus/services/radicale.nix) | -| 8416 | [redlib](../hosts/nixos/lapetus/services/redlib.nix) | -| 8417 | [qbittorrent](../hosts/nixos/lapetus/services/qbittorrent.nix) | -| 8418 | [microbin](../hosts/nixos/lapetus/services/microbin.nix) | -| 8419 | [forgejo](../hosts/nixos/lapetus/services/forgejo.nix) | -| 8420 | [jupyterjub](../hosts/nixos/lapetus/services/jupyter.nix) | diff --git a/hosts/nixos/common/global/default.nix b/hosts/nixos/common/global/default.nix index f484391..0f5a2c5 100644 --- a/hosts/nixos/common/global/default.nix +++ b/hosts/nixos/common/global/default.nix @@ -16,6 +16,7 @@ let ./nix.nix ./locale.nix ./persistence.nix + ./ports.nix ./wireless ../../../../common diff --git a/hosts/nixos/common/global/ports.nix b/hosts/nixos/common/global/ports.nix new file mode 100644 index 0000000..6af19e6 --- /dev/null +++ b/hosts/nixos/common/global/ports.nix @@ -0,0 +1,26 @@ +# The idea is to always use consecutive ports, but never go back and try to +# recycle older no longer used ports (for the sake of keeping things clean). +{ + satellite.ports = { + whoogle = 8401; + intray-api = 8402; + intray-client = 8403; + smos-docs = 8404; + smos-api = 8405; + smos-client = 8406; + vaultwarden = 8407; + actual = 8408; + grafana = 8409; + prometheus = 8410; + prometheus-node-exporter = 8411; + prometheus-nginx-exporter = 8412; + commafeed = 8413; + invidious = 8414; + radicale = 8415; + redlib = 8416; + qbittorrent = 8417; + microbin = 8418; + forgejo = 8419; + jupyterhub = 8420; + }; +} diff --git a/hosts/nixos/common/optional/services/nginx.nix b/hosts/nixos/common/optional/services/nginx.nix index 3e6b801..723a441 100644 --- a/hosts/nixos/common/optional/services/nginx.nix +++ b/hosts/nixos/common/optional/services/nginx.nix @@ -1,5 +1,6 @@ { imports = [ ./acme.nix ]; + satellite.nginx.domain = "moonythm.dev"; # Root domain used throughout my config services.nginx = { enable = true; recommendedGzipSettings = true; diff --git a/hosts/nixos/lapetus/default.nix b/hosts/nixos/lapetus/default.nix index 55658cc..0d6eefd 100644 --- a/hosts/nixos/lapetus/default.nix +++ b/hosts/nixos/lapetus/default.nix @@ -2,31 +2,39 @@ imports = [ ../common/global ../common/users/pilot.nix + ../common/optional/oci.nix + ../common/optional/services/acme.nix ../common/optional/services/kanata.nix + ../common/optional/services/nginx.nix + ../common/optional/services/postgres.nix ../common/optional/services/restic - ./services/syncthing.nix - ./services/whoogle.nix - ./services/pounce.nix - ./services/intray.nix - ./services/smos.nix - ./services/vaultwarden.nix + # ./services/commafeed.nix + # ./services/ddclient.nix ./services/actual.nix - ./services/homer.nix - ./services/zfs.nix - ./services/prometheus.nix - ./services/grafana.nix - ./services/commafeed.nix - ./services/invidious.nix + ./services/cloudflared.nix ./services/diptime.nix + ./services/forgejo.nix + ./services/grafana.nix + ./services/guacamole + ./services/homer.nix + ./services/intray.nix + ./services/invidious.nix + ./services/jellyfin.nix + ./services/jupyter.nix + ./services/microbin.nix + ./services/pounce.nix + ./services/prometheus.nix + ./services/prometheus.nix + ./services/qbittorrent.nix # turned on/off depending on whether my vpn is paid for ./services/radicale.nix ./services/redlib.nix - ./services/jellyfin.nix - ./services/qbittorrent.nix # turned on/off depending on whether my vpn is paid for - ./services/microbin.nix - ./services/forgejo.nix - ./services/jupyter.nix - # ./services/ddclient.nix + ./services/smos.nix + ./services/syncthing.nix + ./services/vaultwarden.nix + ./services/whoogle.nix + ./services/zfs.nix + ./filesystems ./hardware ]; diff --git a/hosts/nixos/lapetus/secrets.yaml b/hosts/nixos/lapetus/secrets.yaml index 0eae1bb..c45c1d4 100644 --- a/hosts/nixos/lapetus/secrets.yaml +++ b/hosts/nixos/lapetus/secrets.yaml @@ -8,6 +8,7 @@ microbin_env: ENC[AES256_GCM,data:nxiE9GIvEb0xgqomDdMyy2UtG25pt7h+6JUZkAgIejZbJf forgejo_mail_password: ENC[AES256_GCM,data:linrpmA8b+8e1+tWNl0=,iv:Mk7suPq0Jt960Zl9s2jj3SSAKt4t8Lv4eKdIo0o8JbE=,tag:TZ0qGJIVSFSUt/0cqamvdw==,type:str] javi_password: ENC[AES256_GCM,data:5Ifh/DclUz0/AL69Th/GckolrjerLOnDW77SOf+/L3v39T+EOYgK2GDNKtWGGWYX5sdxZ9JwLS3ZVsIOnN4zjFhgV+GChJWkkzjdpJEtpHlmmBKlyS31Fw7SixVkL3y3VJhw72aVv3bMKQ==,iv:FzAmvIlrhna5InsQCRrWVdrKZGmHMb0njWdvgBurdYs=,tag:/Iguu2FbdV/4RSGTnFdyYA==,type:str] vpn_env: ENC[AES256_GCM,data:+61Ft1xj1WnaGH6SdUj3sQunDeTWTQ/G2GVQr1KxXVmLehAdO3W2qwqPRsq0qaad3E6eXd7kMU78w1/9fXM34mJXArmXNPW1X+0549+NX4t3QVP83cIRw6B5vwlWMIA8ixEk46a+t7/C6A10hqpyhqHmeyQEOwJvG+Pou61lBmhSkMQy5gjH4ZNsHHZV0/6ZxSk0yAPQq76cPz4dFvyDzdonLnb+2s1KhHC3D7P6SfuWnfJ1EglrDT8R+A==,iv:mw26zTyFnq9CjN06eRmBTWNjh6SRDY7WOCyhBCmyglg=,tag:cPJvzgtruQNLSg7B+br6xQ==,type:str] +guacamole_users: ENC[AES256_GCM,data:owqflMMpGLUWPcab8JDlQ12zOuCrfkohxims8we9gKuFX28hrjN1wCmgFDGgX5VqWp07SOKdQVI05xMMO2e9pYgUpeKx5FIa/S/4Q/RNelwWPLmhxqGyEt59L5IBgTfgW5qQMvsl1Q7Xgf8X5bFFUSRmzAx0RFamMPqr71vwPphT7XNnPT8QWQo/2bEUqH0Tb5ITkb1FRSMQzIempuKe4K+awISIDAMwLf87esnoHx+dzQQQObSkKGNDpZ39+IUmeyvTIgN7uWQ349jIzkjNTVMzMUWdpDM6Mn9NwQA8m9BXns9vAe03Ama5cQ0ei64eZSb5uYki0BIV2pYccmIBn4Y/QgfMi5F/L9khr94iiVfH6EWtrDIpVwFt9TNZA/gHbOkQVPyHUMGOpCn2tK5ifFDK0URH5E7WM66BiL3yKd7B9SvQuEN8bnFn64QgiYxSp5NxxGx1ZLE7pzSCEtXkWkCYDHe0xDpOUd+zEfOIeQo7Cdn7y5QaXFyrcwryprYb5Hx/5TtTkCm/+r9nl7BbMKnPLblJvsA77/7pws8xcLgNSAR0ROWqB88vauI1uvwdWN5U5VxsEJmoNQXQKOLOtiQ2mFfIY3DYdHtw1L26ISIYOU6XR7jI/MwOBPO94izEW/j1SwGNgMN5Aydu0RRUhyK9RojjR5CEYjyuqclcD0asJ4faYQn8GvnXJPKF/+U7C6O1g6/ejl3fjwyWRb4kreIATdRfZH+m3nVHgSMvPNk8aPlIs51+SIYMtzf32lKp/AVn2hFKF5g+r2rhWH13Lt9poUg2l//l3jPDY1hpc6dm/5H9ZIGKIqcBlYxqnQngUu51lGO0r6z7u/EsIbInnd5TLK5JrTfnuLuwbyo1yetT2J0MNumy9FcrTsDK4+7DEdAJUxPBRrzllgi+hrnDlVLgLH+7y/gc8lB0cE53GBBXp1N7SfJ1,iv:RFuPux63nSefW3+F08jb94q/NwIKE9g/DGjN++oMdXc=,tag:tCCUIttbK5wfbNpjzY0Bgw==,type:str] sops: kms: [] gcp_kms: [] @@ -32,8 +33,8 @@ sops: RHZ6alYrUU5BZ2xlMkdGR1dWRG5aeGMKJdsdtVZ6Mk9Vo3a+tS+rzAgaF2wpH+8U lWhA+c0Kbe8EJT8hm7Vr8PqBmElz4V9AnXSCTp7D+Cu4pfWsHopLUQ== -----END AGE ENCRYPTED FILE----- - lastmodified: "2024-05-31T23:18:45Z" - mac: ENC[AES256_GCM,data:IUiFsu7+ANxUSr5hR6L3lwK+hP2LpGQFPliGOC3XyhxjLsEkbdCi/CqkaJH7tWZTSUoxMPtdn8JC8mGsnW0puhB6YWA26dbXjlvKGWO+02wcMONy3+prW8v7KLXWe513wsLx1fHOjHMchZj/p8gagOGw19aoGdsTNXnQczwPumo=,iv:hH5R9KFTWvps0JC8iKOkDJMeOfdatFHkz6LedeyY9WE=,tag:2pLvEplrGHpBHbtVfFxCfQ==,type:str] + lastmodified: "2024-06-13T13:36:09Z" + mac: ENC[AES256_GCM,data:3YUMJJaAeU6S7BwB5FzUuke3SKMZ0naRtRQoAnSRMMj39dQmg20rQy8F5cWsPvQAbDhOnY/1t3IxGbc8LGQkapcJJhbLiWuQmnPylZuMIgXhsnEzSyZ195FJcTGP5JTfmUb0GZ29MSBAlqRcZb0IDZjbOpVigp5BbD+s64HpdFE=,iv:p1pg4A1JEX3YlvoG6ncaavbJvURPlkAQM/jKbE+9sgE=,tag:WvULhegnyz/HXRfCEP6DiQ==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.8.1 diff --git a/hosts/nixos/lapetus/services/actual.nix b/hosts/nixos/lapetus/services/actual.nix index 269cf06..3a05634 100644 --- a/hosts/nixos/lapetus/services/actual.nix +++ b/hosts/nixos/lapetus/services/actual.nix @@ -1,23 +1,15 @@ { config, ... }: -let - port = 8408; - host = "actual.moonythm.dev"; - dataDir = "/persist/state/var/lib/actual"; +let dataDir = "/persist/state/var/lib/actual"; in { - imports = [ - ../../common/optional/services/nginx.nix - ../../common/optional/oci.nix - ]; - - services.nginx.virtualHosts.${host} = config.satellite.proxy port { }; + satellite.nginx.at.actual.port = config.satellite.ports.actual; systemd.tmpfiles.rules = [ "d ${dataDir}" ]; virtualisation.oci-containers.containers.actual = { image = "actualbudget/actual-server:latest"; autoStart = true; - ports = [ "${toString port}:5006" ]; # server:docker + ports = [ "${toString config.satellite.nginx.at.actual.port}:5006" ]; # server:docker volumes = [ "${dataDir}:/data" ]; # server:docker }; } diff --git a/hosts/nixos/lapetus/services/commafeed.nix b/hosts/nixos/lapetus/services/commafeed.nix index e792a87..156cfcd 100644 --- a/hosts/nixos/lapetus/services/commafeed.nix +++ b/hosts/nixos/lapetus/services/commafeed.nix @@ -1,18 +1,11 @@ { config, ... }: let - port = 8413; - host = "rss.moonythm.dev"; + port = config.satellite.ports.commafeed; dataDir = "/persist/state/var/lib/commafeed"; in { - imports = [ - ../../common/optional/services/nginx.nix - ../../common/optional/oci.nix - ]; - systemd.tmpfiles.rules = [ "d ${dataDir}" ]; - services.nginx.virtualHosts.${host} = config.satellite.proxy port - { proxyWebsockets = true; }; + satellite.nginx.at.rss.port = port; virtualisation.oci-containers.containers.commafeed = { image = "athou/commafeed:latest"; @@ -27,7 +20,7 @@ in # https://github.com/Athou/commafeed/blob/master/commafeed-server/config.yml.example environment = { - CF_APP_PUBLICURL = "https://${host}"; + CF_APP_PUBLICURL = "https://${config.satellite.nginx.at.rss.host}"; CF_APP_ALLOWREGISTRATIONS = "false"; # I already made an account CF_APP_MAXENTRIESAGEDAYS = "0"; # Fetch old entries diff --git a/hosts/nixos/lapetus/services/ddclient.nix b/hosts/nixos/lapetus/services/ddclient.nix index 3c3f16d..aee905f 100644 --- a/hosts/nixos/lapetus/services/ddclient.nix +++ b/hosts/nixos/lapetus/services/ddclient.nix @@ -1,8 +1,6 @@ # DDClient is a dynamic dns service { config, pkgs, ... }: { - imports = [ ../../common/optional/services/acme.nix ]; - services.ddclient = { enable = true; interval = "1m"; diff --git a/hosts/nixos/lapetus/services/diptime.nix b/hosts/nixos/lapetus/services/diptime.nix index 9a345d5..38d998f 100644 --- a/hosts/nixos/lapetus/services/diptime.nix +++ b/hosts/nixos/lapetus/services/diptime.nix @@ -1,12 +1,9 @@ # I couldn't find a hosted version of this { pkgs, config, ... }: { - imports = [ ../../common/optional/services/nginx.nix ]; - - services.nginx.virtualHosts."diptime.moonythm.dev" = - config.satellite.static (pkgs.fetchFromGitHub { - owner = "bhickey"; - repo = "diplomatic-timekeeper"; - rev = "d6ea7b9d9e94ee6d2db8e4e7cff5f8f1c3f04464"; - sha256 = "09s6awz5m6hzpc6jp96c118i372430c7b41acm5m62bllcvrj9vk"; - }); + satellite.nginx.at.diptime.files = pkgs.fetchFromGitHub { + owner = "bhickey"; + repo = "diplomatic-timekeeper"; + rev = "d6ea7b9d9e94ee6d2db8e4e7cff5f8f1c3f04464"; + sha256 = "09s6awz5m6hzpc6jp96c118i372430c7b41acm5m62bllcvrj9vk"; + }; } diff --git a/hosts/nixos/lapetus/services/forgejo.nix b/hosts/nixos/lapetus/services/forgejo.nix index 64c0927..7f002c7 100644 --- a/hosts/nixos/lapetus/services/forgejo.nix +++ b/hosts/nixos/lapetus/services/forgejo.nix @@ -1,6 +1,6 @@ { lib, config, ... }: let - port = 8419; + port = config.satellite.ports.forgejo; host = "git.moonythm.dev"; cfg = config.services.forgejo; in diff --git a/hosts/nixos/lapetus/services/grafana.nix b/hosts/nixos/lapetus/services/grafana.nix index f6f4abf..2466323 100644 --- a/hosts/nixos/lapetus/services/grafana.nix +++ b/hosts/nixos/lapetus/services/grafana.nix @@ -1,5 +1,6 @@ { config, pkgs, ... }: let + port = config.satellite.ports.grafana; secret = name: "$__file{${config.sops.secrets.${name}.path}}"; sopsSettings = { sopsFile = ../secrets.yaml; @@ -7,11 +8,6 @@ let }; in { - imports = [ - ../../common/optional/services/nginx.nix - ./prometheus.nix - ]; - sops.secrets.grafana_smtp_pass = sopsSettings; sops.secrets.grafana_discord_webhook = sopsSettings; @@ -21,9 +17,9 @@ in settings = { server = rec { - domain = "grafana.moonythm.dev"; + domain = config.satellite.nginx.at.grafana.host; root_url = "https://${domain}"; - http_port = 8409; + http_port = port; }; # {{{ Smtp @@ -90,8 +86,7 @@ in }; # }}} # {{{ Networking & storage - services.nginx.virtualHosts.${config.services.grafana.settings.server.domain} = - config.satellite.proxy config.services.grafana.settings.server.http_port { }; + satellite.nginx.at.grafana.port = port; environment.persistence."/persist/state".directories = [{ directory = config.services.grafana.dataDir; diff --git a/hosts/nixos/lapetus/services/guacamole/default.nix b/hosts/nixos/lapetus/services/guacamole/default.nix new file mode 100644 index 0000000..7e8e5ca --- /dev/null +++ b/hosts/nixos/lapetus/services/guacamole/default.nix @@ -0,0 +1,14 @@ +{ config, ... }: +{ + sops.secrets.guacamoleUsers.sopsFile = ../../secrets.yaml; + satellite.nginx.at.guacamole.port = 8443; # default tomcat port + + services.guacamole-server = { + enable = true; + services.guacamole-server.userMappingXml = config.sops.secrets.guacamoleUsers.path; + }; + + services.guacamole-client = { + enable = true; + }; +} diff --git a/hosts/nixos/lapetus/services/guacamole/ed25519.pub b/hosts/nixos/lapetus/services/guacamole/ed25519.pub new file mode 100644 index 0000000..0f74877 --- /dev/null +++ b/hosts/nixos/lapetus/services/guacamole/ed25519.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL4xXKQ07lTMuCIg9Grejp2+o50Fo1ptxyK1oGnWt8jA adrielus@tethys diff --git a/hosts/nixos/lapetus/services/homer.nix b/hosts/nixos/lapetus/services/homer.nix index 4d5f93b..523bb91 100644 --- a/hosts/nixos/lapetus/services/homer.nix +++ b/hosts/nixos/lapetus/services/homer.nix @@ -20,184 +20,193 @@ let icon = file: "assets/${iconPath}/${file}"; in { - imports = [ ../../common/optional/services/nginx.nix ]; + satellite.nginx.at.lab.files = pkgs.homer.withAssets { + extraAssets = [ iconPath ]; + config = { + title = "✨ The celestial citadel ✨"; - services.nginx.virtualHosts."lab.moonythm.dev" = - config.satellite.static (pkgs.homer.withAssets { - extraAssets = [ iconPath ]; - config = { - title = "✨ The celestial citadel ✨"; + header = false; + footer = false; + connectivityCheck = true; - header = false; - footer = false; - connectivityCheck = true; + colors.light = colors; + colors.dark = colors; - colors.light = colors; - colors.dark = colors; - - services = [ - # {{{ Infrastructure - { - name = "Infrastructure"; - icon = fa "code"; - items = [ - { - name = "Prometheus"; - type = "Prometheus"; - subtitle = "Monitoring system"; - logo = icon "prometheus.png"; - url = "https://prometheus.moonythm.dev"; - } - { - name = "Grafana"; - subtitle = "Pretty dashboards :3"; - logo = icon "grafana.png"; - url = "https://grafana.moonythm.dev"; - } - { - name = "Syncthing"; - subtitle = "File synchronization"; - logo = icon "syncthing.png"; - url = "https://lapetus.syncthing.moonythm.dev"; - } - ]; - } - # }}} - # {{{ External - { - name = "External"; - icon = fa "arrow-up-right-from-square"; - items = [ - { - name = "Tailscale"; - subtitle = "Access this homelab from anywhere"; - logo = icon "tailscale.png"; - url = "https://tailscale.com/"; - } - { - name = "Dotfiles"; - subtitle = "Configuration for all my machines"; - logo = icon "github.png"; - url = "https://github.com/prescientmoon/everything-nix"; - } - { - name = "Cloudflare"; - subtitle = "Domain management"; - logo = icon "cloudflare.png"; - url = "https://dash.cloudflare.com/761d3e81b3e42551e33c4b73274ecc82/moonythm.dev/"; - } - ]; - } - # }}} - # {{{ Productivity - { - name = "Productivity"; - icon = fa "rocket"; - items = [ - { - name = "Intray"; - subtitle = "GTD capture tool"; - icon = fa "inbox"; - url = "https://intray.moonythm.dev"; - } - { - name = "Smos"; - subtitle = "A comprehensive self-management system."; - icon = fa "cubes-stacked"; - url = "https://smos.moonythm.dev"; - } - { - name = "Actual"; - subtitle = "Budgeting tool"; - logo = icon "actual.png"; - url = "https://actual.moonythm.dev"; - } - ]; - } - # }}} - # {{{ Pillars - { - name = "Tooling"; - icon = fa "toolbox"; - items = [ - { - name = "Vaultwarden"; - subtitle = "Password manager"; - logo = icon "bitwarden.png"; - url = "https://warden.moonythm.dev"; - } - { - name = "Whoogle"; - subtitle = "Search engine"; - logo = icon "whoogle.webp"; - url = "https://search.moonythm.dev"; - } - { - name = "Radicale"; - subtitle = "Calendar server"; - logo = icon "radicale.svg"; - url = "https://cal.moonythm.dev"; - } - { - name = "Microbin"; - subtitle = "Code & file sharing"; - logo = icon "microbin.png"; - url = "https://cal.moonythm.dev"; - } - { - name = "Forgejo"; - subtitle = "Git forge"; - logo = icon "forgejo.svg"; - url = "https://git.moonythm.dev"; - } - ]; - } - # }}} - # {{{ Entertainment - { - name = "Entertainment"; - icon = fa "gamepad"; - items = [ - { - name = "Invidious"; - subtitle = "Youtube client"; - logo = icon "invidious.png"; - url = "https://yt.moonythm.dev"; - } - { - name = "Redlib"; - subtitle = "Reddit client"; - logo = icon "libreddit.png"; - url = "https://redlib.moonythm.dev"; - } - { - name = "Diptime"; - subtitle = "Diplomacy timer"; - icon = fa "globe"; - url = "https://diptime.moonythm.dev"; - } - { - name = "Commafeed"; - subtitle = "RSS reader"; - logo = icon "commafeed.png"; - url = "https://rss.moonythm.dev"; - } - { - name = "Qbittorrent"; - subtitle = "Torrent client"; - logo = icon "qbittorrent.png"; - url = "https://qbit.moonythm.dev"; - } - { - name = "Jellyfin"; - subtitle = "Media server"; - logo = icon "jellyfin.png"; - url = "https://media.moonythm.dev"; - } - ]; - } - # }}} - ]; - }; - }); + services = [ + # {{{ Infrastructure + { + name = "Infrastructure"; + icon = fa "code"; + items = [ + { + name = "Prometheus"; + type = "Prometheus"; + subtitle = "Monitoring system"; + logo = icon "prometheus.png"; + url = "https://prometheus.moonythm.dev"; + } + { + name = "Grafana"; + subtitle = "Pretty dashboards :3"; + logo = icon "grafana.png"; + url = "https://grafana.moonythm.dev"; + } + { + name = "Syncthing"; + subtitle = "File synchronization"; + logo = icon "syncthing.png"; + url = "https://lapetus.syncthing.moonythm.dev"; + } + { + name = "Guacamole"; + subtitle = "Server remote access"; + logo = icon "guacamole.png"; + url = "https://guacamole.moonythm.dev"; + } + ]; + } + # }}} + # {{{ External + { + name = "External"; + icon = fa "arrow-up-right-from-square"; + items = [ + { + name = "Tailscale"; + subtitle = "Access this homelab from anywhere"; + logo = icon "tailscale.png"; + url = "https://tailscale.com/"; + } + { + name = "Dotfiles"; + subtitle = "Configuration for all my machines"; + logo = icon "github.png"; + url = "https://github.com/prescientmoon/everything-nix"; + } + { + name = "Cloudflare"; + subtitle = "Domain management"; + logo = icon "cloudflare.png"; + url = "https://dash.cloudflare.com/761d3e81b3e42551e33c4b73274ecc82/moonythm.dev/"; + } + ]; + } + # }}} + # {{{ Productivity + { + name = "Productivity"; + icon = fa "rocket"; + items = [ + { + name = "Intray"; + subtitle = "GTD capture tool"; + icon = fa "inbox"; + url = "https://intray.moonythm.dev"; + } + { + name = "Smos"; + subtitle = "A comprehensive self-management system."; + icon = fa "cubes-stacked"; + url = "https://smos.moonythm.dev"; + } + { + name = "Actual"; + subtitle = "Budgeting tool"; + logo = icon "actual.png"; + url = "https://actual.moonythm.dev"; + } + ]; + } + # }}} + # {{{ Tooling + { + name = "Tooling"; + icon = fa "toolbox"; + items = [ + { + name = "Vaultwarden"; + subtitle = "Password manager"; + logo = icon "bitwarden.png"; + url = "https://warden.moonythm.dev"; + } + { + name = "Whoogle"; + subtitle = "Search engine"; + logo = icon "whoogle.webp"; + url = "https://search.moonythm.dev"; + } + { + name = "Radicale"; + subtitle = "Calendar server"; + logo = icon "radicale.svg"; + url = "https://cal.moonythm.dev"; + } + { + name = "Microbin"; + subtitle = "Code & file sharing"; + logo = icon "microbin.png"; + url = "https://bin.moonythm.dev"; + } + { + name = "Forgejo"; + subtitle = "Git forge"; + logo = icon "forgejo.svg"; + url = "https://git.moonythm.dev"; + } + { + name = "Jupyterhub"; + subtitle = "Notebook collaboration suite"; + logo = icon "jupyter.png"; + url = "https://jupyter.moonythm.dev"; + } + ]; + } + # }}} + # {{{ Entertainment + { + name = "Entertainment"; + icon = fa "gamepad"; + items = [ + { + name = "Invidious"; + subtitle = "Youtube client"; + logo = icon "invidious.png"; + url = "https://yt.moonythm.dev"; + } + { + name = "Redlib"; + subtitle = "Reddit client"; + logo = icon "libreddit.png"; + url = "https://redlib.moonythm.dev"; + } + { + name = "Diptime"; + subtitle = "Diplomacy timer"; + icon = fa "globe"; + url = "https://diptime.moonythm.dev"; + } + { + name = "Commafeed"; + subtitle = "RSS reader"; + logo = icon "commafeed.png"; + url = "https://rss.moonythm.dev"; + } + { + name = "Qbittorrent"; + subtitle = "Torrent client"; + logo = icon "qbittorrent.png"; + url = "https://qbit.moonythm.dev"; + } + { + name = "Jellyfin"; + subtitle = "Media server"; + logo = icon "jellyfin.png"; + url = "https://media.moonythm.dev"; + } + ]; + } + # }}} + ]; + }; + }; } diff --git a/hosts/nixos/lapetus/services/intray.nix b/hosts/nixos/lapetus/services/intray.nix index e177150..29163f9 100644 --- a/hosts/nixos/lapetus/services/intray.nix +++ b/hosts/nixos/lapetus/services/intray.nix @@ -1,15 +1,11 @@ { inputs, config, ... }: let username = "prescientmoon"; - apiHost = "api.intray.moonythm.dev"; - apiPort = 8402; - webPort = 8403; + apiPort = config.satellite.ports.intray-api; + webPort = config.satellite.ports.intray-client; in { - imports = [ - ../../common/optional/services/nginx.nix - inputs.intray.nixosModules.x86_64-linux.default - ]; + imports = [ inputs.intray.nixosModules.x86_64-linux.default ]; # {{{ Configure intray services.intray.production = { @@ -22,13 +18,13 @@ in web-server = { enable = true; port = webPort; - api-url = "https://${apiHost}"; + api-url = config.satellite.nginx.at."api.intray".url; }; }; # }}} # {{{ Networking & storage - services.nginx.virtualHosts.${apiHost} = config.satellite.proxy apiPort { }; - services.nginx.virtualHosts."intray.moonythm.dev" = config.satellite.proxy webPort { }; + satellite.nginx.at."intray".port = webPort; + satellite.nginx.at."api.intray".port = apiPort; environment.persistence."/persist/state".directories = [ "/www/intray/production/data" diff --git a/hosts/nixos/lapetus/services/invidious.nix b/hosts/nixos/lapetus/services/invidious.nix index 37ba2a1..1542ca8 100644 --- a/hosts/nixos/lapetus/services/invidious.nix +++ b/hosts/nixos/lapetus/services/invidious.nix @@ -1,22 +1,16 @@ { config, pkgs, ... }: { - imports = [ - ../../common/optional/services/nginx.nix - ../../common/optional/services/postgres.nix - ]; - sops.secrets.invidious_hmac_key.sopsFile = ../secrets.yaml; sops.templates."invidious_hmac_key.json" = { content = ''{ "hmac_key": "${config.sops.placeholder.invidious_hmac_key}" }''; mode = "0444"; # I don't care about this key that much, as I'm the only user of this instance }; - services.nginx.virtualHosts.${config.services.invidious.domain} = - config.satellite.proxy config.services.invidious.port { }; + satellite.nginx.at.yt.port = config.satellite.ports.invidious; services.invidious = { enable = true; - domain = "yt.moonythm.dev"; - port = 8414; + domain = config.satellite.nginx.at.yt.host; + port = config.satellite.nginx.at.yt.port; hmacKeyFile = config.sops.templates."invidious_hmac_key.json".path; settings = { diff --git a/hosts/nixos/lapetus/services/jellyfin.nix b/hosts/nixos/lapetus/services/jellyfin.nix index 60bd844..b0c4809 100644 --- a/hosts/nixos/lapetus/services/jellyfin.nix +++ b/hosts/nixos/lapetus/services/jellyfin.nix @@ -1,9 +1,6 @@ { config, pkgs, ... }: { - imports = [ ../../common/optional/services/nginx.nix ]; - - services.nginx.virtualHosts."media.moonythm.dev" = - config.satellite.proxy 8096 { }; # This is the default port, and can only be changed via the GUI - + # This is the default port, and can only be changed via the GUI + satellite.nginx.at.media.port = 8096; services.jellyfin.enable = true; # {{{ Storage diff --git a/hosts/nixos/lapetus/services/jupyter.nix b/hosts/nixos/lapetus/services/jupyter.nix index 38bc882..addfa69 100644 --- a/hosts/nixos/lapetus/services/jupyter.nix +++ b/hosts/nixos/lapetus/services/jupyter.nix @@ -18,7 +18,7 @@ in services.jupyterhub = { enable = true; - port = 8420; + port = config.satellite.ports.jupyterhub; jupyterhubEnv = appEnv; jupyterlabEnv = appEnv; diff --git a/hosts/nixos/lapetus/services/microbin.nix b/hosts/nixos/lapetus/services/microbin.nix index 0b857eb..52da379 100644 --- a/hosts/nixos/lapetus/services/microbin.nix +++ b/hosts/nixos/lapetus/services/microbin.nix @@ -1,11 +1,9 @@ { config, lib, ... }: let - port = 8418; + port = config.satellite.ports.microbin; host = "bin.moonythm.dev"; in { - imports = [ ./cloudflared.nix ]; - sops.secrets.microbin_env.sopsFile = ../secrets.yaml; satellite.cloudflared.targets.${host}.port = port; diff --git a/hosts/nixos/lapetus/services/prometheus.nix b/hosts/nixos/lapetus/services/prometheus.nix index 593d044..8b8f3d1 100644 --- a/hosts/nixos/lapetus/services/prometheus.nix +++ b/hosts/nixos/lapetus/services/prometheus.nix @@ -1,14 +1,10 @@ { config, pkgs, ... }: -let host = "prometheus.moonythm.dev"; -in { - imports = [ ../../common/optional/services/nginx.nix ]; - # {{{ Main config services.prometheus = { enable = true; - port = 8410; - webExternalUrl = "https://${host}"; + port = config.satellite.ports.prometheus; + webExternalUrl = config.satellite.nginx.at.prometheus.url; # {{{ Base exporters exporters = { @@ -16,12 +12,12 @@ in node = { enable = true; enabledCollectors = [ "systemd" ]; - port = 8411; + port = config.satellite.ports.prometheus-node-exporter; }; nginx = { enable = true; - port = 8412; + port = config.satellite.ports.prometheus-nginx-exporter; }; }; @@ -38,9 +34,7 @@ in }; # }}} # {{{ Networking & storage - services.nginx.virtualHosts.${host} = - config.satellite.proxy config.services.prometheus.port - { proxyWebsockets = true; }; + satellite.nginx.at.prometheus.port = config.services.prometheus.port; environment.persistence."/persist/state".directories = [{ directory = "/var/lib/prometheus2"; diff --git a/hosts/nixos/lapetus/services/qbittorrent.nix b/hosts/nixos/lapetus/services/qbittorrent.nix index b4b606a..c0a6170 100644 --- a/hosts/nixos/lapetus/services/qbittorrent.nix +++ b/hosts/nixos/lapetus/services/qbittorrent.nix @@ -3,27 +3,20 @@ # https://www.reddit.com/r/HomeServer/comments/xapl93/a_minimal_configuration_stepbystep_guide_to_media/ { config, pkgs, ... }: let - port = 8417; + port = config.satellite.ports.qbittorrent; dataDir = "/persist/data/media"; configDir = "/persist/state/var/lib/qbittorrent"; in { - imports = [ - ../../common/optional/services/nginx.nix - ../../common/optional/oci.nix - ]; - + # {{{ Networking & storage + satellite.nginx.at.qbit.port = port; sops.secrets.vpn_env.sopsFile = ../secrets.yaml; - - services.nginx.virtualHosts."qbit.moonythm.dev" = - config.satellite.proxy port { proxyWebsockets = true; }; - systemd.tmpfiles.rules = [ "d ${dataDir} 777 ${config.users.users.pilot.name} users" "d ${configDir}" ]; - - # {{{ qbit + # }}} + # {{{ Qbit virtualisation.oci-containers.containers.qbittorrent = { image = "linuxserver/qbittorrent:latest"; extraOptions = [ "--network=container:gluetun" ]; @@ -37,7 +30,7 @@ in }; }; # }}} - # {{{ vpn + # {{{ Vpn virtualisation.oci-containers.containers.gluetun = { image = "qmcgaw/gluetun"; extraOptions = [ diff --git a/hosts/nixos/lapetus/services/radicale.nix b/hosts/nixos/lapetus/services/radicale.nix index 726cdbb..c7eafad 100644 --- a/hosts/nixos/lapetus/services/radicale.nix +++ b/hosts/nixos/lapetus/services/radicale.nix @@ -1,6 +1,6 @@ { config, ... }: let - port = 8415; + port = config.satellite.ports.radicale; dataDir = "/persist/data/radicale"; in { @@ -14,7 +14,5 @@ in }; systemd.tmpfiles.rules = [ "d ${dataDir} 0700 radicale radicale" ]; - - services.nginx.virtualHosts."cal.moonythm.dev" = - config.satellite.proxy port { }; + satellite.nginx.at.cal.port = port; } diff --git a/hosts/nixos/lapetus/services/redlib.nix b/hosts/nixos/lapetus/services/redlib.nix index 739b5cd..c588024 100644 --- a/hosts/nixos/lapetus/services/redlib.nix +++ b/hosts/nixos/lapetus/services/redlib.nix @@ -1,13 +1,9 @@ { config, lib, upkgs, ... }: -let port = 8416; +let port = config.satellite.ports.redlib; in { - imports = [ ../../common/optional/services/nginx.nix ]; - - services.nginx.virtualHosts."redlib.moonythm.dev" = - config.satellite.proxy port { }; - services.libreddit.enable = true; + satellite.nginx.at.redlib.port = port; systemd.services.libreddit.serviceConfig.ExecStart = lib.mkForce "${upkgs.redlib}/bin/redlib --port ${toString port}"; } diff --git a/hosts/nixos/lapetus/services/smos.nix b/hosts/nixos/lapetus/services/smos.nix index 70122df..d149846 100644 --- a/hosts/nixos/lapetus/services/smos.nix +++ b/hosts/nixos/lapetus/services/smos.nix @@ -1,20 +1,8 @@ { inputs, config, ... }: -let - username = "prescientmoon"; - docsHost = "docs.smos.moonythm.dev"; - apiHost = "api.smos.moonythm.dev"; - webHost = "smos.moonythm.dev"; - docsPort = 8404; - apiPort = 8405; - webPort = 8406; - - https = host: "https://${host}"; +let username = "prescientmoon"; in { - imports = [ - ../../common/optional/services/nginx.nix - inputs.smos.nixosModules.x86_64-linux.default - ]; + imports = [ inputs.smos.nixosModules.x86_64-linux.default ]; # {{{ Configure smos services.smos.production = { @@ -24,16 +12,16 @@ in docs-site = { enable = true; openFirewall = false; - port = docsPort; - api-url = https apiHost; - web-url = https webHost; + port = config.satellite.nginx.at."docs.smos".port; + api-url = config.satellite.nginx.at."api.smos".url; + web-url = config.satellite.nginx.at."smos".url; }; # }}} # {{{ Api server api-server = { enable = true; openFirewall = false; - port = apiPort; + port = config.satellite.nginx.at."api.smos".port; admin = username; max-backups-per-user = 5; @@ -45,25 +33,18 @@ in web-server = { enable = true; openFirewall = false; - port = webPort; - docs-url = https docsHost; - api-url = https apiHost; - web-url = https webHost; + port = config.satellite.nginx.at."smos".port; + docs-url = config.satellite.nginx.at."docs.smos".url; + api-url = config.satellite.nginx.at."api.smos".url; + web-url = config.satellite.nginx.at."smos".url; }; # }}} }; # }}} # {{{ Networking & storage - services.nginx.virtualHosts.${docsHost} = config.satellite.proxy docsPort { }; - services.nginx.virtualHosts.${apiHost} = config.satellite.proxy apiPort { }; - services.nginx.virtualHosts.${webHost} = config.satellite.proxy webPort { - proxyWebsockets = true; - - # Just to make sure we don't run into 413 errors on big syncs - extraConfig = '' - client_max_body_size 0; - ''; - }; + satellite.nginx.at."docs.smos".port = config.satellite.ports.smos-docs; + satellite.nginx.at."api.smos".port = config.satellite.ports.smos-api; + satellite.nginx.at."smos".port = config.satellite.ports.smos-client; environment.persistence."/persist/state".directories = [ "/www/smos/production" diff --git a/hosts/nixos/lapetus/services/syncthing.nix b/hosts/nixos/lapetus/services/syncthing.nix index 734fc40..6b50103 100644 --- a/hosts/nixos/lapetus/services/syncthing.nix +++ b/hosts/nixos/lapetus/services/syncthing.nix @@ -2,16 +2,11 @@ let port = 8384; in { - imports = [ - ../../common/optional/services/syncthing.nix - ../../common/optional/services/nginx.nix - ]; - services.syncthing = { settings.folders = { }; guiAddress = "127.0.0.1:${toString port}"; settings.gui.insecureSkipHostcheck = true; }; - services.nginx.virtualHosts."lapetus.syncthing.moonythm.dev" = config.satellite.proxy port { }; + satellite.nginx.at."lapetus.syncthing".port = port; } diff --git a/hosts/nixos/lapetus/services/vaultwarden.nix b/hosts/nixos/lapetus/services/vaultwarden.nix index d726e31..41932b9 100644 --- a/hosts/nixos/lapetus/services/vaultwarden.nix +++ b/hosts/nixos/lapetus/services/vaultwarden.nix @@ -1,13 +1,6 @@ { config, ... }: -let - port = 8407; - host = "warden.moonythm.dev"; -in { - imports = [ ../../common/optional/services/nginx.nix ]; - - services.nginx.virtualHosts.${host} = - config.satellite.proxy port { proxyWebsockets = true; }; + satellite.nginx.at.warden.port = config.satellite.ports.vaultwarden; # {{{ Secrets sops.secrets.vaultwarden_env = { @@ -21,11 +14,11 @@ in enable = true; environmentFile = config.sops.secrets.vaultwarden_env.path; config = { - DOMAIN = "https://${host}"; + DOMAIN = "https://${config.satellite.nginx.at.warden.host}"; + ROCKET_PORT = config.satellite.nginx.at.warden.port; ROCKET_ADDRESS = "127.0.0.1"; - ROCKET_PORT = port; - SIGNUPS_ALLOWED = true; + SIGNUPS_ALLOWED = false; SHOW_PASSWORD_HINT = false; SMTP_SECURITY = "force_tls"; diff --git a/hosts/nixos/lapetus/services/whoogle.nix b/hosts/nixos/lapetus/services/whoogle.nix index 4346294..f23d6de 100644 --- a/hosts/nixos/lapetus/services/whoogle.nix +++ b/hosts/nixos/lapetus/services/whoogle.nix @@ -1,39 +1,32 @@ { lib, config, ... }: -let - port = 8401; - websiteBlocklist = [ - "www.saashub.com" - "slant.co" - "nix-united.com" - "libhunt.com" - "www.devopsschool.com" - "medevel.com" - "alternativeto.net" - "linuxiac.com" - "www.linuxlinks.com" - "sourceforge.net" - ]; +let websiteBlocklist = [ + "www.saashub.com" + "slant.co" + "nix-united.com" + "libhunt.com" + "www.devopsschool.com" + "medevel.com" + "alternativeto.net" + "linuxiac.com" + "www.linuxlinks.com" + "sourceforge.net" +]; in { - imports = [ - ../../common/optional/services/nginx.nix - ../../common/optional/oci.nix - ]; - virtualisation.oci-containers.containers.whoogle-search = { image = "benbusby/whoogle-search"; autoStart = true; - ports = [ "${toString port}:5000" ]; # server:docker + ports = [ "${toString config.satellite.nginx.at.search.port}:5000" ]; # server:docker environment = { WHOOGLE_UPDATE_CHECK = "0"; WHOOGLE_CONFIG_DISABLE = "0"; WHOOGLE_CONFIG_BLOCK = lib.concatStringsSep "," websiteBlocklist; WHOOGLE_CONFIG_THEME = "system"; WHOOGLE_ALT_WIKI = ""; # disable redirecting wikipedia links - WHOOGLE_ALT_RD = "redlib.moonythm.dev"; - WHOOGLE_ALT_YT = "yt.moonythm.dev"; + WHOOGLE_ALT_RD = config.satellite.nginx.at.redlib.host; + WHOOGLE_ALT_YT = config.satellite.nginx.at.yt.host; }; }; - services.nginx.virtualHosts."search.moonythm.dev" = config.satellite.proxy port { }; + satellite.nginx.at.search.port = config.satellite.ports.whoogle; } diff --git a/modules/README.md b/modules/README.md index b388f86..18e7d21 100644 --- a/modules/README.md +++ b/modules/README.md @@ -26,7 +26,8 @@ This directory contains custom module definitions used throughout my config. | Name | Attribute | Description | | -------------------------------------- | ----------------------- | ------------------------------------------- | | [pounce](./nixos/pounce.nix) | `services.pounce` | Module for pounce & calico configuration | -| [nginx](./nixos/nginx.nix) | `satellite.proxy` | Helpers for nginx configuration | +| [nginx](./nixos/nginx.nix) | `satellite.nginx` | Helpers for nginx configuration | +| [ports](./nixos/ports.nix) | `satellite.ports` | Global port specification | | [cloudflared](./nixos/cloudflared.nix) | `satellite.cloudflared` | Helpers for cloudflare tunnel configuration | | [pilot](./nixos/pilot.nix) | `satellite.pilot` | Defined the concept of a "main user" | diff --git a/modules/nixos/default.nix b/modules/nixos/default.nix index 950c9f5..4f811fa 100644 --- a/modules/nixos/default.nix +++ b/modules/nixos/default.nix @@ -3,6 +3,7 @@ { # example = import ./example.nix; cloudflared = import ./cloudflared.nix; + ports = import ./ports.nix; nginx = import ./nginx.nix; pilot = import ./pilot.nix; pounce = import ./pounce.nix; diff --git a/modules/nixos/nginx.nix b/modules/nixos/nginx.nix index b6c37a0..a507aad 100644 --- a/modules/nixos/nginx.nix +++ b/modules/nixos/nginx.nix @@ -1,25 +1,85 @@ -{ lib, ... }: { - options.satellite.proxy = lib.mkOption { - type = lib.types.functionTo (lib.types.functionTo lib.types.anything); - description = "Helper function for generating a quick proxy config"; +{ config, lib, ... }: +let cfg = config.satellite.nginx; +in +{ + options.satellite.nginx = { + domain = lib.mkOption { + description = "Root domain to use as a default for configurations."; + type = lib.types.str; + }; + + at = lib.mkOption { + description = "Per-subdomain nginx configuration"; + type = lib.types.attrsOf (lib.types.submodule ({ name, config, ... }: { + options.name = lib.mkOption { + description = "Attribute name leading to this submodule"; + type = lib.types.str; + }; + + config.name = name; + + options.host = lib.mkOption { + description = "Host to route requests from"; + type = lib.types.str; + default = "${name}.${cfg.domain}"; + }; + + options.url = lib.mkOption { + description = "External https url used to access this host"; + type = lib.types.str; + }; + + config.url = "https://${config.host}"; + + options.port = lib.mkOption { + description = "Port to proxy requests to"; + type = lib.types.nullOr lib.types.port; + default = null; + }; + + options.files = lib.mkOption { + description = "Path to serve files from"; + type = lib.types.nullOr lib.types.path; + default = null; + }; + })); + default = { }; + }; }; - options.satellite.static = lib.mkOption { - type = lib.types.functionTo lib.types.anything; - description = "Helper function for generating a quick file serving config"; - }; + config = { + assertions = + let assertSingleTarget = config: + { + assertion = (config.port == null) == (config.files != null); + message = '' + Precisely one of the options 'satellite.nginx.at.${config.name}.port' + and 'satellite.nginx.at.${config.name}.files' must be specified. + ''; + }; + in lib.mapAttrsToList (_: assertSingleTarget) cfg.at; - config.satellite.proxy = port: extra: { - enableACME = true; - acmeRoot = null; - forceSSL = true; - locations."/" = { proxyPass = "http://localhost:${toString port}"; } // extra; - }; - - config.satellite.static = root: { - inherit root; - enableACME = true; - acmeRoot = null; - forceSSL = true; + services.nginx.virtualHosts = + let mkNginxConfig = { host, port, files }: { + name = host; + value = + let extra = + if port != null then { + locations."/" = { + proxyPass = "http://localhost:${toString port}"; + proxyWebsockets = true; + }; + } + else { + root = files; + }; + in + { + enableACME = true; + acmeRoot = null; + forceSSL = true; + } // extra; + }; + in lib.attrsets.mapAttrs' (_: mkNginxConfig) cfg.at; }; } diff --git a/modules/nixos/ports.nix b/modules/nixos/ports.nix new file mode 100644 index 0000000..72c8bb4 --- /dev/null +++ b/modules/nixos/ports.nix @@ -0,0 +1,9 @@ +# Generic interface for working specifying a single-source of truth for ports! +{ lib, ... }: +{ + options.satellite.ports = lib.mkOption { + description = "Record of custom app-port mappings to use throughput the config"; + type = lib.types.lazyAttrsOf lib.types.port; + default = { }; + }; +} diff --git a/scripts/dns/dns.txt b/scripts/dns/dns.txt index 16399c8..670816a 100644 --- a/scripts/dns/dns.txt +++ b/scripts/dns/dns.txt @@ -16,6 +16,7 @@ cal IN CNAME lapetus diptime IN CNAME lapetus docs.smos IN CNAME lapetus grafana IN CNAME lapetus +guacamole IN CNAME lapetus intray IN CNAME lapetus irc IN CNAME lapetus jupyter IN CNAME lapetus @@ -37,8 +38,8 @@ tunnel.lapetus IN CNAME 347d9ead-a523-4f8b-bca7-3066e31e2952.cfargotunnel.c ; lapetus services using cloudflare tunnels bin IN CNAME tunnel.lapetus -jupyter IN CNAME tunnel.lapetus git IN CNAME tunnel.lapetus +jupyter IN CNAME tunnel.lapetus ; github pages doffycup IN CNAME prescientmoon.github.io. diff --git a/scripts/rebuild.sh b/scripts/rebuild.sh index 3c9c12d..8b106b2 100755 --- a/scripts/rebuild.sh +++ b/scripts/rebuild.sh @@ -1,2 +1,2 @@ #!/usr/bin/env bash -sudo nixos-rebuild switch --flake .#$hostname --show-trace --fast +sudo nixos-rebuild switch --flake .#$HOSTNAME --show-trace --fast diff --git a/scripts/repl.sh b/scripts/repl.sh new file mode 100755 index 0000000..12ec9e4 --- /dev/null +++ b/scripts/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +nix repl ".#nixosConfigurations.$1.config"