Add nginx,traefik,caddy,docker,podman

This commit is contained in:
Alexander Derevianko
2025-07-26 22:53:41 +02:00
parent 945b8ade7a
commit 5a3ef4684b
14 changed files with 494 additions and 23 deletions
+8
View File
@@ -0,0 +1,8 @@
{ config, lib, pkgs, ... }:
{
imports = [
./reverse-proxy
./virtualisation
];
}
+62
View File
@@ -0,0 +1,62 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.dov.reverse-proxy.caddy;
caddyWithDuckDNS = pkgs.caddy.withPlugins {
plugins = [
"github.com/caddy-dns/duckdns@v0.5.0"
];
# Replace with the hash NixOS provides on the first build attempt.
hash = "sha256-83ETc9K4T13Ws8gVOYwLarhuCA48Drs/i3rVLBMHyrc=";
};
email = "susano@local.com";
in {
options.dov.reverse-proxy.caddy = { enable = mkEnableOption "caddy config"; };
config = mkIf cfg.enable {
sops.secrets.duckdns-token = {
owner = config.services.caddy.user;
group = config.services.caddy.group;
};
services.caddy = {
enable = cfg.enable;
package = caddyWithDuckDNS;
environmentFile = config.sops.secrets.duckdns-token.path;
# Add a global options block.
# Let's Encrypt will use this email to send you important notices.
globalConfig = ''
email ${email}
'';
virtualHosts."test.susano-lab.duckdns.org" = {
extraConfig = ''
# Reverse proxy to your Immich instance.
reverse_proxy http://192.168.1.57:2283 {
# Send correct headers to the backend service.
header_up Host {host}
header_up X-Real-IP {remote_ip}
header_up X-Forwarded-For {remote_ip}
header_up X-Forwarded-Proto {scheme}
# Recommended for large file uploads in Immich.
transport http {
read_buffer 1m
}
}
# Configure automatic HTTPS with the DuckDNS provider.
tls {
dns duckdns {env.DUCKDNS_TOKEN}
propagation_timeout -1
}
'';
};
};
};
}
+9
View File
@@ -0,0 +1,9 @@
{ config, lib, pkgs, ... }:
{
imports = [
./nginx
./traefik
./caddy
];
}
+150
View File
@@ -0,0 +1,150 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.dov.reverse-proxy.nginx;
email = "susano@local.com";
# configFile = pkgs.writeText "duckdns_config"
# ''
# example config file bla bla
# '';
in {
options.dov.reverse-proxy.nginx = { enable = mkEnableOption "nginx config"; };
config = mkIf cfg.enable {
sops.secrets.duckdns-token = {
owner = config.services.nginx.user;
group = config.services.nginx.group;
};
# 1. Enable Nginx
# 2. Enable Automatic Certificate Management (ACME)
# NixOS uses acme.sh to handle Let's Encrypt certificates.
security.acme = {
acceptTerms = true;
defaults.email = email;
# Define the certificates you want to obtain.
# We use the DNS-01 challenge for wildcard domains.
certs = {
# Certificate for *.susano-lab.duckdns.org
"susano-lab.duckdns.org" = {
domain = "*.susano-lab.duckdns.org";
extraDomainNames = [ "susano-lab.duckdns.org" ];
dnsProvider = "duckdns";
# The credentialsFile points to the secret file we created.
credentialsFile = config.sops.secrets.duckdns-token.path;
group = config.services.nginx.group;
};
# Certificate for *.susano-tailscale.duckdns.org
"susano-tailscale.duckdns.org" = {
domain = "*.susano-tailscale.duckdns.org";
extraDomainNames = [ "susano-tailscale.duckdns.org" ];
dnsProvider = "duckdns";
credentialsFile = config.sops.secrets.duckdns-token.path;
group = config.services.nginx.group;
};
};
};
# 3. Define Nginx Reverse Proxy Configuration
services.nginx = {
enable = cfg.enable;
# Use httpConfig to define 'map' blocks at the correct level.
httpConfig = ''
# Map for susano-lab.duckdns.org domains
map $host $lab_proxy_pass {
"immich.susano-lab.duckdns.org" "http://192.168.1.57:2283";
"jellyfin.susano-lab.duckdns.org" "http://192.168.1.64:8096";
"jellyseer.susano-lab.duckdns.org" "http://192.168.1.68:5055";
"nginx.susano-lab.duckdns.org" "http://192.168.1.57:81";
"portainer.susano-lab.duckdns.org" "https://192.168.1.57:9443";
"qbittorrent.susano-lab.duckdns.org" "http://192.168.1.57:8080";
"radarr.susano-lab.duckdns.org" "http://192.168.1.57:7878";
"searxng.susano-lab.duckdns.org" "http://192.168.1.82:8080";
"sonarr.susano-lab.duckdns.org" "http://192.168.1.57:8989";
"susano-lab.duckdns.org" "http://192.168.1.53:8006";
default "http://127.0.0.1:8000"; # Optional: a default to avoid errors if no host matches
}
# Map for susano-tailscale.duckdns.org domains
map $host $tailscale_proxy_pass {
"immich.susano-tailscale.duckdns.org" "http://192.168.1.57:2283";
"searxng.susano-tailscale.duckdns.org" "http://192.168.1.82:8080";
default "http://127.0.0.1:8000"; # Optional: a default
}
# Map for susano-traefik.duckdns.org domains
map $host $traefik_proxy_pass {
"immich.susano-traefik.duckdns.org" "http://192.168.1.57:2283";
default "http://127.0.0.1:8000"; # Optional: a default
}
'';
virtualHosts = {
# === Group for susano-lab.duckdns.org subdomains ===
"susano-lab" = {
serverName = "susano-lab.duckdns.org";
serverAliases = [
"test.susano-lab.duckdns.org"
"immich.susano-lab.duckdns.org"
"jellyfin.susano-lab.duckdns.org"
"jellyseer.susano-lab.duckdns.org"
"nginx.susano-lab.duckdns.org"
"portainer.susano-lab.duckdns.org"
"qbittorrent.susano-lab.duckdns.org"
"radarr.susano-lab.duckdns.org"
"searxng.susano-lab.duckdns.org"
"sonarr.susano-lab.duckdns.org"
];
useACMEHost = "susano-lab.duckdns.org";
forceSSL = true;
locations."/".extraConfig = ''
# The map block is removed from here.
# We now use the variable defined in httpConfig.
proxy_pass $lab_proxy_pass;
# Standard proxy headers for websockets and correct IP forwarding.
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
'';
};
# === Group for susano-tailscale.duckdns.org subdomains ===
"susano-tailscale" = {
serverName = "susano-tailscale.duckdns.org";
serverAliases = [
"immich.susano-tailscale.duckdns.org"
"searxng.susano-tailscale.duckdns.org"
];
useACMEHost = "susano-tailscale.duckdns.org";
forceSSL = true;
locations."/".extraConfig = ''
# Use the second variable defined in httpConfig.
proxy_pass $tailscale_proxy_pass;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
'';
};
};
};
};
}
+114
View File
@@ -0,0 +1,114 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.dov.reverse-proxy.traefik;
in {
options.dov.reverse-proxy.traefik = { enable = mkEnableOption "traefik config"; };
config = mkIf cfg.enable {
# 1. SOPS Configuration for the DuckDNS Token
# This decrypts the secret and provides it to the Traefik service.
sops.secrets.duckdns-token = {
# The Traefik service needs permission to read this file.
owner = "traefik";
group = config.services.traefik.group;
};
# 3. Traefik Service Configuration
services.traefik = {
enable = true;
# Load the DuckDNS token as an environment variable for Traefik.
environmentFiles = [ config.sops.secrets.duckdns-token.path ];
# Static configuration (traefik.yml) - defines entrypoints and certificate resolvers.
staticConfigOptions = {
# -- EntryPoints: Where Traefik listens for traffic --
entryPoints = {
# Unsecured HTTP on port 80, mainly for redirection
web = {
address = ":80";
# Redirect all traffic from this entrypoint to the 'websecure' (HTTPS) entrypoint
http.redirections.entryPoint = {
to = "websecure";
scheme = "https";
permanent = true;
};
};
# Secured HTTPS on port 443
websecure = {
address = ":443";
};
};
# -- Certificate Resolver: How Traefik gets SSL certs --
certificatesResolvers = {
# We'll name our resolver 'duckdns'
duckdns = {
acme = {
email = "susano@local.com";
storage = "/var/lib/traefik/acme.json"; # Where Traefik stores certs
# Use the DNS-01 challenge with the DuckDNS provider
dnsChallenge = {
provider = "duckdns";
# Traefik will get the DUCKDNS_TOKEN from the environment file.
resolvers = [
"1.1.1.1:53"
"8.8.8.8:53"
];
};
};
};
};
# Optional but recommended: Enable the Traefik Dashboard
api.dashboard = true;
};
# Dynamic configuration - defines the actual routers and services.
dynamicConfigOptions = {
http = {
routers = {
# --- Router for the Traefik dashboard (optional) ---
dashboard-router = {
rule = "Host(`traefik.local.susano-traefik.duckdns.org`)"; # Example: A local-only subdomain
entryPoints = [ "websecure" ];
service = "api@internal"; # Special service for the dashboard
tls.certResolver = "duckdns";
};
immich-router = {
rule = "Host(`immich.susano-traefik.duckdns.org`)"; # 1. The new domain
entryPoints = [ "websecure" ]; # 2. Listen on HTTPS
service = "immich-service"; # 3. Link to the new Immich service
tls.certResolver = "duckdns"; # 4. Use the same SSL resolver
};
};
services = {
immich-service = {
loadBalancer.servers = [
# The backend URL for Immich
{ url = "http://192.168.1.57:2283"; }
];
};
};
middlewares = {
# --- Middleware for dashboard authentication (optional) ---
auth = {
# Run `nix-shell -p apacheHttpdTools --run "htpasswd -nb your-user your-password"`
# to generate the user:password hash.
basicAuth.users = [
"your-user:$apr1$....some-hash-here...."
];
};
};
};
};
};
};
}
+8
View File
@@ -0,0 +1,8 @@
{ config, lib, pkgs, ... }:
{
imports = [
./podman
./docker
];
}
+26
View File
@@ -0,0 +1,26 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.dov.virtualisation.docker;
username = "susano";
in {
options.dov.virtualisation.docker = { enable = mkEnableOption "docker config"; };
config = mkIf cfg.enable {
users.extraGroups.docker.members = [ username ];
virtualisation.docker = {
enable = true;
rootless = {
enable = true;
setSocketVariable = true;
};
# TODO use if disko is btrfs
storageDriver = "btrfs";
};
};
}
+34
View File
@@ -0,0 +1,34 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.dov.virtualisation.podman;
in {
options.dov.virtualisation.podman = { enable = mkEnableOption "podman config"; };
config = mkIf cfg.enable {
# Enable common container config files in /etc/containers
virtualisation.containers.enable = true;
virtualisation = {
podman = {
enable = true;
# Create a `docker` alias for podman, to use it as a drop-in replacement
dockerCompat = true;
# Required for containers under podman-compose to be able to talk to each other.
defaultNetwork.settings.dns_enabled = true;
};
};
# Useful other development tools
environment.systemPackages = with pkgs; [
dive # look into docker image layers
podman-tui # status of containers in the terminal
#docker-compose # start group of containers for dev
podman-compose # start group of containers for dev
];
};
}