enforce new flake schema. formatting.
Some checks failed
Build tests / build-hosts (pull_request) Failing after 3s
Flake check / flake-check (pull_request) Failing after 13s

This commit is contained in:
sid 2026-05-31 18:50:41 +02:00
parent 4b0a90e00d
commit ecf5132cbb
121 changed files with 1606 additions and 1554 deletions

View file

@ -4,10 +4,16 @@ let
inherit (lib) mkDefault;
in
{
hardware.bluetooth.enable = mkDefault true;
hardware.bluetooth.powerOnBoot = mkDefault false;
hardware.bluetooth.settings.General.Enable = mkDefault "Source,Sink,Media,Socket";
hardware.bluetooth.settings.General.Experimental = mkDefault true;
hardware = {
bluetooth = {
enable = mkDefault true;
powerOnBoot = mkDefault false;
settings.General = {
Enable = mkDefault "Source,Sink,Media,Socket";
Experimental = mkDefault true;
};
};
};
environment.systemPackages = with pkgs; [
blueman

View file

@ -84,8 +84,6 @@ in
) { } cfg.remotes;
# Ensure that all cifs-mount services are started with the graphical session
systemd.user.targets.graphical-session.wants = map (
remote: "cifs-mount-${remote.shareName}.service"
) cfg.remotes;
systemd.user.targets.graphical-session.wants = map (remote: "cifs-mount-${remote.shareName}.service") cfg.remotes;
};
}

View file

@ -1,20 +1,20 @@
{ lib, pkgs, ... }:
{
# fix CVE-2026-31431
boot.kernelPackages = lib.mkIf (lib.versionOlder pkgs.linux.version "6.18.22") (
lib.mkDefault pkgs.linuxPackages_6_18
);
boot = {
# fix CVE-2026-31431
kernelPackages = lib.mkIf (lib.versionOlder pkgs.linux.version "6.18.22") (lib.mkDefault pkgs.linuxPackages_6_18);
# fix CVE-2026-43500
boot.extraModprobeConfig = ''
install esp4 ${pkgs.coreutils}/bin/false
install esp6 ${pkgs.coreutils}/bin/false
install rxrpc ${pkgs.coreutils}/bin/false
'';
boot.blacklistedKernelModules = [
"esp4"
"esp6"
"rxrpc"
];
# fix CVE-2026-43500
extraModprobeConfig = ''
install esp4 ${pkgs.coreutils}/bin/false
install esp6 ${pkgs.coreutils}/bin/false
install rxrpc ${pkgs.coreutils}/bin/false
'';
blacklistedKernelModules = [
"esp4"
"esp6"
"rxrpc"
];
};
}

View file

@ -9,55 +9,59 @@ let
inherit (lib) mkDefault optionals;
in
{
environment.systemPackages =
with pkgs;
[
cryptsetup
curl
dig
dnsutils
fzf
gptfdisk
iproute2
jq
lm_sensors
lsof
netcat-openbsd
nettools
nixos-container
nmap
nurl
p7zip
pciutils
psmisc
rclone
rsync
tcpdump
tmux
tree
unzip
usbutils
wget
xxd
zip
environment = {
systemPackages =
with pkgs;
[
cryptsetup
curl
dig
dnsutils
fzf
gptfdisk
iproute2
jq
lm_sensors
lsof
netcat-openbsd
nettools
nixos-container
nmap
nurl
p7zip
pciutils
psmisc
rclone
rsync
tcpdump
tmux
tree
unzip
usbutils
wget
xxd
zip
(callPackage ../../../apps/rebuild { })
]
++ optionals (pkgs.stdenv.hostPlatform == pkgs.stdenv.buildPlatform) [
pkgs.kitty.terminfo
];
(callPackage ../../../apps/rebuild { })
]
++ optionals (pkgs.stdenv.hostPlatform == pkgs.stdenv.buildPlatform) [
pkgs.kitty.terminfo
];
environment.shellAliases = {
l = "ls -lh";
ll = "ls -lAh";
ports = "ss -tulpn";
publicip = "curl ifconfig.me/all";
sudo = "sudo "; # make aliases work with `sudo`
shellAliases = {
l = "ls -lh";
ll = "ls -lAh";
ports = "ss -tulpn";
publicip = "curl ifconfig.me/all";
sudo = "sudo "; # make aliases work with `sudo`
};
# saves one instance of nixpkgs.
ldso32 = null;
};
# saves one instance of nixpkgs.
environment.ldso32 = null;
boot.tmp.cleanOnBoot = mkDefault true;
boot.initrd.systemd.enable = mkDefault (!config.boot.swraid.enable && !config.boot.isContainer);
boot = {
tmp.cleanOnBoot = mkDefault true;
initrd.systemd.enable = mkDefault (!config.boot.swraid.enable && !config.boot.isContainer);
};
}

View file

@ -2,16 +2,13 @@
# avoid TOFU MITM
programs.ssh.knownHosts = {
"github.com".hostNames = [ "github.com" ];
"github.com".publicKey =
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl";
"github.com".publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl";
"gitlab.com".hostNames = [ "gitlab.com" ];
"gitlab.com".publicKey =
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf";
"gitlab.com".publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf";
"git.sr.ht".hostNames = [ "git.sr.ht" ];
"git.sr.ht".publicKey =
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMZvRd4EtM7R+IHVMWmDkVU3VLQTSwQDSAvW0t2Tkj60";
"git.sr.ht".publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMZvRd4EtM7R+IHVMWmDkVU3VLQTSwQDSAvW0t2Tkj60";
};
# TODO: add synix
}

View file

@ -42,12 +42,8 @@ in
static-auth-secret-file = mkIf cfg.sops config.sops.secrets."coturn/static-auth-secret".path;
realm = mkDefault "turn.${config.networking.domain}";
cert =
mkIf (!cfg.no-tls && cfg.sops)
"${config.security.acme.certs.${cfg.realm}.directory}/full.pem";
pkey =
mkIf (!cfg.no-tls && cfg.sops)
"${config.security.acme.certs.${cfg.realm}.directory}/key.pem";
cert = mkIf (!cfg.no-tls && cfg.sops) "${config.security.acme.certs.${cfg.realm}.directory}/full.pem";
pkey = mkIf (!cfg.no-tls && cfg.sops) "${config.security.acme.certs.${cfg.realm}.directory}/key.pem";
extraConfig = ''
# ban private IP ranges

View file

@ -33,11 +33,13 @@ in
fonts.fontconfig.enable = mkDefault false;
xdg.autostart.enable = mkDefault false;
xdg.icons.enable = mkDefault false;
xdg.menus.enable = mkDefault false;
xdg.mime.enable = mkDefault false;
xdg.sounds.enable = mkDefault false;
xdg = {
autostart.enable = mkDefault false;
icons.enable = mkDefault false;
menus.enable = mkDefault false;
mime.enable = mkDefault false;
sounds.enable = mkDefault false;
};
programs.git.package = mkDefault pkgs.gitMinimal;
@ -48,22 +50,25 @@ in
viAlias = mkDefault true;
};
# emergency mode is useless on headless machines
systemd.enableEmergencyMode = false;
systemd = {
# emergency mode is useless on headless machines
enableEmergencyMode = false;
sleep.extraConfig = ''
AllowSuspend=no
AllowHibernation=no
'';
# force reboots
settings.Manager = {
RuntimeWatchdogSec = mkDefault "15s";
RebootWatchdogSec = mkDefault "30s";
KExecWatchdogSec = mkDefault "1m";
};
};
boot.initrd.systemd.suppressedUnits = mkIf config.systemd.enableEmergencyMode [
"emergency.service"
"emergency.target"
];
systemd.sleep.extraConfig = ''
AllowSuspend=no
AllowHibernation=no
'';
# force reboots
systemd.settings.Manager = {
RuntimeWatchdogSec = mkDefault "15s";
RebootWatchdogSec = mkDefault "30s";
KExecWatchdogSec = mkDefault "1m";
};
}

