This commit is contained in:
Tibo De Peuter 2025-10-01 16:33:55 +02:00
parent 59f721f4d7
commit f1ba0a98e8
Signed by: tdpeuter
GPG key ID: 38297DE43F75FFE2
12 changed files with 95 additions and 109 deletions

12
flake.lock generated
View file

@ -20,11 +20,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1735291276, "lastModified": 1756787288,
"narHash": "sha256-NYVcA06+blsLG6wpAbSPTCyLvxD/92Hy4vlY9WxFI1M=", "narHash": "sha256-rw/PHa1cqiePdBxhF66V7R+WAP8WekQ0mCDG4CFqT8Y=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "634fd46801442d760e09493a794c4f15db2d0cbb", "rev": "d0fc30899600b9b3466ddb260fd83deb486c32f1",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -62,11 +62,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1722363685, "lastModified": 1738591040,
"narHash": "sha256-XCf2PIAT6lH7BwytgioPmVf/wkzXjSKScC4KzcZgb64=", "narHash": "sha256-4WNeriUToshQ/L5J+dTSWC5OJIwT39SEP7V7oylndi8=",
"owner": "gytis-ivaskevicius", "owner": "gytis-ivaskevicius",
"repo": "flake-utils-plus", "repo": "flake-utils-plus",
"rev": "6b10f51ff73a66bb29f3bc8151a59d217713f496", "rev": "afcb15b845e74ac5e998358709b2b5fe42a948d1",
"type": "github" "type": "github"
}, },
"original": { "original": {

View file

@ -32,18 +32,24 @@
}; };
hosts = { hosts = {
Niko.modules = [ ./hosts/Niko ]; # Physical hosts
Niko.modules = [ ./hosts/Niko ];
# Virtual machines
# Single-service
Ingress.modules = [ ./hosts/Ingress ]; Ingress.modules = [ ./hosts/Ingress ];
Gitea.modules = [ ./hosts/Gitea ]; Gitea.modules = [ ./hosts/Gitea ];
Vaultwarden.modules = [ ./hosts/Vaultwarden ]; Vaultwarden.modules = [ ./hosts/Vaultwarden ];
# Production multi-service
Binnenpost.modules = [ ./hosts/Binnenpost ]; Binnenpost.modules = [ ./hosts/Binnenpost ];
Production.modules = [ ./hosts/Production ]; Production.modules = [ ./hosts/Production ];
ProductionGPU.modules = [ ./hosts/ProductionGPU ]; ProductionGPU.modules = [ ./hosts/ProductionGPU ];
ProductionArr.modules = [ ./hosts/ProductionArr ]; ProductionArr.modules = [ ./hosts/ProductionArr ];
ACE.modules = [ ./hosts/ACE ]; ACE.modules = [ ./hosts/ACE ];
# Others
Template.modules = [ ./hosts/Template ]; Template.modules = [ ./hosts/Template ];
Development.modules = [ ./hosts/Development ]; Development.modules = [ ./hosts/Development ];
Testing.modules = [ ./hosts/Testing ]; Testing.modules = [ ./hosts/Testing ];

View file

@ -59,6 +59,7 @@ prefixLength = 24;
}; };
"cloud.depeuter.dev" = { }; "cloud.depeuter.dev" = { };
"git.depeuter.dev" = { }; "git.depeuter.dev" = { };
"home.depeuter.dev" = { };
"jelly.depeuter.dev" = { }; "jelly.depeuter.dev" = { };
"vault.depeuter.dev" = { }; "vault.depeuter.dev" = { };
}; };
@ -136,10 +137,27 @@ prefixLength = 24;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
''; '';
}; };
"calendar.depeuter.dev".locations."/".return = "301 https://cloud.depeuter.dev/apps/calendar"; "calendar.depeuter.dev" = {
useACMEHost = "depeuter.dev";
locations."/".return = "301 https://cloud.depeuter.dev/apps/calendar";
};
"tasks.depeuter.dev".locations."/".return = "301 https://cloud.depeuter.dev/apps/tasks"; "tasks.depeuter.dev".locations."/".return = "301 https://cloud.depeuter.dev/apps/tasks";
"notes.depeuter.dev".locations."/".return = "301 https://cloud.depeuter.dev/apps/notes"; "notes.depeuter.dev".locations."/".return = "301 https://cloud.depeuter.dev/apps/notes";
"home.depeuter.dev" = {
enableACME = true;
forceSSL = true;
locations."/" = {
proxyPass = "http://192.168.0.21:8123";
extraConfig = ''
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
'';
};
};
"jelly.depeuter.dev" = { "jelly.depeuter.dev" = {
enableACME = true; enableACME = true;
forceSSL = true; forceSSL = true;
@ -176,7 +194,7 @@ prefixLength = 24;
}; };
}; };
extraConfig = '' extraConfig = ''
client_max_body_size 20M; client_max_body_size 512M;
# Security / XSS Mitigation Headers # Security / XSS Mitigation Headers
# NOTE: X-Frame-Options may cause issues with the webOS app # NOTE: X-Frame-Options may cause issues with the webOS app
@ -206,7 +224,7 @@ prefixLength = 24;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Proto $scheme;
client_max_body_size 512M; client_max_body_size 10G;
keepalive_timeout 600s; keepalive_timeout 600s;
proxy_buffers 4 256k; # Number and size of buffers for reading response proxy_buffers 4 256k; # Number and size of buffers for reading response
proxy_buffer_size 256k; # Buffer for the first part of the response proxy_buffer_size 256k; # Buffer for the first part of the response
@ -220,10 +238,18 @@ prefixLength = 24;
enableACME = true; enableACME = true;
forceSSL = true; forceSSL = true;
locations = { locations = {
"/".proxyPass = "http://192.168.0.22:10102"; "/" = {
proxyPass = "http://192.168.0.22:10102";
proxyWebSockets = true;
};
"~ ^/admin".return = 403; "~ ^/admin".return = 403;
}; };
}; };
"rss.depeuter.dev" = {
enableACME = true;
forceSSL = true;
locations."/".proxyPass = "http://192.168.92:${toString config.homelab.apps.freshrss.port}";
};
}; };
}; };
}; };

