forked from KptltD00M/nixy
Add new server modules and configurations for various services
- Introduced `default-creds` module for managing default credentials with Umami integration. - Added `fail2ban` module for brute-force attack protection with configurable ban times. - Created `firewall` module to enable and configure basic firewall settings. - Implemented `gitea` module for self-hosted Git service with PostgreSQL backend. - Developed `glance` module for a customizable dashboard with various widgets and themes. - Added `iknowyou` module for a self-hosted password manager with production and demo environments. - Introduced `kernel-hardening` module for enhancing kernel security settings. - Created `mazanoke` module for a simple web application with Nginx integration. - Added `mealie` module for a self-hosted meal planning application. - Implemented `stirling-pdf` module for PDF generation service. - Developed `umami` module for self-hosted analytics with secret management. - Added `ssh` module for secure SSH configuration with user restrictions. - Introduced `nixy` theme for a customized aesthetic experience across services.
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
# Adguard is a network-wide ad blocker
|
||||
# When installed, open localhost:3000 to setup
|
||||
{config, ...}: {
|
||||
services.adguardhome = {
|
||||
enable = true;
|
||||
port = 3000;
|
||||
};
|
||||
|
||||
networking.firewall = {
|
||||
allowedTCPPorts = [53];
|
||||
allowedUDPPorts = [53];
|
||||
# Allow containers to reach adguard UI (for glance dns-stats widget)
|
||||
extraCommands = ''
|
||||
iptables -I INPUT 1 -s 10.233.0.0/16 -p tcp --dport 3000 -j ACCEPT
|
||||
'';
|
||||
extraStopCommands = ''
|
||||
iptables -D INPUT -s 10.233.0.0/16 -p tcp --dport 3000 -j ACCEPT 2>/dev/null || true
|
||||
'';
|
||||
};
|
||||
|
||||
services.cloudflared.tunnels."${config.var.tunnelId}".ingress."adguard.${config.var.domain}" = "http://localhost:${toString config.services.adguardhome.port}";
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
# *arr is a collection of media management applications.
|
||||
# See https://github.com/rasmus-kirk/nixarr
|
||||
# Setup guide: https://nixarr.com/wiki/setup/
|
||||
{config, ...}: let
|
||||
username = config.var.username;
|
||||
in {
|
||||
# Add my secrets
|
||||
sops.secrets = {
|
||||
recyclarr = {
|
||||
owner = "recyclarr";
|
||||
mode = "0777";
|
||||
};
|
||||
wireguard-pia = {
|
||||
group = "media";
|
||||
mode = "0600";
|
||||
};
|
||||
};
|
||||
|
||||
nixarr = {
|
||||
enable = true;
|
||||
|
||||
mediaUsers = [username];
|
||||
mediaDir = "/mnt/data/media";
|
||||
stateDir = "/mnt/data/.state/nixarr";
|
||||
|
||||
vpn = {
|
||||
enable = true;
|
||||
wgConf = config.sops.secrets.wireguard-pia.path;
|
||||
};
|
||||
|
||||
jellyfin.enable = true;
|
||||
jellyseerr.enable = true;
|
||||
prowlarr.enable = true;
|
||||
radarr.enable = true;
|
||||
sonarr.enable = true;
|
||||
bazarr.enable = true;
|
||||
transmission = {
|
||||
enable = true;
|
||||
extraSettings = {
|
||||
trash-original-torrent-files = true;
|
||||
rpc-whitelist-enabled = false;
|
||||
rpc-host-whitelist-enabled = false;
|
||||
};
|
||||
vpn.enable = true;
|
||||
};
|
||||
recyclarr = {
|
||||
enable = true;
|
||||
configFile = config.sops.secrets.recyclarr.path;
|
||||
};
|
||||
};
|
||||
|
||||
users.users.jellyfin.extraGroups = [
|
||||
"video"
|
||||
"render"
|
||||
];
|
||||
|
||||
services.cloudflared.tunnels."${config.var.tunnelId}".ingress = {
|
||||
"media.${config.var.domain}" = "http://localhost:8096";
|
||||
"demandemedia.${config.var.domain}" = "http://localhost:5055";
|
||||
"bazarr.${config.var.domain}" = "http://localhost:6767";
|
||||
"prowlarr.${config.var.domain}" = "http://localhost:9696";
|
||||
"radarr.${config.var.domain}" = "http://localhost:7878";
|
||||
"sonarr.${config.var.domain}" = "http://localhost:8989";
|
||||
"transmission.${config.var.domain}" = "http://localhost:9091";
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
config,
|
||||
inputs,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (import ./mk-container.nix {inherit lib config;}) mkContainer;
|
||||
in {
|
||||
imports = [
|
||||
(mkContainer {
|
||||
name = "wallpapers";
|
||||
hostIp = "10.233.4.1";
|
||||
containerIp = "10.233.4.2";
|
||||
nixosConfig = {pkgs, ...}: {
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
virtualHosts."wallpapers" = {
|
||||
root = "${inputs.awesome-wallpapers.packages.${pkgs.stdenv.hostPlatform.system}.default}/share/awesome-wallpapers";
|
||||
listen = [
|
||||
{
|
||||
addr = "0.0.0.0";
|
||||
port = 8080;
|
||||
}
|
||||
];
|
||||
locations."/" = {
|
||||
tryFiles = "$uri $uri/ /index.html";
|
||||
};
|
||||
extraConfig = ''
|
||||
port_in_redirect off;
|
||||
absolute_redirect off;
|
||||
'';
|
||||
};
|
||||
};
|
||||
networking.firewall.allowedTCPPorts = [8080];
|
||||
system.stateVersion = "24.05";
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
services.cloudflared.tunnels."${config.var.tunnelId}".ingress."wallpapers.${config.var.domain}" = "http://10.233.4.2:8080";
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
{
|
||||
config,
|
||||
inputs,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (import ./mk-container.nix {inherit lib config;}) mkContainer;
|
||||
domain = config.var.domain;
|
||||
in {
|
||||
imports = [
|
||||
(mkContainer {
|
||||
name = "blog";
|
||||
hostIp = "10.233.3.1";
|
||||
containerIp = "10.233.3.2";
|
||||
nixosConfig = {pkgs, ...}: {
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
virtualHosts = {
|
||||
"blog" = {
|
||||
root = "${inputs.blog.packages.${pkgs.stdenv.hostPlatform.system}.default}/share/blog";
|
||||
listen = [
|
||||
{
|
||||
addr = "0.0.0.0";
|
||||
port = 8080;
|
||||
}
|
||||
];
|
||||
locations."/" = {
|
||||
tryFiles = "$uri $uri/ =404";
|
||||
};
|
||||
extraConfig = ''
|
||||
port_in_redirect off;
|
||||
absolute_redirect off;
|
||||
error_page 403 /403.html;
|
||||
error_page 404 /404.html;
|
||||
error_page 500 /500.html;
|
||||
error_page 503 /503.html;
|
||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' data: https://umami.${domain}; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://git.${domain}; connect-src 'self' https://umami.${domain};" always;
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
|
||||
'';
|
||||
};
|
||||
"www-redirect" = {
|
||||
listen = [
|
||||
{
|
||||
addr = "0.0.0.0";
|
||||
port = 8081;
|
||||
}
|
||||
];
|
||||
extraConfig = "return 301 https://${domain}$request_uri;";
|
||||
};
|
||||
};
|
||||
};
|
||||
networking.firewall.allowedTCPPorts = [
|
||||
8080
|
||||
8081
|
||||
];
|
||||
system.stateVersion = "24.05";
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
services.cloudflared.tunnels."${config.var.tunnelId}".ingress = {
|
||||
"${config.var.domain}" = "http://10.233.3.2:8080";
|
||||
"www.${config.var.domain}" = "http://10.233.3.2:8081";
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
# Cloudflared tunnel configuration for NixOS
|
||||
# It allows exposing services securely via Cloudflare Tunnel
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
sops.secrets.cloudflared-token.mode = "0400";
|
||||
|
||||
# To setup cloudflared, run:
|
||||
# - `cloudflared tunnel login`
|
||||
# - `cloudflared tunnel create YourTunnelName`
|
||||
#
|
||||
# This will create a credentials file & give you the tunnel ID to use below.
|
||||
services.cloudflared = {
|
||||
enable = true;
|
||||
tunnels."${config.var.tunnelId}" = {
|
||||
credentialsFile = config.sops.secrets."cloudflared-token".path;
|
||||
default = "http_status:404";
|
||||
};
|
||||
};
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
cloudflared
|
||||
];
|
||||
|
||||
systemd.services."cloudflared-tunnel-${config.var.tunnelId}" = {
|
||||
wantedBy = ["multi-user.target"];
|
||||
after = ["network-online.target"];
|
||||
wants = ["network-online.target"];
|
||||
};
|
||||
|
||||
# At the moment (2025), for support of browser rendering of the tunnels, this line is required:
|
||||
services.openssh.settings.Macs = [
|
||||
"hmac-sha2-256"
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (import ./mk-container.nix {inherit lib config;}) mkContainer;
|
||||
in {
|
||||
imports = [
|
||||
(mkContainer {
|
||||
name = "cyberchef";
|
||||
hostIp = "10.233.5.1";
|
||||
containerIp = "10.233.5.2";
|
||||
nixosConfig = {pkgs, ...}: {
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
virtualHosts."cyberchef" = {
|
||||
root = "${pkgs.cyberchef}/share/cyberchef";
|
||||
listen = [
|
||||
{
|
||||
addr = "0.0.0.0";
|
||||
port = 8080;
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
networking.firewall.allowedTCPPorts = [8080];
|
||||
system.stateVersion = "24.05";
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
services.cloudflared.tunnels."${config.var.tunnelId}".ingress."cyberchef.${config.var.domain}" = "http://10.233.5.2:8080";
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
config,
|
||||
inputs,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (import ./mk-container.nix {inherit lib config;}) mkContainer;
|
||||
domain = config.var.domain;
|
||||
in {
|
||||
imports = [
|
||||
(mkContainer {
|
||||
name = "def-creds";
|
||||
hostIp = "10.233.6.1";
|
||||
containerIp = "10.233.6.2";
|
||||
nixosConfig = {...}: {
|
||||
imports = [inputs.default-creds.nixosModules.default];
|
||||
services.default-creds = {
|
||||
enable = true;
|
||||
port = 8087;
|
||||
};
|
||||
networking.firewall.allowedTCPPorts = [8087];
|
||||
systemd.services.default-creds.environment = {
|
||||
HOST = lib.mkForce "0.0.0.0";
|
||||
PUBLIC_UMAMI_URL = "https://umami.${domain}";
|
||||
PUBLIC_UMAMI_WEBSITE_ID = "7197484c-01ad-488e-9caa-5ab7b7595f08";
|
||||
UMAMI_URL = "https://umami.${domain}";
|
||||
UMAMI_WEBSITE_ID = "7197484c-01ad-488e-9caa-5ab7b7595f08";
|
||||
};
|
||||
system.stateVersion = "24.05";
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
services.default-creds.enable = lib.mkForce false;
|
||||
services.cloudflared.tunnels."${config.var.tunnelId}".ingress."default-creds.${config.var.domain}" = "http://10.233.6.2:8087";
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
# Fail2Ban is a log-parsing application that protects Linux servers from brute-force attacks.
|
||||
{
|
||||
services.fail2ban = {
|
||||
enable = true;
|
||||
maxretry = 5;
|
||||
bantime = "24h"; # Ban IPs for one day on the first ban
|
||||
bantime-increment = {
|
||||
enable = true; # Enable increment of bantime after each violation
|
||||
multipliers = "1 2 4 8 16 32 64";
|
||||
maxtime = "168h"; # Do not ban for more than 1 week
|
||||
overalljails = true; # Calculate the bantime based on all the violations
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
# Firewall configuration for NixOS
|
||||
{
|
||||
networking.firewall = {
|
||||
enable = true;
|
||||
allowPing = false;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (import ./mk-container.nix {inherit lib config;}) mkContainer;
|
||||
domain = config.var.domain;
|
||||
catppuccin-gitea = pkgs.fetchzip {
|
||||
url = "https://github.com/catppuccin/gitea/releases/download/v1.0.2/catppuccin-gitea.tar.gz";
|
||||
sha256 = "sha256-rZHLORwLUfIFcB6K9yhrzr+UwdPNQVSadsw6rg8Q7gs=";
|
||||
stripRoot = false;
|
||||
};
|
||||
in {
|
||||
imports = [
|
||||
(mkContainer {
|
||||
name = "gitea";
|
||||
hostIp = "10.233.11.1";
|
||||
containerIp = "10.233.11.2";
|
||||
internet = true;
|
||||
bindMounts."/var/lib/gitea" = {
|
||||
hostPath = "/var/lib/gitea";
|
||||
isReadOnly = false;
|
||||
};
|
||||
nixosConfig = {lib, ...}: {
|
||||
users.users.gitea.uid = lib.mkForce 978;
|
||||
users.groups.gitea.gid = lib.mkForce 968;
|
||||
|
||||
services.postgresql = {
|
||||
enable = true;
|
||||
ensureDatabases = ["gitea"];
|
||||
ensureUsers = [
|
||||
{
|
||||
name = "gitea";
|
||||
ensureDBOwnership = true;
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
services.gitea = {
|
||||
enable = true;
|
||||
database.type = "postgres";
|
||||
settings = {
|
||||
server = {
|
||||
HTTP_ADDR = "0.0.0.0";
|
||||
HTTP_PORT = 3002;
|
||||
ROOT_URL = "https://git.${domain}/";
|
||||
DOMAIN = "git.${domain}";
|
||||
LANDING_PAGE = "/anotherhadi";
|
||||
};
|
||||
service = {
|
||||
REGISTER_MANUAL_CONFIRM = true;
|
||||
DISABLE_REGISTRATION = true;
|
||||
DEFAULT_KEEP_EMAIL_PRIVATE = true;
|
||||
SHOW_REGISTRATION_BUTTON = false;
|
||||
};
|
||||
ui = {
|
||||
DEFAULT_THEME = "catppuccin-mocha-mauve";
|
||||
THEMES = "catppuccin-latte-mauve,catppuccin-frappe-mauve,catppuccin-macchiato-mauve,catppuccin-mocha-mauve";
|
||||
};
|
||||
explore = {
|
||||
DISABLE_USERS_PAGE = true;
|
||||
DISABLE_ORGANIZATIONS_PAGE = true;
|
||||
};
|
||||
repository.DISABLE_STARS = true;
|
||||
mailer.ENABLED = false;
|
||||
api.ENABLE_SWAGGER = false;
|
||||
other.SHOW_FOOTER_VERSION = false;
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.gitea.preStart = lib.mkAfter ''
|
||||
mkdir -p /var/lib/gitea/custom/public/assets
|
||||
ln -sfn ${catppuccin-gitea} /var/lib/gitea/custom/public/assets/css
|
||||
'';
|
||||
|
||||
networking.firewall.allowedTCPPorts = [3002];
|
||||
system.stateVersion = "24.05";
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
services.cloudflared.tunnels."${config.var.tunnelId}".ingress."git.${domain}" = "http://10.233.11.2:3002";
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (import ../mk-container.nix {inherit lib config;}) mkContainer;
|
||||
domain = config.var.domain;
|
||||
hostIp = "10.233.12.1";
|
||||
|
||||
# Convert 6-char hex color to "H S L" string for glance (integers, no % sign)
|
||||
hexToGlanceHsl = hex: let
|
||||
h = lib.toLower hex;
|
||||
d = c:
|
||||
if c == "a"
|
||||
then 10
|
||||
else if c == "b"
|
||||
then 11
|
||||
else if c == "c"
|
||||
then 12
|
||||
else if c == "d"
|
||||
then 13
|
||||
else if c == "e"
|
||||
then 14
|
||||
else if c == "f"
|
||||
then 15
|
||||
else lib.toInt c;
|
||||
byte = pos: d (builtins.substring pos 1 h) * 16 + d (builtins.substring (pos + 1) 1 h);
|
||||
ri = byte 0;
|
||||
gi = byte 2;
|
||||
bi = byte 4;
|
||||
r = ri * 1.0 / 255.0;
|
||||
g = gi * 1.0 / 255.0;
|
||||
b = bi * 1.0 / 255.0;
|
||||
mx =
|
||||
if r >= g && r >= b
|
||||
then "r"
|
||||
else if g >= b
|
||||
then "g"
|
||||
else "b";
|
||||
mn =
|
||||
if r <= g && r <= b
|
||||
then "r"
|
||||
else if g <= b
|
||||
then "g"
|
||||
else "b";
|
||||
cmax =
|
||||
if mx == "r"
|
||||
then r
|
||||
else if mx == "g"
|
||||
then g
|
||||
else b;
|
||||
cmin =
|
||||
if mn == "r"
|
||||
then r
|
||||
else if mn == "g"
|
||||
then g
|
||||
else b;
|
||||
delta = cmax - cmin;
|
||||
l = (cmax + cmin) / 2.0;
|
||||
s =
|
||||
if delta < 0.0001
|
||||
then 0.0
|
||||
else if l <= 0.5
|
||||
then delta / (cmax + cmin)
|
||||
else delta / (2.0 - cmax - cmin);
|
||||
hue =
|
||||
if delta < 0.0001
|
||||
then 0.0
|
||||
else if mx == "r"
|
||||
then let
|
||||
raw = 60.0 * (g - b) / delta;
|
||||
in
|
||||
if raw < 0.0
|
||||
then raw + 360.0
|
||||
else raw
|
||||
else if mx == "g"
|
||||
then 60.0 * ((b - r) / delta + 2.0)
|
||||
else 60.0 * ((r - g) / delta + 4.0);
|
||||
in "${toString (builtins.floor (hue + 0.5))} ${toString (builtins.floor (s * 100.0 + 0.5))} ${
|
||||
toString (builtins.floor (l * 100.0 + 0.5))
|
||||
}";
|
||||
|
||||
c = config.stylix.base16Scheme;
|
||||
in {
|
||||
# 0444 so the glance user inside the container can read the bind-mounted file
|
||||
sops.secrets.adguard-pwd.mode = "0444";
|
||||
|
||||
imports = [
|
||||
(mkContainer {
|
||||
name = "glance";
|
||||
hostIp = hostIp;
|
||||
containerIp = "10.233.12.2";
|
||||
internet = true;
|
||||
bindMounts."/run/secrets/adguard-pwd" = {
|
||||
hostPath = config.sops.secrets.adguard-pwd.path;
|
||||
isReadOnly = true;
|
||||
};
|
||||
nixosConfig = {lib, ...}: {
|
||||
_module.args.domain = domain;
|
||||
_module.args.adguardUrl = "http://${hostIp}:3000";
|
||||
imports = [
|
||||
./home.nix
|
||||
./server.nix
|
||||
];
|
||||
|
||||
services.glance = {
|
||||
enable = true;
|
||||
settings = {
|
||||
server = {
|
||||
port = 5678;
|
||||
host = "127.0.0.1";
|
||||
};
|
||||
theme = {
|
||||
light = false;
|
||||
background-color = hexToGlanceHsl c.base00; # background
|
||||
primary-color = hexToGlanceHsl c.base0D; # accent (iris/purple)
|
||||
positive-color = hexToGlanceHsl c.base0B; # positive (pine/teal)
|
||||
negative-color = hexToGlanceHsl c.base08; # negative (love/rose)
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
appendHttpConfig = ''
|
||||
proxy_cache_path /var/cache/nginx/glance levels=1:2 keys_zone=glance:1m inactive=30m max_size=100m;
|
||||
'';
|
||||
virtualHosts."glance" = {
|
||||
listen = [
|
||||
{
|
||||
addr = "0.0.0.0";
|
||||
port = 8080;
|
||||
}
|
||||
];
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:5678";
|
||||
extraConfig = ''
|
||||
proxy_cache glance;
|
||||
proxy_cache_valid 200 30m;
|
||||
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
|
||||
add_header X-Cache-Status $upstream_cache_status;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [8080];
|
||||
system.stateVersion = "24.05";
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
services.cloudflared.tunnels."${config.var.tunnelId}".ingress."home.${domain}" = "http://10.233.12.2:8080";
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
{domain, ...}: {
|
||||
services.glance.settings.pages = [
|
||||
{
|
||||
name = "Home";
|
||||
hide-desktop-navigation = false;
|
||||
columns = [
|
||||
{
|
||||
size = "small";
|
||||
widgets = [
|
||||
{
|
||||
type = "clock";
|
||||
hour-format = "24h";
|
||||
}
|
||||
{
|
||||
type = "weather";
|
||||
location = "Paris, France";
|
||||
}
|
||||
{
|
||||
type = "markets";
|
||||
markets = [
|
||||
{
|
||||
symbol = "BTC-USD";
|
||||
name = "Bitcoin";
|
||||
chart-link = "https://www.tradingview.com/chart/?symbol=INDEX:BTCUSD";
|
||||
}
|
||||
{
|
||||
symbol = "SOL-USD";
|
||||
name = "Solana";
|
||||
chart-link = "https://www.tradingview.com/chart/?symbol=INDEX:SOLUSD";
|
||||
}
|
||||
{
|
||||
symbol = "ETH-USD";
|
||||
name = "Ethereum";
|
||||
chart-link = "https://www.tradingview.com/chart/?symbol=INDEX:ETHUSD";
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
size = "full";
|
||||
widgets = [
|
||||
{
|
||||
type = "search";
|
||||
search-engine = "startpage";
|
||||
}
|
||||
{
|
||||
type = "group";
|
||||
widgets = [
|
||||
{
|
||||
type = "bookmarks";
|
||||
title = "Bookmarks";
|
||||
groups = [
|
||||
{
|
||||
title = "";
|
||||
same-tab = true;
|
||||
color = "245 50 64";
|
||||
links = [
|
||||
{
|
||||
title = "Mail";
|
||||
url = "https://mail.proton.me";
|
||||
}
|
||||
{
|
||||
title = "Drive";
|
||||
url = "https://drive.proton.me";
|
||||
}
|
||||
{
|
||||
title = "Lumo";
|
||||
url = "https://lumo.proton.me";
|
||||
}
|
||||
{
|
||||
title = "Calendar";
|
||||
url = "https://calendar.proton.me";
|
||||
}
|
||||
{
|
||||
title = "Maps";
|
||||
url = "https://maps.apple.com";
|
||||
}
|
||||
{
|
||||
title = "Amazon";
|
||||
url = "https://amazon.fr";
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
title = "Tools";
|
||||
same-tab = true;
|
||||
color = "245 50 64";
|
||||
links = [
|
||||
{
|
||||
title = "Excalidraw";
|
||||
url = "https://excalidraw.com";
|
||||
}
|
||||
{
|
||||
title = "Cobalt (downloader)";
|
||||
url = "https://cobalt.meowing.de";
|
||||
}
|
||||
{
|
||||
title = "Mazanoke (image downgrading)";
|
||||
url = "https://mazanoke.${domain}";
|
||||
}
|
||||
{
|
||||
title = "Stirling PDF";
|
||||
url = "https://pdf.${domain}";
|
||||
}
|
||||
{
|
||||
title = "Vert (file converter)";
|
||||
url = "https://vert.sh";
|
||||
}
|
||||
{
|
||||
title = "Markdown to pdf";
|
||||
url = "https://md2file.com";
|
||||
}
|
||||
{
|
||||
title = "Image to Vector";
|
||||
url = "https://www.vectorcascade.com/";
|
||||
}
|
||||
{
|
||||
title = "PrivateBin";
|
||||
url = "https://privatebin.net";
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
title = "Social";
|
||||
same-tab = true;
|
||||
color = "245 50 64";
|
||||
links = [
|
||||
{
|
||||
title = "Bsky";
|
||||
url = "https://bsky.app";
|
||||
}
|
||||
{
|
||||
title = "Reddit";
|
||||
url = "https://reddit.com";
|
||||
}
|
||||
{
|
||||
title = "Youtube";
|
||||
url = "https://youtube.com";
|
||||
}
|
||||
{
|
||||
title = "Instagram";
|
||||
url = "https://instagram.com";
|
||||
}
|
||||
{
|
||||
title = "Github";
|
||||
url = "https://github.com";
|
||||
}
|
||||
{
|
||||
title = "Discord";
|
||||
url = "https://discord.com/channels/@me/";
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
title = "Other";
|
||||
same-tab = true;
|
||||
color = "245 50 64";
|
||||
links = [
|
||||
{
|
||||
title = "Startpage config";
|
||||
url = "https://www.startpage.com/do/mypage.pl?prfe=45d331deb05471d659dba933e7400df51d952bb103da6f6125c0e769a6be1d65610456a479f495ceeee7e97311cf227d7c1bb198de0ceeb193d8cddf9c455c19a409cc35c3e3f542ee27bd7cecd3";
|
||||
}
|
||||
{
|
||||
title = "Hyprland Wiki";
|
||||
url = "https://wiki.hypr.land";
|
||||
}
|
||||
{
|
||||
title = "Search NixOS";
|
||||
url = "https://mynixos.com";
|
||||
}
|
||||
{
|
||||
title = "Nixpkgs";
|
||||
url = "https://github.com/NixOS/nixpkgs";
|
||||
}
|
||||
{
|
||||
title = "Claude";
|
||||
url = "https://claude.ai";
|
||||
}
|
||||
{
|
||||
title = "Gemini";
|
||||
url = "https://gemini.google.com";
|
||||
}
|
||||
{
|
||||
title = "Medium";
|
||||
url = "https://medium.com";
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
type = "bookmarks";
|
||||
title = "Infosec";
|
||||
groups = [
|
||||
{
|
||||
title = "";
|
||||
same-tab = true;
|
||||
color = "245 50 64";
|
||||
links = [
|
||||
{
|
||||
title = "Nix 4 Cyber";
|
||||
url = "https://n4c.${domain}";
|
||||
}
|
||||
{
|
||||
title = "Cyberchef";
|
||||
url = "https://cyberchef.${domain}";
|
||||
}
|
||||
{
|
||||
title = "TryHackMe";
|
||||
url = "https://tryhackme.com";
|
||||
}
|
||||
{
|
||||
title = "Root-Me";
|
||||
url = "https://root-me.org";
|
||||
}
|
||||
{
|
||||
title = "Exploit-DB";
|
||||
url = "https://exploit-db.com";
|
||||
}
|
||||
{
|
||||
title = "Crack Station";
|
||||
url = "https://crackstation.net";
|
||||
}
|
||||
{
|
||||
title = "Osint Tracker";
|
||||
url = "https://app.osintracker.com";
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
type = "hacker-news";
|
||||
limit = 15;
|
||||
collapse-after = 5;
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
{
|
||||
domain,
|
||||
adguardUrl,
|
||||
...
|
||||
}: {
|
||||
services.glance.settings.pages = [
|
||||
{
|
||||
name = "Server";
|
||||
hide-desktop-navigation = false;
|
||||
columns = [
|
||||
{
|
||||
size = "full";
|
||||
widgets = [
|
||||
{
|
||||
type = "server-stats";
|
||||
servers = [
|
||||
{
|
||||
type = "local";
|
||||
name = "Jack";
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
type = "group";
|
||||
widgets = [
|
||||
{
|
||||
type = "monitor";
|
||||
title = "Services";
|
||||
cache = "1m";
|
||||
sites = [
|
||||
{
|
||||
title = "Adguard";
|
||||
url = "https://adguard.${domain}";
|
||||
icon = "si:adguard";
|
||||
}
|
||||
{
|
||||
title = "Blog";
|
||||
url = "https://${domain}";
|
||||
icon = "si:blogger";
|
||||
}
|
||||
{
|
||||
title = "Gitea";
|
||||
url = "https://git.${domain}";
|
||||
icon = "si:gitea";
|
||||
}
|
||||
{
|
||||
title = "Mealie";
|
||||
url = "https://mealie.${domain}";
|
||||
icon = "si:mealie";
|
||||
}
|
||||
{
|
||||
title = "Umami";
|
||||
url = "https://umami.${domain}";
|
||||
icon = "si:umami";
|
||||
}
|
||||
{
|
||||
title = "Iknowyou";
|
||||
url = "https://iknowyou.${domain}";
|
||||
icon = "sh:iknowyou";
|
||||
}
|
||||
{
|
||||
title = "Iknowyou Prod";
|
||||
url = "https://iknowyou-prod.${domain}";
|
||||
icon = "sh:iknowyou";
|
||||
}
|
||||
{
|
||||
title = "Wallpapers";
|
||||
url = "https://wallpapers.${domain}";
|
||||
icon = "si:unsplash";
|
||||
}
|
||||
{
|
||||
title = "Mazanoke";
|
||||
url = "https://mazanoke.${domain}";
|
||||
icon = "sh:mazanoke";
|
||||
}
|
||||
{
|
||||
title = "Stirling PDF";
|
||||
url = "https://pdf.${domain}";
|
||||
icon = "sh:stirling-pdf";
|
||||
}
|
||||
{
|
||||
title = "Default-creds";
|
||||
url = "https://default-creds.${domain}";
|
||||
icon = "si:passbolt";
|
||||
}
|
||||
{
|
||||
title = "Cyberchef";
|
||||
url = "https://cyberchef.${domain}";
|
||||
icon = "si:codechef";
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
type = "monitor";
|
||||
title = "*arr";
|
||||
cache = "1m";
|
||||
sites = [
|
||||
{
|
||||
title = "Jellyfin";
|
||||
url = "https://media.${domain}";
|
||||
icon = "si:jellyfin";
|
||||
}
|
||||
{
|
||||
title = "Jellyseerr";
|
||||
url = "https://demandemedia.${domain}";
|
||||
icon = "si:odysee";
|
||||
}
|
||||
{
|
||||
title = "Radarr";
|
||||
url = "https://radarr.${domain}";
|
||||
icon = "si:radarr";
|
||||
}
|
||||
{
|
||||
title = "Sonarr";
|
||||
url = "https://sonarr.${domain}";
|
||||
icon = "si:sonarr";
|
||||
}
|
||||
{
|
||||
title = "Bazarr";
|
||||
url = "https://bazarr.${domain}";
|
||||
icon = "si:subtitleedit";
|
||||
}
|
||||
{
|
||||
title = "Prowlarr";
|
||||
url = "https://prowlarr.${domain}";
|
||||
icon = "si:podcastindex";
|
||||
}
|
||||
{
|
||||
title = "Transmission";
|
||||
url = "https://transmission.${domain}";
|
||||
icon = "si:transmission";
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
{
|
||||
type = "dns-stats";
|
||||
service = "adguard";
|
||||
url = adguardUrl;
|
||||
username = "hadi";
|
||||
password = "\${secret:adguard-pwd}";
|
||||
}
|
||||
|
||||
{
|
||||
type = "bookmarks";
|
||||
groups = [
|
||||
{
|
||||
title = "";
|
||||
same-tab = true;
|
||||
color = "245 50 64";
|
||||
links = [
|
||||
{
|
||||
title = "Router";
|
||||
url = "http://192.168.1.254/";
|
||||
}
|
||||
{
|
||||
title = "Cloudflare";
|
||||
url = "https://dash.cloudflare.com/";
|
||||
}
|
||||
{
|
||||
title = "Cloudflare Zero Trust";
|
||||
url = "https://one.dash.cloudflare.com/";
|
||||
}
|
||||
{
|
||||
title = "Cloudflare Access";
|
||||
url = "https://anotherhadi.cloudflareaccess.com";
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
{
|
||||
config,
|
||||
inputs,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (import ./mk-container.nix {inherit lib config;}) mkContainer;
|
||||
in {
|
||||
imports = [
|
||||
(mkContainer {
|
||||
name = "iky-prod";
|
||||
hostIp = "10.233.1.1";
|
||||
containerIp = "10.233.1.2";
|
||||
internet = true;
|
||||
bindMounts."/etc/iky/config.yaml" = {
|
||||
hostPath = "/var/lib/iknowyou-prod/config.yaml";
|
||||
isReadOnly = false;
|
||||
};
|
||||
nixosConfig = {...}: {
|
||||
imports = [inputs.iknowyou.nixosModules.default];
|
||||
users.users.iknowyou.uid = 999;
|
||||
users.groups.iknowyou.gid = 999;
|
||||
services.iknowyou = {
|
||||
enable = true;
|
||||
port = 8080;
|
||||
openFirewall = true;
|
||||
};
|
||||
system.stateVersion = "24.05";
|
||||
};
|
||||
})
|
||||
|
||||
(mkContainer {
|
||||
name = "iky-demo";
|
||||
hostIp = "10.233.2.1";
|
||||
containerIp = "10.233.2.2";
|
||||
nixosConfig = {...}: {
|
||||
imports = [inputs.iknowyou.nixosModules.default];
|
||||
services.iknowyou = {
|
||||
enable = true;
|
||||
port = 8080;
|
||||
openFirewall = true;
|
||||
};
|
||||
systemd.services.iknowyou.environment.IKY_DEMO = "true";
|
||||
system.stateVersion = "24.05";
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
users.users.iknowyou = {
|
||||
isSystemUser = true;
|
||||
group = "iknowyou";
|
||||
uid = 999;
|
||||
};
|
||||
users.groups.iknowyou.gid = 999;
|
||||
|
||||
systemd.tmpfiles.rules = [
|
||||
"f /var/lib/iknowyou-prod/config.yaml 0600 iknowyou iknowyou -"
|
||||
];
|
||||
|
||||
services.cloudflared.tunnels."${config.var.tunnelId}".ingress = {
|
||||
"iknowyou-prod.${config.var.domain}" = "http://10.233.1.2:8080";
|
||||
"iknowyou.${config.var.domain}" = "http://10.233.2.2:8080";
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
# Kernel hardening for the server
|
||||
{
|
||||
boot.kernel.sysctl = {
|
||||
# Restrict access to kernel logs and pointers
|
||||
"kernel.dmesg_restrict" = 1;
|
||||
"kernel.kptr_restrict" = 2;
|
||||
|
||||
# BPF hardening
|
||||
"net.core.bpf_jit_harden" = 2;
|
||||
"kernel.unprivileged_bpf_disabled" = 1;
|
||||
|
||||
# Reverse path filtering (anti-spoofing)
|
||||
"net.ipv4.conf.all.rp_filter" = 1;
|
||||
"net.ipv4.conf.default.rp_filter" = 1;
|
||||
|
||||
# SYN flood protection
|
||||
"net.ipv4.tcp_syncookies" = 1;
|
||||
|
||||
# Disable IP source routing
|
||||
"net.ipv4.conf.all.accept_source_route" = 0;
|
||||
"net.ipv4.conf.default.accept_source_route" = 0;
|
||||
|
||||
# Ignore ICMP redirects (prevent MITM)
|
||||
"net.ipv4.conf.all.accept_redirects" = 0;
|
||||
"net.ipv4.conf.default.accept_redirects" = 0;
|
||||
"net.ipv4.conf.all.secure_redirects" = 0;
|
||||
"net.ipv6.conf.all.accept_redirects" = 0;
|
||||
|
||||
# Don't send ICMP redirects
|
||||
"net.ipv4.conf.all.send_redirects" = 0;
|
||||
|
||||
# Restrict ptrace to parent processes only
|
||||
"kernel.yama.ptrace_scope" = 1;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (import ./mk-container.nix {inherit lib config;}) mkContainer;
|
||||
in {
|
||||
imports = [
|
||||
(mkContainer {
|
||||
name = "mazanoke";
|
||||
hostIp = "10.233.7.1";
|
||||
containerIp = "10.233.7.2";
|
||||
nixosConfig = {pkgs, ...}: let
|
||||
version = "1.1.5";
|
||||
mazanoke-pkg = pkgs.stdenv.mkDerivation {
|
||||
inherit version;
|
||||
pname = "mazanoke";
|
||||
src = pkgs.fetchFromGitHub {
|
||||
owner = "civilblur";
|
||||
repo = "mazanoke";
|
||||
rev = "v${version}";
|
||||
hash = "sha256-B/AF4diMNxN94BzpZP/C+K8kNj9q+4SDKWa/qd4LrVU=";
|
||||
};
|
||||
installPhase = ''
|
||||
mkdir -p $out/share/mazanoke
|
||||
cp -r ./index.html ./favicon.ico ./manifest.json ./service-worker.js ./assets $out/share/mazanoke/
|
||||
'';
|
||||
};
|
||||
in {
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
virtualHosts."mazanoke" = {
|
||||
root = "${mazanoke-pkg}/share/mazanoke";
|
||||
listen = [
|
||||
{
|
||||
addr = "0.0.0.0";
|
||||
port = 8080;
|
||||
}
|
||||
];
|
||||
locations."/" = {
|
||||
index = "index.html";
|
||||
};
|
||||
};
|
||||
};
|
||||
networking.firewall.allowedTCPPorts = [8080];
|
||||
system.stateVersion = "24.05";
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
services.cloudflared.tunnels."${config.var.tunnelId}".ingress."mazanoke.${config.var.domain}" = "http://10.233.7.2:8080";
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (import ./mk-container.nix {inherit lib config;}) mkContainer;
|
||||
in {
|
||||
imports = [
|
||||
(mkContainer {
|
||||
name = "mealie";
|
||||
hostIp = "10.233.8.1";
|
||||
containerIp = "10.233.8.2";
|
||||
internet = true;
|
||||
nixosConfig = {...}: {
|
||||
services.mealie = {
|
||||
enable = true;
|
||||
port = 8080;
|
||||
};
|
||||
networking.firewall.allowedTCPPorts = [8080];
|
||||
system.stateVersion = "24.05";
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
services.cloudflared.tunnels."${config.var.tunnelId}".ingress."mealie.${config.var.domain}" = "http://10.233.8.2:8080";
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
}:
|
||||
# Returns a NixOS module (attrset), to be used in `imports`.
|
||||
#
|
||||
# Options:
|
||||
# internet - allow outbound internet access via NAT (default: false)
|
||||
# externalInterface - WAN interface for NAT, required when internet = true
|
||||
# bindMounts - host paths to mount into the container (see containers.<name>.bindMounts)
|
||||
# config - NixOS module for the container
|
||||
let
|
||||
nginxHardening = {config, ...}:
|
||||
lib.mkIf config.services.nginx.enable {
|
||||
services.nginx.serverTokens = false;
|
||||
};
|
||||
in {
|
||||
mkContainer = {
|
||||
name,
|
||||
hostIp,
|
||||
containerIp,
|
||||
internet ? false,
|
||||
externalInterface ? config.var.networkInterface,
|
||||
bindMounts ? {},
|
||||
nixosConfig,
|
||||
}:
|
||||
assert lib.assertMsg (lib.stringLength "ve-${name}" <= 15)
|
||||
"mkContainer: interface name 've-${name}' is ${toString (lib.stringLength "ve-${name}")} chars, max is 15";
|
||||
{
|
||||
containers.${name} = {
|
||||
autoStart = true;
|
||||
privateNetwork = true;
|
||||
hostAddress = hostIp;
|
||||
localAddress = containerIp;
|
||||
inherit bindMounts;
|
||||
config = {...}: {
|
||||
imports = [
|
||||
nixosConfig
|
||||
nginxHardening
|
||||
];
|
||||
networking.nameservers = lib.mkIf internet [
|
||||
"1.1.1.1"
|
||||
"1.0.0.1"
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
// (lib.optionalAttrs internet {
|
||||
boot.kernel.sysctl."net.ipv4.ip_forward" = lib.mkDefault true;
|
||||
networking.nat = {
|
||||
enable = true;
|
||||
externalInterface = externalInterface;
|
||||
internalInterfaces = ["ve-${name}"];
|
||||
};
|
||||
# CONTAINER-FWD (defined by another module) blocks all forwarding by default.
|
||||
# Insert rules in FORWARD before it: allow return traffic, block LAN, allow internet.
|
||||
networking.firewall.extraCommands = ''
|
||||
iptables -I FORWARD 1 -s ${containerIp} -m conntrack --ctstate NEW -j ACCEPT
|
||||
iptables -I FORWARD 1 -s ${containerIp} -d 192.168.0.0/16 -j DROP
|
||||
iptables -I FORWARD 1 -s ${containerIp} -d 172.16.0.0/12 -j DROP
|
||||
iptables -I FORWARD 1 -s ${containerIp} -d 10.0.0.0/8 -j DROP
|
||||
iptables -I FORWARD 1 -d ${containerIp} -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
|
||||
'';
|
||||
networking.firewall.extraStopCommands = ''
|
||||
iptables -D FORWARD -s ${containerIp} -m conntrack --ctstate NEW -j ACCEPT 2>/dev/null || true
|
||||
iptables -D FORWARD -s ${containerIp} -d 192.168.0.0/16 -j DROP 2>/dev/null || true
|
||||
iptables -D FORWARD -s ${containerIp} -d 172.16.0.0/12 -j DROP 2>/dev/null || true
|
||||
iptables -D FORWARD -s ${containerIp} -d 10.0.0.0/8 -j DROP 2>/dev/null || true
|
||||
iptables -D FORWARD -d ${containerIp} -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || true
|
||||
'';
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
# SSH configuration
|
||||
{config, ...}: let
|
||||
username = config.var.username;
|
||||
in {
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
ports = [22];
|
||||
openFirewall = true;
|
||||
settings = {
|
||||
PermitRootLogin = "no";
|
||||
PasswordAuthentication = false;
|
||||
AllowUsers = [username];
|
||||
MaxAuthTries = 3;
|
||||
LoginGraceTime = 20;
|
||||
X11Forwarding = false;
|
||||
AllowAgentForwarding = false;
|
||||
AllowTcpForwarding = false;
|
||||
ClientAliveInterval = 300;
|
||||
ClientAliveCountMax = 2;
|
||||
KexAlgorithms = [
|
||||
"curve25519-sha256"
|
||||
"curve25519-sha256@libssh.org"
|
||||
];
|
||||
Ciphers = [
|
||||
"chacha20-poly1305@openssh.com"
|
||||
"aes256-gcm@openssh.com"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
# Add my public SSH key to my user
|
||||
users.users."${username}".openssh.authorizedKeys.keys = [
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPG9SE80ZyBcXZK/f5ypSKudaM5Jo3XtQikCnGo0jI5E hadi@nixy"
|
||||
];
|
||||
|
||||
services.cloudflared.tunnels."${config.var.tunnelId}".ingress."ssh.${config.var.domain}" = "ssh://localhost:22";
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (import ./mk-container.nix {inherit lib config;}) mkContainer;
|
||||
in {
|
||||
imports = [
|
||||
(mkContainer {
|
||||
name = "stirling-pdf";
|
||||
hostIp = "10.233.9.1";
|
||||
containerIp = "10.233.9.2";
|
||||
nixosConfig = {...}: {
|
||||
services.stirling-pdf = {
|
||||
enable = true;
|
||||
environment."SERVER_PORT" = "8080";
|
||||
};
|
||||
networking.firewall.allowedTCPPorts = [8080];
|
||||
system.stateVersion = "24.05";
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
services.cloudflared.tunnels."${config.var.tunnelId}".ingress."pdf.${config.var.domain}" = "http://10.233.9.2:8080";
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (import ./mk-container.nix {inherit lib config;}) mkContainer;
|
||||
in {
|
||||
sops.secrets.umami-secret.mode = "0400";
|
||||
|
||||
imports = [
|
||||
(mkContainer {
|
||||
name = "umami";
|
||||
hostIp = "10.233.10.1";
|
||||
containerIp = "10.233.10.2";
|
||||
bindMounts."/run/secrets/umami-secret" = {
|
||||
hostPath = config.sops.secrets.umami-secret.path;
|
||||
isReadOnly = true;
|
||||
};
|
||||
nixosConfig = {...}: {
|
||||
services.umami = {
|
||||
enable = true;
|
||||
settings = {
|
||||
PORT = 8080;
|
||||
HOSTNAME = "0.0.0.0";
|
||||
APP_SECRET_FILE = "/run/secrets/umami-secret";
|
||||
DISABLE_TELEMETRY = true;
|
||||
DISABLE_BOT_CHECK = true;
|
||||
};
|
||||
};
|
||||
# PrivateUsers breaks systemd-creds inside nspawn containers (nested user namespaces)
|
||||
systemd.services.umami.serviceConfig.PrivateUsers = lib.mkForce false;
|
||||
networking.firewall.allowedTCPPorts = [8080];
|
||||
system.stateVersion = "24.05";
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
services.cloudflared.tunnels."${config.var.tunnelId}".ingress."umami.${config.var.domain}" = "http://10.233.10.2:8080";
|
||||
}
|
||||
Reference in New Issue
Block a user