View file

@ -4,7 +4,9 @@ let
inherit (lib) mkDefault;
in
{
services.qemuGuest.enable = mkDefault true;
services.spice-vdagentd.enable = mkDefault true;
services.spice-webdavd.enable = mkDefault true;
services = {
qemuGuest.enable = mkDefault true;
spice-vdagentd.enable = mkDefault true;
spice-webdavd.enable = mkDefault true;
};
}

View file

@ -2,9 +2,9 @@
let
cfg = config.services.ftp-webserver;
domain = config.networking.domain;
inherit (config.networking) domain;
fqdn = if (cfg.subdomain != "") then "${cfg.subdomain}.${domain}" else domain;
nginx = config.services.nginx;
inherit (config.services) nginx;
inherit (lib)
mkEnableOption
@ -35,7 +35,7 @@ in
config = mkIf cfg.enable {
services.nginx.virtualHosts."${fqdn}" = {
root = cfg.root;
inherit (cfg) root;
locations."/" = {
extraConfig = ''
autoindex on;
@ -43,7 +43,7 @@ in
autoindex_localtime on;
'';
};
forceSSL = cfg.forceSSL;
inherit (cfg) forceSSL;
enableACME = cfg.forceSSL;
sslCertificate = mkIf cfg.forceSSL "${config.security.acme.certs."${fqdn}".directory}/cert.pem";
sslCertificateKey = mkIf cfg.forceSSL "${config.security.acme.certs."${fqdn}".directory}/key.pem";

View file

@ -7,10 +7,10 @@
let
cfg = config.services.headplane;
domain = config.networking.domain;
subdomain = cfg.reverseProxy.subdomain;
inherit (config.networking) domain;
inherit (cfg.reverseProxy) subdomain;
fqdn = if (cfg.reverseProxy.enable && subdomain != "") then "${subdomain}.${domain}" else domain;
headscale = config.services.headscale;
inherit (config.services) headscale;
inherit (lib)
mkDefault
@ -55,7 +55,7 @@ in
services.nginx.virtualHosts = mkIf cfg.reverseProxy.enable {
"${fqdn}" = mkVirtualHost {
port = cfg.settings.server.port;
inherit (cfg.settings.server) port;
ssl = cfg.reverseProxy.forceSSL;
};
};
@ -63,7 +63,7 @@ in
sops.secrets =
let
owner = headscale.user;
group = headscale.group;
inherit (headscale) group;
mode = "0400";
in
{

View file

@ -6,8 +6,8 @@
let
cfg = config.services.headscale;
domain = config.networking.domain;
subdomain = cfg.reverseProxy.subdomain;
inherit (config.networking) domain;
inherit (cfg.reverseProxy) subdomain;
fqdn = if (cfg.reverseProxy.enable && subdomain != "") then "${subdomain}.${domain}" else domain;
acl = "headscale/acl.hujson";

View file

@ -8,23 +8,9 @@ in
programs.dconf.enable = true; # fixes nixvim hm module
services.flatpak.enable = true;
xdg.portal = {
enable = true;
extraPortals = with pkgs; [
xdg-desktop-portal-gtk
];
config.common.default = "gtk";
services = {
flatpak.enable = true;
gnome.gnome-keyring.enable = true;
udisks2.enable = mkDefault true;
};
services.gnome.gnome-keyring.enable = true;
security.pam.services = {
login = {
enableGnomeKeyring = true;
};
hyprlock = { };
};
services.udisks2.enable = mkDefault true;
}

View file

@ -7,8 +7,8 @@
let
cfg = config.services.jellyfin;
domain = config.networking.domain;
subdomain = cfg.reverseProxy.subdomain;
inherit (config.networking) domain;
inherit (cfg.reverseProxy) subdomain;
fqdn = if (cfg.reverseProxy.enable && subdomain != "") then "${subdomain}.${domain}" else domain;
inherit (lib)
@ -48,9 +48,7 @@ in
];
systemd.tmpfiles.rules =
(map (
library: "d ${cfg.dataDir}/libraries/${library} 0770 ${cfg.user} ${cfg.group} -"
) cfg.libraries)
(map (library: "d ${cfg.dataDir}/libraries/${library} 0770 ${cfg.user} ${cfg.group} -") cfg.libraries)
++ [
"z ${cfg.dataDir} 0770 ${cfg.user} ${cfg.group} -"
"Z ${cfg.dataDir}/libraries 0770 ${cfg.user} ${cfg.group} -"

View file

@ -2,8 +2,8 @@
let
cfg = config.services.jirafeau;
domain = config.networking.domain;
subdomain = cfg.reverseProxy.subdomain;
inherit (config.networking) domain;
inherit (cfg.reverseProxy) subdomain;
fqdn = if (cfg.reverseProxy.enable && subdomain != "") then "${subdomain}.${domain}" else domain;
inherit (lib)

View file

@ -155,7 +155,7 @@ let
mkOption {
type = types.package;
default = defaultImages.${name};
description = description;
inherit description;
};
inherit (lib)
@ -236,10 +236,123 @@ in
};
config = mkIf cfg.enable {
virtualisation.podman = {
enable = true;
autoPrune.enable = true;
dockerCompat = true;
virtualisation = {
podman = {
enable = true;
autoPrune.enable = true;
dockerCompat = true;
};
oci-containers = {
backend = "podman";
containers = {
librechat-mongodb = {
image = with cfg.images.mongodb; "${imageName}:${imageTag}";
imageFile = cfg.images.mongodb;
cmd = [
"mongod"
"--noauth"
];
volumes = [
"librechat_mongodb_data:/data/db:rw"
];
log-driver = "journald";
extraOptions = [
"--network-alias=mongodb"
"--network=librechat_default"
];
};
librechat-meilisearch = {
image = with cfg.images.meilisearch; "${imageName}:${imageTag}";
imageFile = cfg.images.meilisearch;
environment = {
MEILI_NO_ANALYTICS = "true";
MEILI_HOST = "http://meilisearch:${toString cfg.meiliPort}";
};
environmentFiles = optional (cfg.environmentFile != null) cfg.environmentFile;
volumes = [
"librechat_meili_data:/meili_data:rw"
];
log-driver = "journald";
extraOptions = [
"--network-alias=meilisearch"
"--network=librechat_default"
];
};
librechat-vectordb = {
image = with cfg.images.vectordb; "${imageName}:${imageTag}";
imageFile = cfg.images.vectordb;
environment = {
POSTGRES_DB = "mydatabase";
POSTGRES_USER = "myuser";
POSTGRES_PASSWORD = "mypassword";
};
volumes = [
"librechat_pgdata:/var/lib/postgresql/data:rw"
];
log-driver = "journald";
extraOptions = [
"--network-alias=vectordb"
"--network=librechat_default"
];
};
librechat-rag-api = {
image = with cfg.images.ragApi; "${imageName}:${imageTag}";
imageFile = cfg.images.ragApi;
environment = {
DB_HOST = "vectordb";
RAG_PORT = toString cfg.ragPort;
};
environmentFiles = optional (cfg.environmentFile != null) cfg.environmentFile;
dependsOn = [ "librechat-vectordb" ];
log-driver = "journald";
extraOptions = [
"--network-alias=rag_api"
"--network=librechat_default"
];
};
librechat = {
image = with cfg.images.librechat; "${imageName}:${imageTag}";
imageFile = cfg.images.librechat;
environment =
defaultEnv
// {
MONGO_URI = "mongodb://mongodb:27017/LibreChat";
MEILI_HOST = "http://meilisearch:${toString cfg.meiliPort}";
RAG_PORT = toString cfg.ragPort;
RAG_API_URL = "http://rag_api:${toString cfg.ragPort}";
DOMAIN_CLIENT = if cfg.externalUrl != null then cfg.externalUrl else "http://localhost:${toString cfg.port}";
DOMAIN_SERVER = if cfg.externalUrl != null then cfg.externalUrl else "http://localhost:${toString cfg.port}";
}
// cfg.environment;
environmentFiles = optional (cfg.environmentFile != null) cfg.environmentFile;
volumes = [
"librechat_images:/app/client/public/images:rw"
"librechat_uploads:/app/uploads:rw"
"librechat_logs:/app/logs:rw"
]
++ optional (cfg.configFile != null) "${cfg.configFile}:/app/librechat.yaml:ro";
ports = [
"0.0.0.0:${toString cfg.port}:${toString cfg.port}/tcp"
];
dependsOn = [
"librechat-mongodb"
"librechat-rag-api"
];
log-driver = "journald";
extraOptions = [
"--network-alias=api"
"--network=librechat_default"
];
};
};
};
};
networking.firewall.interfaces =
@ -250,278 +363,173 @@ in
"${matchAll}".allowedUDPPorts = [ 53 ];
};
virtualisation.oci-containers.backend = "podman";
systemd = {
services = {
podman-librechat-mongodb = {
serviceConfig.Restart = mkOverride 90 "always";
after = [
"podman-network-librechat_default.service"
"podman-volume-librechat_mongodb_data.service"
];
requires = [
"podman-network-librechat_default.service"
"podman-volume-librechat_mongodb_data.service"
];
partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ];
};
virtualisation.oci-containers.containers.librechat-mongodb = {
image = with cfg.images.mongodb; "${imageName}:${imageTag}";
imageFile = cfg.images.mongodb;
cmd = [
"mongod"
"--noauth"
];
volumes = [
"librechat_mongodb_data:/data/db:rw"
];
log-driver = "journald";
extraOptions = [
"--network-alias=mongodb"
"--network=librechat_default"
];
};
podman-librechat-meilisearch = {
serviceConfig.Restart = mkOverride 90 "always";
after = [
"podman-network-librechat_default.service"
"podman-volume-librechat_meili_data.service"
];
requires = [
"podman-network-librechat_default.service"
"podman-volume-librechat_meili_data.service"
];
partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ];
};
virtualisation.oci-containers.containers.librechat-meilisearch = {
image = with cfg.images.meilisearch; "${imageName}:${imageTag}";
imageFile = cfg.images.meilisearch;
environment = {
MEILI_NO_ANALYTICS = "true";
MEILI_HOST = "http://meilisearch:${toString cfg.meiliPort}";
podman-librechat-vectordb = {
serviceConfig.Restart = mkOverride 90 "always";
after = [
"podman-network-librechat_default.service"
"podman-volume-librechat_pgdata.service"
];
requires = [
"podman-network-librechat_default.service"
"podman-volume-librechat_pgdata.service"
];
partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ];
};
podman-librechat-rag-api = {
serviceConfig.Restart = mkOverride 90 "always";
after = [
"podman-network-librechat_default.service"
"podman-librechat-vectordb.service"
];
requires = [
"podman-network-librechat_default.service"
"podman-librechat-vectordb.service"
];
partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ];
};
podman-librechat = {
serviceConfig.Restart = mkOverride 90 "always";
after = [
"podman-network-librechat_default.service"
"podman-volume-librechat_images.service"
"podman-volume-librechat_uploads.service"
"podman-volume-librechat_logs.service"
"podman-librechat-mongodb.service"
"podman-librechat-meilisearch.service"
"podman-librechat-rag-api.service"
];
requires = [
"podman-network-librechat_default.service"
"podman-volume-librechat_images.service"
"podman-volume-librechat_uploads.service"
"podman-volume-librechat_logs.service"
"podman-librechat-mongodb.service"
"podman-librechat-meilisearch.service"
"podman-librechat-rag-api.service"
];
partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ];
};
podman-network-librechat_default = {
path = [ pkgs.podman ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStop = "podman network rm -f librechat_default";
};
script = ''
podman network inspect librechat_default || podman network create librechat_default
'';
partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ];
};
podman-volume-librechat_mongodb_data = {
path = [ pkgs.podman ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = "podman volume inspect librechat_mongodb_data || podman volume create librechat_mongodb_data";
partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ];
};
podman-volume-librechat_meili_data = {
path = [ pkgs.podman ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = "podman volume inspect librechat_meili_data || podman volume create librechat_meili_data";
partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ];
};
podman-volume-librechat_pgdata = {
path = [ pkgs.podman ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = "podman volume inspect librechat_pgdata || podman volume create librechat_pgdata";
partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ];
};
podman-volume-librechat_images = {
path = [ pkgs.podman ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = "podman volume inspect librechat_images || podman volume create librechat_images";
partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ];
};
podman-volume-librechat_uploads = {
path = [ pkgs.podman ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = "podman volume inspect librechat_uploads || podman volume create librechat_uploads";
partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ];
};
podman-volume-librechat_logs = {
path = [ pkgs.podman ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = "podman volume inspect librechat_logs || podman volume create librechat_logs";
partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ];
};
};
environmentFiles = optional (cfg.environmentFile != null) cfg.environmentFile;
volumes = [
"librechat_meili_data:/meili_data:rw"
];
log-driver = "journald";
extraOptions = [
"--network-alias=meilisearch"
"--network=librechat_default"
];
};
virtualisation.oci-containers.containers.librechat-vectordb = {
image = with cfg.images.vectordb; "${imageName}:${imageTag}";
imageFile = cfg.images.vectordb;
environment = {
POSTGRES_DB = "mydatabase";
POSTGRES_USER = "myuser";
POSTGRES_PASSWORD = "mypassword";
targets.podman-compose-librechat-root = {
unitConfig.Description = "Root target generated by compose2nix.";
wantedBy = [ "multi-user.target" ];
};
volumes = [
"librechat_pgdata:/var/lib/postgresql/data:rw"
];
log-driver = "journald";
extraOptions = [
"--network-alias=vectordb"
"--network=librechat_default"
];
};
virtualisation.oci-containers.containers.librechat-rag-api = {
image = with cfg.images.ragApi; "${imageName}:${imageTag}";
imageFile = cfg.images.ragApi;
environment = {
DB_HOST = "vectordb";
RAG_PORT = toString cfg.ragPort;
};
environmentFiles = optional (cfg.environmentFile != null) cfg.environmentFile;
dependsOn = [ "librechat-vectordb" ];
log-driver = "journald";
extraOptions = [
"--network-alias=rag_api"
"--network=librechat_default"
];
};
virtualisation.oci-containers.containers.librechat = {
image = with cfg.images.librechat; "${imageName}:${imageTag}";
imageFile = cfg.images.librechat;
environment =
defaultEnv
// {
MONGO_URI = "mongodb://mongodb:27017/LibreChat";
MEILI_HOST = "http://meilisearch:${toString cfg.meiliPort}";
RAG_PORT = toString cfg.ragPort;
RAG_API_URL = "http://rag_api:${toString cfg.ragPort}";
DOMAIN_CLIENT =
if cfg.externalUrl != null then cfg.externalUrl else "http://localhost:${toString cfg.port}";
DOMAIN_SERVER =
if cfg.externalUrl != null then cfg.externalUrl else "http://localhost:${toString cfg.port}";
}
// cfg.environment;
environmentFiles = optional (cfg.environmentFile != null) cfg.environmentFile;
volumes = [
"librechat_images:/app/client/public/images:rw"
"librechat_uploads:/app/uploads:rw"
"librechat_logs:/app/logs:rw"
]
++ optional (cfg.configFile != null) "${cfg.configFile}:/app/librechat.yaml:ro";
ports = [
"0.0.0.0:${toString cfg.port}:${toString cfg.port}/tcp"
];
dependsOn = [
"librechat-mongodb"
"librechat-rag-api"
];
log-driver = "journald";
extraOptions = [
"--network-alias=api"
"--network=librechat_default"
];
};
systemd.services.podman-librechat-mongodb = {
serviceConfig.Restart = mkOverride 90 "always";
after = [
"podman-network-librechat_default.service"
"podman-volume-librechat_mongodb_data.service"
];
requires = [
"podman-network-librechat_default.service"
"podman-volume-librechat_mongodb_data.service"
];
partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ];
};
systemd.services.podman-librechat-meilisearch = {
serviceConfig.Restart = mkOverride 90 "always";
after = [
"podman-network-librechat_default.service"
"podman-volume-librechat_meili_data.service"
];
requires = [
"podman-network-librechat_default.service"
"podman-volume-librechat_meili_data.service"
];
partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ];
};
systemd.services.podman-librechat-vectordb = {
serviceConfig.Restart = mkOverride 90 "always";
after = [
"podman-network-librechat_default.service"
"podman-volume-librechat_pgdata.service"
];
requires = [
"podman-network-librechat_default.service"
"podman-volume-librechat_pgdata.service"
];
partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ];
};
systemd.services.podman-librechat-rag-api = {
serviceConfig.Restart = mkOverride 90 "always";
after = [
"podman-network-librechat_default.service"
"podman-librechat-vectordb.service"
];
requires = [
"podman-network-librechat_default.service"
"podman-librechat-vectordb.service"
];
partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ];
};
systemd.services.podman-librechat = {
serviceConfig.Restart = mkOverride 90 "always";
after = [
"podman-network-librechat_default.service"
"podman-volume-librechat_images.service"
"podman-volume-librechat_uploads.service"
"podman-volume-librechat_logs.service"
"podman-librechat-mongodb.service"
"podman-librechat-meilisearch.service"
"podman-librechat-rag-api.service"
];
requires = [
"podman-network-librechat_default.service"
"podman-volume-librechat_images.service"
"podman-volume-librechat_uploads.service"
"podman-volume-librechat_logs.service"
"podman-librechat-mongodb.service"
"podman-librechat-meilisearch.service"
"podman-librechat-rag-api.service"
];
partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ];
};
systemd.services.podman-network-librechat_default = {
path = [ pkgs.podman ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStop = "podman network rm -f librechat_default";
};
script = ''
podman network inspect librechat_default || podman network create librechat_default
'';
partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ];
};
systemd.services.podman-volume-librechat_mongodb_data = {
path = [ pkgs.podman ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = "podman volume inspect librechat_mongodb_data || podman volume create librechat_mongodb_data";
partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ];
};
systemd.services.podman-volume-librechat_meili_data = {
path = [ pkgs.podman ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = "podman volume inspect librechat_meili_data || podman volume create librechat_meili_data";
partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ];
};
systemd.services.podman-volume-librechat_pgdata = {
path = [ pkgs.podman ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = "podman volume inspect librechat_pgdata || podman volume create librechat_pgdata";
partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ];
};
systemd.services.podman-volume-librechat_images = {
path = [ pkgs.podman ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = "podman volume inspect librechat_images || podman volume create librechat_images";
partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ];
};
systemd.services.podman-volume-librechat_uploads = {
path = [ pkgs.podman ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = "podman volume inspect librechat_uploads || podman volume create librechat_uploads";
partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ];
};
systemd.services.podman-volume-librechat_logs = {
path = [ pkgs.podman ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = "podman volume inspect librechat_logs || podman volume create librechat_logs";
partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ];
};
systemd.targets.podman-compose-librechat-root = {
unitConfig.Description = "Root target generated by compose2nix.";
wantedBy = [ "multi-user.target" ];
};
};
}