View file

@ -7,7 +7,10 @@
]; ];
homelab = { homelab = {
apps.technitiumDNS.enable = true; apps = {
technitiumDNS.enable = true;
traefik.enable = true;
};
users.deploy.enable = true; users.deploy.enable = true;
}; };
@ -34,12 +37,11 @@
hardware = { hardware = {
enableRedistributableFirmware = true; enableRedistributableFirmware = true;
enableAllFirmware = true; enableAllFirmware = true;
pulseaudio.enable = true; graphics.enable = true;
opengl.enable = true;
}; };
# Select internationalisation properties. # Select internationalisation properties.
i18n.defaultLocale = "en_GB.utf8"; i18n.defaultLocale = "en_GB.UTF-8";
networking = { networking = {
hostName = "Niko"; hostName = "Niko";
@ -79,6 +81,8 @@
user = config.users.users.jellyfin-mpv-shim.name; user = config.users.users.jellyfin-mpv-shim.name;
}; };
pulseaudio.enable = true;
tailscale = { tailscale = {
enable = true; enable = true;
useRoutingFeatures = "server"; useRoutingFeatures = "server";
@ -94,8 +98,6 @@
# resolved.enable = true; # resolved.enable = true;
}; };
sound.enable = true;
# Define a user account. Don't forget to set a password with 'passwd'. # Define a user account. Don't forget to set a password with 'passwd'.
users.users.jellyfin-mpv-shim = { users.users.jellyfin-mpv-shim = {
description = "Jellyfin MPV Shim User"; description = "Jellyfin MPV Shim User";
@ -114,67 +116,4 @@
systemd.services."cage-tty1".serviceConfig.Restart = "always"; systemd.services."cage-tty1".serviceConfig.Restart = "always";
system.stateVersion = "24.05"; system.stateVersion = "24.05";
virtualisation = {
# Enable Android emulator
# waydroid.enable = true;
docker = {
enable = true;
autoPrune.enable = true;
};
oci-containers = {
backend = "docker";
containers = {
reverse-proxy = {
hostname = "traefik";
image = "traefik:v3.0";
cmd = [
"--api.insecure=true"
# Add Docker provider
"--providers.docker=true"
"--providers.docker.exposedByDefault=false"
# Add web entrypoint
"--entrypoints.web.address=:80/tcp"
"--entrypoints.web.http.redirections.entrypoint.to=websecure"
"--entrypoints.web.http.redirections.entrypoint.scheme=https"
# Add websecure entrypoint
"--entrypoints.websecure.address=:443/tcp"
"--entrypoints.websecure.http.tls=true"
"--entrypoints.websecure.http.tls.certResolver=letsencrypt"
"--entrypoints.websecure.http.tls.domains[0].main=depeuter.dev"
"--entrypoints.websecure.http.tls.domains[0].sans=*.depeuter.dev"
"--entrypoints.websecure.http.tls.domains[1].sans=*.niko.depeuter.dev"
# Certificates
"--certificatesresolvers.letsencrypt.acme.dnschallenge=true"
"--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=cloudflare"
"--certificatesresolvers.letsencrypt.acme.email=tibo.depeuter@telenet.be"
"--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
];
ports = [
"80:80/tcp"
"443:443/tcp"
# "8080:8080/tcp" # The Web UI (enabled by --api.insecure=true)
];
environment = {
# TODO Hide this!
"CLOUDFLARE_DNS_API_TOKEN" = "6Vz64Op_a6Ls1ljGeBxFoOVfQ-yB-svRbf6OyPv2";
};
environmentFiles = [
];
volumes = [
"/var/run/docker.sock:/var/run/docker.sock:ro" # So that Traefik can listen to the Docker events
"letsencrypt:/letsencrypt"
];
labels = {
"traefik.enable" = "true";
"traefik.http.routers.traefik.rule" = "Host(`traefik.niko.depeuter.dev`)";
"traefik.http.services.traefik.loadbalancer.server.port" = "8080";
};
autoStart = true;
};
};
};
};
} }

