Compare commits

...

3 commits

Author SHA1 Message Date
79e14c015c Minor fixes: removed xserver configs, hyprland cache, and some mkDefault values in ssh; flake.lock update 2025-06-15 19:57:27 -04:00
9f2b2a986c Dconf update for Rune, winprops and audio device
- random comments fixes
2025-06-14 19:11:02 -04:00
86495b11a7 Replace caddy with newt; add pangolin as a homelab Proxy service
- Add newt service definitions and corresponding nix modules
- Replace caddy configurations across cloud, komo, proxy, and sock hosts with newt
- Implement compose configurations for pangolin in proxy host
- Update adguard naming and systemd service definitions
- Refresh secrets with newt and pangolin credentials
2025-06-14 18:47:31 -04:00
24 changed files with 624 additions and 305 deletions

View file

@ -3,7 +3,7 @@
"editor.formatOnSaveMode": "file",
"explorer.fileNesting.patterns": {
".gitignore": ".gitattributes, .envrc, readme",
"flake.nix": "flake.lock, shell.nix, secrets.nix"
"flake.nix": "flake.lock, *.nix"
},
"files.exclude": {
".git-crypt": true

50
flake.lock generated
View file

@ -402,11 +402,11 @@
},
"hardware": {
"locked": {
"lastModified": 1749195551,
"narHash": "sha256-W5GKQHgunda/OP9sbKENBZhMBDNu2QahoIPwnsF6CeM=",
"lastModified": 1749832440,
"narHash": "sha256-lfxhuxAaHlYFGr8yOrAXZqdMt8PrFLzjVqH9v3lQaoY=",
"owner": "nixos",
"repo": "nixos-hardware",
"rev": "4602f7e1d3f197b3cb540d5accf5669121629628",
"rev": "db030f62a449568345372bd62ed8c5be4824fa49",
"type": "github"
},
"original": {
@ -443,11 +443,11 @@
]
},
"locked": {
"lastModified": 1749483884,
"narHash": "sha256-HdyfdVx0NbgrVtLY4lXdX9X/YE3PZjGZFnSyoAy1GJc=",
"lastModified": 1749935160,
"narHash": "sha256-lTLR7AyrrIS/b4frHKb5pw/gcPM0GgoGCURqeiOX9k8=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "74d196c9943a67908d1883f61154e594d03863e5",
"rev": "8fabeb9c142a303e02270c3a3a0d8e00af9d0dfe",
"type": "github"
},
"original": {
@ -529,11 +529,11 @@
]
},
"locked": {
"lastModified": 1749348095,
"narHash": "sha256-4KaUocEPNoU6gpFE6WPLMvMK5tmvJyc0qf84Mp8Chlw=",
"lastModified": 1749847109,
"narHash": "sha256-9i/A5yrjyYT63YZ6wOxOFru/kzQPIKZVSVWS1Clerr4=",
"owner": "fufexan",
"repo": "nix-gaming",
"rev": "4221d80488883c40003f0704af78699a583f0c9f",
"rev": "9a9f441bb894ee929e93596f0dc0f23c3d9a7532",
"type": "github"
},
"original": {
@ -598,27 +598,27 @@
},
"nixpkgs-stable": {
"locked": {
"lastModified": 1749173751,
"narHash": "sha256-ENY3y3v6S9ZmLDDLI3LUT8MXmfXg/fSt2eA4GCnMVCE=",
"lastModified": 1749727998,
"narHash": "sha256-mHv/yeUbmL91/TvV95p+mBVahm9mdQMJoqaTVTALaFw=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "ed29f002b6d6e5e7e32590deb065c34a31dc3e91",
"rev": "fd487183437963a59ba763c0cc4f27e3447dd6dd",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-24.11",
"ref": "nixos-25.05",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-unstable": {
"locked": {
"lastModified": 1749285348,
"narHash": "sha256-frdhQvPbmDYaScPFiCnfdh3B/Vh81Uuoo0w5TkWmmjU=",
"lastModified": 1749794982,
"narHash": "sha256-Kh9K4taXbVuaLC0IL+9HcfvxsSUx8dPB5s5weJcc9pc=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "3e3afe5174c561dee0df6f2c2b2236990146329f",
"rev": "ee930f9755f58096ac6e8ca94a1887e0534e2d81",
"type": "github"
},
"original": {
@ -630,11 +630,11 @@
},
"nixpkgs_2": {
"locked": {
"lastModified": 1749285348,
"narHash": "sha256-frdhQvPbmDYaScPFiCnfdh3B/Vh81Uuoo0w5TkWmmjU=",
"lastModified": 1749794982,
"narHash": "sha256-Kh9K4taXbVuaLC0IL+9HcfvxsSUx8dPB5s5weJcc9pc=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "3e3afe5174c561dee0df6f2c2b2236990146329f",
"rev": "ee930f9755f58096ac6e8ca94a1887e0534e2d81",
"type": "github"
},
"original": {
@ -884,11 +884,11 @@
"tinted-zed": "tinted-zed"
},
"locked": {
"lastModified": 1749481862,
"narHash": "sha256-CXZL1Kt4rP1SAQhT4wCM207pcjkTeZMza9iIVFKV71c=",
"lastModified": 1749905587,
"narHash": "sha256-sZpQM+InPCYwJQiTxs/PCCupwbYNaSCFi2Hvpl1/pOo=",
"owner": "danth",
"repo": "stylix",
"rev": "d73d8f6a4834716496bf8930a492b115cc3d7d17",
"rev": "77a8b26520f48305f3b1bacffaa8740dde8afa2a",
"type": "github"
},
"original": {
@ -1172,11 +1172,11 @@
]
},
"locked": {
"lastModified": 1748971473,
"narHash": "sha256-0Xh6sZI86Ops6u7wyDQlVvV+MvRRXIDb1r3sMnLNk9M=",
"lastModified": 1749874024,
"narHash": "sha256-bFNesH4+qRcsA/bL+HT4ep1rNkn1A1AZ2RmlZlETwlw=",
"owner": "youwen5",
"repo": "zen-browser-flake",
"rev": "5cc269976ca876674d8ccc7f40debb61e05583ab",
"rev": "d3d3c12550f1d4196bd7f2971c65ffde2bd92a07",
"type": "github"
},
"original": {

View file

@ -321,20 +321,26 @@ with lib.hm.gvariant;
vertical-margin-bottom = 8;
window-gap = 8;
winprops = [
''
{"wm_class":"Code","preferredWidth":"70%","spaceIndex":0}
''
''
{"wm_class":"com.mitchellh.ghostty","scratch_layer":true}
''
''
{"wm_class":"code","preferredWidth":"70%"}
''
''
{"wm_class":"discord","preferredWidth":"100%","spaceIndex":1}
''
''
{"wm_class":"gnome-control-center","scratch_layer":true}
''
''
{"wm_class":"gnome-extensions-app","scratch_layer":true}
''
''
{"wm_class":"org.gnome.Nautilus","scratch_layer":true}
''
''
{"wm_class":"gnome-control-center","scratch_layer":true}
{"wm_class":"TelegramDesktop","spaceIndex":1}
''
];
};

View file

@ -111,10 +111,10 @@ with lib.hm.gvariant;
"Microphone 8211 USB Live camera"
];
excluded-output-names = [
"Analog Output HyperX Cloud Alpha S"
"Analog Output \8211 HyperX Cloud Alpha S"
"Analog Output 8211 HyperX Cloud Alpha S"
"Analog Output 8211 HyperX Cloud Alpha S"
# "Analog Output HyperX Cloud Alpha S"
# "Analog Output \8211 HyperX Cloud Alpha S"
# "Analog Output 8211 HyperX Cloud Alpha S"
# "Analog Output 8211 HyperX Cloud Alpha S"
"HDMI / DisplayPort Rembrandt Radeon High Definition Audio Controller"
"HDMI / DisplayPort \8211 Rembrandt Radeon High Definition Audio Controller"
"HDMI / DisplayPort 8211 Rembrandt Radeon High Definition Audio Controller"
@ -148,7 +148,7 @@ with lib.hm.gvariant;
])
(lib.hm.gvariant.mkDictionaryEntry [
"Analog Output HyperX Cloud Alpha S"
"NO"
"Cloud S - 7.1"
])
(lib.hm.gvariant.mkDictionaryEntry [
"Digital Output (S/PDIF) HyperX Cloud Alpha S"

View file

@ -1,7 +1,7 @@
###############################################################
#
# Caenus - Oracle VPS
# NixOS VPS, ____, ____
# NixOS VPS, 4vCPU, 24Ggb RAM, 200GB
#
# Public IP
#

View file

@ -0,0 +1,3 @@
{
# TBD; Not working well yet in X Elite Laptop
}

View file

@ -1,11 +1,7 @@
{ pkgs, config, ... }:
{
## DE ##
services.xserver = {
enable = true;
desktopManager.gnome = {
services.desktopManager.gnome = {
enable = true;
extraGSettingsOverridePackages = [ pkgs.mutter ];
extraGSettingsOverrides = ''
@ -13,7 +9,8 @@
experimental-features=['scale-monitor-framebuffer']
'';
};
displayManager = {
services.displayManager = {
gdm = {
enable = true;
wayland = true;
@ -24,12 +21,6 @@
};
};
xkb = {
layout = "us";
variant = "";
};
};
#INFO: Fix for autoLogin
systemd.services."getty@tty1".enable = false;
systemd.services."autovt@tty1".enable = false;
@ -54,7 +45,6 @@
];
## Exclusions ##
services.xserver.excludePackages = [ pkgs.xterm ];
environment.gnome.excludePackages = (
with pkgs;
[

View file

@ -17,6 +17,7 @@ in
(map lib.custom.relativeToRoot [
"modules/global"
"modules/nixos"
])
];
@ -104,9 +105,6 @@ in
min-free = 128000000; # 128MB
max-free = 1000000000; # 1GB
substituters = [ "https://hyprland.cachix.org" ];
trusted-public-keys = [ "hyprland.cachix.org-1:a7pgxzMz7+chwVL3/pzj6jIBMioiJM7ypFP8PwtkuGc=" ];
trusted-users = [ "@wheel" ];
# Deduplicate and optimize nix store
auto-optimise-store = true;

View file

@ -1,3 +1,4 @@
{ lib, ... }:
{
programs.ssh.startAgent = true;
@ -7,8 +8,8 @@
settings = {
AllowUsers = null; # everyone
PasswordAuthentication = false;
PermitRootLogin = "no";
PasswordAuthentication = lib.mkDefault false;
PermitRootLogin = lib.mkDefault "no";
KbdInteractiveAuthentication = false;
# Automatically remove stale sockets
StreamLocalBindUnlink = "yes";

View file

@ -1,20 +0,0 @@
{
services.caddy = {
enable = true;
virtualHosts = {
## Filerun ##
"drive.ryot.foo" = {
useACMEHost = "ryot.foo";
extraConfig = ''
reverse_proxy http://localhost:8181 {
header_up Host {host}
# header_up X-Forwarded-For {remote}
# header_up X-Forwarded-Proto {scheme}
# header_up X-Forwarded-Protocol {scheme}
# header_up X-Forwarded-Port {server_port}
}
'';
};
};
};
}

View file

@ -0,0 +1,11 @@
{ config, ... }:
let
cfg = config.secretsSpec.docker.newt-cloud;
in
{
services.newt = {
enable = true;
id = cfg.ID;
secret = cfg.SECRET;
};
}

View file

@ -31,7 +31,6 @@ in
"hosts/global/core"
## Optional Configs ##
"hosts/global/common/acme"
"hosts/global/common/docker.nix"
])
];

View file

@ -1,119 +0,0 @@
{
services.caddy = {
enable = true;
virtualHosts = {
## TOPH.CC ##
"blog.toph.cc" = {
useACMEHost = "toph.cc";
extraConfig = ''
reverse_proxy localhost:2368
'';
};
## RYOT.FOO ##
"auth.ryot.foo" = {
useACMEHost = "ryot.foo";
extraConfig = ''
reverse_proxy localhost:9000 {
header_up Host {host}
header_up X-Forwarded-For {remote}
header_up X-Forwarded-Proto {scheme}
header_up X-Forwarded-Protocol {scheme}
header_up X-Forwarded-Port {server_port}
}
'';
};
"frp.ryot.foo" = {
useACMEHost = "ryot.foo";
extraConfig = ''
route {
# 1) Proxy all outpost requests back to Authentik
reverse_proxy /outpost.goauthentik.io/* localhost:9000
# 2) Protect everything else via forward_auth
forward_auth localhost:9000 {
uri /outpost.goauthentik.io/auth/caddy
# copy user info headers from Authentik
copy_headers X-Authentik-Username X-Authentik-Groups \
X-Authentik-Entitlements X-Authentik-Email \
X-Authentik-Name X-Authentik-Uid \
X-Authentik-Jwt X-Authentik-Meta-Jwks \
X-Authentik-Meta-Outpost X-Authentik-Meta-Provider \
X-Authentik-Meta-App X-Authentik-Meta-Version
trusted_proxies private_ranges
}
# 3) If authenticated, proxy to your FRP UI
reverse_proxy localhost:4041 {
header_up Host {host}
header_up X-Real-IP {remote}
header_up X-Forwarded-For {remote}
header_up X-Forwarded-Proto {scheme}
header_up X-Forwarded-Port {server_port}
}
}
'';
};
"grafana.ryot.foo" = {
useACMEHost = "ryot.foo";
extraConfig = ''
reverse_proxy localhost:3001
'';
};
"git.ryot.foo" = {
useACMEHost = "ryot.foo";
extraConfig = ''
reverse_proxy localhost:3003
'';
};
"influx.ryot.foo" = {
useACMEHost = "ryot.foo";
extraConfig = ''
reverse_proxy localhost:8086
'';
};
"home.ryot.foo" = {
useACMEHost = "ryot.foo";
extraConfig = ''
reverse_proxy localhost:7475
'';
};
"komodo.ryot.foo" = {
useACMEHost = "ryot.foo";
extraConfig = ''
reverse_proxy localhost:9120
'';
};
"map.ryot.foo" = {
useACMEHost = "ryot.foo";
extraConfig = ''
reverse_proxy localhost:25566
'';
};
"outline.ryot.foo" = {
useACMEHost = "ryot.foo";
extraConfig = ''
reverse_proxy localhost:3480
'';
};
"plane.ryot.foo" = {
useACMEHost = "ryot.foo";
extraConfig = ''
reverse_proxy localhost:3000
'';
};
};
};
}

View file

@ -0,0 +1,12 @@
{ config, ... }:
let
cfg = config.secretsSpec.docker.newt-komo;
in
{
services.newt = {
enable = true;
id = cfg.ID;
secret = cfg.SECRET;
useHostNetwork = true;
};
}

View file

@ -5,7 +5,7 @@
*/
{
# Containers
virtualisation.oci-containers.containers."adguard-adguard" = {
virtualisation.oci-containers.containers."adguard" = {
image = "adguard/adguardhome:latest";
volumes = [
"/etc/adguard/confdir:/opt/adguardhome/conf:rw"
@ -24,7 +24,8 @@
"--network=adguard_default"
];
};
systemd.services."docker-adguard-adguard" = {
systemd.services."docker-adguard" = {
serviceConfig = {
Restart = lib.mkOverride 90 "always";
RestartMaxDelaySec = lib.mkOverride 90 "1m";

View file

@ -1,72 +0,0 @@
{
services.caddy = {
enable = true;
virtualHosts = {
"adguard.ryot.foo" = {
useACMEHost = "ryot.foo";
extraConfig = ''
reverse_proxy localhost:3000
'';
};
"cloudflared.ryot.foo" = {
useACMEHost = "ryot.foo";
extraConfig = ''
reverse_proxy localhost:14333
'';
};
## openWRT ##
"wrt.ryot.foo" = {
useACMEHost = "ryot.foo";
extraConfig = ''
reverse_proxy http://104.40.3.1 {
header_up Host {host}
header_up X-Real-IP {remote}
header_up X-Forwarded-For {remote}
header_up X-Forwarded-Proto {scheme}
header_up X-Forwarded-Port {server_port}
}
'';
};
## PROXMOX NODES ##
"ochre.ryot.foo" = {
useACMEHost = "ryot.foo";
extraConfig = ''
reverse_proxy https://104.40.3.2:8006 {
transport http {
tls_insecure_skip_verify
# optional: tls_server_name 104.40.3.2
}
# ensure Proxmox sees the right Host
header_up Host {host}
header_up X-Real-IP {remote}
header_up X-Forwarded-For {remote}
header_up X-Forwarded-Proto {scheme}
header_up X-Forwarded-Port {server_port}
}
'';
};
"pve.ryot.foo" = {
useACMEHost = "ryot.foo";
extraConfig = ''
reverse_proxy https://104.40.3.3:8006 {
transport http {
tls_insecure_skip_verify
# optional: tls_server_name 104.40.3.3
}
header_up Host {host}
header_up X-Real-IP {remote}
header_up X-Forwarded-For {remote}
header_up X-Forwarded-Proto {scheme}
header_up X-Forwarded-Port {server_port}
}
'';
};
};
};
}

View file

@ -0,0 +1,12 @@
{ config, ... }:
let
cfg = config.secretsSpec.docker.newt-proxy;
in
{
services.newt = {
enable = true;
id = cfg.ID;
secret = cfg.SECRET;
useHostNetwork = true;
};
}

View file

@ -0,0 +1,156 @@
# Auto-generated using compose2nix v0.3.1.
{
pkgs,
lib,
config,
...
}:
{
# Containers
virtualisation.oci-containers.containers."gerbil" = {
image = "fosrl/gerbil:1.0.0";
volumes = [
"/etc/pangolin/config:/var/config:rw"
];
ports = [
"51820:51820/udp"
"443:443/tcp"
"222:222/tcp"
"80:80/tcp"
];
cmd = [
"--reachableAt=http://gerbil:3003"
"--generateAndSaveKeyTo=/var/config/key"
"--remoteConfig=http://pangolin:3001/api/v1/gerbil/get-config"
"--reportBandwidthTo=http://pangolin:3001/api/v1/gerbil/receive-bandwidth"
];
dependsOn = [
"pangolin"
];
log-driver = "journald";
extraOptions = [
"--cap-add=NET_ADMIN"
# "--cap-add=SYS_MODULE"
"--network-alias=gerbil"
"--network=pangolin"
];
};
systemd.services."docker-gerbil" = {
serviceConfig = {
Restart = lib.mkOverride 90 "always";
RestartMaxDelaySec = lib.mkOverride 90 "1m";
RestartSec = lib.mkOverride 90 "100ms";
RestartSteps = lib.mkOverride 90 9;
};
after = [
"docker-network-pangolin.service"
];
requires = [
"docker-network-pangolin.service"
];
partOf = [
"docker-compose-pangolin-root.target"
];
wantedBy = [
"docker-compose-pangolin-root.target"
];
};
virtualisation.oci-containers.containers."pangolin" = {
image = "fosrl/pangolin:1.5.1";
volumes = [
"/etc/pangolin/config:/app/config:rw"
];
log-driver = "journald";
extraOptions = [
"--health-cmd=[\"curl\", \"-f\", \"http://localhost:3001/api/v1/\"]"
"--health-interval=3s"
"--health-retries=15"
"--health-timeout=3s"
"--network-alias=pangolin"
"--network=pangolin"
];
};
systemd.services."docker-pangolin" = {
serviceConfig = {
Restart = lib.mkOverride 90 "always";
RestartMaxDelaySec = lib.mkOverride 90 "1m";
RestartSec = lib.mkOverride 90 "100ms";
RestartSteps = lib.mkOverride 90 9;
};
after = [
"docker-network-pangolin.service"
"pangolin-config-sync.service"
];
requires = [
"docker-network-pangolin.service"
"pangolin-config-sync.service"
];
partOf = [
"docker-compose-pangolin-root.target"
];
wantedBy = [
"docker-compose-pangolin-root.target"
];
};
virtualisation.oci-containers.containers."traefik" = {
image = "traefik:v3.4.0";
environment = {
"CLOUDFLARE_DNS_API_TOKEN" = config.secretsSpec.api.cloudflare;
};
volumes = [
"/etc/pangolin/config/letsencrypt:/letsencrypt:rw"
"/etc/pangolin/config/traefik:/etc/traefik:ro"
];
cmd = [ "--configFile=/etc/traefik/traefik_config.yml" ];
dependsOn = [
"gerbil"
"pangolin"
];
log-driver = "journald";
extraOptions = [
"--network=container:gerbil"
];
};
systemd.services."docker-traefik" = {
serviceConfig = {
Restart = lib.mkOverride 90 "always";
RestartMaxDelaySec = lib.mkOverride 90 "1m";
RestartSec = lib.mkOverride 90 "100ms";
RestartSteps = lib.mkOverride 90 9;
};
partOf = [
"docker-compose-pangolin-root.target"
];
wantedBy = [
"docker-compose-pangolin-root.target"
];
};
# Networks
systemd.services."docker-network-pangolin" = {
path = [ pkgs.docker ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStop = "docker network rm -f pangolin";
};
script = ''
docker network inspect pangolin || docker network create pangolin --driver=bridge
'';
partOf = [ "docker-compose-pangolin-root.target" ];
wantedBy = [ "docker-compose-pangolin-root.target" ];
};
# Root service
# When started, this will automatically create all resources and start
# the containers. When stopped, this will teardown all resources.
systemd.targets."docker-compose-pangolin-root" = {
unitConfig = {
Description = "Root target generated by compose2nix.";
};
wantedBy = [ "multi-user.target" ];
};
}

View file

@ -0,0 +1,230 @@
{
lib,
config,
pkgs,
...
}:
let
smtp = config.secretsSpec.users.admin.smtp;
pangolin = config.secretsSpec.docker.pangolin;
# Create the configuration files as derivations
pangolinConfigFile = pkgs.writeText "pangolin-config.yml" ''
app:
dashboard_url: "https://pangolin.ryot.foo"
log_level: "debug"
save_logs: true
domains:
domain1:
base_domain: "ryot.foo"
cert_resolver: "letsencrypt"
prefer_wildcard_cert: true
domain2:
base_domain: "toph.cc"
cert_resolver: "letsencrypt"
prefer_wildcard_cert: true
domain3:
base_domain: "goldenlemon.cc"
cert_resolver: "letsencrypt"
prefer_wildcard_cert: true
domain4:
base_domain: "kwahson.xyz"
cert_resolver: "letsencrypt"
prefer_wildcard_cert: true
server:
external_port: 3000
internal_port: 3001
next_port: 3002
internal_hostname: "pangolin"
session_cookie_name: "p_session_token"
resource_access_token_param: "p_token"
resource_access_token_headers:
id: "P-Access-Token-Id"
token: "P-Access-Token"
resource_session_request_param: "p_session_request"
secret: "${pangolin.SECRET}"
traefik:
cert_resolver: "letsencrypt"
http_entrypoint: "web"
https_entrypoint: "websecure"
gerbil:
start_port: 51820
base_endpoint: "pangolin.ryot.foo"
use_subdomain: false
block_size: 24
site_block_size: 30
subnet_group: 104.40.3.1/24
rate_limits:
global:
window_minutes: 1
max_requests: 100
email:
smtp_host: "${smtp.host}"
smtp_port: ${toString smtp.port}
smtp_user: "${smtp.user}"
smtp_pass: "${smtp.password}"
no_reply: "no-reply@ryot.foo"
users:
server_admin:
email: "${pangolin.USER}"
password: "${pangolin.PASSWORD}"
flags:
require_email_verification: true
disable_signup_without_invite: true
disable_user_create_org: true
allow_raw_resources: true
allow_base_domain_resources: true
'';
traefikConfigFile = pkgs.writeText "traefik-config.yml" ''
api:
insecure: true
dashboard: true
providers:
http:
endpoint: "http://pangolin:3001/api/v1/traefik-config"
pollInterval: "5s"
file:
filename: "/etc/traefik/dynamic_config.yml"
experimental:
plugins:
badger:
moduleName: "github.com/fosrl/badger"
version: "v1.2.0"
log:
level: "DEBUG"
format: "common"
certificatesResolvers:
letsencrypt:
acme:
dnsChallenge:
provider: cloudflare
delayBeforeCheck: 60
resolvers:
- "1.1.1.1:53"
- "8.8.8.8:53"
email: chris@toph.cc
storage: "/letsencrypt/acme.json"
caServer: "https://acme-v02.api.letsencrypt.org/directory"
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
transport:
respondingTimeouts:
readTimeout: "30m"
http:
tls:
certResolver: "letsencrypt"
tcp-222:
address: ":222/tcp"
serversTransport:
insecureSkipVerify: true
'';
dynamicConfigFile = pkgs.writeText "dynamic-config.yml" ''
http:
middlewares:
redirect-to-https:
redirectScheme:
scheme: https
routers:
# HTTP to HTTPS redirect router
main-app-router-redirect:
rule: "Host(`pangolin.ryot.foo`)"
service: next-service
entryPoints:
- web
middlewares:
- redirect-to-https
# Next.js router
next-router:
rule: "Host(`pangolin.ryot.foo`) && !PathPrefix(`/api/v1`)"
service: next-service
entryPoints:
- websecure
tls:
certResolver: letsencrypt
domains:
- main: "ryot.foo"
sans:
- "*.ryot.foo"
# API router
api-router:
rule: "Host(`pangolin.ryot.foo`) && PathPrefix(`/api/v1`)"
service: api-service
entryPoints:
- websecure
tls:
certResolver: letsencrypt
# WebSocket router
ws-router:
rule: "Host(`pangolin.ryot.foo`)"
service: api-service
entryPoints:
- websecure
tls:
certResolver: letsencrypt
services:
next-service:
loadBalancer:
servers:
- url: "http://pangolin:3002"
api-service:
loadBalancer:
servers:
- url: "http://pangolin:3000"
'';
keyFile = pkgs.writeText "pangolin-key" pangolin.KEY;
in
{
imports = lib.custom.scanPaths ./.;
boot.kernelModules = [ "wireguard" ];
## Tmp files and Service to Avoid symlinks
systemd.tmpfiles.rules = [
"d /etc/pangolin/config 0755 root root -"
"d /etc/pangolin/config/traefik 0755 root root -"
"d /etc/pangolin/config/letsencrypt 0755 root root -"
];
systemd.services.pangolin-config-sync = {
description = "Sync Pangolin configuration files";
wantedBy = [ "multi-user.target" ];
before = [ "docker-compose-pangolin-root.target" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
cp ${keyFile} /etc/pangolin/config/key
chmod 0600 /etc/pangolin/config/key
cp ${pangolinConfigFile} /etc/pangolin/config/config.yml
cp ${traefikConfigFile} /etc/pangolin/config/traefik/traefik_config.yml
cp ${dynamicConfigFile} /etc/pangolin/config/traefik/dynamic_config.yml
'';
};
}

View file

@ -1,20 +0,0 @@
{
services.caddy = {
enable = true;
virtualHosts = {
"upsnap.ryot.foo" = {
useACMEHost = "ryot.foo";
extraConfig = ''
reverse_proxy localhost:8090
'';
};
"sock.ryot.foo" = {
useACMEHost = "ryot.foo";
extraConfig = ''
reverse_proxy localhost:9120
'';
};
};
};
}

View file

@ -0,0 +1,11 @@
{ config, ... }:
let
cfg = config.secretsSpec.docker.newt-sock;
in
{
services.newt = {
enable = true;
id = cfg.ID;
secret = cfg.SECRET;
};
}

View file

@ -16,7 +16,6 @@
let
username = "toph";
user = config.secretsSpec.users.${username};
firewall = config.secretsSpec.firewall.sock;
in
{
imports = lib.flatten [
@ -31,7 +30,6 @@ in
"hosts/global/core"
## Optional Configs ##
"hosts/global/common/acme"
"hosts/global/common/docker.nix"
])
];
@ -50,11 +48,6 @@ in
networking = {
enableIPv6 = false;
firewall = {
allowedTCPPorts = firewall.allowedTCPPorts;
allowedTCPPortRanges = firewall.allowedTCPPortRanges;
allowedUDPPorts = firewall.allowedUDPPorts;
};
};
## System-wide packages ##

127
modules/nixos/newt.nix Normal file
View file

@ -0,0 +1,127 @@
{
config,
lib,
pkgs,
...
}:
with lib;
let
cfg = config.services.newt;
in
{
options.services.newt = {
enable = mkEnableOption "Newt container service";
id = mkOption {
type = types.str;
description = "Newt ID for authentication";
};
image = mkOption {
type = types.str;
default = "fosrl/newt";
description = "Docker image to use for Newt";
};
networkName = mkOption {
type = types.str;
default = "newt";
description = "Docker network name to use";
};
networkAlias = mkOption {
type = types.str;
default = "newt";
description = "Network alias for the container";
};
pangolinEndpoint = mkOption {
type = types.str;
default = "https://pangolin.ryot.foo";
description = "Pangolin endpoint URL";
};
secret = mkOption {
type = types.str;
description = "Newt secret for authentication";
};
useHostNetwork = mkOption {
type = types.bool;
default = false;
description = "Whether to use host networking instead of Docker networks";
};
};
config = mkIf cfg.enable {
virtualisation.oci-containers.containers."newt" = {
image = cfg.image;
environment = {
"DOCKER_SOCKET" = "/var/run/docker.sock";
"NEWT_ID" = cfg.id;
"NEWT_SECRET" = cfg.secret;
"PANGOLIN_ENDPOINT" = cfg.pangolinEndpoint;
};
volumes = [
"/var/run/docker.sock:/var/run/docker.sock:rw"
];
log-driver = "journald";
extraOptions =
if cfg.useHostNetwork then
[
"--network=host"
]
else
[
"--network-alias=${cfg.networkAlias}"
"--network=${cfg.networkName}"
];
};
systemd.services."docker-newt" = {
serviceConfig = {
Restart = lib.mkOverride 90 "always";
RestartMaxDelaySec = lib.mkOverride 90 "1m";
RestartSec = lib.mkOverride 90 "100ms";
RestartSteps = lib.mkOverride 90 9;
};
after = mkIf (!cfg.useHostNetwork) [
"docker-network-${cfg.networkName}.service"
];
requires = mkIf (!cfg.useHostNetwork) [
"docker-network-${cfg.networkName}.service"
];
partOf = [
"docker-compose-newt-root.target"
];
wantedBy = [
"docker-compose-newt-root.target"
];
};
# Docker network service (only when not using host network)
systemd.services."docker-network-${cfg.networkName}" = mkIf (!cfg.useHostNetwork) {
path = [ pkgs.docker ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStop = "docker network rm -f ${cfg.networkName}";
};
script = ''
docker network inspect ${cfg.networkName} || docker network create ${cfg.networkName}
'';
partOf = [ "docker-compose-newt-root.target" ];
wantedBy = [ "docker-compose-newt-root.target" ];
};
# Root target
systemd.targets."docker-compose-newt-root" = {
unitConfig = {
Description = "Root target generated by compose2nix.";
};
wantedBy = [ "multi-user.target" ];
};
};
}

Binary file not shown.