View file

@ -8,7 +8,7 @@
let
cfg = config.mailserver;
domain = config.networking.domain;
inherit (config.networking) domain;
fqdn = "${cfg.subdomain}.${domain}";
inherit (lib)
@ -74,7 +74,7 @@ in
nameValuePair "${user}@${domain}" {
name = "${user}@${domain}";
aliases = map (alias: "${alias}@${domain}") (accConf.aliases or [ ]);
sendOnly = accConf.sendOnly;
inherit (accConf) sendOnly;
quota = mkDefault "5G";
hashedPasswordFile = config.sops.secrets."mailserver/accounts/${user}".path;
}

View file

@ -23,7 +23,7 @@ let
services."mautrix-${name}" = {
enable = true;
package = cfg.bridges.${name}.package;
inherit (cfg.bridges.${name}) package;
environmentFile = mkIf cfg.sops config.sops.templates."mautrix-${name}/env-file".path;
settings = {
bridge = {
@ -71,33 +71,29 @@ let
mode = "0400";
in
{
secrets."mautrix-${name}/encryption-pickle-key" = {
inherit owner group mode;
};
secrets."mautrix-${name}/provisioning-shared-secret" = {
inherit owner group mode;
};
secrets."mautrix-${name}/public-media-signing-key" = {
inherit owner group mode;
};
secrets."mautrix-${name}/direct-media-server-key" = {
inherit owner group mode;
secrets = {
"mautrix-${name}/encryption-pickle-key" = {
inherit owner group mode;
};
"mautrix-${name}/provisioning-shared-secret" = {
inherit owner group mode;
};
"mautrix-${name}/public-media-signing-key" = {
inherit owner group mode;
};
"mautrix-${name}/direct-media-server-key" = {
inherit owner group mode;
};
};
templates."mautrix-${name}/env-file" = {
inherit owner group mode;
content = ''
MAUTRIX_${toUpper name}_ENCRYPTION_PICKLE_KEY=${
config.sops.placeholder."mautrix-${name}/encryption-pickle-key"
}
MAUTRIX_${toUpper name}_ENCRYPTION_PICKLE_KEY=${config.sops.placeholder."mautrix-${name}/encryption-pickle-key"}
MAUTRIX_${toUpper name}_PROVISIONING_SHARED_SECRET=${
config.sops.placeholder."mautrix-${name}/provisioning-shared-secret"
}
MAUTRIX_${toUpper name}_PUBLIC_MEDIA_SIGNING_KEY=${
config.sops.placeholder."mautrix-${name}/public-media-signing-key"
}
MAUTRIX_${toUpper name}_DIRECT_MEDIA_SERVER_KEY=${
config.sops.placeholder."mautrix-${name}/direct-media-server-key"
}
MAUTRIX_${toUpper name}_PUBLIC_MEDIA_SIGNING_KEY=${config.sops.placeholder."mautrix-${name}/public-media-signing-key"}
MAUTRIX_${toUpper name}_DIRECT_MEDIA_SERVER_KEY=${config.sops.placeholder."mautrix-${name}/direct-media-server-key"}
'';
};
}

View file

@ -84,77 +84,74 @@ in
};
config = mkIf cfg.enable {
services.postgresql = {
enable = true;
initialScript = pkgs.writeText "synapse-init.sql" ''
CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse';
CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse"
TEMPLATE template0
LC_COLLATE = 'C'
LC_CTYPE = 'C';
'';
};
services = {
postgresql = {
enable = true;
initialScript = pkgs.writeText "synapse-init.sql" ''
CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse';
CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse"
TEMPLATE template0
LC_COLLATE = 'C'
LC_CTYPE = 'C';
'';
};
services.matrix-synapse = mkMerge [
{
settings = {
registration_shared_secret_path =
mkIf cfg.sops
config.sops.secrets."matrix/registration-shared-secret".path;
server_name = config.networking.domain;
public_baseurl = baseUrl;
listeners = [
{
inherit (cfg) port;
bind_addresses = [ "127.0.0.1" ];
resources = [
{
compress = true;
names = [ "client" ];
}
{
compress = false;
names = [ "federation" ];
}
];
tls = false;
type = "http";
x_forwarded = true;
}
];
matrix-synapse = mkMerge [
{
settings = {
registration_shared_secret_path = mkIf cfg.sops config.sops.secrets."matrix/registration-shared-secret".path;
server_name = config.networking.domain;
public_baseurl = baseUrl;
listeners = [
{
inherit (cfg) port;
bind_addresses = [ "127.0.0.1" ];
resources = [
{
compress = true;
names = [ "client" ];
}
{
compress = false;
names = [ "federation" ];
}
];
tls = false;
type = "http";
x_forwarded = true;
}
];
};
}
(mkIf cfg.coturn.enable {
settings = {
turn_uris = with cfg.coturn; [
"turn:${realm}:${toString listening-port}?transport=udp"
"turn:${realm}:${toString listening-port}?transport=tcp"
"turn:${realm}:${toString tls-listening-port}?transport=udp"
"turn:${realm}:${toString tls-listening-port}?transport=tcp"
"turn:${realm}:${toString alt-listening-port}?transport=udp"
"turn:${realm}:${toString alt-listening-port}?transport=tcp"
"turn:${realm}:${toString alt-tls-listening-port}?transport=udp"
"turn:${realm}:${toString alt-tls-listening-port}?transport=tcp"
];
extraConfigFiles = mkIf cfg.sops [ config.sops.templates."coturn/static-auth-secret.env".path ];
turn_user_lifetime = "1h";
};
})
];
nginx.virtualHosts."${cfg.settings.server_name}" = {
enableACME = true;
forceSSL = true;
locations = {
"= /.well-known/matrix/server".extraConfig = mkWellKnown serverConfig;
"= /.well-known/matrix/client".extraConfig = mkWellKnown clientConfig;
"/_matrix".proxyPass = "http://127.0.0.1:${toString cfg.port}";
"/_synapse".proxyPass = "http://127.0.0.1:${toString cfg.port}";
};
}
(mkIf cfg.coturn.enable {
settings = {
turn_uris = with cfg.coturn; [
"turn:${realm}:${toString listening-port}?transport=udp"
"turn:${realm}:${toString listening-port}?transport=tcp"
"turn:${realm}:${toString tls-listening-port}?transport=udp"
"turn:${realm}:${toString tls-listening-port}?transport=tcp"
"turn:${realm}:${toString alt-listening-port}?transport=udp"
"turn:${realm}:${toString alt-listening-port}?transport=tcp"
"turn:${realm}:${toString alt-tls-listening-port}?transport=udp"
"turn:${realm}:${toString alt-tls-listening-port}?transport=tcp"
];
extraConfigFiles = mkIf cfg.sops [ config.sops.templates."coturn/static-auth-secret.env".path ];
turn_user_lifetime = "1h";
};
})
];
environment.shellAliases = mkIf cfg.sops {
register_new_matrix_user = "${cfg.package}/bin/register_new_matrix_user -k $(sudo cat ${cfg.settings.registration_shared_secret_path})";
};
services.nginx.virtualHosts."${cfg.settings.server_name}" = {
enableACME = true;
forceSSL = true;
locations."= /.well-known/matrix/server".extraConfig = mkWellKnown serverConfig;
locations."= /.well-known/matrix/client".extraConfig = mkWellKnown clientConfig;
locations."/_matrix".proxyPass = "http://127.0.0.1:${toString cfg.port}";
locations."/_synapse".proxyPass = "http://127.0.0.1:${toString cfg.port}";
};
};
sops = mkIf cfg.sops {

View file

@ -6,51 +6,53 @@
let
cfg = config.services.matrix-synapse;
domain = config.networking.domain;
inherit (config.networking) domain;
inherit (lib) mkIf mkDefault;
in
{
config = mkIf cfg.enable {
services.livekit = {
enable = true;
settings.port = mkDefault 7880;
settings.room.auto_create = mkDefault false;
openFirewall = mkDefault true;
keyFile = mkIf cfg.sops config.sops.templates."livekit/key".path;
};
services = {
livekit = {
enable = true;
settings.port = mkDefault 7880;
settings.room.auto_create = mkDefault false;
openFirewall = mkDefault true;
keyFile = mkIf cfg.sops config.sops.templates."livekit/key".path;
};
services.lk-jwt-service = {
enable = true;
port = mkDefault 8080;
livekitUrl = "wss://${domain}/livekit/sfu";
keyFile = mkIf cfg.sops config.sops.templates."livekit/key".path;
};
lk-jwt-service = {
enable = true;
port = mkDefault 8080;
livekitUrl = "wss://${domain}/livekit/sfu";
keyFile = mkIf cfg.sops config.sops.templates."livekit/key".path;
};
systemd.services.lk-jwt-service.environment.LIVEKIT_FULL_ACCESS_HOMESERVERS = domain;
services.nginx.virtualHosts = {
"${domain}".locations = {
"^~ /livekit/jwt/" = {
priority = 400;
proxyPass = "http://127.0.0.1:${toString config.services.lk-jwt-service.port}/";
};
"^~ /livekit/sfu/" = {
priority = 400;
proxyPass = "http://127.0.0.1:${toString config.services.livekit.settings.port}/";
proxyWebsockets = true;
extraConfig = ''
proxy_send_timeout 120;
proxy_read_timeout 120;
proxy_buffering off;
proxy_set_header Accept-Encoding gzip;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
'';
nginx.virtualHosts = {
"${domain}".locations = {
"^~ /livekit/jwt/" = {
priority = 400;
proxyPass = "http://127.0.0.1:${toString config.services.lk-jwt-service.port}/";
};
"^~ /livekit/sfu/" = {
priority = 400;
proxyPass = "http://127.0.0.1:${toString config.services.livekit.settings.port}/";
proxyWebsockets = true;
extraConfig = ''
proxy_send_timeout 120;
proxy_read_timeout 120;
proxy_buffering off;
proxy_set_header Accept-Encoding gzip;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
'';
};
};
};
};
systemd.services.lk-jwt-service.environment.LIVEKIT_FULL_ACCESS_HOMESERVERS = domain;
sops = mkIf cfg.sops {
secrets."livekit/key" = { };
templates."livekit/key".content = ''

View file

@ -76,7 +76,7 @@ in
sops = mkIf cfg.sops (
let
owner = user.name;
group = user.group;
inherit (user) group;
mode = "0400";
in
{
@ -98,9 +98,7 @@ in
''
admins:
''
+ concatLines (
map (admin: " ${admin}: ${config.sops.placeholder."maubot/admins/${admin}"}") cfg.admins
)
+ concatLines (map (admin: " ${admin}: ${config.sops.placeholder."maubot/admins/${admin}"}") cfg.admins)
);
};
}

View file

@ -96,7 +96,7 @@ in
users.users."${cfg.user}" = {
isSystemUser = true;
group = cfg.group;
inherit (cfg) group;
};
users.groups."${cfg.group}" = { };

View file

@ -6,8 +6,8 @@
let
cfg = config.services.miniflux;
domain = config.networking.domain;
subdomain = cfg.reverseProxy.subdomain;
inherit (config.networking) domain;
inherit (cfg.reverseProxy) subdomain;
fqdn = if (cfg.reverseProxy.enable && subdomain != "") then "${subdomain}.${domain}" else domain;
port = 8085;

View file

@ -50,8 +50,7 @@ in
"1.1.1.1"
"2606:4700:4700::1111"
];
resolvers =
if config.networking.nameservers == [ ] then cloudflare else config.networking.nameservers;
resolvers = if config.networking.nameservers == [ ] then cloudflare else config.networking.nameservers;
in
map escapeIPv6 resolvers;
@ -60,7 +59,7 @@ in
virtualHosts = {
"${config.networking.domain}" = mkDefault {
enableACME = cfg.forceSSL;
forceSSL = cfg.forceSSL;
inherit (cfg) forceSSL;
};
};
};

View file

@ -21,7 +21,7 @@ in
types.submodule {
options = {
extraGroups = mkOption {
type = (types.listOf types.str);
type = types.listOf types.str;
default = [ ];
description = "Extra groups for the user";
example = [ "wheel" ];
@ -37,7 +37,7 @@ in
description = "Initial password for the user";
};
sshKeyFiles = mkOption {
type = (types.listOf types.path);
type = types.listOf types.path;
default = [ ];
description = "SSH key files for the user";
example = [ "/path/to/id_rsa.pub" ];

View file

@ -2,8 +2,8 @@
let
cfg = config.services.nostr-relay;
domain = config.networking.domain;
subdomain = cfg.reverseProxy.subdomain;
inherit (config.networking) domain;
inherit (cfg.reverseProxy) subdomain;
fqdn = if (cfg.reverseProxy.enable && subdomain != "") then "${subdomain}.${domain}" else domain;
inherit (lib)
@ -48,9 +48,8 @@ in
services.nginx.virtualHosts = mkIf cfg.reverseProxy.enable {
"${fqdn}" = {
enableACME = cfg.reverseProxy.forceSSL;
forceSSL = cfg.reverseProxy.forceSSL;
locations."/".proxyPass =
"http://127.0.0.1:${toString config.services.nostr-rs-relay.settings.network.port}";
inherit (cfg.reverseProxy) forceSSL;
locations."/".proxyPass = "http://127.0.0.1:${toString config.services.nostr-rs-relay.settings.network.port}";
};
};
};

View file

@ -9,20 +9,26 @@ let
inherit (lib) mkDefault;
in
{
boot.blacklistedKernelModules = [ "nouveau" ];
boot.extraModulePackages = [ config.hardware.nvidia.package ];
boot.initrd.kernelModules = [ "nvidia" ];
boot = {
blacklistedKernelModules = [ "nouveau" ];
extraModulePackages = [ config.hardware.nvidia.package ];
initrd.kernelModules = [ "nvidia" ];
};
environment.systemPackages = with pkgs; [
nvtopPackages.nvidia
];
hardware.enableRedistributableFirmware = true;
hardware.graphics.enable = true;
hardware.nvidia.modesetting.enable = true;
hardware.nvidia.nvidiaSettings = true;
hardware.nvidia.open = false;
hardware.nvidia.package = mkDefault config.boot.kernelPackages.nvidiaPackages.latest;
hardware = {
enableRedistributableFirmware = true;
graphics.enable = true;
nvidia = {
modesetting.enable = true;
nvidiaSettings = true;
open = false;
package = mkDefault config.boot.kernelPackages.nvidiaPackages.latest;
};
};
nixpkgs.config.cudaSupport = true;

View file

@ -2,8 +2,8 @@
let
cfg = config.services.ollama;
domain = config.networking.domain;
subdomain = cfg.reverseProxy.subdomain;
inherit (config.networking) domain;
inherit (cfg.reverseProxy) subdomain;
fqdn = if (cfg.reverseProxy.enable && subdomain != "") then "${subdomain}.${domain}" else domain;
inherit (lib)
@ -31,7 +31,7 @@ in
services.nginx.virtualHosts = mkIf cfg.reverseProxy.enable {
"${fqdn}" = mkVirtualHost {
port = cfg.port;
inherit (cfg) port;
ssl = cfg.reverseProxy.forceSSL;
recommendedProxySettings = mkForce false;
extraConfig = ''

View file

@ -83,10 +83,43 @@ in
};
config = mkIf cfg.enable {
virtualisation.podman = {
enable = true;
autoPrune.enable = true;
dockerCompat = true;
virtualisation = {
podman = {
enable = true;
autoPrune.enable = true;
dockerCompat = true;
};
oci-containers = {
backend = "podman";
containers."open-webui" = {
image = with cfg.image; imageName + ":" + imageTag;
imageFile = cfg.image;
environment =
defaultEnv
// cfg.environment
// {
PORT = "${toString cfg.port}";
CORS_ALLOW_ORIGIN = concatStringsSep ";" (
[
"http://localhost:${toString cfg.port}"
"http://127.0.0.1:${toString cfg.port}"
"http://0.0.0.0:${toString cfg.port}"
]
++ optional (cfg.externalUrl != null) cfg.externalUrl
);
};
environmentFiles = optional (cfg.environmentFile != null) cfg.environmentFile;
volumes = [
"open-webui_open-webui:/app/backend/data:rw"
];
log-driver = "journald";
extraOptions = [
"--network=host"
];
};
};
};
networking.firewall.interfaces =
@ -97,70 +130,44 @@ in
"${matchAll}".allowedUDPPorts = [ 53 ];
};
virtualisation.oci-containers.backend = "podman";
virtualisation.oci-containers.containers."open-webui" = {
image = with cfg.image; imageName + ":" + imageTag;
imageFile = cfg.image;
environment =
defaultEnv
// cfg.environment
// {
PORT = "${toString cfg.port}";
CORS_ALLOW_ORIGIN = concatStringsSep ";" (
[
"http://localhost:${toString cfg.port}"
"http://127.0.0.1:${toString cfg.port}"
"http://0.0.0.0:${toString cfg.port}"
]
++ optional (cfg.externalUrl != null) cfg.externalUrl
);
systemd = {
services."podman-open-webui" = {
serviceConfig = {
Restart = mkOverride 90 "always";
};
environmentFiles = optional (cfg.environmentFile != null) cfg.environmentFile;
volumes = [
"open-webui_open-webui:/app/backend/data:rw"
];
log-driver = "journald";
extraOptions = [
"--network=host"
];
};
systemd.services."podman-open-webui" = {
serviceConfig = {
Restart = mkOverride 90 "always";
after = [
"podman-volume-open-webui_open-webui.service"
];
requires = [
"podman-volume-open-webui_open-webui.service"
];
partOf = [
"podman-compose-open-webui-root.target"
];
wantedBy = [
"podman-compose-open-webui-root.target"
];
};
after = [
"podman-volume-open-webui_open-webui.service"
];
requires = [
"podman-volume-open-webui_open-webui.service"
];
partOf = [
"podman-compose-open-webui-root.target"
];
wantedBy = [
"podman-compose-open-webui-root.target"
];
};
systemd.services."podman-volume-open-webui_open-webui" = {
path = [ pkgs.podman ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
services."podman-volume-open-webui_open-webui" = {
path = [ pkgs.podman ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
podman volume inspect open-webui_open-webui || podman volume create open-webui_open-webui
'';
partOf = [ "podman-compose-open-webui-root.target" ];
wantedBy = [ "podman-compose-open-webui-root.target" ];
};
script = ''
podman volume inspect open-webui_open-webui || podman volume create open-webui_open-webui
'';
partOf = [ "podman-compose-open-webui-root.target" ];
wantedBy = [ "podman-compose-open-webui-root.target" ];
};
systemd.targets."podman-compose-open-webui-root" = {
unitConfig = {
Description = "Root target generated by compose2nix.";
targets."podman-compose-open-webui-root" = {
unitConfig = {
Description = "Root target generated by compose2nix.";
};
wantedBy = [ "multi-user.target" ];
};
wantedBy = [ "multi-user.target" ];
};
};
}

View file

@ -7,8 +7,8 @@
let
cfg = config.services.print-server;
domain = config.networking.domain;
subdomain = cfg.reverseProxy.subdomain;
inherit (config.networking) domain;
inherit (cfg.reverseProxy) subdomain;
fqdn = if (cfg.reverseProxy.enable && subdomain != "") then "${subdomain}.${domain}" else domain;
port = 631;
@ -36,47 +36,49 @@ in
};
config = mkIf cfg.enable {
services.printing = {
enable = true;
listenAddresses = [ "*:${builtins.toString port}" ];
webInterface = true;
tempDir = "/tmp/cups";
allowFrom = [ "all" ];
snmpConf = ''
Address @LOCAL
'';
clientConf = "";
openFirewall = cfg.openFirewall;
drivers = with pkgs; [
brlaser
brgenml1lpr
brgenml1cupswrapper # Brother
postscript-lexmark # Lexmark
hplip
hplipWithPlugin # HP
splix
samsung-unified-linux-driver # Samsung
gutenprint
gutenprintBin # different vendors
];
defaultShared = true;
browsing = true;
browsedConf = ''
BrowsePoll ${fqdn}
'';
};
services = {
printing = {
enable = true;
listenAddresses = [ "*:${builtins.toString port}" ];
webInterface = true;
tempDir = "/tmp/cups";
allowFrom = [ "all" ];
snmpConf = ''
Address @LOCAL
'';
clientConf = "";
inherit (cfg) openFirewall;
drivers = with pkgs; [
brlaser
brgenml1lpr
brgenml1cupswrapper # Brother
postscript-lexmark # Lexmark
hplip
hplipWithPlugin # HP
splix
samsung-unified-linux-driver # Samsung
gutenprint
gutenprintBin # different vendors
];
defaultShared = true;
browsing = true;
browsedConf = ''
BrowsePoll ${fqdn}
'';
};
# autodiscovery of network printers
services.avahi = {
enable = true;
nssmdns4 = true;
openFirewall = cfg.openFirewall;
};
# autodiscovery of network printers
avahi = {
enable = true;
nssmdns4 = true;
inherit (cfg) openFirewall;
};
services.nginx.virtualHosts = mkIf cfg.reverseProxy.enable {
${fqdn} = mkVirtualHost {
inherit port;
ssl = cfg.reverseProxy.forceSSL;
nginx.virtualHosts = mkIf cfg.reverseProxy.enable {
${fqdn} = mkVirtualHost {
inherit port;
ssl = cfg.reverseProxy.forceSSL;
};
};
};
};

View file

@ -7,8 +7,8 @@
let
cfg = config.services.radicale;
domain = config.networking.domain;
subdomain = cfg.reverseProxy.subdomain;
inherit (config.networking) domain;
inherit (cfg.reverseProxy) subdomain;
fqdn = if (cfg.reverseProxy.enable && subdomain != "") then "${subdomain}.${domain}" else domain;
port = 5232;
@ -63,7 +63,7 @@ in
services.nginx.virtualHosts = mkIf cfg.reverseProxy.enable {
"${fqdn}" = {
forceSSL = cfg.reverseProxy.forceSSL;
inherit (cfg.reverseProxy) forceSSL;
enableACME = cfg.reverseProxy.forceSSL;
locations = {
"/" = {

View file

@ -2,8 +2,8 @@
let
cfg = config.services.rss-bridge;
domain = config.networking.domain;
subdomain = cfg.reverseProxy.subdomain;
inherit (config.networking) domain;
inherit (cfg.reverseProxy) subdomain;
fqdn = if (cfg.reverseProxy.enable && subdomain != "") then "${subdomain}.${domain}" else domain;
inherit (lib)
@ -33,7 +33,7 @@ in
services.nginx.virtualHosts = mkIf cfg.reverseProxy.enable {
"${fqdn}" = {
enableACME = cfg.reverseProxy.forceSSL;
forceSSL = cfg.reverseProxy.forceSSL;
inherit (cfg.reverseProxy) forceSSL;
};
};
};

View file

@ -56,8 +56,7 @@ in
config =
let
defaultTailnets = filterAttrs (_: t: t.default) cfg.tailnets;
defaultTailnet =
if defaultTailnets == { } then null else builtins.head (builtins.attrValues defaultTailnets);
defaultTailnet = if defaultTailnets == { } then null else builtins.head (builtins.attrValues defaultTailnets);
entries = mapAttrsToList (name: tcfg: ''
TAILNETS["${name}"]="${tcfg.loginServer}|${if tcfg.enableSSH then "true" else "false"}|${
@ -111,8 +110,7 @@ in
mkIf cfg.enable {
assertions = [
{
assertion =
(builtins.length (builtins.attrValues (filterAttrs (_: t: t.default) cfg.tailnets))) <= 1;
assertion = (builtins.length (builtins.attrValues (filterAttrs (_: t: t.default) cfg.tailnets))) <= 1;
message = "services.tailscale.tailnets: Only one tailnet can be set as default.";
}
{

View file

@ -58,16 +58,18 @@ in
enable = mkDefault true;
onBoot = mkDefault "ignore";
onShutdown = mkDefault "shutdown";
qemu.runAsRoot = mkDefault false;
qemu.verbatimConfig = ''
clear_emulation_capabilities = ${boolToZeroOne cfg.libvirtd.clearEmulationCapabilities}
''
+ optionalString (cfg.libvirtd.deviceACL != [ ]) ''
cgroup_device_acl = [
${aclString}
]
'';
qemu.swtpm.enable = mkDefault true; # TPM 2.0
qemu = {
runAsRoot = mkDefault false;
verbatimConfig = ''
clear_emulation_capabilities = ${boolToZeroOne cfg.libvirtd.clearEmulationCapabilities}
''
+ optionalString (cfg.libvirtd.deviceACL != [ ]) ''
cgroup_device_acl = [
${aclString}
]
'';
swtpm.enable = mkDefault true; # TPM 2.0
};
};
spiceUSBRedirection.enable = mkDefault true;
};

View file

@ -1,3 +1,4 @@
#!/usr/bin/env bash
shopt -s nullglob
for d in /sys/kernel/iommu_groups/*/devices/*; do
n=${d#*/iommu_groups/*}; n=${n%%/*}

View file

@ -78,34 +78,32 @@ let
};
};
deviceType = (
types.submodule (
{ config, options, ... }:
{
options = {
resolution = mkOption {
type = types.nullOr resolutionType;
default = null;
description = "Automatically calculate the minimum device size for a specific resolution. Overrides `size` if set.";
};
size = mkOption {
type = types.number;
description = "Size for the kvmfr device in megabytes.";
};
permissions = mkOption {
type = permissionsType;
default = { };
description = "Permissions of the kvmfr device.";
};
deviceType = types.submodule (
{ config, options, ... }:
{
options = {
resolution = mkOption {
type = types.nullOr resolutionType;
default = null;
description = "Automatically calculate the minimum device size for a specific resolution. Overrides `size` if set.";
};
config = {
size = mkIf (config.resolution != null) (sizeFromResolution config.resolution);
size = mkOption {
type = types.number;
description = "Size for the kvmfr device in megabytes.";
};
}
)
permissions = mkOption {
type = permissionsType;
default = { };
description = "Permissions of the kvmfr device.";
};
};
config = {
size = mkIf (config.resolution != null) (sizeFromResolution config.resolution);
};
}
);
inherit (lib)
@ -144,7 +142,7 @@ in
'';
"modprobe.d/kvmfr.conf".text = ''
options kvmfr static_size_mb=${concatStringsSep "," (map (size: toString size) deviceSizes)}
options kvmfr static_size_mb=${concatStringsSep "," (map toString deviceSizes)}
'';
"apparmor.d/local/abstractions/libvirt-qemu" = mkIf config.security.apparmor.enable {

View file

@ -2,7 +2,7 @@
let
cfg = config.services.webPage;
domain = config.networking.domain;
inherit (config.networking) domain;
fqdn = if (cfg.subdomain != "") then "${cfg.subdomain}.${domain}" else domain;
nginxUser = config.services.nginx.user;
@ -41,7 +41,7 @@ in
config = mkIf cfg.enable {
services.nginx.virtualHosts."${fqdn}" = {
enableACME = cfg.forceSSL;
forceSSL = cfg.forceSSL;
inherit (cfg) forceSSL;
root = cfg.webRoot;
locations."/".index = "index.html";
sslCertificate = mkIf cfg.forceSSL "${config.security.acme.certs."${fqdn}".directory}/cert.pem";

View file

@ -81,90 +81,97 @@ in
};
config = mkIf cfg.enable {
systemd.tmpfiles.rules = [ "d ${cfg.volume} 0755 root podman -" ];
systemd = {
tmpfiles.rules = [ "d ${cfg.volume} 0755 root podman -" ];
virtualisation.podman = {
enable = true;
autoPrune.enable = true;
dockerCompat = true;
defaultNetwork.settings = {
dns_enabled = true;
services = {
"podman-windows" = {
serviceConfig = {
Restart = mkOverride 90 "always";
};
after = [
"podman-network-windows_default.service"
];
requires = [
"podman-network-windows_default.service"
];
partOf = [
"podman-compose-windows-root.target"
];
wantedBy = [
"podman-compose-windows-root.target"
];
};
"podman-network-windows_default" = {
path = [ pkgs.podman ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStop = "podman network rm -f windows_default";
};
script = ''
podman network inspect windows_default || podman network create windows_default
'';
partOf = [ "podman-compose-windows-root.target" ];
wantedBy = [ "podman-compose-windows-root.target" ];
};
};
targets."podman-compose-windows-root" = {
unitConfig = {
Description = "Root target generated by compose2nix.";
};
wantedBy = [ "multi-user.target" ];
};
};
virtualisation = {
podman = {
enable = true;
autoPrune.enable = true;
dockerCompat = true;
defaultNetwork.settings = {
dns_enabled = true;
};
};
oci-containers = {
backend = "podman";
containers."windows" = {
image = "dockurr/windows";
environment = with cfg.settings; {
"VERSION" = version;
"RAM_SIZE" = ramSize;
"CPU_CORES" = cpuCores;
"DISK_SIZE" = diskSize;
"USERNAME" = username;
"PASSWORD" = password;
"REGION" = region;
"KEYBOARD" = keyboard;
};
volumes = [
"${cfg.volume}:/storage:rw"
]
++ optional (cfg.sharedVolume != null) "${cfg.sharedVolume}:/shared:rw";
ports = [
"8006:8006/tcp"
"3389:3389/tcp"
"3389:3389/udp"
];
log-driver = "journald";
extraOptions = [
"--cap-add=NET_ADMIN"
"--device=/dev/kvm:/dev/kvm:rwm"
"--device=/dev/net/tun:/dev/net/tun:rwm"
"--network-alias=windows"
"--network=windows_default"
];
};
};
};
# https://github.com/NixOS/nixpkgs/issues/226365
networking.firewall.interfaces."podman+".allowedUDPPorts = [ 53 ];
virtualisation.oci-containers.backend = "podman";
virtualisation.oci-containers.containers."windows" = {
image = "dockurr/windows";
environment = with cfg.settings; {
"VERSION" = version;
"RAM_SIZE" = ramSize;
"CPU_CORES" = cpuCores;
"DISK_SIZE" = diskSize;
"USERNAME" = username;
"PASSWORD" = password;
"LANGUAGE" = language;
"REGION" = region;
"KEYBOARD" = keyboard;
};
volumes = [
"${cfg.volume}:/storage:rw"
]
++ optional (cfg.sharedVolume != null) "${cfg.sharedVolume}:/shared:rw";
ports = [
"8006:8006/tcp"
"3389:3389/tcp"
"3389:3389/udp"
];
log-driver = "journald";
extraOptions = [
"--cap-add=NET_ADMIN"
"--device=/dev/kvm:/dev/kvm:rwm"
"--device=/dev/net/tun:/dev/net/tun:rwm"
"--network-alias=windows"
"--network=windows_default"
];
};
systemd.services."podman-windows" = {
serviceConfig = {
Restart = mkOverride 90 "always";
};
after = [
"podman-network-windows_default.service"
];
requires = [
"podman-network-windows_default.service"
];
partOf = [
"podman-compose-windows-root.target"
];
wantedBy = [
"podman-compose-windows-root.target"
];
};
systemd.services."podman-network-windows_default" = {
path = [ pkgs.podman ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStop = "podman network rm -f windows_default";
};
script = ''
podman network inspect windows_default || podman network create windows_default
'';
partOf = [ "podman-compose-windows-root.target" ];
wantedBy = [ "podman-compose-windows-root.target" ];
};
systemd.targets."podman-compose-windows-root" = {
unitConfig = {
Description = "Root target generated by compose2nix.";
};
wantedBy = [ "multi-user.target" ];
};
};
}