WIP
This commit is contained in:
@@ -2,6 +2,9 @@
|
||||
{
|
||||
imports = [
|
||||
./git.nix
|
||||
./zsh.nix
|
||||
./packages.nix
|
||||
./podman.nix
|
||||
./selfhosted
|
||||
./sops.nix
|
||||
];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
home.packages = with pkgs; [
|
||||
chezmoi
|
||||
fzf
|
||||
lazygit
|
||||
lazydocker
|
||||
sops
|
||||
];
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
{ config, ... }:
|
||||
{
|
||||
programs.zsh = {
|
||||
services.podman = {
|
||||
enable = true;
|
||||
envExtra = "";
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{ config, lib, ... }:
|
||||
with lib;
|
||||
{
|
||||
options.selfhosted.common = {
|
||||
networkName = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
dataDir = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
sops.secrets = {
|
||||
"domains/serv" = { };
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
{ config, ... }:
|
||||
let
|
||||
prefix = "sh-";
|
||||
cfg = config.selfhosted;
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
./common.nix
|
||||
|
||||
./homarr
|
||||
./netbird
|
||||
./pocket-id
|
||||
./vaultwarden
|
||||
];
|
||||
|
||||
config.selfhosted = {
|
||||
common = {
|
||||
networkName = "selfhosted";
|
||||
dataDir = "/mnt/data";
|
||||
};
|
||||
homarr = {
|
||||
name = "${prefix}homarr";
|
||||
subdomain = "dash";
|
||||
};
|
||||
netbird =
|
||||
let
|
||||
nbPrefix = "${prefix}nb-";
|
||||
in
|
||||
{
|
||||
subdomain = "nb";
|
||||
traefik = {
|
||||
name = "${nbPrefix}traefik";
|
||||
};
|
||||
dashboard = {
|
||||
name = "${nbPrefix}dashboard";
|
||||
};
|
||||
server = {
|
||||
name = "${nbPrefix}server";
|
||||
};
|
||||
proxy = {
|
||||
name = "${nbPrefix}proxy";
|
||||
};
|
||||
};
|
||||
pocket-id = {
|
||||
name = "${prefix}pocket-id";
|
||||
subdomain = "id";
|
||||
};
|
||||
vaultwarden = {
|
||||
name = "${prefix}vaultwarden";
|
||||
subdomain = "vault";
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{ config, lib, ... }:
|
||||
with lib;
|
||||
let
|
||||
common = config.selfhosted.common;
|
||||
cfg = config.selfhosted.homarr;
|
||||
hostDataPath = "${common.dataDir}/homarr/data";
|
||||
in
|
||||
{
|
||||
options.selfhosted.homarr = {
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
subdomain = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
sops.secrets = {
|
||||
"homarr/enc_key" = { };
|
||||
};
|
||||
|
||||
services.podman.containers."${cfg.name}" = {
|
||||
image = "ghcr.io/homarr-labs/homarr:v1.60.0";
|
||||
network = common.networkName;
|
||||
environment = {
|
||||
SECRET_ENCRYPTION_KEY = "${config.sops.secrets."homarr/enc_key".path}";
|
||||
};
|
||||
volumes = [
|
||||
"${hostDataPath}:/appdata"
|
||||
];
|
||||
autoStart = true;
|
||||
extraConfig = {
|
||||
Quadlet = {
|
||||
DefaultDependencies = false;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
{ config, ... }:
|
||||
let
|
||||
cfg = config.selfhosted.netbird;
|
||||
poCfg = config.selfhosted.pocket-id;
|
||||
domain = config.sops.placeholder."domains/serv";
|
||||
fullDomain = "${cfg.subdomain}.${domain}";
|
||||
in
|
||||
{
|
||||
sops.secrets = {
|
||||
"netbird/traefik/letsEncryptEmail" = { };
|
||||
"netbird/auth/client_id" = { };
|
||||
"netbird/auth/client_secret" = { };
|
||||
"netbird/server/auth_secret" = { };
|
||||
"netbird/server/enc_key" = { };
|
||||
"netbird/proxy/token" = { };
|
||||
};
|
||||
|
||||
sops.templates."nb-traefik.yaml".content = ''
|
||||
log:
|
||||
level: INFO
|
||||
|
||||
providers:
|
||||
file:
|
||||
filename: /etc/traefik/dynamic.yaml
|
||||
|
||||
entryPoints:
|
||||
web:
|
||||
address: ":80"
|
||||
http:
|
||||
redirections:
|
||||
entryPoint:
|
||||
to: websecure
|
||||
scheme: https
|
||||
|
||||
websecure:
|
||||
address: ":443"
|
||||
|
||||
certificatesResolvers:
|
||||
letsencrypt:
|
||||
acme:
|
||||
email: ${config.sops.placeholder."netbird/traefik/letsEncryptEmail"}
|
||||
storage: /letsencrypt/acme.json
|
||||
tlsChallenge: true
|
||||
'';
|
||||
|
||||
sops.templates."nb-traefik-dynamic.yaml".content =
|
||||
let
|
||||
nbServerName = "nb-server";
|
||||
nbServerH2cName = "nb-server-h2c";
|
||||
nbDashboardName = "nb-dashboard";
|
||||
in
|
||||
''
|
||||
http:
|
||||
routers:
|
||||
nb-relay:
|
||||
rule: Host(`${fullDomain}`) && PathPrefix(`/relay`)
|
||||
entryPoints:
|
||||
- websecure
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
service: ${nbServerName}
|
||||
priority: 110
|
||||
|
||||
nb-ws-signal:
|
||||
rule: Host(`${fullDomain}`) && PathPrefix(`/ws-proxy/signal`)
|
||||
entryPoints:
|
||||
- websecure
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
service: ${nbServerName}
|
||||
priority: 110
|
||||
|
||||
nb-ws-management:
|
||||
rule: Host(`${fullDomain}`) && PathPrefix(`/ws-proxy/management`)
|
||||
entryPoints:
|
||||
- websecure
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
service: ${nbServerName}
|
||||
priority: 110
|
||||
|
||||
nb-grpc-signal:
|
||||
rule: Host(`${fullDomain}`) && PathPrefix(`/signalexchange.SignalExchange/`)
|
||||
entryPoints:
|
||||
- websecure
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
service: ${nbServerH2cName}
|
||||
priority: 100
|
||||
|
||||
nb-grpc-management:
|
||||
rule: Host(`${fullDomain}`) && PathPrefix(`/management.ManagementService/`)
|
||||
entryPoints:
|
||||
- websecure
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
service: ${nbServerH2cName}
|
||||
priority: 100
|
||||
|
||||
nb-api:
|
||||
rule: Host(`${fullDomain}`) && PathPrefix(`/api`)
|
||||
entryPoints:
|
||||
- websecure
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
service: ${nbServerName}
|
||||
priority: 90
|
||||
|
||||
${nbDashboardName}:
|
||||
rule: Host(`${fullDomain}`)
|
||||
entryPoints:
|
||||
- websecure
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
service: ${nbDashboardName}
|
||||
priority: 10
|
||||
|
||||
services:
|
||||
${nbServerName}:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: http://${cfg.server.name}:80
|
||||
|
||||
${nbServerH2cName}:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: http://${cfg.server.name}:80
|
||||
scheme: h2c
|
||||
|
||||
${nbDashboardName}:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: http://${cfg.dashboard.name}:80
|
||||
tcp:
|
||||
serversTransports:
|
||||
pp-v2:
|
||||
proxyProtocol:
|
||||
version: 2
|
||||
'';
|
||||
|
||||
sops.templates."nb-dashboard.env".content = ''
|
||||
NETBIRD_MGMT_API_ENDPOINT=https://${fullDomain}
|
||||
NETBIRD_MGMT_GRPC_API_ENDPOINT=https://${fullDomain}
|
||||
|
||||
AUTH_AUDIENCE=${cfg.dashboard.name}
|
||||
AUTH_CLIENT_ID=${config.sops.placeholder."netbird/auth/client_id"}
|
||||
AUTH_CLIENT_SECRET=${config.sops.placeholder."netbird/auth/client_secret"}
|
||||
AUTH_AUTHORITY=https://${poCfg.subdomain}.${domain}
|
||||
USE_AUTH0=false
|
||||
AUTH_SUPPORTED_SCOPES=openid profile email groups
|
||||
AUTH_REDIRECT_URI=/nb-auth
|
||||
AUTH_SILENT_REDIRECT_URI=/nb-silent-auth
|
||||
|
||||
LETSENCRYPT_DOMAIN=none
|
||||
LETSENCRYPT_EMAIL=${config.sops.placeholder."netbird/traefik/letsEncryptEmail"}
|
||||
'';
|
||||
|
||||
sops.templates."nb-config.yaml".content = ''
|
||||
server:
|
||||
listenAddress: ":80"
|
||||
exposedAddress: "https://${fullDomain}"
|
||||
stunPorts:
|
||||
- 3478
|
||||
metricsPort: 9090
|
||||
healthcheckAddress: ":9000"
|
||||
logLevel: "info"
|
||||
logFile: "console"
|
||||
|
||||
authSecret: "${config.sops.placeholder."netbird/server/auth_secret"}"
|
||||
|
||||
auth:
|
||||
issuer: "https://${poCfg.subdomain}.${domain}"
|
||||
clientID: "${config.sops.placeholder."netbird/auth/client_id"}"
|
||||
clientSecret: "${config.sops.placeholder."netbird/auth/client_secret"}"
|
||||
|
||||
reverseProxy:
|
||||
trustedHTTPProxies:
|
||||
- "127.0.0.1/32"
|
||||
|
||||
store:
|
||||
engine: "sqlite"
|
||||
encryptionKey: "${config.sops.placeholder."netbird/server/enc_key"}"
|
||||
'';
|
||||
|
||||
sops.templates."nb-proxy.env".content = ''
|
||||
NB_PROXY_DOMAIN=${fullDomain}
|
||||
NB_PROXY_TOKEN=${config.sops.placeholder."netbird/proxy/token"}
|
||||
NB_PROXY_MANAGEMENT_ADDRESS=http://${cfg.server.name}:80
|
||||
NB_PROXY_ALLOW_INSECURE=true
|
||||
NB_PROXY_ADDRESS=:8443
|
||||
NB_PROXY_ACME_CERTIFICATES=true
|
||||
NB_PROXY_ACME_CHALLENGE_TYPE=tls-alpn-01
|
||||
NB_PROXY_CERTIFICATE_DIRECTORY=/certs
|
||||
'';
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
with lib;
|
||||
let
|
||||
common = config.selfhosted.common;
|
||||
cfg = config.selfhosted.netbird;
|
||||
hostDataPath = "${common.dataDir}/netbird";
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
./config.nix
|
||||
];
|
||||
|
||||
options.selfhosted.netbird = {
|
||||
subdomain = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
traefik = {
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
};
|
||||
dashboard = {
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
};
|
||||
server = {
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
};
|
||||
proxy = {
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
services.podman.containers.${cfg.traefik.name} = {
|
||||
image = "traefik:v3.6";
|
||||
network = common.networkName;
|
||||
ports = [
|
||||
"0.0.0.0:80:80"
|
||||
"0.0.0.0:443:443"
|
||||
];
|
||||
autoStart = true;
|
||||
volumes = [
|
||||
"${hostDataPath}/traefik/letsencrypt:/letsencrypt"
|
||||
"${config.sops.templates."nb-traefik.yaml".path}:/etc/traefik/config.yaml"
|
||||
"${config.sops.templates."nb-traefik-dynamic.yaml".path}:/etc/traefik/dynamic.yaml"
|
||||
];
|
||||
extraConfig = {
|
||||
Quadlet = {
|
||||
DefaultDependencies = false;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
services.podman.containers.${cfg.dashboard.name} = {
|
||||
image = "netbirdio/dashboard:v2.37.1";
|
||||
network = common.networkName;
|
||||
environmentFile = [ "${config.sops.templates."nb-dashboard.env".path}" ];
|
||||
autoStart = true;
|
||||
extraConfig = {
|
||||
Quadlet = {
|
||||
DefaultDependencies = false;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
services.podman.containers.${cfg.server.name} = {
|
||||
image = "netbirdio/netbird-server:0.70.5";
|
||||
network = common.networkName;
|
||||
ports = [
|
||||
"0.0.0.0:3478:3478/udp"
|
||||
];
|
||||
autoStart = true;
|
||||
volumes = [
|
||||
"${hostDataPath}/server/data:/var/lib/netbird"
|
||||
"${config.sops.templates."nb-config.yaml".path}:/etc/netbird/config.yaml"
|
||||
];
|
||||
extraConfig = {
|
||||
Quadlet = {
|
||||
DefaultDependencies = false;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
services.podman.containers.${cfg.proxy.name} = {
|
||||
image = "netbirdio/reverse-proxy:0.70.5";
|
||||
network = common.networkName;
|
||||
environmentFile = [ "${config.sops.templates."nb-proxy.env".path}" ];
|
||||
autoStart = true;
|
||||
volumes = [
|
||||
"${hostDataPath}/proxy/certs:/certs"
|
||||
];
|
||||
extraConfig = {
|
||||
Quadlet = {
|
||||
DefaultDependencies = false;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{ config, ... }:
|
||||
let
|
||||
cfg = config.selfhosted.pocket-id;
|
||||
in
|
||||
{
|
||||
sops.secrets = {
|
||||
"pocket_id/enc_key" = { };
|
||||
};
|
||||
|
||||
sops.templates."pocket-id.env" = {
|
||||
content = ''
|
||||
APP_URL=https://${cfg.subdomain}.${config.sops.placeholder."domains/serv"}
|
||||
ENCRYPTION_KEY=${config.sops.placeholder."pocket_id/enc_key"}
|
||||
TRUST_PROXY=true
|
||||
ANALYTICS_DISABLED=true
|
||||
PUID=1000
|
||||
PGID=1000
|
||||
'';
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
{ config, lib, ... }:
|
||||
with lib;
|
||||
let
|
||||
common = config.selfhosted.common;
|
||||
cfg = config.selfhosted.pocket-id;
|
||||
hostDataPath = "${common.dataDir}/pocket-id/data";
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
./config.nix
|
||||
];
|
||||
|
||||
options.selfhosted.pocket-id = {
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
subdomain = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
services.podman.containers.${cfg.name} = {
|
||||
image = "ghcr.io/pocket-id/pocket-id:v2";
|
||||
network = common.networkName;
|
||||
environmentFile = [ "${config.sops.templates."pocket-id.env".path}" ];
|
||||
volumes = [
|
||||
"${hostDataPath}:/app/data"
|
||||
];
|
||||
autoStart = true;
|
||||
extraConfig = {
|
||||
Quadlet = {
|
||||
DefaultDependencies = false;
|
||||
};
|
||||
Container = {
|
||||
HealthCmd = ''"/app/pocket-id" "healthcheck"'';
|
||||
HealthInterval = "1m30s";
|
||||
HealthTimeout = "5s";
|
||||
HealthRetries = "2";
|
||||
HealthStartPeriod = "10s";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{ config, ... }:
|
||||
let
|
||||
cfg = config.selfhosted.vaultwarden;
|
||||
poCfg = config.selfhosted.pocket-id;
|
||||
domain = config.sops.placeholder."domains/serv";
|
||||
in
|
||||
{
|
||||
sops.secrets = {
|
||||
"vaultwarden/client_id" = { };
|
||||
"vaultwarden/client_secret" = { };
|
||||
};
|
||||
|
||||
sops.templates."vaultwarden.env".content = ''
|
||||
DOMAIN=https://${cfg.subdomain}.${domain}
|
||||
LOG_LEVEL=info,vaultwarden::sso=debug
|
||||
SIGNUPS_ALLOWED=false
|
||||
SSO_ENABLED=false
|
||||
SSO_DEBUG_TOKENS=true
|
||||
SSO_ONLY=false
|
||||
SSO_AUTHORITY=https://${poCfg.subdomain}.${domain}
|
||||
SSO_CLIENT_ID=${config.sops.placeholder."vaultwarden/client_id"}
|
||||
SSO_CLIENT_SECRET=${config.sops.placeholder."vaultwarden/client_secret"}
|
||||
SSO_AUTH_ONLY_NOT_SESSION=true
|
||||
SSO_PKCE=true
|
||||
'';
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
{ config, lib, ... }:
|
||||
with lib;
|
||||
let
|
||||
common = config.selfhosted.common;
|
||||
cfg = config.selfhosted.vaultwarden;
|
||||
hostDataPath = "${common.dataDir}/vaultwarden/data";
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
./config.nix
|
||||
];
|
||||
|
||||
options.selfhosted.vaultwarden = {
|
||||
enable = mkEnableOption "Enable container";
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
subdomain = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
services.podman.containers.${cfg.name} = {
|
||||
image = "docker.io/vaultwarden/server:1.36.0";
|
||||
network = config.selfhosted.common.networkName;
|
||||
environmentFile = [ "${config.sops.templates."vaultwarden.env".path}" ];
|
||||
volumes = [
|
||||
"${hostDataPath}:/data"
|
||||
];
|
||||
autoStart = true;
|
||||
extraConfig = {
|
||||
Quadlet = {
|
||||
DefaultDependencies = false;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{ config, ... }:
|
||||
{
|
||||
imports = [
|
||||
./network.nix
|
||||
./containers
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{ config, ... }:
|
||||
let
|
||||
common = config.selfhosted.common;
|
||||
in
|
||||
{
|
||||
services.podman = {
|
||||
networks.${common.networkName} = {
|
||||
driver = "bridge";
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{ config, dotfiles, sops-nix, ... }:
|
||||
{
|
||||
imports = [
|
||||
sops-nix.homeManagerModules.sops
|
||||
];
|
||||
|
||||
sops = {
|
||||
defaultSopsFile = "${dotfiles}/dot_config/sops/secrets.yaml";
|
||||
age.keyFile = "${config.xdg.configHome}/age/key.txt";
|
||||
};
|
||||
|
||||
home.file.".sops.yaml".source = "${dotfiles}/dot_sops.yaml";
|
||||
|
||||
xdg.configFile."sops" = {
|
||||
source = "${dotfiles}/dot_config/sops";
|
||||
recursive = true;
|
||||
};
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
inputs,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
@@ -11,6 +11,9 @@
|
||||
];
|
||||
|
||||
home-manager = {
|
||||
extraSpecialArgs = {
|
||||
inherit (inputs) disko dotfiles sops-nix;
|
||||
};
|
||||
useGlobalPkgs = true;
|
||||
useUserPackages = true;
|
||||
users.benq =
|
||||
@@ -22,15 +25,11 @@
|
||||
"home/benq/core"
|
||||
]
|
||||
++ (map (f: "home/benq/optional/${f}") [
|
||||
|
||||
])
|
||||
))
|
||||
];
|
||||
|
||||
home.packages = with pkgs; [
|
||||
chezmoi
|
||||
lazygit
|
||||
lazydocker
|
||||
];
|
||||
home.stateVersion = "25.05";
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user