mirror of
https://github.com/tuxdotrs/nix-config.git
synced 2026-09-19 16:49:04 +05:30
Compare commits
8 Commits
8f531dfc4e
...
d083b69cd6
| Author | SHA1 | Date | |
|---|---|---|---|
|
d083b69cd6
|
|||
|
7a9ad6fd6c
|
|||
|
b060e4ccb6
|
|||
|
9242347eaf
|
|||
|
f801c6c88c
|
|||
|
b071fe502c
|
|||
|
41a5c5be1a
|
|||
|
6379ff4662
|
@@ -39,29 +39,22 @@
|
||||
};
|
||||
|
||||
services = {
|
||||
nginx = {
|
||||
pangolin = {
|
||||
enable = true;
|
||||
domain = "lab.tux.rs";
|
||||
domain = "pangolin.lab.tux.rs";
|
||||
baseDomain = "lab.tux.rs";
|
||||
environmentFile = innerArgs.config.sops.secrets."pangolin".path;
|
||||
};
|
||||
|
||||
uptime-kuma = {
|
||||
enable = true;
|
||||
port = 1111;
|
||||
domain = "status.lab.tux.rs";
|
||||
};
|
||||
|
||||
mediaflow-proxy = {
|
||||
enable = true;
|
||||
port = 8888;
|
||||
domain = "mf-proxy.lab.tux.rs";
|
||||
environmentFile = innerArgs.config.sops.secrets."mediaflow-proxy".path;
|
||||
};
|
||||
|
||||
vaultwarden = {
|
||||
enable = true;
|
||||
port = 9999;
|
||||
domain = "bw.lab.tux.rs";
|
||||
};
|
||||
};
|
||||
|
||||
virtualisation = {
|
||||
@@ -110,6 +103,10 @@
|
||||
mediaflow-proxy = {
|
||||
sopsFile = ./secrets.yaml;
|
||||
};
|
||||
|
||||
pangolin = {
|
||||
sopsFile = ./secrets.yaml;
|
||||
};
|
||||
};
|
||||
|
||||
# --- Networking ---
|
||||
|
||||
@@ -8,6 +8,7 @@ cloudflare-credentials:
|
||||
dns-api-token: ENC[AES256_GCM,data:aLZqasMaxpv08KuGqhe66J/jHqEnMNdZrYtIurv01xk2/5OW//PaHQ==,iv:7tZYpOT27n/RWaj1CqiZbhA/g3aKbxjdkMA6SuW/YpQ=,tag:oetxyD9XMrihSLyDvl7qfw==,type:str]
|
||||
aiostreams: ENC[AES256_GCM,data:HeV4NONoqTti/4GBpzYaUEGgrSpDfCfcGJ3kbZAUtg5hm1zQCcelx3N4b/woSjaNZrDj98P5R3oZUkgVfv0RS2PKdJc3EdLaPFwXcuJ+W0U373sryU85uIIZi4BvQ4LyCCpuclPU5dgQmb9rzbIvhlu/ftfpKJsRbH2bUgMMo2nohMWUtg==,iv:V60U/omnN+09cSOQGvwwN8DC6/D++MB0axQyzIG97zo=,tag:vwNbXRj3CS+okb0NSwxgYw==,type:str]
|
||||
mediaflow-proxy: ENC[AES256_GCM,data:jk2eYyOmO3XpqFNo3jucB/VvL6pWBGrquYi/OpIwvSPqjbo=,iv:DIsqykv77/TlLhT9uIPGJRBlCQHVdhcuYlc56qQGZgk=,tag:phMXArjIrNNI51U9hpaUzg==,type:str]
|
||||
pangolin: ENC[AES256_GCM,data:G6TscTsWsyvBM/L2boxpDIrczV0cycQNT51mOf0vPKOHdifdBxT6Q3PY+Ms5arc=,iv:qh655lwIcD89D8ufIzJWYrDqPKGCrGMUXsgcFYwm9zY=,tag:kGlGzaOADZyY6gsLuI6EHw==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- enc: |
|
||||
@@ -28,7 +29,7 @@ sops:
|
||||
4TkObqH8ddGpbd7cX5a/wboTjYuEdAviWxjK2oBPgtcFc1f03X3tmA==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
recipient: age1mzxxxzhy3us3rd960ufqv7vlxj5cnug86md6x69llg9ujzw2pqws057llf
|
||||
lastmodified: "2026-07-13T15:24:16Z"
|
||||
mac: ENC[AES256_GCM,data:5NOOqdtJJj0ph3apCwaokiRySW9QIlmR01I7fFZDT2sNHqrJSgVVN8U5WtOnM1S61ID7MRxGLpSegU9M8lPnZd2WmhGIlactJjoSTE9+Xy5hj4m9mdWW0TZg9w4qmyIo8o8DuoDa2LiyilT97XaMnvoDz2ZqWcJxi44URLmk9o0=,iv:czkDfHv9eg1VzyMUT48W4OmmeSaUu6TzeYcyYSBu/+w=,tag:140ldPXqetX3733QnoOU0g==,type:str]
|
||||
lastmodified: "2026-08-07T20:02:00Z"
|
||||
mac: ENC[AES256_GCM,data:VrA2OPCcVvAzYjZTkHPxytclISP24P1FqiIQjSGQItkMLieom80N6933hB0Tdn3BM6600bHt2NweSqHjGx//pn2Gbur4pxeN3TpF9tKXc12IcAThUL9g48fMbk5y+kWWVUF1Pezod0YnzWAlalUXFqvKinfm4RqPNjDjndA/dcI=,iv:xfs9XD5ZIQ6dyMMZ8OE5FEs/hrSr/T2VwC7XvZ7xC2A=,tag:jYWo2kgwwltKB+njiYaPkQ==,type:str]
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.13.1
|
||||
version: 3.13.3
|
||||
|
||||
@@ -42,6 +42,10 @@
|
||||
networking = {
|
||||
openssh.enable = true;
|
||||
netbird-client.enable = true;
|
||||
newt = {
|
||||
enable = true;
|
||||
environmentFile = innerArgs.config.sops.secrets.newt.path;
|
||||
};
|
||||
};
|
||||
|
||||
services = {
|
||||
@@ -49,6 +53,12 @@
|
||||
enable = true;
|
||||
environmentFile = innerArgs.config.sops.secrets.discord-token.path;
|
||||
};
|
||||
|
||||
vaultwarden = {
|
||||
enable = true;
|
||||
domain = "bw.lab.tux.rs";
|
||||
configurePangolin = true;
|
||||
};
|
||||
};
|
||||
|
||||
virtualisation = {
|
||||
@@ -86,6 +96,11 @@
|
||||
sopsFile = ./secrets.yaml;
|
||||
owner = userName;
|
||||
};
|
||||
|
||||
newt = {
|
||||
sopsFile = ./secrets.yaml;
|
||||
owner = userName;
|
||||
};
|
||||
};
|
||||
|
||||
# --- Networking ---
|
||||
|
||||
@@ -4,10 +4,10 @@ gemini-api-key: ENC[AES256_GCM,data:gLZSoYTdKY+rwIpYiXvN9n9PGkUD6q8Oe7dHnYkjEjwD
|
||||
openrouter-api-key: ENC[AES256_GCM,data:6xONCl9lqOoO7b4CEyCz9607tICDUAkpglRjGS5nYq2ppg2UKqYTrWD1BGCA5Xfs/CWskniVhoNG3vscjKiYCCh9gbM6aqdmTQ==,iv:7Iwc9t00HOOBjA7URXcUO41badqYyJCkFHM/uPkLFxY=,tag:Cl39kitr2e0//HVwAdsdUQ==,type:str]
|
||||
opencode-go-api-key: ENC[AES256_GCM,data:dmeRKn7TWHnqvpyPQpcEG6yHTb2bRby/rh10ytL0jHj5R+lRmNVdmqUF92GTznY9vEaB6ZYCJecWhpm8g4upNfOWBg==,iv:9UMJpAlD8gpcNiN+liu3nawoAZQKapEg7sCp561N9E8=,tag:OZlASpOa5BQaQwFWjoLCRw==,type:str]
|
||||
netbird-key: ENC[AES256_GCM,data:q6eKisca04qn/CvALrvXF79MsToDhvLRLv2JTiUBAZglCC9m,iv:jj0/ZD7IDgopprTVUgSfJmdAJmUP3iqewU3dqssGYbk=,tag:6IPRdCm2FGdlTEIX7jt3qA==,type:str]
|
||||
newt: ENC[AES256_GCM,data:r5Rd81ZrzrIYbXtFkypbJltoGCOYrW6P4IpwGCtaH7lqCg7wD/WMboMx13HN4Mm0J4qbBpDakpfVv9qUTrisYP1xwpKkmY1kqPlFWRZN8hzuuNS2Tv3qUjavTp5XGotVPLHj1Cg/cwGcf8EAssYTwTy7H0PgdQKwqigQD1f1s/j4iXQ=,iv:1xP38/Ayt1xvn2fJGa5zgOrVNOw2J5taG1Orx6uNgZI=,tag:H9JXu9gzyyvTPWgXaoTsiw==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age14vktfes95f33vuefwnmuvryas7az04u76dsgyhfvsx73czkvmp2q7njkl4
|
||||
enc: |
|
||||
- enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA3Qkh0cmdHNGJTYmFNUFZW
|
||||
c244RjlyNjlrSWh1bG1IRFFFeFZZVzhaYVdBCmd1N3JNS0IzWDlUMUJSM0pYdi9L
|
||||
@@ -15,8 +15,8 @@ sops:
|
||||
Z3hhRitmdEwxbzcrS0cwNTZVK1lXYlUKSFfKk7JGzxRq9weL4NKJqfmAige2O+1T
|
||||
59PvEFKvvkGb6ajkzwTw0lB3UFzly6FuTnbSLY9r+oT9AMbxLoKdcQ==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
- recipient: age1huqa3hc7wcxk4dpelrzny437nzrx4fnll3d8g9ahznzk268yju5qufapxy
|
||||
enc: |
|
||||
recipient: age14vktfes95f33vuefwnmuvryas7az04u76dsgyhfvsx73czkvmp2q7njkl4
|
||||
- enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBOYlZiak1CSW1NSGt5QTRi
|
||||
RjlUeG5EODVkTVJDY1RrZXJ6OU5NQ0RIOG5jCnJxZ1R6MmlGWXY2SmtaY1pQSWdZ
|
||||
@@ -24,7 +24,8 @@ sops:
|
||||
V3h4dUZLcktrTUZvUm44eVZOWEl4VmMKMTvajoWcktb4jVIP4HyzQiR41Wg8Gdqi
|
||||
TLKEYsPQgOJ7s8P9gw2uPUY6HRz86CtiC6EbO27u0+8BbI85x1QScg==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2026-05-10T00:36:06Z"
|
||||
mac: ENC[AES256_GCM,data:nD0exblrbheP1C5lK8V17V/gkHJO6s6yVjXtQWcUOLVGrzkPSxkymYBHUFMTLVyYQNLCVMc8AHkuHVuJ1tBfXNll1f6/SGtfaBQcOLct70U7nFxd/XybTUlscNp2KafJWy/n4ZUfNDbfrWN1R463CN/M50jGqJPDWYuP9ah2JcI=,iv:izQUT/+HQqJZ48X5bXobFSaWcdcXQ/7eh+SCd9i4YYo=,tag:FJlR2wI4rWQ/SDfQGtQ7AQ==,type:str]
|
||||
recipient: age1huqa3hc7wcxk4dpelrzny437nzrx4fnll3d8g9ahznzk268yju5qufapxy
|
||||
lastmodified: "2026-08-09T11:21:03Z"
|
||||
mac: ENC[AES256_GCM,data:XFy+AiJRfrLhbX3j+0oO24qiHD5Hj2bVFqTMbUOOzsJzR0r8FBrwSNAZ0FVlFPFPAMitAIpZySS+kvbmEdZUfZ0soo83F5qwH6i/H5PZxqyDHst/Ig6Mrypp2DZMNZXNlqyLLmuaNGDf2pqApxCM3eSsgvCsNxdapRKlLSFJou4=,iv:D7gB4J4dhCfRo+1DaUAvOe3dWpoGvzIFouCJBNpwKiY=,tag:eLBZq/+Lce2S5Hu9OIC3gw==,type:str]
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.12.2
|
||||
version: 3.13.3
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
config = mkIf cfg.enable {
|
||||
services.netbird.clients = {
|
||||
${hostName} = {
|
||||
port = 51820;
|
||||
port = 61820;
|
||||
login = {
|
||||
enable = true;
|
||||
setupKeyFile = config.sops.secrets.netbird-key.path;
|
||||
|
||||
30
modules/nixos/networking/newt.nix
Normal file
30
modules/nixos/networking/newt.nix
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
flake.modules.nixos.networking =
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
with lib;
|
||||
let
|
||||
cfg = config.tnix.networking.newt;
|
||||
in
|
||||
{
|
||||
options.tnix.networking.newt = {
|
||||
enable = mkEnableOption "Newt";
|
||||
|
||||
environmentFile = mkOption {
|
||||
type = types.nullOr types.path;
|
||||
default = null;
|
||||
description = "Environment file with secrets passed to Newt";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
services.newt = {
|
||||
enable = true;
|
||||
environmentFile = cfg.environmentFile;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -15,6 +15,12 @@
|
||||
options.tnix.services.aiostreams = {
|
||||
enable = mkEnableOption "AIOStreams";
|
||||
|
||||
host = mkOption {
|
||||
type = types.str;
|
||||
default = "127.0.0.1";
|
||||
description = "Host on which AIOStreams listens";
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.port;
|
||||
default = 3000;
|
||||
@@ -24,7 +30,19 @@
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = "Domain on which nginx serves AIOStreams (disabled when empty)";
|
||||
description = "Domain on which AIOStreams is available";
|
||||
};
|
||||
|
||||
configureNginx = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether to configure Nginx as a reverse proxy for AIOStreams";
|
||||
};
|
||||
|
||||
configurePangolin = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether to configure Pangolin as a reverse proxy for AIOStreams";
|
||||
};
|
||||
|
||||
image = mkOption {
|
||||
@@ -47,10 +65,17 @@
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = cfg.domain != "";
|
||||
message = "tnix.services.aiostreams.domain must be set when tnix.services.aiostreams.enable is true.";
|
||||
}
|
||||
];
|
||||
|
||||
virtualisation.oci-containers.containers.aiostreams = {
|
||||
image = cfg.image;
|
||||
ports = [
|
||||
"127.0.0.1:${port}:3000"
|
||||
"${cfg.host}:${port}:3000"
|
||||
];
|
||||
environment = {
|
||||
ADDON_ID = cfg.domain;
|
||||
@@ -62,11 +87,39 @@
|
||||
];
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts.${cfg.domain} = mkIf (cfg.domain != "") {
|
||||
services = {
|
||||
nginx.virtualHosts.${cfg.domain} = mkIf cfg.configureNginx {
|
||||
forceSSL = acmeHost != "";
|
||||
useACMEHost = mkIf (acmeHost != "") acmeHost;
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:${port}";
|
||||
proxyPass = "http://${cfg.host}:${port}";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
};
|
||||
|
||||
newt.blueprint.proxy-resources = mkIf cfg.configurePangolin {
|
||||
aiostreams = {
|
||||
auth = {
|
||||
sso-enabled = false;
|
||||
};
|
||||
full-domain = cfg.domain;
|
||||
name = "aiostreams";
|
||||
protocol = "http";
|
||||
targets = [
|
||||
{
|
||||
hostname = "localhost";
|
||||
method = "http";
|
||||
port = cfg.port;
|
||||
healthcheck = {
|
||||
hostname = "localhost";
|
||||
port = cfg.port;
|
||||
scheme = "http";
|
||||
method = "GET";
|
||||
path = "/";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
123
modules/nixos/services/gitea.nix
Normal file
123
modules/nixos/services/gitea.nix
Normal file
@@ -0,0 +1,123 @@
|
||||
{
|
||||
flake.modules.nixos.services =
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
with lib;
|
||||
let
|
||||
cfg = config.tnix.services.gitea;
|
||||
port = toString cfg.port;
|
||||
acmeHost = config.tnix.services.nginx.domain;
|
||||
in
|
||||
{
|
||||
options.tnix.services.gitea = {
|
||||
enable = mkEnableOption "Gitea";
|
||||
|
||||
host = mkOption {
|
||||
type = types.str;
|
||||
default = "127.0.0.1";
|
||||
description = "Host on which Gitea listens";
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.port;
|
||||
default = 1114;
|
||||
description = "Port on which Gitea listens";
|
||||
};
|
||||
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = "Domain on which Gitea is available";
|
||||
};
|
||||
|
||||
configureNginx = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether to configure Nginx as a reverse proxy for Gitea";
|
||||
};
|
||||
|
||||
configurePangolin = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether to configure Pangolin as a reverse proxy for Gitea";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = cfg.domain != "";
|
||||
message = "tnix.services.gitea.domain must be set when tnix.services.gitea.enable is true.";
|
||||
}
|
||||
];
|
||||
|
||||
services = {
|
||||
gitea = {
|
||||
enable = true;
|
||||
settings = {
|
||||
service.DISABLE_REGISTRATION = true;
|
||||
server = {
|
||||
HTTP_ADDR = cfg.host;
|
||||
HTTP_PORT = cfg.port;
|
||||
DOMAIN = cfg.domain;
|
||||
ROOT_URL = "https://${cfg.domain}";
|
||||
};
|
||||
};
|
||||
database = {
|
||||
type = "postgres";
|
||||
name = "gitea";
|
||||
user = "gitea";
|
||||
};
|
||||
};
|
||||
|
||||
nginx.virtualHosts.${cfg.domain} = mkIf cfg.configureNginx {
|
||||
forceSSL = acmeHost != "";
|
||||
useACMEHost = mkIf (acmeHost != "") acmeHost;
|
||||
locations."/" = {
|
||||
proxyPass = "http://${cfg.host}:${port}";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
};
|
||||
|
||||
newt.blueprint.proxy-resources = mkIf cfg.configurePangolin {
|
||||
gitea = {
|
||||
auth = {
|
||||
sso-enabled = false;
|
||||
};
|
||||
full-domain = cfg.domain;
|
||||
name = "gitea";
|
||||
protocol = "http";
|
||||
targets = [
|
||||
{
|
||||
hostname = "localhost";
|
||||
method = "http";
|
||||
port = cfg.port;
|
||||
healthcheck = {
|
||||
hostname = "localhost";
|
||||
port = cfg.port;
|
||||
scheme = "http";
|
||||
method = "GET";
|
||||
path = "/";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
postgresql = {
|
||||
enable = true;
|
||||
ensureDatabases = [ "gitea" ];
|
||||
ensureUsers = [
|
||||
{
|
||||
name = "gitea";
|
||||
ensureDBOwnership = true;
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -15,16 +15,34 @@
|
||||
options.tnix.services.mediaflow-proxy = {
|
||||
enable = mkEnableOption "MediaFlow Proxy";
|
||||
|
||||
host = mkOption {
|
||||
type = types.str;
|
||||
default = "0.0.0.0";
|
||||
description = "Host on which MediaFlow Proxy listens";
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.port;
|
||||
default = 8888;
|
||||
default = 1113;
|
||||
description = "Port on which MediaFlow Proxy listens";
|
||||
};
|
||||
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = "Domain on which nginx serves MediaFlow Proxy (disabled when empty)";
|
||||
description = "Domain on which MediaFlow Proxy is available";
|
||||
};
|
||||
|
||||
configureNginx = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether to configure Nginx as a reverse proxy for MediaFlow Proxy";
|
||||
};
|
||||
|
||||
configurePangolin = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether to configure Pangolin as a reverse proxy for MediaFlow Proxy";
|
||||
};
|
||||
|
||||
image = mkOption {
|
||||
@@ -41,10 +59,21 @@
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = !cfg.configureNginx || cfg.domain != "";
|
||||
message = "tnix.services.mediaflow-proxy.domain must be set when tnix.services.mediaflow-proxy.configureNginx is enabled.";
|
||||
}
|
||||
{
|
||||
assertion = !cfg.configurePangolin || cfg.domain != "";
|
||||
message = "tnix.services.mediaflow-proxy.domain must be set when tnix.services.mediaflow-proxy.configurePangolin is enabled.";
|
||||
}
|
||||
];
|
||||
|
||||
virtualisation.oci-containers.containers.mediaflow-proxy = {
|
||||
image = cfg.image;
|
||||
ports = [
|
||||
"${port}:${port}"
|
||||
"${cfg.host}:${port}:${port}"
|
||||
];
|
||||
environment = {
|
||||
APP__SERVER__HOST = "0.0.0.0";
|
||||
@@ -53,14 +82,41 @@
|
||||
environmentFiles = optional (cfg.environmentFile != null) cfg.environmentFile;
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts.${cfg.domain} = mkIf (cfg.domain != "") {
|
||||
services = {
|
||||
nginx.virtualHosts.${cfg.domain} = mkIf cfg.configureNginx {
|
||||
forceSSL = acmeHost != "";
|
||||
useACMEHost = mkIf (acmeHost != "") acmeHost;
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:${port}";
|
||||
proxyPass = "http://${cfg.host}:${port}";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
};
|
||||
|
||||
newt.blueprint.proxy-resources = mkIf cfg.configurePangolin {
|
||||
mediaflow-proxy = {
|
||||
auth = {
|
||||
sso-enabled = false;
|
||||
};
|
||||
full-domain = cfg.domain;
|
||||
name = "mediaflow-proxy";
|
||||
protocol = "http";
|
||||
targets = [
|
||||
{
|
||||
hostname = "localhost";
|
||||
method = "http";
|
||||
port = cfg.port;
|
||||
healthcheck = {
|
||||
hostname = "localhost";
|
||||
port = cfg.port;
|
||||
scheme = "http";
|
||||
method = "GET";
|
||||
path = "/";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
91
modules/nixos/services/pangolin.nix
Normal file
91
modules/nixos/services/pangolin.nix
Normal file
@@ -0,0 +1,91 @@
|
||||
{
|
||||
flake.modules.nixos.services =
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
userEmail,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
with lib;
|
||||
let
|
||||
cfg = config.tnix.services.pangolin;
|
||||
in
|
||||
{
|
||||
options.tnix.services.pangolin = {
|
||||
enable = mkEnableOption "Pangolin";
|
||||
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = "Domain on which Pangolin Dashboard is available";
|
||||
};
|
||||
|
||||
baseDomain = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = "Pangolin base fully qualified domain name";
|
||||
};
|
||||
|
||||
environmentFile = mkOption {
|
||||
type = types.nullOr types.path;
|
||||
default = null;
|
||||
description = "Environment file with secrets passed to Pangolin";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
services = {
|
||||
pangolin = {
|
||||
enable = true;
|
||||
package = (
|
||||
pkgs.fosrl-pangolin.override {
|
||||
databaseType = "pg";
|
||||
}
|
||||
);
|
||||
openFirewall = true;
|
||||
baseDomain = cfg.baseDomain;
|
||||
dashboardDomain = cfg.domain;
|
||||
environmentFile = cfg.environmentFile;
|
||||
letsEncryptEmail = userEmail;
|
||||
|
||||
settings = {
|
||||
app.dashboard_url = "https://${config.services.pangolin.dashboardDomain}";
|
||||
domains.domain1 = {
|
||||
base_domain = config.services.pangolin.baseDomain;
|
||||
prefer_wildcard_cert = false;
|
||||
};
|
||||
server = {
|
||||
external_port = 3000;
|
||||
internal_port = 3001;
|
||||
next_port = 3002;
|
||||
integration_port = 3003;
|
||||
# needs to be set, otherwise this fails silently
|
||||
# see https://github.com/fosrl/newt/issues/37
|
||||
internal_hostname = "localhost";
|
||||
};
|
||||
gerbil.base_endpoint = config.services.pangolin.dashboardDomain;
|
||||
flags = {
|
||||
disable_signup_without_invite = true;
|
||||
enable_integration_api = false;
|
||||
allow_raw_resources = true;
|
||||
disable_enterprise_features = true;
|
||||
};
|
||||
postgres.connection_string = "postgresql:///pangolin?host=/run/postgresql";
|
||||
};
|
||||
};
|
||||
|
||||
postgresql = {
|
||||
enable = true;
|
||||
ensureDatabases = [ "pangolin" ];
|
||||
ensureUsers = [
|
||||
{
|
||||
name = "pangolin";
|
||||
ensureDBOwnership = true;
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -15,6 +15,12 @@
|
||||
options.tnix.services.uptime-kuma = {
|
||||
enable = mkEnableOption "Uptime Kuma";
|
||||
|
||||
host = mkOption {
|
||||
type = types.str;
|
||||
default = "127.0.0.1";
|
||||
description = "Host on which Uptime Kuma listens";
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.port;
|
||||
default = 1111;
|
||||
@@ -24,25 +30,70 @@
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = "Domain on which nginx serves Uptime Kuma (disabled when empty)";
|
||||
description = "Domain on which Uptime Kuma is available";
|
||||
};
|
||||
|
||||
configureNginx = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether to configure Nginx as a reverse proxy for Uptime Kuma";
|
||||
};
|
||||
|
||||
configurePangolin = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether to configure Pangolin as a reverse proxy for Uptime Kuma";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = cfg.domain != "";
|
||||
message = "tnix.services.uptime-kuma.domain must be set when tnix.services.uptime-kuma.enable is true.";
|
||||
}
|
||||
];
|
||||
|
||||
services = {
|
||||
uptime-kuma = {
|
||||
enable = true;
|
||||
settings = {
|
||||
HOST = "127.0.0.1";
|
||||
HOST = cfg.host;
|
||||
PORT = port;
|
||||
};
|
||||
};
|
||||
|
||||
nginx.virtualHosts.${cfg.domain} = mkIf (cfg.domain != "") {
|
||||
nginx.virtualHosts.${cfg.domain} = mkIf cfg.configureNginx {
|
||||
forceSSL = acmeHost != "";
|
||||
useACMEHost = mkIf (acmeHost != "") acmeHost;
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:${port}";
|
||||
proxyPass = "http://${cfg.host}:${port}";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
};
|
||||
|
||||
newt.blueprint.proxy-resources = mkIf cfg.configurePangolin {
|
||||
uptime-kuma = {
|
||||
auth = {
|
||||
sso-enabled = false;
|
||||
};
|
||||
full-domain = cfg.domain;
|
||||
name = "uptime-kuma";
|
||||
protocol = "http";
|
||||
targets = [
|
||||
{
|
||||
hostname = "localhost";
|
||||
method = "http";
|
||||
port = cfg.port;
|
||||
healthcheck = {
|
||||
hostname = "localhost";
|
||||
port = cfg.port;
|
||||
scheme = "http";
|
||||
method = "GET";
|
||||
path = "/";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -15,26 +15,51 @@
|
||||
options.tnix.services.vaultwarden = {
|
||||
enable = mkEnableOption "Vaultwarden";
|
||||
|
||||
host = mkOption {
|
||||
type = types.str;
|
||||
default = "127.0.0.1";
|
||||
description = "Host on which Vaultwarden listens";
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.port;
|
||||
default = 8000;
|
||||
default = 1112;
|
||||
description = "Port on which Vaultwarden listens";
|
||||
};
|
||||
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = "Domain on which nginx serves Vaultwarden (disabled when empty)";
|
||||
description = "Domain on which Vaultwarden is available";
|
||||
};
|
||||
|
||||
configureNginx = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether to configure Nginx as a reverse proxy for Vaultwarden";
|
||||
};
|
||||
|
||||
configurePangolin = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether to configure Pangolin as a reverse proxy for Vaultwarden";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = cfg.domain != "";
|
||||
message = "tnix.services.vaultwarden.domain must be set when tnix.services.vaultwarden.enable is true.";
|
||||
}
|
||||
];
|
||||
|
||||
services = {
|
||||
vaultwarden = {
|
||||
enable = true;
|
||||
dbBackend = "postgresql";
|
||||
config = {
|
||||
ROCKET_ADDRESS = "127.0.0.1";
|
||||
ROCKET_ADDRESS = cfg.host;
|
||||
ROCKET_PORT = cfg.port;
|
||||
DOMAIN = "https://${cfg.domain}";
|
||||
|
||||
@@ -45,15 +70,40 @@
|
||||
};
|
||||
};
|
||||
|
||||
nginx.virtualHosts.${cfg.domain} = mkIf (cfg.domain != "") {
|
||||
nginx.virtualHosts.${cfg.domain} = mkIf cfg.configureNginx {
|
||||
forceSSL = acmeHost != "";
|
||||
useACMEHost = mkIf (acmeHost != "") acmeHost;
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:${port}";
|
||||
proxyPass = "http://${cfg.host}:${port}";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
};
|
||||
|
||||
newt.blueprint.proxy-resources = mkIf cfg.configurePangolin {
|
||||
vaultwarden = {
|
||||
auth = {
|
||||
sso-enabled = false;
|
||||
};
|
||||
full-domain = cfg.domain;
|
||||
name = "vaultwarden";
|
||||
protocol = "http";
|
||||
targets = [
|
||||
{
|
||||
hostname = "localhost";
|
||||
method = "http";
|
||||
port = cfg.port;
|
||||
healthcheck = {
|
||||
hostname = "localhost";
|
||||
port = cfg.port;
|
||||
scheme = "http";
|
||||
method = "GET";
|
||||
path = "/";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
postgresql = {
|
||||
enable = true;
|
||||
ensureDatabases = [ "vaultwarden" ];
|
||||
|
||||
Reference in New Issue
Block a user