Compare commits

..

No commits in common. "79e14c015cb4cbeca77e14f127e18cf2941fe877" and "34085e0870115da9e79c399f743d9fdf1aa07a5f" have entirely different histories.

24 changed files with 306 additions and 625 deletions

View file

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

50
flake.lock generated
View file

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

View file

@ -321,26 +321,20 @@ 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":"TelegramDesktop","spaceIndex":1}
{"wm_class":"gnome-control-center","scratch_layer":true}
''
];
};

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"
"Cloud S - 7.1"
"NO"
])
(lib.hm.gvariant.mkDictionaryEntry [
"Digital Output (S/PDIF) HyperX Cloud Alpha S"

View file

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

View file

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

View file

@ -1,23 +1,32 @@
{ pkgs, config, ... }:
{
## DE ##
services.desktopManager.gnome = {
enable = true;
extraGSettingsOverridePackages = [ pkgs.mutter ];
extraGSettingsOverrides = ''
[org.gnome.mutter]
experimental-features=['scale-monitor-framebuffer']
'';
};
services.displayManager = {
gdm = {
services.xserver = {
enable = true;
desktopManager.gnome = {
enable = true;
wayland = true;
extraGSettingsOverridePackages = [ pkgs.mutter ];
extraGSettingsOverrides = ''
[org.gnome.mutter]
experimental-features=['scale-monitor-framebuffer']
'';
};
autoLogin = {
enable = true;
user = config.hostSpec.username;
displayManager = {
gdm = {
enable = true;
wayland = true;
};
autoLogin = {
enable = true;
user = config.hostSpec.username;
};
};
xkb = {
layout = "us";
variant = "";
};
};
@ -45,6 +54,7 @@
];
## Exclusions ##
services.xserver.excludePackages = [ pkgs.xterm ];
environment.gnome.excludePackages = (
with pkgs;
[

View file

@ -17,7 +17,6 @@ in
(map lib.custom.relativeToRoot [
"modules/global"
"modules/nixos"
])
];
@ -105,6 +104,9 @@ 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,4 +1,3 @@
{ lib, ... }:
{
programs.ssh.startAgent = true;
@ -8,8 +7,8 @@
settings = {
AllowUsers = null; # everyone
PasswordAuthentication = lib.mkDefault false;
PermitRootLogin = lib.mkDefault "no";
PasswordAuthentication = false;
PermitRootLogin = "no";
KbdInteractiveAuthentication = false;
# Automatically remove stale sockets
StreamLocalBindUnlink = "yes";

View file

@ -0,0 +1,20 @@
{
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

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

View file

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

View file

@ -0,0 +1,119 @@
{
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

@ -1,12 +0,0 @@
{ 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" = {
virtualisation.oci-containers.containers."adguard-adguard" = {
image = "adguard/adguardhome:latest";
volumes = [
"/etc/adguard/confdir:/opt/adguardhome/conf:rw"
@ -24,8 +24,7 @@
"--network=adguard_default"
];
};
systemd.services."docker-adguard" = {
systemd.services."docker-adguard-adguard" = {
serviceConfig = {
Restart = lib.mkOverride 90 "always";
RestartMaxDelaySec = lib.mkOverride 90 "1m";

View file

@ -0,0 +1,72 @@
{
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

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

View file

@ -1,156 +0,0 @@
# 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

@ -1,230 +0,0 @@
{
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

@ -0,0 +1,20 @@
{
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

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

View file

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

View file

@ -1,127 +0,0 @@
{
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.