first commit
This commit is contained in:
136
hosts/AZ-CLD-1/configuration.nix
Normal file
136
hosts/AZ-CLD-1/configuration.nix
Normal file
@@ -0,0 +1,136 @@
|
||||
# Edit this configuration file to define what should be installed on
|
||||
# your system. Help is available in the configuration.nix(5) man page, on
|
||||
# https://search.nixos.org/options and in the NixOS manual (`nixos-help`).
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
imports = [
|
||||
# Include the results of the hardware scan.
|
||||
./hardware-configuration.nix
|
||||
./disko-config.nix
|
||||
];
|
||||
|
||||
boot.loader.grub = {
|
||||
efiSupport = true;
|
||||
efiInstallAsRemovable = true;
|
||||
};
|
||||
|
||||
swapDevices = [
|
||||
{
|
||||
device = "/var/lib/swapfile";
|
||||
size = 16 * 1024;
|
||||
}
|
||||
];
|
||||
|
||||
networking.hostName = "AZ-CLD-1"; # Define your hostname.
|
||||
# Pick only one of the below networking options.
|
||||
# networking.wireless.enable = true; # Enables wireless support via wpa_supplicant.
|
||||
networking.networkmanager.enable = true; # Easiest to use and most distros use this by default.
|
||||
|
||||
# Set your time zone.
|
||||
time.timeZone = "Europe/Berlin";
|
||||
|
||||
# Configure network proxy if necessary
|
||||
# networking.proxy.default = "http://user:password@proxy:port/";
|
||||
# networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain";
|
||||
|
||||
# Select internationalisation properties.
|
||||
i18n.defaultLocale = "de_DE.UTF-8";
|
||||
# console = {
|
||||
# font = "Lat2-Terminus16";
|
||||
# keyMap = "us";
|
||||
# useXkbConfig = true; # use xkb.options in tty.
|
||||
# };
|
||||
|
||||
# Enable the X11 windowing system.
|
||||
# services.xserver.enable = true;
|
||||
|
||||
# Configure keymap in X11
|
||||
# services.xserver.xkb.layout = "us";
|
||||
# services.xserver.xkb.options = "eurosign:e,caps:escape";
|
||||
|
||||
# Enable CUPS to print documents.
|
||||
# services.printing.enable = true;
|
||||
|
||||
# Enable sound.
|
||||
# services.pulseaudio.enable = true;
|
||||
# OR
|
||||
# services.pipewire = {
|
||||
# enable = true;
|
||||
# pulse.enable = true;
|
||||
# };
|
||||
|
||||
# Enable touchpad support (enabled default in most desktopManager).
|
||||
# services.libinput.enable = true;
|
||||
|
||||
# Define a user account. Don't forget to set a password with ‘passwd’.
|
||||
# users.users.alice = {
|
||||
# isNormalUser = true;
|
||||
# extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user.
|
||||
# packages = with pkgs; [
|
||||
# tree
|
||||
# ];
|
||||
# };
|
||||
|
||||
# programs.firefox.enable = true;
|
||||
|
||||
# List packages installed in system profile.
|
||||
# You can use https://search.nixos.org/ to find more packages (and options).
|
||||
environment.systemPackages = with pkgs; [
|
||||
neovim # Do not forget to add an editor to edit configuration.nix! The Nano editor is also installed by default.
|
||||
git
|
||||
];
|
||||
|
||||
# Some programs need SUID wrappers, can be configured further or are
|
||||
# started in user sessions.
|
||||
# programs.mtr.enable = true;
|
||||
programs.gnupg.agent = {
|
||||
enable = true;
|
||||
enableSSHSupport = true;
|
||||
};
|
||||
|
||||
# List services that you want to enable:
|
||||
|
||||
# Enable the OpenSSH daemon.
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
ports = [2022];
|
||||
settings = {
|
||||
PermitRootLogin = "no";
|
||||
PasswordAuthentication = false;
|
||||
};
|
||||
};
|
||||
|
||||
# Open ports in the firewall.
|
||||
networking.firewall.allowedTCPPorts = [587];
|
||||
# networking.firewall.allowedUDPPorts = [ ... ];
|
||||
# Or disable the firewall altogether.
|
||||
# networking.firewall.enable = false;
|
||||
|
||||
# Copy the NixOS configuration file and link it from the resulting system
|
||||
# (/run/current-system/configuration.nix). This is useful in case you
|
||||
# accidentally delete configuration.nix.
|
||||
# system.copySystemConfiguration = true;
|
||||
|
||||
# This option defines the first version of NixOS you have installed on this particular machine,
|
||||
# and is used to maintain compatibility with application data (e.g. databases) created on older NixOS versions.
|
||||
#
|
||||
# Most users should NEVER change this value after the initial install, for any reason,
|
||||
# even if you've upgraded your system to a new NixOS release.
|
||||
#
|
||||
# This value does NOT affect the Nixpkgs version your packages and OS are pulled from,
|
||||
# so changing it will NOT upgrade your system - see https://nixos.org/manual/nixos/stable/#sec-upgrading for how
|
||||
# to actually do that.
|
||||
#
|
||||
# This value being lower than the current NixOS release does NOT mean your system is
|
||||
# out of date, out of support, or vulnerable.
|
||||
#
|
||||
# Do NOT change this value unless you have manually inspected all the changes it would make to your configuration,
|
||||
# and migrated your data accordingly.
|
||||
#
|
||||
# For more information, see `man configuration.nix` or https://nixos.org/manual/nixos/stable/options#opt-system.stateVersion .
|
||||
system.stateVersion = "25.05"; # Did you read the comment?
|
||||
}
|
||||
12
hosts/AZ-CLD-1/default.nix
Normal file
12
hosts/AZ-CLD-1/default.nix
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
imports = [
|
||||
../common
|
||||
./configuration.nix
|
||||
./secrets.nix
|
||||
./services
|
||||
];
|
||||
|
||||
extraServices = {
|
||||
podman.enable = true;
|
||||
};
|
||||
}
|
||||
39
hosts/AZ-CLD-1/disko-config.nix
Normal file
39
hosts/AZ-CLD-1/disko-config.nix
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
main = {
|
||||
type = "disk";
|
||||
device = "/dev/vda"; # CHANGE ME
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
boot = {
|
||||
size = "1M";
|
||||
type = "EF02"; # for GRUB MBR
|
||||
priority = 1;
|
||||
};
|
||||
esp = {
|
||||
size = "512M";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = ["defaults" "umask=0077"];
|
||||
};
|
||||
};
|
||||
root = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
mountOptions = ["noatime" "nodiratime" "discard"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
28
hosts/AZ-CLD-1/hardware-configuration.nix
Normal file
28
hosts/AZ-CLD-1/hardware-configuration.nix
Normal file
@@ -0,0 +1,28 @@
|
||||
# Do not modify this file! It was generated by ‘nixos-generate-config’
|
||||
# and may be overwritten by future invocations. Please make changes
|
||||
# to /etc/nixos/configuration.nix instead.
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
modulesPath,
|
||||
...
|
||||
}: {
|
||||
imports = [
|
||||
(modulesPath + "/profiles/qemu-guest.nix")
|
||||
];
|
||||
|
||||
boot.initrd.availableKernelModules = ["ata_piix" "uhci_hcd" "virtio_pci" "virtio_scsi" "sd_mod" "sr_mod"];
|
||||
boot.initrd.kernelModules = [];
|
||||
boot.kernelModules = [];
|
||||
boot.extraModulePackages = [];
|
||||
|
||||
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
|
||||
# (the default) this is the recommended approach. When using systemd-networkd it's
|
||||
# still possible to use this option, but it's recommended to use it in conjunction
|
||||
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
|
||||
networking.useDHCP = lib.mkDefault true;
|
||||
# networking.interfaces.ens18.useDHCP = lib.mkDefault true;
|
||||
|
||||
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||
}
|
||||
81
hosts/AZ-CLD-1/secrets.nix
Normal file
81
hosts/AZ-CLD-1/secrets.nix
Normal file
@@ -0,0 +1,81 @@
|
||||
{
|
||||
age = {
|
||||
secrets = {
|
||||
traefik-env = {
|
||||
file = ../../secrets/traefik-env.age;
|
||||
};
|
||||
baserow-env = {
|
||||
file = ../../secrets/baserow-env.age;
|
||||
};
|
||||
librechat = {
|
||||
file = ../../secrets/librechat.age;
|
||||
};
|
||||
librechat-env = {
|
||||
file = ../../secrets/librechat-env.age;
|
||||
};
|
||||
librechat-env-dev = {
|
||||
file = ../../secrets/librechat-env-dev.age;
|
||||
};
|
||||
librechat-env-prod = {
|
||||
file = ../../secrets/librechat-env-prod.age;
|
||||
};
|
||||
litellm-env = {
|
||||
file = ../../secrets/litellm-env.age;
|
||||
};
|
||||
metabase-env = {
|
||||
file = ../../secrets/metabase-env.age;
|
||||
};
|
||||
n8n-env = {
|
||||
file = ../../secrets/n8n-env.age;
|
||||
};
|
||||
netbird-auth-secret = {
|
||||
file = ../../secrets/netbird-auth-secret.age;
|
||||
};
|
||||
netbird-db-password = {
|
||||
file = ../../secrets/netbird-db-password.age;
|
||||
};
|
||||
netbird-encryption-key = {
|
||||
file = ../../secrets/netbird-encryption-key.age;
|
||||
};
|
||||
netbird-dashboard-env = {
|
||||
file = ../../secrets/netbird-dashboard-env.age;
|
||||
};
|
||||
netbird-server-env = {
|
||||
file = ../../secrets/netbird-server-env.age;
|
||||
};
|
||||
netbird-proxy-env = {
|
||||
file = ../../secrets/netbird-proxy-env.age;
|
||||
};
|
||||
outline-env = {
|
||||
file = ../../secrets/outline-env.age;
|
||||
owner = "outline";
|
||||
};
|
||||
pgadmin-pw = {
|
||||
file = ../../secrets/pgadmin-pw.age;
|
||||
owner = "pgadmin";
|
||||
};
|
||||
vaultwarden-env = {
|
||||
file = ../../secrets/vaultwarden-env.age;
|
||||
};
|
||||
hetzner-s3-az-intern-secret-key = {
|
||||
file = ../../secrets/hetzner-s3-az-intern-secret-key.age;
|
||||
owner = "outline";
|
||||
};
|
||||
hetzner-s3-az-intern-access-key = {
|
||||
file = ../../secrets/hetzner-s3-az-intern-access-key.age;
|
||||
};
|
||||
zammad-pw = {
|
||||
file = ../../secrets/zammad-pw.age;
|
||||
};
|
||||
zammad-secret = {
|
||||
file = ../../secrets/zammad-secret.age;
|
||||
};
|
||||
zammad-hr-env-prod = {
|
||||
file = ../../secrets/zammad-hr-env-prod.age;
|
||||
};
|
||||
zammad-hr-env = {
|
||||
file = ../../secrets/zammad-hr-env.age;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
70
hosts/AZ-CLD-1/services/containers/baserow.nix
Normal file
70
hosts/AZ-CLD-1/services/containers/baserow.nix
Normal file
@@ -0,0 +1,70 @@
|
||||
{config, ...}: let
|
||||
serviceName = "baserow";
|
||||
servicePort = config.m3ta.ports.get serviceName;
|
||||
in {
|
||||
virtualisation.oci-containers.containers.${serviceName} = {
|
||||
image = "docker.io/baserow/baserow:2.1.6";
|
||||
environment = {
|
||||
BASEROW_AMOUNT_OF_GUNICORN_WORKERS = "4";
|
||||
BASEROW_AMOUNT_OF_WORKERS = "2";
|
||||
DATABASE_CONN_MAX_AGE = "60";
|
||||
# Proxy: tell Django the connection is HTTPS so cookies get Secure flag
|
||||
BASEROW_ENABLE_SECURE_PROXY_SSL_HEADER = "yes";
|
||||
# Published apps run on different origins — allow cross-origin cookie delivery
|
||||
BASEROW_FRONTEND_SAME_SITE_COOKIE = "none";
|
||||
# Valid base domain for published app subdomains
|
||||
BASEROW_BUILDER_DOMAINS = "az-gruppe.com";
|
||||
# Disable Caddy's on_demand TLS — Traefik handles TLS termination
|
||||
BASEROW_CADDY_GLOBAL_CONF = "auto_https off";
|
||||
};
|
||||
environmentFiles = [config.age.secrets.baserow-env.path];
|
||||
ports = ["127.0.0.1:${toString servicePort}:80"];
|
||||
volumes = ["baserow_data:/baserow/data"];
|
||||
extraOptions = ["--add-host=postgres:10.89.0.1" "--ip=10.89.0.10" "--network=web"];
|
||||
};
|
||||
|
||||
# Traefik configuration
|
||||
services.traefik.dynamicConfigOptions.http = {
|
||||
services.${serviceName}.loadBalancer.servers = [
|
||||
{
|
||||
url = "http://localhost:${toString servicePort}/";
|
||||
}
|
||||
];
|
||||
|
||||
middlewares."${serviceName}-headers".headers = {
|
||||
customRequestHeaders = {
|
||||
X-Forwarded-Proto = "https";
|
||||
X-Forwarded-Port = "443";
|
||||
};
|
||||
};
|
||||
|
||||
routers.${serviceName} = {
|
||||
rule = "Host(`br.az-gruppe.com`)";
|
||||
tls = {
|
||||
certResolver = "ionos";
|
||||
};
|
||||
service = serviceName;
|
||||
entrypoints = "websecure";
|
||||
middlewares = ["${serviceName}-headers"];
|
||||
};
|
||||
|
||||
routers.azubi = {
|
||||
rule = "Host(`azubi.az-gruppe.com`)";
|
||||
tls = {
|
||||
certResolver = "ionos";
|
||||
};
|
||||
service = serviceName;
|
||||
entrypoints = "websecure";
|
||||
middlewares = ["${serviceName}-headers"];
|
||||
};
|
||||
routers.ausbilder = {
|
||||
rule = "Host(`ausbilder.az-gruppe.com`)";
|
||||
tls = {
|
||||
certResolver = "ionos";
|
||||
};
|
||||
service = serviceName;
|
||||
entrypoints = "websecure";
|
||||
middlewares = ["${serviceName}-headers"];
|
||||
};
|
||||
};
|
||||
}
|
||||
20
hosts/AZ-CLD-1/services/containers/default.nix
Normal file
20
hosts/AZ-CLD-1/services/containers/default.nix
Normal file
@@ -0,0 +1,20 @@
|
||||
{lib, ...}: {
|
||||
imports = [
|
||||
./baserow.nix
|
||||
./it-tools.nix
|
||||
./librechat.nix
|
||||
./litellm.nix
|
||||
./librechat-dev.nix
|
||||
./netbird.nix
|
||||
./portainer.nix
|
||||
./zammad-hr.nix
|
||||
];
|
||||
system.activationScripts.createPodmanNetworkWeb = lib.mkAfter ''
|
||||
if ! /run/current-system/sw/bin/podman network exists web; then
|
||||
/run/current-system/sw/bin/podman network create web --subnet=10.89.0.0/24 --internal
|
||||
fi
|
||||
if ! /run/current-system/sw/bin/podman network exists web-dev; then
|
||||
/run/current-system/sw/bin/podman network create web-dev --subnet=10.89.1.0/24 --internal
|
||||
fi
|
||||
'';
|
||||
}
|
||||
27
hosts/AZ-CLD-1/services/containers/it-tools.nix
Normal file
27
hosts/AZ-CLD-1/services/containers/it-tools.nix
Normal file
@@ -0,0 +1,27 @@
|
||||
{config, ...}: let
|
||||
serviceName = "it-tools";
|
||||
servicePort = config.m3ta.ports.get serviceName;
|
||||
in {
|
||||
virtualisation.oci-containers.containers.${serviceName} = {
|
||||
image = "docker.io/sharevb/it-tools:latest";
|
||||
ports = ["127.0.0.1:${toString servicePort}:8080"];
|
||||
};
|
||||
|
||||
# Traefik configuration
|
||||
services.traefik.dynamicConfigOptions.http = {
|
||||
services.${serviceName}.loadBalancer.servers = [
|
||||
{
|
||||
url = "http://localhost:${toString servicePort}/";
|
||||
}
|
||||
];
|
||||
|
||||
routers.${serviceName} = {
|
||||
rule = "Host(`tools.az-gruppe.com`)";
|
||||
tls = {
|
||||
certResolver = "ionos";
|
||||
};
|
||||
service = serviceName;
|
||||
entrypoints = "websecure";
|
||||
};
|
||||
};
|
||||
}
|
||||
133
hosts/AZ-CLD-1/services/containers/librechat-dev.nix
Normal file
133
hosts/AZ-CLD-1/services/containers/librechat-dev.nix
Normal file
@@ -0,0 +1,133 @@
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
serviceName = "librechat-dev";
|
||||
servicePort = config.m3ta.ports.get serviceName;
|
||||
ragApiDevServiceName = "rag-api-dev";
|
||||
ragApiDevPort = config.m3ta.ports.get ragApiDevServiceName;
|
||||
envFileDev = config.age.secrets.librechat-env-dev.path;
|
||||
envFileCommon = config.age.secrets.librechat.path;
|
||||
in {
|
||||
virtualisation.oci-containers = {
|
||||
containers.meilisearch-dev = {
|
||||
image = "getmeili/meilisearch:v1.12.3";
|
||||
autoStart = false;
|
||||
volumes = ["librechat_dev_meili:/meili_data"];
|
||||
environment = {
|
||||
MEILI_HTTP_ADDR = "0.0.0.0:7700";
|
||||
MEILI_NO_ANALYTICS = "true";
|
||||
};
|
||||
environmentFiles = [envFileDev envFileCommon];
|
||||
extraOptions = ["--ip=10.89.1.20" "--network=web-dev"];
|
||||
};
|
||||
|
||||
containers.rag_api-dev = {
|
||||
image = "ghcr.io/danny-avila/librechat-rag-api-dev-lite:latest";
|
||||
autoStart = false;
|
||||
environment = {
|
||||
RAG_PORT = "8000";
|
||||
DB_HOST = "10.89.1.1";
|
||||
DB_PORT = "5432";
|
||||
};
|
||||
environmentFiles = [envFileDev envFileCommon];
|
||||
dependsOn = ["meilisearch-dev"];
|
||||
extraOptions = ["--add-host=postgres:10.89.1.1" "--ip=10.89.1.21" "--network=web-dev"];
|
||||
ports = ["127.0.0.1:${toString ragApiDevPort}:8000"];
|
||||
};
|
||||
|
||||
containers.mongodb-dev = {
|
||||
image = "mongo:7";
|
||||
autoStart = false;
|
||||
volumes = [
|
||||
"librechat_dev_mongo:/data/db"
|
||||
"/var/backup/mongodb-dev:/data/backups"
|
||||
];
|
||||
extraOptions = ["--ip=10.89.1.22" "--network=web-dev"];
|
||||
};
|
||||
|
||||
containers.${serviceName} = {
|
||||
image = "ghcr.io/danny-avila/librechat-dev-api:latest";
|
||||
autoStart = false;
|
||||
ports = ["127.0.0.1:${toString servicePort}:3080"];
|
||||
dependsOn = ["mongodb-dev" "rag_api-dev" "meilisearch-dev"];
|
||||
environment = {
|
||||
HOST = "0.0.0.0";
|
||||
NODE_ENV = "development";
|
||||
MONGO_URI = "mongodb://mongodb-dev:27017/LibreChatDev";
|
||||
MEILI_HOST = "http://meilisearch-dev:7700";
|
||||
RAG_PORT = "8000";
|
||||
RAG_API_URL = "http://rag_api-dev:8000";
|
||||
};
|
||||
environmentFiles = [envFileDev envFileCommon];
|
||||
volumes = [
|
||||
"/var/lib/librechat-dev/librechat.yaml:/app/librechat.yaml:ro"
|
||||
"librechat_dev_images:/app/client/public/images"
|
||||
"librechat_dev_uploads:/app/uploads"
|
||||
"librechat_dev_logs:/app/api/logs"
|
||||
];
|
||||
extraOptions = ["--ip=10.89.1.23" "--network=web-dev"];
|
||||
};
|
||||
};
|
||||
|
||||
# Traefik configuration
|
||||
services.traefik.dynamicConfigOptions.http = {
|
||||
services.${serviceName}.loadBalancer.servers = [
|
||||
{
|
||||
url = "http://localhost:${toString servicePort}/";
|
||||
}
|
||||
];
|
||||
|
||||
routers.${serviceName} = {
|
||||
rule = "Host(`chat-dev.az-gruppe.com`)";
|
||||
tls = {
|
||||
certResolver = "ionos";
|
||||
};
|
||||
service = serviceName;
|
||||
entrypoints = "websecure";
|
||||
};
|
||||
};
|
||||
|
||||
environment.systemPackages = [
|
||||
(pkgs.writeShellScriptBin "librechat-dev" ''
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
SERVICES=(
|
||||
podman-meilisearch-dev
|
||||
podman-mongodb-dev
|
||||
podman-rag_api-dev
|
||||
podman-librechat-dev
|
||||
)
|
||||
|
||||
case "$1" in
|
||||
up)
|
||||
echo "🚀 Starte LibreChat-Dev-Umgebung..."
|
||||
for svc in "''${SERVICES[@]}"; do
|
||||
sudo systemctl start "$svc"
|
||||
done
|
||||
;;
|
||||
down)
|
||||
echo "🛑 Stoppe LibreChat-Dev-Umgebung..."
|
||||
for svc in "''${SERVICES[@]}"; do
|
||||
sudo systemctl stop "$svc"
|
||||
done
|
||||
;;
|
||||
restart)
|
||||
echo "🔄 Neustart der LibreChat-Dev-Umgebung..."
|
||||
for svc in "''${SERVICES[@]}"; do
|
||||
sudo systemctl restart "$svc"
|
||||
done
|
||||
;;
|
||||
status)
|
||||
systemctl status "''${SERVICES[@]}"
|
||||
;;
|
||||
*)
|
||||
echo "Usage: librechat-dev {up|down|restart|status}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
'')
|
||||
];
|
||||
}
|
||||
169
hosts/AZ-CLD-1/services/containers/librechat.nix
Normal file
169
hosts/AZ-CLD-1/services/containers/librechat.nix
Normal file
@@ -0,0 +1,169 @@
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
serviceName = "librechat";
|
||||
servicePort = config.m3ta.ports.get serviceName;
|
||||
ragApiServiceName = "rag-api";
|
||||
ragApiPort = config.m3ta.ports.get ragApiServiceName;
|
||||
envFileProd = config.age.secrets.librechat-env-prod.path;
|
||||
envFileCommon = config.age.secrets.librechat.path;
|
||||
in {
|
||||
virtualisation.oci-containers = {
|
||||
containers.meilisearch = {
|
||||
image = "getmeili/meilisearch:v1.35.1";
|
||||
autoStart = true;
|
||||
volumes = ["librechat_meili:/meili_data"];
|
||||
environment = {
|
||||
MEILI_HTTP_ADDR = "0.0.0.0:7700";
|
||||
MEILI_NO_ANALYTICS = "true";
|
||||
};
|
||||
environmentFiles = [envFileCommon envFileProd];
|
||||
extraOptions = ["--ip=10.89.0.20" "--network=web"];
|
||||
};
|
||||
|
||||
containers.rag_api = {
|
||||
image = "registry.librechat.ai/danny-avila/librechat-rag-api-dev-lite:latest";
|
||||
autoStart = true;
|
||||
environment = {
|
||||
RAG_PORT = "8000";
|
||||
DB_HOST = "10.89.0.1";
|
||||
DB_PORT = "5432";
|
||||
};
|
||||
environmentFiles = [envFileCommon envFileProd];
|
||||
dependsOn = ["meilisearch"];
|
||||
extraOptions = ["--add-host=postgres:10.89.0.1" "--ip=10.89.0.21" "--network=web"];
|
||||
ports = ["127.0.0.1:${toString ragApiPort}:8000"];
|
||||
};
|
||||
|
||||
containers.mongodb = {
|
||||
image = "mongo:8.0.17";
|
||||
autoStart = true;
|
||||
volumes = [
|
||||
"librechat_mongo:/data/db"
|
||||
"/var/backup/mongodb:/data/backups"
|
||||
];
|
||||
# Enable auth once users exist; see Mongo auth doc.
|
||||
# command = [ "mongod", "--auth" ];
|
||||
extraOptions = ["--ip=10.89.0.22" "--network=web"];
|
||||
};
|
||||
|
||||
containers.${serviceName} = {
|
||||
image = "registry.librechat.ai/danny-avila/librechat-dev:latest";
|
||||
autoStart = true;
|
||||
user = "1000:1000";
|
||||
ports = ["127.0.0.1:${toString servicePort}:3080"];
|
||||
dependsOn = ["mongodb" "rag_api" "meilisearch"];
|
||||
environment = {
|
||||
HOST = "0.0.0.0";
|
||||
NODE_ENV = "production";
|
||||
# Mongo URI (start without auth; switch to mongodb://user:pass@mongodb:27017/LibreChat after Step 4)
|
||||
MONGO_URI = "mongodb://mongodb:27017/LibreChat";
|
||||
MEILI_HOST = "http://meilisearch:7700";
|
||||
RAG_PORT = "8000";
|
||||
RAG_API_URL = "http://rag_api:8000";
|
||||
};
|
||||
environmentFiles = [envFileCommon envFileProd];
|
||||
volumes = [
|
||||
# Config file still needs to be a bind mount for host management
|
||||
"/var/lib/librechat/librechat.yaml:/app/librechat.yaml:ro"
|
||||
# Use named volumes for application data
|
||||
"librechat_images:/app/client/public/images"
|
||||
"librechat_uploads:/app/uploads"
|
||||
"librechat_logs:/app/api/logs"
|
||||
];
|
||||
extraOptions = ["--ip=10.89.0.23" "--network=web" "--dns=8.8.8.8" "--dns=8.8.4.4"];
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services."mongo-backup" = {
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
User = "root";
|
||||
Group = "root";
|
||||
};
|
||||
script = ''
|
||||
set -euo pipefail
|
||||
|
||||
BACKUP_DIR="/var/backup/mongodb"
|
||||
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
||||
TEMP_BACKUP="mongodb_backup_$TIMESTAMP"
|
||||
ARCHIVE_NAME="mongodb_backup_$TIMESTAMP.tar.gz"
|
||||
|
||||
# Ensure backup directory exists with proper permissions
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
chown root:root "$BACKUP_DIR"
|
||||
chmod 750 "$BACKUP_DIR"
|
||||
|
||||
echo "Starting MongoDB backup at $(date)"
|
||||
|
||||
# Create the backup dump in container
|
||||
if ${pkgs.podman}/bin/podman exec mongodb mongodump --out "/data/backups/$TEMP_BACKUP"; then
|
||||
echo "MongoDB dump completed successfully"
|
||||
|
||||
# Create compressed archive from the backup
|
||||
cd "$BACKUP_DIR"
|
||||
if [ -d "$TEMP_BACKUP" ]; then
|
||||
echo "Creating compressed archive: $ARCHIVE_NAME"
|
||||
${pkgs.gnutar}/bin/tar --use-compress-program=${pkgs.gzip}/bin/gzip -cf "$ARCHIVE_NAME" -C . "$TEMP_BACKUP"
|
||||
|
||||
# Remove the uncompressed backup directory
|
||||
rm -rf "$TEMP_BACKUP"
|
||||
|
||||
# Verify archive was created
|
||||
if [ -f "$ARCHIVE_NAME" ]; then
|
||||
ARCHIVE_SIZE=$(${pkgs.coreutils}/bin/du -sh "$ARCHIVE_NAME" | cut -f1)
|
||||
echo "Compressed backup created: $ARCHIVE_NAME (Size: $ARCHIVE_SIZE)"
|
||||
|
||||
# Keep only the 2 most recent backup archives
|
||||
ls -1t mongodb_backup_*.tar.gz | tail -n +3 | xargs -r rm -f
|
||||
echo "Old backup archives cleaned up, keeping 2 most recent"
|
||||
|
||||
# List current backups
|
||||
echo "Current backups:"
|
||||
ls -lah mongodb_backup_*.tar.gz 2>/dev/null || echo "No previous backups found"
|
||||
else
|
||||
echo "ERROR: Failed to create compressed archive" >&2
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "ERROR: Backup directory not found at $BACKUP_DIR/$TEMP_BACKUP" >&2
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "ERROR: MongoDB backup failed" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "MongoDB backup completed successfully at $(date)"
|
||||
'';
|
||||
};
|
||||
|
||||
systemd.timers."mongo-backup" = {
|
||||
wantedBy = ["timers.target"];
|
||||
timerConfig = {
|
||||
OnCalendar = "*-*-* 02:00:00";
|
||||
RandomizedDelaySec = "30m";
|
||||
Persistent = true;
|
||||
};
|
||||
};
|
||||
|
||||
# Traefik configuration
|
||||
services.traefik.dynamicConfigOptions.http = {
|
||||
services.${serviceName}.loadBalancer.servers = [
|
||||
{
|
||||
url = "http://localhost:${toString servicePort}/";
|
||||
}
|
||||
];
|
||||
|
||||
routers.${serviceName} = {
|
||||
rule = "Host(`chat.az-gruppe.com`)";
|
||||
tls = {
|
||||
certResolver = "ionos";
|
||||
};
|
||||
service = serviceName;
|
||||
entrypoints = "websecure";
|
||||
};
|
||||
};
|
||||
}
|
||||
37
hosts/AZ-CLD-1/services/containers/litellm.nix
Normal file
37
hosts/AZ-CLD-1/services/containers/litellm.nix
Normal file
@@ -0,0 +1,37 @@
|
||||
{config, ...}: let
|
||||
serviceName = "litellm";
|
||||
servicePort = config.m3ta.ports.get serviceName;
|
||||
in {
|
||||
virtualisation.oci-containers.containers.${serviceName} = {
|
||||
#image = "ghcr.io/berriai/litellm:v1.78.5-stable";
|
||||
image = "docker.litellm.ai/berriai/litellm:v1.82.3-stable";
|
||||
ports = ["127.0.0.1:${toString servicePort}:4000"];
|
||||
environmentFiles = [config.age.secrets.litellm-env.path];
|
||||
environment = {
|
||||
ANONYMIZED_TELEMETRY = "False";
|
||||
DO_NOT_TRACK = "True";
|
||||
SCARF_NO_ANALYTICS = "True";
|
||||
STORE_MODEL_IN_DB = "True";
|
||||
};
|
||||
volumes = ["/var/lib/litellm/config.yaml:/app/config.yaml"];
|
||||
extraOptions = ["--add-host=postgres:10.89.0.1" "--ip=10.89.0.30" "--network=web"];
|
||||
};
|
||||
|
||||
# Traefik configuration
|
||||
services.traefik.dynamicConfigOptions.http = {
|
||||
services.${serviceName}.loadBalancer.servers = [
|
||||
{
|
||||
url = "http://localhost:${toString servicePort}/";
|
||||
}
|
||||
];
|
||||
|
||||
routers.${serviceName} = {
|
||||
rule = "Host(`llm.az-gruppe.com`)";
|
||||
tls = {
|
||||
certResolver = "ionos";
|
||||
};
|
||||
service = serviceName;
|
||||
entrypoints = "websecure";
|
||||
};
|
||||
};
|
||||
}
|
||||
243
hosts/AZ-CLD-1/services/containers/netbird.nix
Normal file
243
hosts/AZ-CLD-1/services/containers/netbird.nix
Normal file
@@ -0,0 +1,243 @@
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
serviceName = "netbird";
|
||||
|
||||
servicePort = config.m3ta.ports.get serviceName;
|
||||
|
||||
domain = "v.az-gruppe.com";
|
||||
proxyDomain = "p.az-gruppe.com";
|
||||
|
||||
ipBase = "10.89.0";
|
||||
ipOffset = 50;
|
||||
|
||||
# Derived IPs
|
||||
gatewayIp = "${ipBase}.1";
|
||||
dashboardIp = "${ipBase}.${toString ipOffset}";
|
||||
serverIp = "${ipBase}.${toString (ipOffset + 1)}";
|
||||
proxyIp = "${ipBase}.${toString (ipOffset + 2)}";
|
||||
|
||||
# Database configuration
|
||||
dbName = "netbird";
|
||||
dbUser = "netbird";
|
||||
dbHost = gatewayIp;
|
||||
|
||||
# NetBird config as Nix attribute set
|
||||
netbirdConfig = {
|
||||
server = {
|
||||
listenAddress = ":80";
|
||||
exposedAddress = "https://${domain}:443";
|
||||
stunPorts = [3478];
|
||||
metricsPort = 9090;
|
||||
healthcheckAddress = ":9000";
|
||||
logLevel = "info";
|
||||
logFile = "console";
|
||||
dataDir = "/var/lib/netbird";
|
||||
|
||||
auth = {
|
||||
issuer = "https://${domain}/oauth2";
|
||||
localAuthDisabled = true;
|
||||
signKeyRefreshEnabled = true;
|
||||
dashboardRedirectURIs = [
|
||||
"https://${domain}/nb-auth"
|
||||
"https://${domain}/nb-silent-auth"
|
||||
];
|
||||
cliRedirectURIs = ["http://localhost:53000/"];
|
||||
};
|
||||
|
||||
reverseProxy = {
|
||||
trustedHTTPProxies = ["${gatewayIp}/32"];
|
||||
};
|
||||
|
||||
# Proxy Feature
|
||||
proxy = {
|
||||
enabled = true;
|
||||
domain = proxyDomain;
|
||||
};
|
||||
|
||||
store = {
|
||||
engine = "postgres";
|
||||
postgres = {
|
||||
host = dbHost;
|
||||
port = 5432;
|
||||
database = dbName;
|
||||
username = dbUser;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Generate YAML config
|
||||
yamlFormat = pkgs.formats.yaml {};
|
||||
configYamlBase = yamlFormat.generate "netbird-config-base.yaml" netbirdConfig;
|
||||
|
||||
# Script to inject secrets at runtime
|
||||
configGenScript = pkgs.writeShellScript "netbird-gen-config" ''
|
||||
set -euo pipefail
|
||||
|
||||
AUTH_SECRET=$(cat "$1")
|
||||
DB_PASSWORD=$(cat "$2")
|
||||
ENCRYPTION_KEY=$(cat "$3")
|
||||
|
||||
${pkgs.yq-go}/bin/yq eval "
|
||||
.server.authSecret = \"$AUTH_SECRET\" |
|
||||
.server.store.encryptionKey = \"$ENCRYPTION_KEY\" |
|
||||
.server.store.postgres.password = \"$DB_PASSWORD\"
|
||||
" ${configYamlBase}
|
||||
'';
|
||||
in {
|
||||
age.secrets."${serviceName}-auth-secret".file = ../../../../secrets/${serviceName}-auth-secret.age;
|
||||
age.secrets."${serviceName}-db-password".file = ../../../../secrets/${serviceName}-db-password.age;
|
||||
age.secrets."${serviceName}-encryption-key".file = ../../../../secrets/${serviceName}-encryption-key.age;
|
||||
age.secrets."${serviceName}-dashboard-env".file = ../../../../secrets/${serviceName}-dashboard-env.age;
|
||||
age.secrets."${serviceName}-server-env".file = ../../../../secrets/${serviceName}-server-env.age;
|
||||
age.secrets."${serviceName}-proxy-env".file = ../../../../secrets/${serviceName}-proxy-env.age;
|
||||
|
||||
# Systemd oneshot service to generate config with secrets
|
||||
systemd.services."${serviceName}-config" = {
|
||||
description = "Generate NetBird config with secrets";
|
||||
wantedBy = ["multi-user.target"];
|
||||
before = ["podman-${serviceName}-server.service"];
|
||||
requiredBy = ["podman-${serviceName}-server.service"];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
ExecStart = pkgs.writeShellScript "netbird-write-config" ''
|
||||
mkdir -p /var/lib/${serviceName}
|
||||
${configGenScript} \
|
||||
${config.age.secrets."${serviceName}-auth-secret".path} \
|
||||
${config.age.secrets."${serviceName}-db-password".path} \
|
||||
${config.age.secrets."${serviceName}-encryption-key".path} \
|
||||
> /var/lib/${serviceName}/config.yaml
|
||||
chmod 600 /var/lib/${serviceName}/config.yaml
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
virtualisation.oci-containers.containers = {
|
||||
"${serviceName}-dashboard" = {
|
||||
image = "netbirdio/dashboard:latest";
|
||||
autoStart = true;
|
||||
ports = ["127.0.0.1:${toString servicePort}:80"];
|
||||
environmentFiles = [config.age.secrets."${serviceName}-dashboard-env".path];
|
||||
extraOptions = [
|
||||
"--ip=${dashboardIp}"
|
||||
"--network=web"
|
||||
];
|
||||
};
|
||||
|
||||
"${serviceName}-server" = {
|
||||
image = "netbirdio/netbird-server:latest";
|
||||
autoStart = true;
|
||||
ports = ["3478:3478/udp"];
|
||||
environmentFiles = [config.age.secrets."${serviceName}-server-env".path];
|
||||
volumes = [
|
||||
"${serviceName}_data:/var/lib/netbird"
|
||||
"/var/lib/${serviceName}/config.yaml:/etc/netbird/config.yaml:ro"
|
||||
];
|
||||
cmd = ["--config" "/etc/netbird/config.yaml"];
|
||||
extraOptions = [
|
||||
"--ip=${serverIp}"
|
||||
"--network=web"
|
||||
];
|
||||
};
|
||||
|
||||
"${serviceName}-proxy" = {
|
||||
image = "netbirdio/reverse-proxy:latest";
|
||||
autoStart = true;
|
||||
ports = ["51820:51820/udp"];
|
||||
volumes = [
|
||||
"${serviceName}_proxy_certs:/certs"
|
||||
];
|
||||
environmentFiles = [config.age.secrets."${serviceName}-proxy-env".path];
|
||||
cmd = [
|
||||
"--domain=${proxyDomain}"
|
||||
"--mgmt=https://${domain}:443"
|
||||
"--addr=:8443"
|
||||
"--cert-dir=/certs"
|
||||
"--acme-certs"
|
||||
"--trusted-proxies=${gatewayIp}/32"
|
||||
];
|
||||
dependsOn = ["${serviceName}-server"];
|
||||
extraOptions = [
|
||||
"--ip=${proxyIp}"
|
||||
"--network=web"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
services.traefik.dynamicConfigOptions = {
|
||||
# HTTP services and routers
|
||||
http = {
|
||||
services = {
|
||||
"${serviceName}-dashboard".loadBalancer.servers = [
|
||||
{url = "http://localhost:${toString servicePort}/";}
|
||||
];
|
||||
|
||||
"${serviceName}-server".loadBalancer.servers = [
|
||||
{url = "http://${serverIp}:80/";}
|
||||
];
|
||||
|
||||
"${serviceName}-server-h2c".loadBalancer.servers = [
|
||||
{url = "h2c://${serverIp}:80";}
|
||||
];
|
||||
};
|
||||
|
||||
routers = {
|
||||
# gRPC (Signal + Management)
|
||||
"${serviceName}-grpc" = {
|
||||
rule = "Host(`${domain}`) && (PathPrefix(`/signalexchange.SignalExchange/`) || PathPrefix(`/management.ManagementService/`) || PathPrefix(`/management.ProxyService/`))";
|
||||
entrypoints = "websecure";
|
||||
tls.certResolver = "ionos";
|
||||
service = "${serviceName}-server-h2c";
|
||||
priority = 100;
|
||||
};
|
||||
# Backend (relay, WebSocket, API, OAuth2)
|
||||
"${serviceName}-backend" = {
|
||||
rule = "Host(`${domain}`) && (PathPrefix(`/relay`) || PathPrefix(`/ws-proxy/`) || PathPrefix(`/api`) || PathPrefix(`/oauth2`))";
|
||||
entrypoints = "websecure";
|
||||
tls.certResolver = "ionos";
|
||||
service = "${serviceName}-server";
|
||||
priority = 100;
|
||||
};
|
||||
|
||||
# Dashboard (catch-all, lowest priority)
|
||||
"${serviceName}-dashboard" = {
|
||||
rule = "Host(`${domain}`)";
|
||||
entrypoints = "websecure";
|
||||
tls.certResolver = "ionos";
|
||||
service = "${serviceName}-dashboard";
|
||||
priority = 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# TCP for proxy TLS passthrough
|
||||
tcp = {
|
||||
services."${serviceName}-proxy-tls".loadBalancer.servers = [
|
||||
{address = "${proxyIp}:8443";}
|
||||
];
|
||||
|
||||
routers."${serviceName}-proxy-passthrough" = {
|
||||
entryPoints = ["websecure"];
|
||||
rule = "HostSNI(`*`)";
|
||||
service = "${serviceName}-proxy-tls";
|
||||
priority = 1;
|
||||
tls.passthrough = true;
|
||||
};
|
||||
};
|
||||
|
||||
# ServersTransport for proxy protocol v2 (optional)
|
||||
serversTransports."pp-v2" = {
|
||||
proxyProtocol.version = 2;
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall.allowedUDPPorts = [
|
||||
3478 # STUN
|
||||
51820 # WireGuard for proxy
|
||||
];
|
||||
}
|
||||
32
hosts/AZ-CLD-1/services/containers/portainer.nix
Normal file
32
hosts/AZ-CLD-1/services/containers/portainer.nix
Normal file
@@ -0,0 +1,32 @@
|
||||
{config, ...}: let
|
||||
serviceName = "portainer";
|
||||
servicePort = config.m3ta.ports.get serviceName;
|
||||
in {
|
||||
virtualisation.oci-containers.containers.${serviceName} = {
|
||||
image = "docker.io/portainer/portainer-ce:latest";
|
||||
ports = ["127.0.0.1:${toString servicePort}:9000"];
|
||||
volumes = [
|
||||
"/etc/localtime:/etc/localtime:ro"
|
||||
"/run/podman/podman.sock:/var/run/docker.sock:ro"
|
||||
"portainer_data:/data"
|
||||
];
|
||||
};
|
||||
|
||||
# Traefik configuration
|
||||
services.traefik.dynamicConfigOptions.http = {
|
||||
services.${serviceName}.loadBalancer.servers = [
|
||||
{
|
||||
url = "http://localhost:${toString servicePort}/";
|
||||
}
|
||||
];
|
||||
|
||||
routers.${serviceName} = {
|
||||
rule = "Host(`pt.az-gruppe.com`)";
|
||||
tls = {
|
||||
certResolver = "ionos";
|
||||
};
|
||||
service = serviceName;
|
||||
entrypoints = "websecure";
|
||||
};
|
||||
};
|
||||
}
|
||||
296
hosts/AZ-CLD-1/services/containers/zammad-hr.nix
Normal file
296
hosts/AZ-CLD-1/services/containers/zammad-hr.nix
Normal file
@@ -0,0 +1,296 @@
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
instanceName = "hr";
|
||||
serviceName = "zammad-${instanceName}";
|
||||
|
||||
servicePort = config.m3ta.ports.get serviceName;
|
||||
elasticsearchServiceName = "${serviceName}-elasticsearch";
|
||||
elasticsearchPort = config.m3ta.ports.get elasticsearchServiceName;
|
||||
|
||||
envFileProd = config.age.secrets."${serviceName}-env-prod".path;
|
||||
envFileCommon = config.age.secrets."${serviceName}-env".path;
|
||||
|
||||
zammadVersion = "6.5.2-22";
|
||||
zammadImage = "ghcr.io/zammad/zammad:${zammadVersion}";
|
||||
|
||||
ipBase = "10.89.0";
|
||||
ipOffset = 40;
|
||||
|
||||
# Domain-Konfiguration
|
||||
zammadDomain = "hr-ticket.az-gruppe.com";
|
||||
|
||||
sharedEnvironment = {
|
||||
MEMCACHE_SERVERS = "zammad-memcached:11211";
|
||||
POSTGRESQL_DB = "zammad_${instanceName}";
|
||||
POSTGRESQL_HOST = "10.89.0.1";
|
||||
POSTGRESQL_USER = "zammad_${instanceName}";
|
||||
POSTGRESQL_PORT = "5432";
|
||||
POSTGRESQL_OPTIONS = "?pool=50";
|
||||
REDIS_URL = "redis://zammad-redis:6379";
|
||||
TZ = "Europe/Berlin";
|
||||
BACKUP_DIR = "/var/tmp/zammad";
|
||||
BACKUP_TIME = "03:00";
|
||||
HOLD_DAYS = "10";
|
||||
ELASTICSEARCH_ENABLED = "true";
|
||||
ELASTICSEARCH_HOST = "zammad-elasticsearch";
|
||||
ELASTICSEARCH_PORT = "9200";
|
||||
ELASTICSEARCH_NAMESPACE = "zammad_${instanceName}";
|
||||
NGINX_PORT = "8080";
|
||||
|
||||
# CSRF & Reverse Proxy Settings
|
||||
NGINX_SERVER_SCHEME = "https";
|
||||
NGINX_SERVER_NAME = zammadDomain;
|
||||
ZAMMAD_HTTP_TYPE = "https";
|
||||
ZAMMAD_FQDN = zammadDomain;
|
||||
RAILS_TRUSTED_PROXIES = "['127.0.0.1', '::1', '10.89.0.0/24']";
|
||||
};
|
||||
in {
|
||||
virtualisation.oci-containers = {
|
||||
containers."${serviceName}-elasticsearch" = {
|
||||
image = "elasticsearch:8.19.6";
|
||||
autoStart = true;
|
||||
volumes = ["${serviceName}_elasticsearch:/usr/share/elasticsearch/data"];
|
||||
environment = {
|
||||
"discovery.type" = "single-node";
|
||||
"xpack.security.enabled" = "false";
|
||||
ES_JAVA_OPTS = "-Xms1g -Xmx1g";
|
||||
};
|
||||
extraOptions = [
|
||||
"--ip=${ipBase}.${toString ipOffset}"
|
||||
"--network=web"
|
||||
"--network-alias=zammad-elasticsearch"
|
||||
];
|
||||
ports = ["127.0.0.1:${toString elasticsearchPort}:9200"];
|
||||
};
|
||||
|
||||
containers."${serviceName}-memcached" = {
|
||||
image = "memcached:1.6.39-alpine";
|
||||
autoStart = true;
|
||||
cmd = ["memcached" "-m" "256M"];
|
||||
extraOptions = [
|
||||
"--ip=${ipBase}.${toString (ipOffset + 1)}"
|
||||
"--network=web"
|
||||
"--network-alias=zammad-memcached"
|
||||
];
|
||||
};
|
||||
|
||||
containers."${serviceName}-redis" = {
|
||||
image = "redis:7.4.6-alpine";
|
||||
autoStart = true;
|
||||
volumes = ["${serviceName}_redis:/data"];
|
||||
extraOptions = [
|
||||
"--ip=${ipBase}.${toString (ipOffset + 2)}"
|
||||
"--network=web"
|
||||
"--network-alias=zammad-redis"
|
||||
];
|
||||
};
|
||||
|
||||
containers."${serviceName}-railsserver" = {
|
||||
image = zammadImage;
|
||||
autoStart = true;
|
||||
cmd = ["zammad-railsserver"];
|
||||
environment = sharedEnvironment;
|
||||
environmentFiles = [envFileCommon envFileProd];
|
||||
volumes = ["${serviceName}_storage:/opt/zammad/storage"];
|
||||
dependsOn = ["${serviceName}-memcached" "${serviceName}-redis" "${serviceName}-elasticsearch"];
|
||||
extraOptions = [
|
||||
"--ip=${ipBase}.${toString (ipOffset + 4)}"
|
||||
"--network=web"
|
||||
"--add-host=postgres:10.89.0.1"
|
||||
"--network-alias=zammad-railsserver"
|
||||
];
|
||||
};
|
||||
|
||||
containers."${serviceName}-scheduler" = {
|
||||
image = zammadImage;
|
||||
autoStart = true;
|
||||
cmd = ["zammad-scheduler"];
|
||||
environment = sharedEnvironment;
|
||||
environmentFiles = [envFileCommon envFileProd];
|
||||
volumes = ["${serviceName}_storage:/opt/zammad/storage"];
|
||||
dependsOn = ["${serviceName}-memcached" "${serviceName}-redis"];
|
||||
extraOptions = [
|
||||
"--ip=${ipBase}.${toString (ipOffset + 5)}"
|
||||
"--network=web"
|
||||
"--add-host=postgres:10.89.0.1"
|
||||
];
|
||||
};
|
||||
|
||||
containers."${serviceName}-websocket" = {
|
||||
image = zammadImage;
|
||||
autoStart = true;
|
||||
cmd = ["zammad-websocket"];
|
||||
environment = sharedEnvironment;
|
||||
environmentFiles = [envFileCommon envFileProd];
|
||||
volumes = ["${serviceName}_storage:/opt/zammad/storage"];
|
||||
dependsOn = ["${serviceName}-memcached" "${serviceName}-redis"];
|
||||
extraOptions = [
|
||||
"--ip=${ipBase}.${toString (ipOffset + 6)}"
|
||||
"--network=web"
|
||||
"--add-host=postgres:10.89.0.1"
|
||||
"--network-alias=zammad-websocket"
|
||||
];
|
||||
};
|
||||
|
||||
containers."${serviceName}-nginx" = {
|
||||
image = zammadImage;
|
||||
autoStart = true;
|
||||
cmd = ["zammad-nginx"];
|
||||
environment = sharedEnvironment;
|
||||
environmentFiles = [envFileCommon envFileProd];
|
||||
volumes = ["${serviceName}_storage:/opt/zammad/storage"];
|
||||
dependsOn = ["${serviceName}-railsserver"];
|
||||
ports = ["127.0.0.1:${toString servicePort}:8080"];
|
||||
extraOptions = [
|
||||
"--ip=${ipBase}.${toString (ipOffset + 7)}"
|
||||
"--network=web"
|
||||
"--add-host=postgres:10.89.0.1"
|
||||
];
|
||||
};
|
||||
|
||||
containers."${serviceName}-backup" = {
|
||||
image = zammadImage;
|
||||
autoStart = true;
|
||||
cmd = ["zammad-backup"];
|
||||
environment = sharedEnvironment;
|
||||
environmentFiles = [envFileCommon envFileProd];
|
||||
volumes = [
|
||||
"${serviceName}_storage:/opt/zammad/storage:ro"
|
||||
"/var/backup/${serviceName}:/var/tmp/zammad:rw"
|
||||
];
|
||||
dependsOn = ["${serviceName}-memcached" "${serviceName}-redis"];
|
||||
extraOptions = [
|
||||
"--ip=${ipBase}.${toString (ipOffset + 8)}"
|
||||
"--network=web"
|
||||
"--add-host=postgres:10.89.0.1"
|
||||
"--user=0:0"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
# Init als oneshot systemd-Service
|
||||
systemd.services."${serviceName}-init" = {
|
||||
description = "Zammad ${instanceName} Database Initialization";
|
||||
after = [
|
||||
"podman-${serviceName}-memcached.service"
|
||||
"podman-${serviceName}-redis.service"
|
||||
"podman-${serviceName}-elasticsearch.service"
|
||||
];
|
||||
requires = [
|
||||
"podman-${serviceName}-memcached.service"
|
||||
"podman-${serviceName}-redis.service"
|
||||
];
|
||||
wantedBy = [];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
User = "root";
|
||||
Group = "root";
|
||||
};
|
||||
|
||||
script = ''
|
||||
set -euo pipefail
|
||||
|
||||
echo "Starting Zammad ${instanceName} database initialization..."
|
||||
|
||||
${pkgs.podman}/bin/podman run --rm \
|
||||
--name ${serviceName}-init-oneshot \
|
||||
--network web \
|
||||
--ip ${ipBase}.${toString (ipOffset + 3)} \
|
||||
--add-host=postgres:10.89.0.1 \
|
||||
--user 0:0 \
|
||||
--env-file ${envFileCommon} \
|
||||
--env-file ${envFileProd} \
|
||||
--env MEMCACHE_SERVERS=zammad-memcached:11211 \
|
||||
--env POSTGRESQL_DB=zammad_${instanceName} \
|
||||
--env POSTGRESQL_HOST=10.89.0.1 \
|
||||
--env POSTGRESQL_USER=zammad_${instanceName} \
|
||||
--env POSTGRESQL_PORT=5432 \
|
||||
--env POSTGRESQL_OPTIONS='?pool=50' \
|
||||
--env REDIS_URL=redis://zammad-redis:6379 \
|
||||
--env TZ=Europe/Berlin \
|
||||
--env ELASTICSEARCH_ENABLED=true \
|
||||
--env ELASTICSEARCH_HOST=zammad-elasticsearch \
|
||||
--env ELASTICSEARCH_PORT=9200 \
|
||||
--env ELASTICSEARCH_NAMESPACE=zammad_${instanceName} \
|
||||
--env NGINX_SERVER_SCHEME=https \
|
||||
--env NGINX_SERVER_NAME=${zammadDomain} \
|
||||
--env ZAMMAD_HTTP_TYPE=https \
|
||||
--env ZAMMAD_FQDN=${zammadDomain} \
|
||||
-v ${serviceName}_storage:/opt/zammad/storage \
|
||||
${zammadImage} \
|
||||
zammad-init
|
||||
|
||||
echo "Zammad ${instanceName} initialization completed successfully"
|
||||
'';
|
||||
};
|
||||
|
||||
# Backup retention service
|
||||
systemd.services."${serviceName}-backup-cleanup" = {
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
User = "root";
|
||||
Group = "root";
|
||||
};
|
||||
script = ''
|
||||
set -euo pipefail
|
||||
|
||||
BACKUP_DIR="/var/backup/${serviceName}"
|
||||
HOLD_DAYS=10
|
||||
|
||||
echo "Starting ${serviceName} backup cleanup at $(date)"
|
||||
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
chown root:root "$BACKUP_DIR"
|
||||
chmod 750 "$BACKUP_DIR"
|
||||
|
||||
${pkgs.findutils}/bin/find "$BACKUP_DIR" -type f -name "*.gz" -mtime +$HOLD_DAYS -delete
|
||||
|
||||
echo "Current backups:"
|
||||
ls -lah "$BACKUP_DIR" || echo "No backups found"
|
||||
|
||||
echo "${serviceName} backup cleanup completed at $(date)"
|
||||
'';
|
||||
};
|
||||
|
||||
systemd.timers."${serviceName}-backup-cleanup" = {
|
||||
wantedBy = ["timers.target"];
|
||||
timerConfig = {
|
||||
OnCalendar = "*-*-* 04:00:00";
|
||||
RandomizedDelaySec = "30m";
|
||||
Persistent = true;
|
||||
};
|
||||
};
|
||||
|
||||
# Traefik configuration with proper headers
|
||||
services.traefik.dynamicConfigOptions.http = {
|
||||
services.${serviceName}.loadBalancer.servers = [
|
||||
{
|
||||
url = "http://localhost:${toString servicePort}/";
|
||||
}
|
||||
];
|
||||
|
||||
middlewares."${serviceName}-headers".headers = {
|
||||
customRequestHeaders = {
|
||||
X-Forwarded-Proto = "https";
|
||||
X-Forwarded-Port = "443";
|
||||
X-Forwarded-Host = zammadDomain;
|
||||
X-Real-IP = "";
|
||||
};
|
||||
};
|
||||
|
||||
routers.${serviceName} = {
|
||||
rule = "Host(`${zammadDomain}`)";
|
||||
tls = {
|
||||
certResolver = "ionos";
|
||||
};
|
||||
service = serviceName;
|
||||
entrypoints = "websecure";
|
||||
middlewares = ["${serviceName}-headers"];
|
||||
};
|
||||
};
|
||||
}
|
||||
18
hosts/AZ-CLD-1/services/default.nix
Normal file
18
hosts/AZ-CLD-1/services/default.nix
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
imports = [
|
||||
./containers
|
||||
|
||||
./gitea.nix
|
||||
./gotenberg.nix
|
||||
./metabase.nix
|
||||
./n8n.nix
|
||||
./netbird.nix
|
||||
./ntfy.nix
|
||||
./outline.nix
|
||||
./postgres.nix
|
||||
./traefik.nix
|
||||
./vaultwarden.nix
|
||||
./zugferd.nix
|
||||
# ./zammad.nix
|
||||
];
|
||||
}
|
||||
41
hosts/AZ-CLD-1/services/gitea.nix
Normal file
41
hosts/AZ-CLD-1/services/gitea.nix
Normal file
@@ -0,0 +1,41 @@
|
||||
{config, ...}: let
|
||||
serviceName = "gitea";
|
||||
servicePort = config.m3ta.ports.get serviceName;
|
||||
in {
|
||||
services.${serviceName} = {
|
||||
enable = true;
|
||||
settings = {
|
||||
server = {
|
||||
ROOT_URL = "https://git.az-gruppe.com";
|
||||
HTTP_PORT = servicePort;
|
||||
};
|
||||
mailer.SENDMAIL_PATH = "/run/wrappers/bin/sendmail";
|
||||
service.DISABLE_REGISTRATION = true;
|
||||
};
|
||||
lfs.enable = true;
|
||||
dump = {
|
||||
enable = true;
|
||||
type = "tar.gz";
|
||||
interval = "03:30:00";
|
||||
backupDir = "/var/backup/gitea";
|
||||
};
|
||||
};
|
||||
|
||||
# Traefik configuration
|
||||
services.traefik.dynamicConfigOptions.http = {
|
||||
services.${serviceName}.loadBalancer.servers = [
|
||||
{
|
||||
url = "http://localhost:${toString servicePort}/";
|
||||
}
|
||||
];
|
||||
|
||||
routers.${serviceName} = {
|
||||
rule = "Host(`git.az-gruppe.com`)";
|
||||
tls = {
|
||||
certResolver = "ionos";
|
||||
};
|
||||
service = serviceName;
|
||||
entrypoints = "websecure";
|
||||
};
|
||||
};
|
||||
}
|
||||
10
hosts/AZ-CLD-1/services/gotenberg.nix
Normal file
10
hosts/AZ-CLD-1/services/gotenberg.nix
Normal file
@@ -0,0 +1,10 @@
|
||||
{config, ...}: let
|
||||
serviceName = "gotenberg";
|
||||
servicePort = config.m3ta.ports.get serviceName;
|
||||
in {
|
||||
services.gotenberg = {
|
||||
enable = true;
|
||||
port = servicePort;
|
||||
bindIP = "127.0.0.1";
|
||||
};
|
||||
}
|
||||
31
hosts/AZ-CLD-1/services/metabase.nix
Normal file
31
hosts/AZ-CLD-1/services/metabase.nix
Normal file
@@ -0,0 +1,31 @@
|
||||
{config, ...}: let
|
||||
serviceName = "metabase";
|
||||
servicePort = config.m3ta.ports.get serviceName;
|
||||
in {
|
||||
services.${serviceName} = {
|
||||
enable = true;
|
||||
listen.port = servicePort;
|
||||
};
|
||||
|
||||
systemd.services.${serviceName}.serviceConfig = {
|
||||
EnvironmentFile = config.age.secrets.metabase-env.path;
|
||||
};
|
||||
|
||||
# Traefik configuration
|
||||
services.traefik.dynamicConfigOptions.http = {
|
||||
services.${serviceName}.loadBalancer.servers = [
|
||||
{
|
||||
url = "http://localhost:${toString servicePort}/";
|
||||
}
|
||||
];
|
||||
|
||||
routers.${serviceName} = {
|
||||
rule = "Host(`kpi.az-gruppe.com`)";
|
||||
tls = {
|
||||
certResolver = "ionos";
|
||||
};
|
||||
service = serviceName;
|
||||
entrypoints = "websecure";
|
||||
};
|
||||
};
|
||||
}
|
||||
31
hosts/AZ-CLD-1/services/n8n.nix
Normal file
31
hosts/AZ-CLD-1/services/n8n.nix
Normal file
@@ -0,0 +1,31 @@
|
||||
{config, ...}: let
|
||||
serviceName = "n8n";
|
||||
servicePort = config.m3ta.ports.get serviceName;
|
||||
in {
|
||||
services.${serviceName} = {
|
||||
enable = true;
|
||||
environment.WEBHOOK_URL = "https://wf.az-gruppe.com";
|
||||
};
|
||||
|
||||
systemd.services.${serviceName}.serviceConfig = {
|
||||
EnvironmentFile = config.age.secrets.n8n-env.path;
|
||||
};
|
||||
|
||||
# Traefik configuration
|
||||
services.traefik.dynamicConfigOptions.http = {
|
||||
services.${serviceName}.loadBalancer.servers = [
|
||||
{
|
||||
url = "http://localhost:${toString servicePort}/";
|
||||
}
|
||||
];
|
||||
|
||||
routers.${serviceName} = {
|
||||
rule = "Host(`wf.az-gruppe.com`)";
|
||||
tls = {
|
||||
certResolver = "ionos";
|
||||
};
|
||||
service = serviceName;
|
||||
entrypoints = "websecure";
|
||||
};
|
||||
};
|
||||
}
|
||||
31
hosts/AZ-CLD-1/services/netbird.nix
Normal file
31
hosts/AZ-CLD-1/services/netbird.nix
Normal file
@@ -0,0 +1,31 @@
|
||||
{pkgs, ...}: {
|
||||
services.netbird = {
|
||||
enable = true;
|
||||
package = pkgs.unstable.netbird;
|
||||
};
|
||||
|
||||
systemd.services.netbird = {
|
||||
environment = {
|
||||
NB_DISABLE_SSH_CONFIG = "true";
|
||||
};
|
||||
path = [
|
||||
pkgs.shadow
|
||||
pkgs.util-linux
|
||||
];
|
||||
};
|
||||
|
||||
programs.ssh.extraConfig = ''
|
||||
Match exec "${pkgs.netbird}/bin/netbird ssh detect %h %p"
|
||||
PreferredAuthentications password,publickey,keyboard-interactive
|
||||
PasswordAuthentication yes
|
||||
PubkeyAuthentication yes
|
||||
BatchMode no
|
||||
ProxyCommand ${pkgs.netbird}/bin/netbird ssh proxy %h %p
|
||||
StrictHostKeyChecking no
|
||||
UserKnownHostsFile /dev/null
|
||||
CheckHostIP no
|
||||
LogLevel ERROR
|
||||
'';
|
||||
|
||||
networking.firewall.checkReversePath = "loose";
|
||||
}
|
||||
32
hosts/AZ-CLD-1/services/ntfy.nix
Normal file
32
hosts/AZ-CLD-1/services/ntfy.nix
Normal file
@@ -0,0 +1,32 @@
|
||||
{config, ...}: let
|
||||
serviceName = "ntfy-sh";
|
||||
servicePort = config.m3ta.ports.get serviceName;
|
||||
in {
|
||||
services.${serviceName} = {
|
||||
enable = true;
|
||||
settings = {
|
||||
base-url = "https://ping.az-gruppe.com";
|
||||
listen-http = ":${toString servicePort}";
|
||||
auth-file = "/var/lib/ntfy-sh/user.db";
|
||||
auth-default-access = "deny-all";
|
||||
};
|
||||
};
|
||||
|
||||
# Traefik configuration
|
||||
services.traefik.dynamicConfigOptions.http = {
|
||||
services.${serviceName}.loadBalancer.servers = [
|
||||
{
|
||||
url = "http://localhost:${toString servicePort}/";
|
||||
}
|
||||
];
|
||||
|
||||
routers.${serviceName} = {
|
||||
rule = "Host(`ping.az-gruppe.com`)";
|
||||
tls = {
|
||||
certResolver = "ionos";
|
||||
};
|
||||
service = serviceName;
|
||||
entrypoints = "websecure";
|
||||
};
|
||||
};
|
||||
}
|
||||
41
hosts/AZ-CLD-1/services/outline.nix
Normal file
41
hosts/AZ-CLD-1/services/outline.nix
Normal file
@@ -0,0 +1,41 @@
|
||||
{config, ...}: let
|
||||
serviceName = "outline";
|
||||
servicePort = config.m3ta.ports.get serviceName;
|
||||
in {
|
||||
services.${serviceName} = {
|
||||
enable = true;
|
||||
port = servicePort;
|
||||
publicUrl = "https://wiki.az-gruppe.com";
|
||||
databaseUrl = "postgresql://outline:outline@127.0.0.1:5432/outline";
|
||||
storage = {
|
||||
storageType = "s3";
|
||||
region = "eu-central";
|
||||
uploadBucketUrl = "https://nbg1.your-objectstorage.com";
|
||||
uploadBucketName = "az-wiki";
|
||||
secretKeyFile = config.age.secrets.hetzner-s3-az-intern-secret-key.path;
|
||||
accessKey = "CRT7V4HR5CG9NHICD2WW";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.${serviceName}.serviceConfig = {
|
||||
EnvironmentFile = config.age.secrets.outline-env.path;
|
||||
};
|
||||
|
||||
# Traefik configuration
|
||||
services.traefik.dynamicConfigOptions.http = {
|
||||
services.${serviceName}.loadBalancer.servers = [
|
||||
{
|
||||
url = "http://localhost:${toString servicePort}/";
|
||||
}
|
||||
];
|
||||
|
||||
routers.${serviceName} = {
|
||||
rule = "Host(`wiki.az-gruppe.com`)";
|
||||
tls = {
|
||||
certResolver = "ionos";
|
||||
};
|
||||
service = serviceName;
|
||||
entrypoints = "websecure";
|
||||
};
|
||||
};
|
||||
}
|
||||
182
hosts/AZ-CLD-1/services/postgres.nix
Normal file
182
hosts/AZ-CLD-1/services/postgres.nix
Normal file
@@ -0,0 +1,182 @@
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
serviceName = "pgadmin";
|
||||
pgadminPort = config.m3ta.ports.get serviceName;
|
||||
in {
|
||||
services.postgresql = {
|
||||
enable = true;
|
||||
enableTCPIP = true;
|
||||
package = pkgs.postgresql_17;
|
||||
settings = {
|
||||
ssl = true;
|
||||
max_connections = 200;
|
||||
shared_buffers = "4GB";
|
||||
superuser_reserved_connections = 5;
|
||||
|
||||
idle_in_transaction_session_timeout = "10min";
|
||||
idle_session_timeout = "2h";
|
||||
|
||||
tcp_keepalives_idle = 60;
|
||||
tcp_keepalives_interval = 10;
|
||||
tcp_keepalives_count = 6;
|
||||
|
||||
deadlock_timeout = "1s";
|
||||
|
||||
authentication_timeout = "30s";
|
||||
|
||||
log_connections = true;
|
||||
log_disconnections = true;
|
||||
log_lock_waits = true;
|
||||
};
|
||||
extensions = with pkgs.postgresql17Packages; [
|
||||
pgvector
|
||||
];
|
||||
initialScript = pkgs.writeText "backend-initScript" ''
|
||||
CREATE USER baserow WITH ENCRYPTED PASSWORD 'baserow';
|
||||
CREATE DATABASE baserow;
|
||||
ALTER DATABASE baserow OWNER to baserow;
|
||||
ALTER DATABASE baserow CONNECTION LIMIT 60;
|
||||
|
||||
CREATE USER kestra WITH ENCRYPTED PASSWORD 'kestra';
|
||||
CREATE DATABASE kestra;
|
||||
ALTER DATABASE kestra OWNER to kestra;
|
||||
ALTER DATABASE kestra CONNECTION LIMIT 10;
|
||||
|
||||
CREATE USER librechat_rag WITH ENCRYPTED PASSWORD 'librechat_rag';
|
||||
CREATE DATABASE librechat_rag;
|
||||
ALTER DATABASE librechat_rag OWNER to librechat_rag;
|
||||
ALTER DATABASE librechat_rag CONNECTION LIMIT 20;
|
||||
|
||||
CREATE USER librechat_rag_dev WITH ENCRYPTED PASSWORD 'librechat_rag_dev';
|
||||
CREATE DATABASE librechat_rag_dev;
|
||||
ALTER DATABASE librechat_rag_dev OWNER to librechat_rag_dev;
|
||||
ALTER DATABASE librechat_rag_dev CONNECTION LIMIT 10;
|
||||
|
||||
CREATE USER metabase WITH ENCRYPTED PASSWORD 'metabase';
|
||||
CREATE DATABASE metabase;
|
||||
ALTER DATABASE metabase OWNER to metabase;
|
||||
ALTER DATABASE metabase CONNECTION LIMIT 15;
|
||||
|
||||
CREATE USER n8n WITH ENCRYPTED PASSWORD 'n8n';
|
||||
CREATE DATABASE n8n;
|
||||
ALTER DATABASE n8n OWNER to n8n;
|
||||
ALTER DATABASE n8n CONNECTION LIMIT 5;
|
||||
|
||||
CREATE USER outline WITH ENCRYPTED PASSWORD 'outline';
|
||||
CREATE DATABASE outline;
|
||||
ALTER DATABASE outline OWNER to outline;
|
||||
ALTER DATABASE outline CONNECTION LIMIT 5;
|
||||
|
||||
CREATE USER vaultwarden WITH ENCRYPTED PASSWORD 'vaultwarden';
|
||||
CREATE DATABASE vaultwarden;
|
||||
ALTER DATABASE vaultwarden OWNER to vaultwarden;
|
||||
ALTER DATABASE vaultwarden CONNECTION LIMIT 20;
|
||||
|
||||
CREATE USER zammad-hr WITH ENCRYPTED PASSWORD 'zammad-hr';
|
||||
CREATE DATABASE zammad-hr;
|
||||
ALTER DATABASE zammad-hr OWNER to zammad-hr;
|
||||
ALTER DATABASE zammad-hr CONNECTION LIMIT 50;
|
||||
|
||||
-- Group roles (NOLOGIN, for permission management)
|
||||
CREATE ROLE admin NOLOGIN;
|
||||
CREATE ROLE dba NOLOGIN;
|
||||
|
||||
-- Personal login roles
|
||||
CREATE USER sascha_koenig WITH ENCRYPTED PASSWORD 'sascha_koenig';
|
||||
GRANT admin TO sascha_koenig;
|
||||
|
||||
CREATE USER jannik_mueller WITH ENCRYPTED PASSWORD 'jannik_mueller';
|
||||
GRANT admin TO jannik_mueller;
|
||||
'';
|
||||
authentication = pkgs.lib.mkOverride 10 ''
|
||||
# Local connections (Unix socket)
|
||||
local all postgres peer
|
||||
local all sascha_koenig scram-sha-256
|
||||
local all jannik_mueller scram-sha-256
|
||||
local az_test az_test scram-sha-256
|
||||
local metabase,az_kpi_raw metabase scram-sha-256
|
||||
local n8n n8n scram-sha-256
|
||||
local outline outline scram-sha-256
|
||||
local vaultwarden vaultwarden scram-sha-256
|
||||
local zammad zammad scram-sha-256
|
||||
|
||||
# Localhost connections (IPv4 and IPv6)
|
||||
host all postgres 127.0.0.1/32 scram-sha-256
|
||||
host all postgres ::1/128 scram-sha-256
|
||||
|
||||
host all sascha_koenig 127.0.0.1/32 scram-sha-256
|
||||
host all sascha_koenig ::1/128 scram-sha-256
|
||||
|
||||
host all jannik_mueller 127.0.0.1/32 scram-sha-256
|
||||
host all jannik_mueller ::1/128 scram-sha-256
|
||||
|
||||
host az_test az_test 127.0.0.1/32 scram-sha-256
|
||||
host az_test az_test ::1/128 scram-sha-256
|
||||
|
||||
host outline outline 127.0.0.1/32 scram-sha-256
|
||||
host outline outline ::1/128 scram-sha-256
|
||||
|
||||
host metabase,az_kpi_raw metabase 127.0.0.1/32 scram-sha-256
|
||||
host metabase,az_kpi_raw metabase ::1/128 scram-sha-256
|
||||
|
||||
host n8n n8n 127.0.0.1/32 scram-sha-256
|
||||
host n8n n8n ::1/128 scram-sha-256
|
||||
|
||||
host vaultwarden vaultwarden 127.0.0.1/32 scram-sha-256
|
||||
host vaultwarden vaultwarden ::1/128 scram-sha-256
|
||||
|
||||
host zammad zammad 127.0.0.1/32 scram-sha-256
|
||||
host zammad zammad ::1/128 scram-sha-256
|
||||
|
||||
# Podman network connections for Baserow
|
||||
host baserow baserow 10.89.0.0/24 scram-sha-256
|
||||
host kestra kestra 10.89.0.0/24 scram-sha-256
|
||||
host librechat_rag librechat_rag 10.89.0.0/24 scram-sha-256
|
||||
host librechat_rag_dev librechat_rag_dev 10.89.1.0/24 scram-sha-256
|
||||
host zammad_hr zammad_hr 10.89.0.0/24 scram-sha-256
|
||||
host postgres zammad_hr 10.89.0.0/24 scram-sha-256
|
||||
host litellm litellm 10.89.0.0/24 scram-sha-256
|
||||
host netbird netbird 10.89.0.0/24 scram-sha-256
|
||||
|
||||
# Netbird network connections
|
||||
host az_kpi_raw kestra_prm 100.91.49.26/32 scram-sha-256
|
||||
|
||||
# Deny all other connections
|
||||
local all all reject
|
||||
host all all 0.0.0.0/0 reject
|
||||
host all all ::/0 reject
|
||||
'';
|
||||
};
|
||||
services.postgresqlBackup = {
|
||||
enable = true;
|
||||
startAt = "03:10:00";
|
||||
databases = ["az_kpi_raw" "baserow" "kestra" "librechat_rag" "litellm" "metabase" "n8n" "outline" "vaultwarden" "zammad" "zammad_hr"];
|
||||
};
|
||||
services.pgadmin = {
|
||||
enable = true;
|
||||
initialPasswordFile = "${config.age.secrets.pgadmin-pw.path}";
|
||||
initialEmail = "sascha.koenig@azintec.com";
|
||||
};
|
||||
|
||||
# Traefik configuration specific to pgadmin
|
||||
services.traefik.dynamicConfigOptions.http = {
|
||||
services.pgadmin.loadBalancer.servers = [{url = "http://localhost:${toString pgadminPort}/";}];
|
||||
routers.pgadmin = {
|
||||
rule = "Host(`pg.az-gruppe.com`)";
|
||||
tls.certResolver = "ionos";
|
||||
service = "pgadmin";
|
||||
entrypoints = "websecure";
|
||||
};
|
||||
};
|
||||
networking.firewall = {
|
||||
extraCommands = ''
|
||||
iptables -A INPUT -p tcp -s 127.0.0.1 --dport 5432 -j ACCEPT
|
||||
iptables -A INPUT -p tcp -s 10.89.0.0/24 --dport 5432 -j ACCEPT
|
||||
iptables -A INPUT -p tcp -s 10.89.1.0/24 --dport 5432 -j ACCEPT
|
||||
iptables -A INPUT -p tcp -s 100.91.49.26/32 --dport 5432 -j ACCEPT
|
||||
'';
|
||||
};
|
||||
}
|
||||
77
hosts/AZ-CLD-1/services/traefik.nix
Normal file
77
hosts/AZ-CLD-1/services/traefik.nix
Normal file
@@ -0,0 +1,77 @@
|
||||
{config, ...}: let
|
||||
httpPort = config.m3ta.ports.get "traefik";
|
||||
httpsPort = config.m3ta.ports.get "traefik-ssl";
|
||||
in {
|
||||
services.traefik = {
|
||||
enable = true;
|
||||
staticConfigOptions = {
|
||||
log = {level = "WARN";};
|
||||
certificatesResolvers = {
|
||||
ionos = {
|
||||
acme = {
|
||||
email = "sascha.koenig@azintec.com";
|
||||
storage = "/var/lib/traefik/acme.json";
|
||||
caserver = "https://acme-v02.api.letsencrypt.org/directory";
|
||||
dnsChallenge = {
|
||||
provider = "ionos";
|
||||
resolvers = ["1.1.1.1:53" "8.8.8.8:53"];
|
||||
propagation = {
|
||||
delayBeforeChecks = 60;
|
||||
disableChecks = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
api = {};
|
||||
entryPoints = {
|
||||
web = {
|
||||
address = ":${toString httpPort}";
|
||||
http.redirections.entryPoint = {
|
||||
to = "websecure";
|
||||
scheme = "https";
|
||||
};
|
||||
};
|
||||
websecure = {
|
||||
address = ":${toString httpsPort}";
|
||||
};
|
||||
};
|
||||
};
|
||||
dynamicConfigOptions = {
|
||||
http = {
|
||||
services = {
|
||||
dummy = {
|
||||
loadBalancer.servers = [
|
||||
{url = "http://192.168.0.1";} # Diese URL wird nie verwendet
|
||||
];
|
||||
};
|
||||
};
|
||||
middlewares = {
|
||||
auth = {
|
||||
basicAuth = {
|
||||
users = ["sascha.koenig:$apr1$1xqdta2b$DIVNvvp5iTUGNccJjguKh."];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
routers = {
|
||||
api = {
|
||||
rule = "Host(`r.az-gruppe.com`)";
|
||||
service = "api@internal";
|
||||
middlewares = ["auth"];
|
||||
entrypoints = ["websecure"];
|
||||
tls = {
|
||||
certResolver = "ionos";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.traefik.serviceConfig = {
|
||||
EnvironmentFile = ["${config.age.secrets.traefik-env.path}"];
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [httpPort httpsPort];
|
||||
}
|
||||
32
hosts/AZ-CLD-1/services/vaultwarden.nix
Normal file
32
hosts/AZ-CLD-1/services/vaultwarden.nix
Normal file
@@ -0,0 +1,32 @@
|
||||
{config, ...}: let
|
||||
serviceName = "vaultwarden";
|
||||
servicePort = config.m3ta.ports.get serviceName;
|
||||
in {
|
||||
services.${serviceName} = {
|
||||
enable = true;
|
||||
dbBackend = "postgresql";
|
||||
config = {
|
||||
ROCKET_ADDRESS = "127.0.0.1";
|
||||
ROCKET_PORT = servicePort;
|
||||
};
|
||||
environmentFile = config.age.secrets.vaultwarden-env.path;
|
||||
};
|
||||
|
||||
# Traefik configuration
|
||||
services.traefik.dynamicConfigOptions.http = {
|
||||
services.${serviceName}.loadBalancer.servers = [
|
||||
{
|
||||
url = "http://localhost:${toString servicePort}/";
|
||||
}
|
||||
];
|
||||
|
||||
routers.${serviceName} = {
|
||||
rule = "Host(`pw.az-gruppe.com`)";
|
||||
tls = {
|
||||
certResolver = "ionos";
|
||||
};
|
||||
service = serviceName;
|
||||
entrypoints = "websecure";
|
||||
};
|
||||
};
|
||||
}
|
||||
35
hosts/AZ-CLD-1/services/zammad.nix
Normal file
35
hosts/AZ-CLD-1/services/zammad.nix
Normal file
@@ -0,0 +1,35 @@
|
||||
{config, ...}: let
|
||||
serviceName = "zammad";
|
||||
servicePort = config.m3ta.ports.get serviceName;
|
||||
in {
|
||||
services.${serviceName} = {
|
||||
enable = true;
|
||||
openPorts = false;
|
||||
port = servicePort;
|
||||
secretKeyBaseFile = config.age.secrets.zammad-secret.path;
|
||||
database = {
|
||||
createLocally = false;
|
||||
port = 5432;
|
||||
host = "127.0.0.1";
|
||||
passwordFile = config.age.secrets.zammad-pw.path;
|
||||
};
|
||||
};
|
||||
|
||||
# Traefik configuration
|
||||
services.traefik.dynamicConfigOptions.http = {
|
||||
services.${serviceName}.loadBalancer.servers = [
|
||||
{
|
||||
url = "http://localhost:${toString servicePort}/";
|
||||
}
|
||||
];
|
||||
|
||||
routers.${serviceName} = {
|
||||
rule = "Host(`help.az-gruppe.com`)";
|
||||
tls = {
|
||||
certResolver = "ionos";
|
||||
};
|
||||
service = serviceName;
|
||||
entrypoints = "websecure";
|
||||
};
|
||||
};
|
||||
}
|
||||
10
hosts/AZ-CLD-1/services/zugferd.nix
Normal file
10
hosts/AZ-CLD-1/services/zugferd.nix
Normal file
@@ -0,0 +1,10 @@
|
||||
{config, ...}: let
|
||||
serviceName = "zugferd-service";
|
||||
zugferdPort = config.m3ta.ports.get serviceName;
|
||||
in {
|
||||
services.${serviceName} = {
|
||||
enable = true;
|
||||
port = zugferdPort;
|
||||
host = "127.0.0.1";
|
||||
};
|
||||
}
|
||||
41
hosts/AZ-PRM-1/configuration.nix
Normal file
41
hosts/AZ-PRM-1/configuration.nix
Normal file
@@ -0,0 +1,41 @@
|
||||
{pkgs, ...}: {
|
||||
imports = [
|
||||
./hardware-configuration.nix
|
||||
./disko-config.nix
|
||||
];
|
||||
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
boot.loader.efi.canTouchEfiVariables = true;
|
||||
|
||||
networking.hostName = "AZ-PRM-1";
|
||||
networking.networkmanager.enable = true;
|
||||
|
||||
time.timeZone = "Europe/Berlin";
|
||||
|
||||
i18n.defaultLocale = "de_DE.UTF-8";
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
neovim
|
||||
git
|
||||
python3
|
||||
python3Packages.pysmb
|
||||
];
|
||||
|
||||
programs.gnupg.agent = {
|
||||
enable = true;
|
||||
enableSSHSupport = true;
|
||||
};
|
||||
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
ports = [2022];
|
||||
settings = {
|
||||
PermitRootLogin = "no";
|
||||
PasswordAuthentication = false;
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [587];
|
||||
|
||||
system.stateVersion = "25.05";
|
||||
}
|
||||
11
hosts/AZ-PRM-1/default.nix
Normal file
11
hosts/AZ-PRM-1/default.nix
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
imports = [
|
||||
../common
|
||||
./configuration.nix
|
||||
./secrets.nix
|
||||
./services
|
||||
];
|
||||
extraServices = {
|
||||
podman.enable = true;
|
||||
};
|
||||
}
|
||||
34
hosts/AZ-PRM-1/disko-config.nix
Normal file
34
hosts/AZ-PRM-1/disko-config.nix
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
main = {
|
||||
type = "disk";
|
||||
device = "/dev/sda";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
esp = {
|
||||
size = "512M";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = ["defaults" "umask=0077"];
|
||||
};
|
||||
};
|
||||
root = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
mountOptions = ["noatime" "nodiratime" "discard"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
17
hosts/AZ-PRM-1/hardware-configuration.nix
Normal file
17
hosts/AZ-PRM-1/hardware-configuration.nix
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
virtualisation.hypervGuest.enable = true;
|
||||
|
||||
boot.initrd.availableKernelModules = ["sd_mod" "sr_mod" "hv_storvsc"];
|
||||
boot.initrd.kernelModules = [];
|
||||
boot.kernelModules = [];
|
||||
boot.extraModulePackages = [];
|
||||
|
||||
networking.useDHCP = lib.mkDefault true;
|
||||
|
||||
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||
}
|
||||
37
hosts/AZ-PRM-1/secrets.nix
Normal file
37
hosts/AZ-PRM-1/secrets.nix
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
age = {
|
||||
secrets = {
|
||||
azion-env = {
|
||||
file = ../../secrets/azion-env.age;
|
||||
};
|
||||
traefik-env = {
|
||||
file = ../../secrets/traefik-env.age;
|
||||
};
|
||||
kestra-config = {
|
||||
file = ../../secrets/kestra-config.age;
|
||||
mode = "644";
|
||||
};
|
||||
kestra-env = {file = ../../secrets/kestra-env.age;};
|
||||
kestra-secrets = {file = ../../secrets/kestra-secrets.age;};
|
||||
n8n-env = {
|
||||
file = ../../secrets/n8n-env-prm.age;
|
||||
};
|
||||
pgadmin-pw = {
|
||||
file = ../../secrets/pgadmin-pw.age;
|
||||
owner = "pgadmin";
|
||||
};
|
||||
pg-cert = {
|
||||
file = ../../secrets/server.crt.age;
|
||||
owner = "postgres";
|
||||
group = "postgres";
|
||||
mode = "0644";
|
||||
};
|
||||
pg-key = {
|
||||
file = ../../secrets/server.key.age;
|
||||
owner = "postgres";
|
||||
group = "postgres";
|
||||
mode = "0600";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
36
hosts/AZ-PRM-1/services/azion-scheduler.nix
Normal file
36
hosts/AZ-PRM-1/services/azion-scheduler.nix
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
inputs,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
serviceName = "azion-scheduler";
|
||||
proxyServiceName = "${serviceName}-proxy";
|
||||
servicePort = config.m3ta.ports.get serviceName;
|
||||
schedulerProxyPort = config.m3ta.ports.get proxyServiceName;
|
||||
in {
|
||||
services.azion-scheduler = {
|
||||
enable = true;
|
||||
package = inputs.azion-scheduler.packages.${pkgs.stdenv.hostPlatform.system}.default;
|
||||
port = servicePort;
|
||||
proxyPort = schedulerProxyPort;
|
||||
environmentFile = config.age.secrets.azion-env.path;
|
||||
};
|
||||
|
||||
# Traefik configuration
|
||||
services.traefik.dynamicConfigOptions.http = {
|
||||
services.${serviceName}.loadBalancer.servers = [
|
||||
{url = "http://localhost:${toString servicePort}/";}
|
||||
];
|
||||
|
||||
routers.${serviceName} = {
|
||||
rule = "Host(`azion.l.az-gruppe.com`)";
|
||||
tls = {
|
||||
certResolver = "ionos";
|
||||
};
|
||||
service = serviceName;
|
||||
entrypoints = "websecure";
|
||||
};
|
||||
};
|
||||
}
|
||||
80
hosts/AZ-PRM-1/services/bpi.nix
Normal file
80
hosts/AZ-PRM-1/services/bpi.nix
Normal file
@@ -0,0 +1,80 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
serviceName = "bpi";
|
||||
servicePort = config.m3ta.ports.get serviceName;
|
||||
appDir = "/var/lib/bpi/app";
|
||||
in {
|
||||
users.users.bpi = {
|
||||
isSystemUser = true;
|
||||
group = "bpi";
|
||||
home = "/var/lib/bpi";
|
||||
createHome = true;
|
||||
};
|
||||
users.groups.bpi = {};
|
||||
|
||||
systemd.services.bpi = {
|
||||
description = "AZ INTEC Basispreis Index";
|
||||
after = ["network-online.target"];
|
||||
wants = ["network-online.target"];
|
||||
wantedBy = ["multi-user.target"];
|
||||
|
||||
path = with pkgs; [
|
||||
git
|
||||
nodejs
|
||||
openssh
|
||||
];
|
||||
|
||||
environment = {
|
||||
PORT = toString servicePort;
|
||||
HOME = "/var/lib/bpi";
|
||||
BPI_BACKUP_DIR = "/var/lib/bpi/backups";
|
||||
BPI_MAX_BACKUPS = "10";
|
||||
};
|
||||
|
||||
preStart = ''
|
||||
set -euo pipefail
|
||||
|
||||
if [ ! -d "${appDir}/.git" ]; then
|
||||
rm -rf "${appDir}"
|
||||
git clone --depth=1 https://git.az-gruppe.com/AZ-Intec-GmbH/BPI.git "${appDir}"
|
||||
else
|
||||
git -C "${appDir}" pull --ff-only
|
||||
fi
|
||||
|
||||
if [ ! -f "${appDir}/server.js" ]; then
|
||||
echo "${appDir}/server.js fehlt. Bitte server.js in das BPI Repository committen."
|
||||
exit 1
|
||||
fi
|
||||
'';
|
||||
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
User = "bpi";
|
||||
Group = "bpi";
|
||||
StateDirectory = "bpi";
|
||||
WorkingDirectory = "/var/lib/bpi";
|
||||
ExecStart = "${pkgs.nodejs}/bin/node ${appDir}/server.js";
|
||||
Restart = "on-failure";
|
||||
RestartSec = "10s";
|
||||
};
|
||||
};
|
||||
|
||||
services.traefik.dynamicConfigOptions.http = {
|
||||
services.bpi.loadBalancer.servers = [
|
||||
{url = "http://localhost:${toString servicePort}/";}
|
||||
];
|
||||
|
||||
routers.bpi = {
|
||||
rule = "Host(`bpi.l.az-gruppe.com`)";
|
||||
tls = {
|
||||
certResolver = "ionos";
|
||||
};
|
||||
service = "bpi";
|
||||
entrypoints = "websecure";
|
||||
};
|
||||
};
|
||||
}
|
||||
15
hosts/AZ-PRM-1/services/containers/default.nix
Normal file
15
hosts/AZ-PRM-1/services/containers/default.nix
Normal file
@@ -0,0 +1,15 @@
|
||||
{lib, ...}: {
|
||||
imports = [
|
||||
#./baserow.nix
|
||||
./kestra.nix
|
||||
./stirling-pdf.nix
|
||||
];
|
||||
system.activationScripts.createPodmanNetworkWeb = lib.mkAfter ''
|
||||
if ! /run/current-system/sw/bin/podman network exists web; then
|
||||
/run/current-system/sw/bin/podman network create web --subnet=10.89.0.0/24 --internal
|
||||
fi
|
||||
if ! /run/current-system/sw/bin/podman network exists web-dev; then
|
||||
/run/current-system/sw/bin/podman network create web-dev --subnet=10.89.1.0/24 --internal
|
||||
fi
|
||||
'';
|
||||
}
|
||||
38
hosts/AZ-PRM-1/services/containers/kestra.nix
Normal file
38
hosts/AZ-PRM-1/services/containers/kestra.nix
Normal file
@@ -0,0 +1,38 @@
|
||||
{config, ...}: let
|
||||
serviceName = "kestra";
|
||||
servicePort = config.m3ta.ports.get serviceName;
|
||||
in {
|
||||
virtualisation.oci-containers.containers."${serviceName}" = {
|
||||
image = "docker.io/kestra/kestra:latest";
|
||||
environmentFiles = [
|
||||
config.age.secrets.kestra-env.path
|
||||
config.age.secrets.kestra-secrets.path
|
||||
];
|
||||
cmd = ["server" "standalone" "--config" "/etc/config/application.yaml"];
|
||||
ports = ["127.0.0.1:${toString servicePort}:8080"];
|
||||
user = "root";
|
||||
volumes = [
|
||||
"/var/run/podman/podman.sock:/var/run/docker.sock"
|
||||
"${config.age.secrets.kestra-config.path}:/etc/config/application.yaml"
|
||||
"kestra_data:/app/storage"
|
||||
"/tmp/kestra-wd:/tmp/kestra-wd"
|
||||
];
|
||||
extraOptions = ["--add-host=postgres:10.89.0.1" "--ip=10.89.0.12" "--network=web"];
|
||||
};
|
||||
|
||||
systemd.tmpfiles.rules = [
|
||||
"d /tmp/kestra-wd 0750 1000 1000 - -"
|
||||
];
|
||||
|
||||
# Traefik configuration specific to kestra
|
||||
services.traefik.dynamicConfigOptions.http = {
|
||||
services.kestra.loadBalancer.servers = [{url = "http://localhost:${toString servicePort}/";}];
|
||||
|
||||
routers.kestra = {
|
||||
rule = "Host(`k.l.az-gruppe.com`)";
|
||||
tls = {certResolver = "ionos";};
|
||||
service = "kestra";
|
||||
entrypoints = "websecure";
|
||||
};
|
||||
};
|
||||
}
|
||||
30
hosts/AZ-PRM-1/services/containers/stirling-pdf.nix
Normal file
30
hosts/AZ-PRM-1/services/containers/stirling-pdf.nix
Normal file
@@ -0,0 +1,30 @@
|
||||
{config, ...}: let
|
||||
serviceName = "stirling-pdf";
|
||||
servicePort = config.m3ta.ports.get serviceName;
|
||||
in {
|
||||
virtualisation.oci-containers.containers."${serviceName}" = {
|
||||
image = "docker.stirlingpdf.com/stirlingtools/stirling-pdf:latest-fat";
|
||||
ports = ["127.0.0.1:${toString servicePort}:8080"];
|
||||
environment = {
|
||||
SECURITY_ENABLELOGIN = "False";
|
||||
DISABLE_ADDITIONAL_FEATURES = "False";
|
||||
};
|
||||
|
||||
volumes = [
|
||||
"stirling_pdf_data:/usr/share/tessdata"
|
||||
"stirling_pdf_configs:/configs"
|
||||
];
|
||||
extraOptions = ["--ip=10.89.0.13" "--network=web"];
|
||||
};
|
||||
|
||||
services.traefik.dynamicConfigOptions.http = {
|
||||
services.${serviceName}.loadBalancer.servers = [{url = "http://localhost:${toString servicePort}/";}];
|
||||
|
||||
routers.${serviceName} = {
|
||||
rule = "Host(`pdf.l.az-gruppe.com`)";
|
||||
tls = {certResolver = "ionos";};
|
||||
service = serviceName;
|
||||
entrypoints = "websecure";
|
||||
};
|
||||
};
|
||||
}
|
||||
14
hosts/AZ-PRM-1/services/default.nix
Normal file
14
hosts/AZ-PRM-1/services/default.nix
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
imports = [
|
||||
./containers
|
||||
./azion-scheduler.nix
|
||||
./bpi.nix
|
||||
./n8n.nix
|
||||
./netbird.nix
|
||||
./pgadmin.nix
|
||||
./postgres.nix
|
||||
./printing.nix
|
||||
./traefik.nix
|
||||
./traefik-routing.nix
|
||||
];
|
||||
}
|
||||
32
hosts/AZ-PRM-1/services/n8n.nix
Normal file
32
hosts/AZ-PRM-1/services/n8n.nix
Normal file
@@ -0,0 +1,32 @@
|
||||
{config, ...}: let
|
||||
serviceName = "n8n";
|
||||
servicePort = config.m3ta.ports.get serviceName;
|
||||
in {
|
||||
services.n8n = {
|
||||
enable = true;
|
||||
environment = {
|
||||
WEBHOOK_URL = "https://wf.l.az-gruppe.com";
|
||||
NODES_EXCLUDE = "[]";
|
||||
};
|
||||
};
|
||||
systemd.services.n8n.serviceConfig = {
|
||||
EnvironmentFile = ["${config.age.secrets.n8n-env.path}"];
|
||||
};
|
||||
# Traefik configuration specific to n8n
|
||||
services.traefik.dynamicConfigOptions.http = {
|
||||
services.${serviceName}.loadBalancer.servers = [
|
||||
{
|
||||
url = "http://localhost:${toString servicePort}/";
|
||||
}
|
||||
];
|
||||
|
||||
routers.${serviceName} = {
|
||||
rule = "Host(`wf.l.az-gruppe.com`)";
|
||||
tls = {
|
||||
certResolver = "ionos";
|
||||
};
|
||||
service = serviceName;
|
||||
entrypoints = "websecure";
|
||||
};
|
||||
};
|
||||
}
|
||||
31
hosts/AZ-PRM-1/services/netbird.nix
Normal file
31
hosts/AZ-PRM-1/services/netbird.nix
Normal file
@@ -0,0 +1,31 @@
|
||||
{pkgs, ...}: {
|
||||
services.netbird = {
|
||||
enable = true;
|
||||
package = pkgs.unstable.netbird;
|
||||
};
|
||||
|
||||
systemd.services.netbird = {
|
||||
environment = {
|
||||
NB_DISABLE_SSH_CONFIG = "true";
|
||||
};
|
||||
path = [
|
||||
pkgs.shadow
|
||||
pkgs.util-linux
|
||||
];
|
||||
};
|
||||
|
||||
programs.ssh.extraConfig = ''
|
||||
Match exec "${pkgs.netbird}/bin/netbird ssh detect %h %p"
|
||||
PreferredAuthentications password,publickey,keyboard-interactive
|
||||
PasswordAuthentication yes
|
||||
PubkeyAuthentication yes
|
||||
BatchMode no
|
||||
ProxyCommand ${pkgs.netbird}/bin/netbird ssh proxy %h %p
|
||||
StrictHostKeyChecking no
|
||||
UserKnownHostsFile /dev/null
|
||||
CheckHostIP no
|
||||
LogLevel ERROR
|
||||
'';
|
||||
|
||||
networking.firewall.checkReversePath = "loose";
|
||||
}
|
||||
21
hosts/AZ-PRM-1/services/pgadmin.nix
Normal file
21
hosts/AZ-PRM-1/services/pgadmin.nix
Normal file
@@ -0,0 +1,21 @@
|
||||
{config, ...}: let
|
||||
serviceName = "pgadmin";
|
||||
servicePort = config.m3ta.ports.get serviceName;
|
||||
in {
|
||||
services.pgadmin = {
|
||||
enable = true;
|
||||
initialPasswordFile = "${config.age.secrets.pgadmin-pw.path}";
|
||||
initialEmail = "sascha.koenig@azintec.com";
|
||||
};
|
||||
|
||||
# Traefik configuration specific to pgadmin
|
||||
services.traefik.dynamicConfigOptions.http = {
|
||||
services.pgadmin.loadBalancer.servers = [{url = "http://localhost:${toString servicePort}/";}];
|
||||
routers.pgadmin = {
|
||||
rule = "Host(`pg.l.az-gruppe.com`)";
|
||||
tls.certResolver = "ionos";
|
||||
service = "pgadmin";
|
||||
entrypoints = "websecure";
|
||||
};
|
||||
};
|
||||
}
|
||||
67
hosts/AZ-PRM-1/services/postgres.nix
Normal file
67
hosts/AZ-PRM-1/services/postgres.nix
Normal file
@@ -0,0 +1,67 @@
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
services.postgresql = {
|
||||
enable = true;
|
||||
enableTCPIP = true;
|
||||
package = pkgs.postgresql_17;
|
||||
settings = {
|
||||
ssl = true;
|
||||
ssl_cert_file = config.age.secrets.pg-cert.path;
|
||||
ssl_key_file = config.age.secrets.pg-key.path;
|
||||
};
|
||||
extensions = with pkgs.postgresql17Packages; [
|
||||
pgvector
|
||||
];
|
||||
initialScript = pkgs.writeText "backend-initScript" ''
|
||||
CREATE USER baserow WITH ENCRYPTED PASSWORD 'baserow';
|
||||
CREATE DATABASE baserow;
|
||||
ALTER DATABASE baserow OWNER to baserow;
|
||||
|
||||
CREATE USER kestra WITH ENCRYPTED PASSWORD 'kestra';
|
||||
CREATE DATABASE kestra;
|
||||
ALTER DATABASE kestra OWNER to kestra;
|
||||
|
||||
CREATE USER n8n WITH ENCRYPTED PASSWORD 'n8n';
|
||||
CREATE DATABASE n8n;
|
||||
ALTER DATABASE n8n OWNER to n8n;
|
||||
|
||||
CREATE USER vaultwarden WITH ENCRYPTED PASSWORD 'n8n';
|
||||
CREATE DATABASE vaultwarden;
|
||||
ALTER DATABASE vaultwarden OWNER to vaultwarden;
|
||||
'';
|
||||
authentication = pkgs.lib.mkOverride 10 ''
|
||||
# Local connections (Unix socket)
|
||||
local all postgres peer
|
||||
local n8n n8n scram-sha-256
|
||||
|
||||
# Localhost connections (IPv4 and IPv6)
|
||||
host all postgres 127.0.0.1/32 scram-sha-256
|
||||
host all postgres ::1/128 scram-sha-256
|
||||
|
||||
host n8n n8n 127.0.0.1/32 scram-sha-256
|
||||
host n8n n8n ::1/128 scram-sha-256
|
||||
|
||||
# Podman network connections
|
||||
host baserow baserow 10.89.0.0/24 scram-sha-256
|
||||
host kestra kestra 10.89.0.0/24 scram-sha-256
|
||||
|
||||
# Deny all other connections
|
||||
host all all 0.0.0.0/0 reject
|
||||
host all all ::/0 reject
|
||||
'';
|
||||
};
|
||||
services.postgresqlBackup = {
|
||||
enable = true;
|
||||
startAt = "03:10:00";
|
||||
databases = ["baserow" "kestra" "n8n"];
|
||||
};
|
||||
networking.firewall = {
|
||||
extraCommands = ''
|
||||
iptables -A INPUT -p tcp -s 127.0.0.1 --dport 5432 -j ACCEPT
|
||||
iptables -A INPUT -p tcp -s 10.89.0.0/24 --dport 5432 -j ACCEPT
|
||||
'';
|
||||
};
|
||||
}
|
||||
40
hosts/AZ-PRM-1/services/printing.nix
Normal file
40
hosts/AZ-PRM-1/services/printing.nix
Normal file
@@ -0,0 +1,40 @@
|
||||
{pkgs, ...}: {
|
||||
# CUPS Druckdienst für PDF-Druck aus n8n
|
||||
# Drucker: Kyocera TASKalfa 4054ci @ 192.168.152.137
|
||||
services.printing = {
|
||||
enable = true;
|
||||
drivers = with pkgs; [
|
||||
cups-filters # driverless IPP Everywhere Support
|
||||
];
|
||||
};
|
||||
|
||||
# Avahi für mDNS/IPP-Druckererkennung
|
||||
services.avahi = {
|
||||
enable = true;
|
||||
nssmdns4 = true;
|
||||
openFirewall = true;
|
||||
};
|
||||
|
||||
# Kyocera TASKalfa 4054ci deklarativ einrichten
|
||||
hardware.printers = {
|
||||
ensurePrinters = [
|
||||
{
|
||||
name = "JW2OG";
|
||||
location = "Buero";
|
||||
description = "Kyocera TASKalfa 4054ci";
|
||||
deviceUri = "ipps://192.168.152.137:443/ipp/print";
|
||||
model = "everywhere";
|
||||
ppdOptions = {
|
||||
PageSize = "A4";
|
||||
};
|
||||
}
|
||||
];
|
||||
ensureDefaultPrinter = "JW2OG";
|
||||
};
|
||||
|
||||
# n8n braucht Zugriff auf lp/lpr zum Drucken
|
||||
systemd.services.n8n = {
|
||||
path = [pkgs.cups];
|
||||
serviceConfig.SupplementaryGroups = ["lp"];
|
||||
};
|
||||
}
|
||||
7
hosts/AZ-PRM-1/services/samba.nix
Normal file
7
hosts/AZ-PRM-1/services/samba.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
{pkgs, ...}: {
|
||||
services.samba = {
|
||||
enable = true;
|
||||
package = pkgs.samba4Full;
|
||||
openFirewall = true;
|
||||
};
|
||||
}
|
||||
31
hosts/AZ-PRM-1/services/traefik-routing.nix
Normal file
31
hosts/AZ-PRM-1/services/traefik-routing.nix
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
services.traefik.dynamicConfigOptions.http = {
|
||||
services.ptrg.loadBalancer.servers = [{url = "http://192.168.152.102:7784/";}];
|
||||
|
||||
routers.prtg = {
|
||||
rule = "Host(`m.l.az-gruppe.com`)";
|
||||
tls = {certResolver = "ionos";};
|
||||
service = "ptrg";
|
||||
entrypoints = "websecure";
|
||||
};
|
||||
|
||||
services.AZHA.loadBalancer.servers = [{url = "http://192.168.152.47:8123/";}];
|
||||
routers.AZHA = {
|
||||
rule = "Host(`ha.l.az-gruppe.com`)";
|
||||
tls = {certResolver = "ionos";};
|
||||
service = "AZHA";
|
||||
entrypoints = "websecure";
|
||||
};
|
||||
services.AZDESK.loadBalancer.servers = [
|
||||
{
|
||||
url = "https://azdesk.az-group.local:443/";
|
||||
}
|
||||
];
|
||||
routers.AZDESK = {
|
||||
rule = "Host(`it-ticket.l.az-gruppe.com`)";
|
||||
tls = {certResolver = "ionos";};
|
||||
service = "AZDESK";
|
||||
entrypoints = "websecure";
|
||||
};
|
||||
};
|
||||
}
|
||||
92
hosts/AZ-PRM-1/services/traefik.nix
Normal file
92
hosts/AZ-PRM-1/services/traefik.nix
Normal file
@@ -0,0 +1,92 @@
|
||||
{config, ...}: let
|
||||
httpPort = config.m3ta.ports.get "traefik";
|
||||
httpsPort = config.m3ta.ports.get "traefik-ssl";
|
||||
in {
|
||||
services.traefik = {
|
||||
enable = true;
|
||||
staticConfigOptions = {
|
||||
log = {level = "WARN";};
|
||||
serversTransport.insecureSkipVerify = true;
|
||||
certificatesResolvers = {
|
||||
ionos = {
|
||||
acme = {
|
||||
email = "sascha.koenig@azintec.com";
|
||||
storage = "/var/lib/traefik/acme.json";
|
||||
caserver = "https://acme-v02.api.letsencrypt.org/directory";
|
||||
dnsChallenge = {
|
||||
provider = "ionos";
|
||||
resolvers = ["1.1.1.1:53" "8.8.8.8:53"];
|
||||
propagation = {
|
||||
delayBeforeChecks = 60;
|
||||
disableChecks = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
api = {};
|
||||
entryPoints = {
|
||||
web = {
|
||||
address = ":${toString httpPort}";
|
||||
http.redirections.entryPoint = {
|
||||
to = "websecure";
|
||||
scheme = "https";
|
||||
};
|
||||
};
|
||||
websecure = {
|
||||
address = ":${toString httpsPort}";
|
||||
http.tls = {
|
||||
certResolver = "ionos";
|
||||
domains = [
|
||||
{
|
||||
main = "l.az-gruppe.com";
|
||||
sans = ["*.l.az-gruppe.com"];
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
dynamicConfigOptions = {
|
||||
http = {
|
||||
services = {
|
||||
dummy = {
|
||||
loadBalancer.servers = [
|
||||
{url = "http://192.168.0.1";}
|
||||
];
|
||||
};
|
||||
};
|
||||
middlewares = {
|
||||
auth = {
|
||||
basicAuth = {
|
||||
users = ["sascha.koenig:$apr1$1xqdta2b$DIVNvvp5iTUGNccJjguKh."];
|
||||
};
|
||||
};
|
||||
};
|
||||
routers = {
|
||||
api = {
|
||||
rule = "Host(`r.l.az-gruppe.com`)";
|
||||
service = "api@internal";
|
||||
middlewares = ["auth"];
|
||||
entrypoints = ["websecure"];
|
||||
tls = {
|
||||
certResolver = "ionos";
|
||||
domains = [
|
||||
{
|
||||
main = "l.az-gruppe.com";
|
||||
sans = ["*.l.az-gruppe.com"];
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.traefik.serviceConfig = {
|
||||
EnvironmentFile = ["${config.age.secrets.traefik-env.path}"];
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [httpPort httpsPort];
|
||||
}
|
||||
76
hosts/common/default.nix
Normal file
76
hosts/common/default.nix
Normal file
@@ -0,0 +1,76 @@
|
||||
# Common configuration for all hosts
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
inputs,
|
||||
outputs,
|
||||
system,
|
||||
...
|
||||
}: {
|
||||
imports = [
|
||||
./extraServices
|
||||
./users
|
||||
./ports.nix
|
||||
inputs.m3ta-nixpkgs.nixosModules.ports
|
||||
inputs.home-manager.nixosModules.home-manager
|
||||
];
|
||||
|
||||
home-manager = {
|
||||
useGlobalPkgs = true;
|
||||
useUserPackages = true;
|
||||
extraSpecialArgs = {
|
||||
inherit inputs outputs system;
|
||||
videoDrivers = config.services.xserver.videoDrivers or [];
|
||||
};
|
||||
};
|
||||
|
||||
nixpkgs = {
|
||||
# You can add overlays here
|
||||
overlays = [
|
||||
# Add overlays your own flake exports (from overlays and pkgs dir):
|
||||
outputs.overlays.additions
|
||||
outputs.overlays.modifications
|
||||
outputs.overlays.unstable-packages
|
||||
|
||||
inputs.nur.overlays.default
|
||||
inputs.m3ta-nixpkgs.overlays.default
|
||||
|
||||
(outputs.lib.mkLlmAgentsOverlay system)
|
||||
# You can also add overlays exported from other flakes:
|
||||
# neovim-nightly-overlay.overlays.default
|
||||
|
||||
# Or define it inline, for example:
|
||||
# (final: prev: {
|
||||
# hi = final.hello.overrideAttrs (oldAttrs: {
|
||||
# patches = [ ./change-hello-to-hi.patch ];
|
||||
# });
|
||||
# })
|
||||
];
|
||||
# Configure your nixpkgs instance
|
||||
config = {
|
||||
# Disable if you don't want unfree packages
|
||||
allowUnfree = true;
|
||||
};
|
||||
};
|
||||
|
||||
nix = {
|
||||
settings = {
|
||||
experimental-features = "nix-command flakes";
|
||||
trusted-users = [
|
||||
"root"
|
||||
"sascha.koenig"
|
||||
"jannik.mueller"
|
||||
]; # Set users that are allowed to use the flake command
|
||||
};
|
||||
gc = {
|
||||
automatic = true;
|
||||
options = "--delete-older-than 30d";
|
||||
};
|
||||
optimise.automatic = true;
|
||||
registry =
|
||||
(lib.mapAttrs (_: flake: {inherit flake;}))
|
||||
((lib.filterAttrs (_: lib.isType "flake")) inputs);
|
||||
nixPath = ["/etc/nix/path"];
|
||||
};
|
||||
}
|
||||
8
hosts/common/extraServices/default.nix
Normal file
8
hosts/common/extraServices/default.nix
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
imports = [
|
||||
./flatpak.nix
|
||||
./ollama.nix
|
||||
./podman.nix
|
||||
./virtualisation.nix
|
||||
];
|
||||
}
|
||||
23
hosts/common/extraServices/flatpak.nix
Normal file
23
hosts/common/extraServices/flatpak.nix
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
with lib; let
|
||||
cfg = config.extraServices.flatpak;
|
||||
in {
|
||||
options.extraServices.flatpak.enable = mkEnableOption "enable flatpak";
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
services.flatpak.enable = true;
|
||||
xdg.portal = {
|
||||
# xdg desktop intergration (required for flatpak)
|
||||
enable = true;
|
||||
extraPortals = with pkgs; [
|
||||
xdg-desktop-portal-hyprland
|
||||
];
|
||||
config.common.default = "*";
|
||||
};
|
||||
};
|
||||
}
|
||||
27
hosts/common/extraServices/ollama.nix
Normal file
27
hosts/common/extraServices/ollama.nix
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
with lib; let
|
||||
cfg = config.extraServices.ollama;
|
||||
in {
|
||||
options.extraServices.ollama.enable = mkEnableOption "enable ollama";
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
services.ollama = {
|
||||
enable = true;
|
||||
package = pkgs.ollama-vulkan;
|
||||
host = "[::]";
|
||||
openFirewall = true;
|
||||
environmentVariables = {
|
||||
OLLAMA_HOST = "0.0.0.0";
|
||||
};
|
||||
};
|
||||
nixpkgs.config = {
|
||||
rocmSupport = config.services.xserver.videoDrivers == ["amdgpu"];
|
||||
cudaSupport = config.services.xserver.videoDrivers == ["nvidia"];
|
||||
};
|
||||
};
|
||||
}
|
||||
33
hosts/common/extraServices/podman.nix
Normal file
33
hosts/common/extraServices/podman.nix
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
with lib; let
|
||||
cfg = config.extraServices.podman;
|
||||
in {
|
||||
options.extraServices.podman.enable = mkEnableOption "enable podman";
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
virtualisation = {
|
||||
podman = {
|
||||
enable = true;
|
||||
dockerCompat = true;
|
||||
dockerSocket.enable = true;
|
||||
autoPrune = {
|
||||
enable = true;
|
||||
dates = "weekly";
|
||||
flags = [
|
||||
"--filter=until=24h"
|
||||
"--filter=label!=important"
|
||||
];
|
||||
};
|
||||
defaultNetwork.settings.dns_enabled = true;
|
||||
};
|
||||
};
|
||||
environment.systemPackages = with pkgs; [
|
||||
podman-compose
|
||||
];
|
||||
};
|
||||
}
|
||||
42
hosts/common/extraServices/virtualisation.nix
Normal file
42
hosts/common/extraServices/virtualisation.nix
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
with lib; let
|
||||
cfg = config.extraServices.virtualisation;
|
||||
in {
|
||||
options.extraServices.virtualisation.enable = mkEnableOption "enable virtualisation";
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
virtualisation = {
|
||||
libvirtd = {
|
||||
enable = true;
|
||||
qemu = {
|
||||
package = pkgs.qemu_kvm;
|
||||
runAsRoot = true;
|
||||
swtpm.enable = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
programs.virt-manager.enable = true;
|
||||
environment = {
|
||||
systemPackages = [pkgs.qemu];
|
||||
etc = {
|
||||
"ovmf/OVMF_CODE.fd" = {
|
||||
source = "${(pkgs.OVMF.override {
|
||||
secureBoot = true;
|
||||
tpmSupport = true;
|
||||
}).fd}/FV/OVMF_CODE.fd";
|
||||
};
|
||||
"ovmf/OVMF_VARS.fd" = {
|
||||
source = "${(pkgs.OVMF.override {
|
||||
secureBoot = true;
|
||||
tpmSupport = true;
|
||||
}).fd}/FV/OVMF_VARS.fd";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
63
hosts/common/ports.nix
Normal file
63
hosts/common/ports.nix
Normal file
@@ -0,0 +1,63 @@
|
||||
{config, ...}: {
|
||||
m3ta.ports = {
|
||||
enable = true;
|
||||
|
||||
definitions = {
|
||||
ssh = 2022;
|
||||
|
||||
traefik = 80;
|
||||
traefik-ssl = 443;
|
||||
|
||||
gitea = 3030;
|
||||
outline = 3031;
|
||||
vaultwarden = 3032;
|
||||
ntfy-sh = 3033;
|
||||
zammad = 3034;
|
||||
it-tools = 3035;
|
||||
zammad-hr = 3036;
|
||||
zammad-hr-elasticsearch = 3037;
|
||||
netbird = 3038;
|
||||
azion-scheduler = 3039;
|
||||
azion-scheduler-proxy = 3049;
|
||||
|
||||
metabase = 3013;
|
||||
baserow = 3050;
|
||||
|
||||
librechat = 3040;
|
||||
librechat-dev = 3141;
|
||||
rag-api = 8000;
|
||||
rag-api-dev = 8100;
|
||||
litellm = 4000;
|
||||
|
||||
n8n = 5678;
|
||||
kestra = 5080;
|
||||
zugferd-service = 5060;
|
||||
gotenberg = 5070;
|
||||
|
||||
portainer = 9000;
|
||||
|
||||
postgres = 5432;
|
||||
pgadmin = 5050;
|
||||
};
|
||||
|
||||
hostOverrides = {
|
||||
AZ-CLD-1 = {
|
||||
baserow = 3050;
|
||||
librechat-dev = 3141;
|
||||
rag-api-dev = 8100;
|
||||
};
|
||||
|
||||
AZ-PRM-1 = {
|
||||
baserow = 3051;
|
||||
kestra = 5080;
|
||||
stirling-pdf = 3032;
|
||||
bpi = 3033;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
environment.etc."info/all-ports.json".text = builtins.toJSON {
|
||||
hostname = config.networking.hostName;
|
||||
ports = config.m3ta.ports.all;
|
||||
};
|
||||
}
|
||||
6
hosts/common/users/default.nix
Normal file
6
hosts/common/users/default.nix
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
imports = [
|
||||
./jannik.mueller.nix
|
||||
./sascha.koenig.nix
|
||||
];
|
||||
}
|
||||
25
hosts/common/users/jannik.mueller.nix
Normal file
25
hosts/common/users/jannik.mueller.nix
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
inputs,
|
||||
...
|
||||
}: {
|
||||
users.users."jannik.mueller" = {
|
||||
hashedPassword = "$y$j9T$09RgD3AU3PK9Oi6JGLe0V1$i8J2ZOD1h1b6Zpw28ub.kExujoDKHzokeXzkM23Tfd/";
|
||||
isNormalUser = true;
|
||||
extraGroups = [
|
||||
"wheel"
|
||||
"networkmanager"
|
||||
"libvirtd"
|
||||
"flatpak"
|
||||
"plugdev"
|
||||
"input"
|
||||
"kvm"
|
||||
"qemu-libvirtd"
|
||||
];
|
||||
openssh.authorizedKeys.keys = [
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPvZazSuIoWoRWhkAqQDMLeurxVUyy1MTllp1wfw1tzq"
|
||||
];
|
||||
packages = [inputs.home-manager.packages.${pkgs.stdenv.hostPlatform.system}.default];
|
||||
};
|
||||
}
|
||||
125
hosts/common/users/sascha.koenig.nix
Normal file
125
hosts/common/users/sascha.koenig.nix
Normal file
@@ -0,0 +1,125 @@
|
||||
# hosts/common/users/m3tam3re.nix — Central user definition with m3ta-home integration.
|
||||
#
|
||||
# This module:
|
||||
# 1. Creates the m3tam3re NixOS user
|
||||
# 2. Loads the m3ta-home profile system via mkHome
|
||||
# 3. Sets per-host feature flags based on a host profile mapping
|
||||
# 4. Imports per-host home.nix overrides (monitors, HW-specific config)
|
||||
#
|
||||
# To add a new host:
|
||||
# 1. Add entry to hostProfiles below
|
||||
# 2. Add feature flags in the hostFlags section
|
||||
# 3. Create hosts/<hostname>/home.nix if the host needs overrides (monitors, etc.)
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
inputs,
|
||||
...
|
||||
}: let
|
||||
hostname = config.networking.hostName;
|
||||
|
||||
# ── Per-host profile mapping ──
|
||||
# Determines which m3ta-home context and sets each host gets.
|
||||
hostProfiles = {
|
||||
# ── Server hosts ──
|
||||
AZ-CLD-1 = {
|
||||
context = "server";
|
||||
sets = [];
|
||||
};
|
||||
AZ-PRM-1 = {
|
||||
context = "server";
|
||||
sets = [];
|
||||
};
|
||||
};
|
||||
|
||||
profile =
|
||||
hostProfiles.${
|
||||
hostname
|
||||
} or {
|
||||
context = "server";
|
||||
sets = [];
|
||||
};
|
||||
m3ta-lib = inputs.m3ta-home.lib;
|
||||
|
||||
# Check if a per-host home.nix exists
|
||||
hostHomeFile = ./../../${hostname}/home.nix;
|
||||
hostHomeExists = builtins.pathExists hostHomeFile;
|
||||
|
||||
# ── Per-host feature flags ──
|
||||
# These enable/disable specific m3ta-home modules per host.
|
||||
hostFlags =
|
||||
if hostname == "AZ-CLD-1"
|
||||
then {
|
||||
# Full desktop workstation
|
||||
base = {
|
||||
shell = {
|
||||
fish.enable = true;
|
||||
nushell.enable = true;
|
||||
starship.enable = true;
|
||||
};
|
||||
cliTools = {
|
||||
fzf.enable = true;
|
||||
nitch.enable = true;
|
||||
television.enable = true;
|
||||
};
|
||||
secrets.enable = true;
|
||||
};
|
||||
}
|
||||
else {
|
||||
# m3-helios, m3-hermes, m3-aether — minimal server
|
||||
base = {
|
||||
shell = {
|
||||
fish.enable = true;
|
||||
starship.enable = true;
|
||||
};
|
||||
cliTools = {
|
||||
fzf.enable = true;
|
||||
nitch.enable = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
in {
|
||||
# ── NixOS user definition ──
|
||||
users.users."sascha.koenig" = {
|
||||
hashedPassword = "$y$j9T$ORX4btVZgs9Xjq2oIvzJm0$lXiPwaa0D6t.eMDIx1UBesEAMOkWXBoGwpeI7X0aS8D";
|
||||
isNormalUser = true;
|
||||
shell = pkgs.nushell;
|
||||
extraGroups = [
|
||||
"wheel"
|
||||
"networkmanager"
|
||||
"libvirtd"
|
||||
"flatpak"
|
||||
"plugdev"
|
||||
"input"
|
||||
"kvm"
|
||||
"qemu-libvirtd"
|
||||
];
|
||||
openssh.authorizedKeys.keys = [
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEZbg/Z9mnflXuLahGY8WOSBMqbgeqVIkIwRkquys1Ml sascha.koenig@azintec.com"
|
||||
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC3YEmpYbM+cpmyD10tzNRHEn526Z3LJOzYpWEKdJg8DaYyPbDn9iyVX30Nja2SrW4Wadws0Y8DW+Urs25/wVB6mKl7jgPJVkMi5hfobu3XAz8gwSdjDzRSWJrhjynuaXiTtRYED2INbvjLuxx3X8coNwMw58OuUuw5kNJp5aS2qFmHEYQErQsGT4MNqESe3jvTP27Z5pSneBj45LmGK+RcaSnJe7hG+KRtjuhjI7RdzMeDCX73SfUsal+rHeuEw/mmjYmiIItXhFTDn8ZvVwpBKv7xsJG90DkaX2vaTk0wgJdMnpVIuIRBa4EkmMWOQ3bMLGkLQeK/4FUkNcvQ/4+zcZsg4cY9Q7Fj55DD41hAUdF6SYODtn5qMPsTCnJz44glHt/oseKXMSd556NIw2HOvihbJW7Rwl4OEjGaO/dF4nUw4c9tHWmMn9dLslAVpUuZOb7ykgP0jk79ldT3Dv+2Hj0CdAWT2cJAdFX58KQ9jUPT3tBnObSF1lGMI7t77VU= m3tam3re@MBP-Sascha.fritz.box"
|
||||
];
|
||||
packages = [inputs.home-manager.packages.${pkgs.stdenv.hostPlatform.system}.default];
|
||||
};
|
||||
|
||||
# ── Home-Manager configuration via m3ta-home ──
|
||||
home-manager.users."sascha.koenig" = {
|
||||
home.stateVersion = "25.11";
|
||||
imports =
|
||||
[
|
||||
# Load m3ta-home composition engine
|
||||
(m3ta-lib.mkHome {
|
||||
user = "m3tam3re";
|
||||
identity = "work";
|
||||
inherit (profile) context sets;
|
||||
})
|
||||
# Per-host feature flags
|
||||
hostFlags
|
||||
]
|
||||
# Per-host home.nix (Hyprland monitors, XDG/MIME, HW-specific overrides)
|
||||
++ (
|
||||
if hostHomeExists
|
||||
then [hostHomeFile]
|
||||
else []
|
||||
);
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user