View file

@ -17,7 +17,7 @@
defaultGateway = { defaultGateway = {
address = "192.168.0.1"; address = "192.168.0.1";
interface = "enp6s18"; interface = "ens18";
}; };
# Open ports in the firewall. # Open ports in the firewall.
@ -25,7 +25,7 @@
enable = true; enable = true;
}; };
interfaces.enp6s18 = { interfaces.ens18 = {
ipv4.addresses = [ ipv4.addresses = [
{ {
address = "192.168.0.94"; address = "192.168.0.94";
@ -40,7 +40,7 @@
]; ];
}; };
system.stateVersion = "unstable"; system.stateVersion = "24.11";
### Nvidia GPU support ### ### Nvidia GPU support ###
@ -64,7 +64,7 @@
}; };
hardware = { hardware = {
opengl = { graphics = {
enable = true; enable = true;
# driSupport = true; # driSupport = true;
# driSupport32Bit = true; # driSupport32Bit = true;

View file

@ -3,7 +3,10 @@
{ {
config = { config = {
homelab = { homelab = {
apps.freshrss.enable = true; apps = {
freshrss.enable = true;
traefik.enable = true;
};
virtualisation.guest.enable = true; virtualisation.guest.enable = true;
}; };

View file

@ -343,7 +343,7 @@ in {
port = 7878; port = 7878;
in lib.mkIf cfg.radarr.enable { in lib.mkIf cfg.radarr.enable {
hostname = "radarr"; hostname = "radarr";
image = "ghcr.io/hotio/radarr:release-5.28.0.10205"; image = "ghcr.io/hotio/radarr:testing-5.28.0.10205";
autoStart = true; autoStart = true;
ports = lib.mkIf cfg.radarr.exposePorts [ ports = lib.mkIf cfg.radarr.exposePorts [
"${toString port}:${toString port}/tcp" "${toString port}:${toString port}/tcp"

View file

@ -27,7 +27,7 @@ in {
"rw" "rw"
"auto" "auto"
"nfsvers=4.2" "nfsvers=4.2"
"sync" "hard" "timeo=600" "async" "soft" "timeo=600"
"retrans=2" "retrans=2"
"_netdev" "_netdev"
"nosuid" "nosuid"
@ -53,24 +53,41 @@ in {
virtualisation.oci-containers.containers.freshrss = { virtualisation.oci-containers.containers.freshrss = {
hostname = "freshrss"; hostname = "freshrss";
image = "freshrss/freshrss:1.24.0"; image = "freshrss/freshrss:1.25.0";
autoStart = true; autoStart = true;
user = "0:33"; user = "0:33";
ports = [ ports = [
"${toString port}:${toString port}/tcp" "${toString port}:80/tcp"
]; ];
extraOptions = [ extraOptions = [
"--network=${networkName}" "--network=${networkName}"
]; ];
environment = { environment = {
TZ = config.time.timeZone; TZ = config.time.timeZone;
CRON_TIME = "3,18,33,48"; # Alternatively, configure cron inside container. CRON_MIN = "3,18,33,48"; # Alternatively, configure cron inside container.
LISTEN = "0.0.0.0:${toString port}"; SERVER_DNS = "rss.depeuter.dev";
TRUSTED_PROXY = "172.16.0.1/12 192.168.0.1/16";
}; };
volumes = [ volumes = [
"/srv/freshrss/www/freshrss/data:/var/www/FreshRSS/data" "/srv/freshrss/www/freshrss/data:/var/www/FreshRSS/data"
"/srv/freshrss/www/freshrss/extensions:/var/www/FreshRSS/extensions" "/srv/freshrss/www/freshrss/extensions:/var/www/FreshRSS/extensions"
]; ];
labels = {
"traefik.enable" = "true";
"traefik.http.middlewares.freshrssM1.compress" = "true";
"traefik.http.middlewares.freshrssM2.headers.browserXssFilter" = "true";
"traefik.http.middlewares.freshrssM2.headers.forceSTSHeader" = "true";
"traefik.http.middlewares.freshrssM2.headers.frameDeny" = "true";
"traefik.http.middlewares.freshrssM2.headers.referrerPolicy" = "no-referrer-when-downgrade";
"traefik.http.middlewares.freshrssM2.headers.stsSeconds" = "31536000";
"traefik.http.routers.freshrss.entryPoints" = "websecure";
"traefik.http.routers.freshrss.tls" = "true";
"traefik.http.services.freshrss.loadbalancer.server.port" = "80";
"traefik.http.routers.freshrss.middlewares" = "freshrssM1,freshrssM2";
"traefik.http.routers.freshrss.rule" = "Host(`rss.depeuter.dev`)";
};
}; };
}; };
} }

View file

@ -124,7 +124,7 @@ in {
gitea = { gitea = {
hostname = "gitea"; hostname = "gitea";
image = "codeberg.org/forgejo/forgejo:8.0.3-rootless"; image = "codeberg.org/forgejo/forgejo:11.0.1-rootless";
autoStart = true; autoStart = true;
user = "${toString UID}:${toString GID}"; user = "${toString UID}:${toString GID}";
ports = [ ports = [
@ -576,7 +576,7 @@ in {
#FORGEJO__picture__AVATAR_RENDERED_SIZE_FACTOR = "2"; #FORGEJO__picture__AVATAR_RENDERED_SIZE_FACTOR = "2";
# Maximum allowed file size for uploaded avatars. # Maximum allowed file size for uploaded avatars.
# This is to limit the amount of RAM used when resizing the image. # This is to limit the amount of RAM used when resizing the image.
#FORGEJO__picture__AVATAR_MAX_FILE_SIZE = "1048576"; FORGEJO__picture__AVATAR_MAX_FILE_SIZE = "1048576";
# If the uploaded file is not larger than this byte size, the image will be used as is, without resizing/converting. # If the uploaded file is not larger than this byte size, the image will be used as is, without resizing/converting.
#FORGEJO__picture__AVATAR_MAX_ORIGIN_SIZE = "262144"; #FORGEJO__picture__AVATAR_MAX_ORIGIN_SIZE = "262144";
# Chinese users can choose "duoshuo" # Chinese users can choose "duoshuo"

View file

@ -4,6 +4,7 @@ let
cfg = config.homelab.apps.jellyfin; cfg = config.homelab.apps.jellyfin;
networkName = "jellyfin"; networkName = "jellyfin";
inherit (config.homelab.fileSystems) media;
UID = 3008; UID = 3008;
GID = config.users.groups.media.gid; GID = config.users.groups.media.gid;
@ -12,6 +13,11 @@ in {
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
homelab = { homelab = {
fileSystems.media.video = {
enable = true;
permissions = [ "read" ];
};
users = { users = {
apps.enable = true; apps.enable = true;
media.enable = true; media.enable = true;
@ -32,18 +38,6 @@ in {
]; ];
}; };
"/srv/video" = {
device = "192.168.0.11:/mnt/SMALL/MEDIA/VIDEO";
fsType = "nfs";
options = [
"ro"
"nfsvers=4.2"
"async" "soft"
"timeo=100" "retry=50" "actimeo=1800" "lookupcache=all"
"nosuid" "tcp"
];
};
"/srv/homevideo" = { "/srv/homevideo" = {
device = "192.168.0.11:/mnt/BIG/MEDIA/HOMEVIDEO/ARCHIVE"; device = "192.168.0.11:/mnt/BIG/MEDIA/HOMEVIDEO/ARCHIVE";
fsType = "nfs"; fsType = "nfs";
@ -101,7 +95,7 @@ in {
virtualisation.oci-containers.containers = { virtualisation.oci-containers.containers = {
jellyfin = { jellyfin = {
hostname = "jellyfin"; hostname = "jellyfin";
image = "jellyfin/jellyfin:10.10.0"; image = "jellyfin/jellyfin:10.10.7";
user = "${toString UID}:${toString GID}"; user = "${toString UID}:${toString GID}";
autoStart = true; autoStart = true;
ports = [ ports = [
@ -117,7 +111,7 @@ in {
"cache:/cache" "cache:/cache"
"/srv/audio:/media/audio" "/srv/audio:/media/audio"
"/srv/video:/media/video" "${media.video.hostPath}:/media/video"
"/srv/homevideo:/media/homevideo" "/srv/homevideo:/media/homevideo"
"/srv/photo:/media/photo" "/srv/photo:/media/photo"
]; ];
@ -144,7 +138,7 @@ in {
feishinPort = "9180"; feishinPort = "9180";
in { in {
hostname = "feishin"; hostname = "feishin";
image = "ghcr.io/jeffvli/feishin:0.7.1"; image = "ghcr.io/jeffvli/feishin:0.19.0";
autoStart = true; autoStart = true;
ports = [ ports = [
"${feishinPort}:9180/tcp" # Web player (HTTP) "${feishinPort}:9180/tcp" # Web player (HTTP)

View file

@ -1,6 +1,7 @@
{ {
imports = [ imports = [
./apps ./apps
./fileSystems
./services ./services
./virtualisation ./virtualisation

View file

@ -44,6 +44,6 @@ in {
]; ];
}; };
}; };
}; };
} }