This commit is contained in:
ashisgreat22 2026-03-21 20:23:32 +00:00
parent ad55793d41
commit 6b64254eab
11 changed files with 155 additions and 12 deletions

View file

@ -185,12 +185,18 @@ in
iptables -t nat -D PREROUTING -i tailscale0 -p tcp --dport 53 -j REDIRECT --to-ports 5353 || true
'';
# Nginx reverse proxy for AdGuard Home Web UI and DoH
# Nginx reverse proxy for AdGuard Home Web UI and DoH (Tailscale only)
myModules.nginx.domains."${cfg.domain}" = {
port = cfg.port;
internalOnly = true; # Restrict access to Tailscale network and localhost only
contentSecurityPolicy = null; # AdGuard Home handles its own CSP
};
# Allow direct Tailscale access to AdGuard Home dashboard
networking.firewall.extraCommands = lib.mkAfter ''
iptables -I ts-input 3 -p tcp --dport ${toString cfg.port} -s 100.64.0.0/10 -j ACCEPT
'';
# Ensure nginx user can access ACME certs
users.users.nginx.extraGroups = [ "acme" ];
};

View file

@ -67,7 +67,7 @@
enable = true;
database.type = "postgres";
customDir = toString (pkgs.copyPathToStore ../custom);
customDir = "/var/lib/forgejo/custom";
settings = {
server = {
DOMAIN = cfg.domain;
@ -116,6 +116,13 @@
config.services.forgejo.stateDir
];
# Copy branding assets to custom directory (Forgejo serves from /assets/img/)
systemd.tmpfiles.rules = [
"d /var/lib/forgejo/custom/public/assets/img 0755 forgejo forgejo -"
"C+ /var/lib/forgejo/custom/public/assets/img/logo.svg - - - - ${toString ../custom/public/assets/img/logo.svg}"
"C+ /var/lib/forgejo/custom/public/assets/img/favicon.svg - - - - ${toString ../custom/public/assets/img/favicon.svg}"
];
services.gitea-actions-runner = lib.mkIf cfg.runner.enable {
package = pkgs.forgejo-runner;
instances.default = {

View file

@ -56,7 +56,7 @@ in
# Allow direct Tailscale access to Netdata port
networking.firewall.extraCommands = lib.mkAfter ''
iptables -I INPUT 1 -p tcp --dport ${toString cfg.port} -s 100.64.0.0/10 -j ACCEPT
iptables -I ts-input 3 -p tcp --dport ${toString cfg.port} -s 100.64.0.0/10 -j ACCEPT
'';
};

View file

@ -89,6 +89,10 @@
};
};
websockets = {
enable = lib.mkEnableOption "WebSocket proxy support for this domain";
};
extraLocations = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule {
options = {
@ -135,6 +139,12 @@
commonHttpConfig = lib.optionalString cfg.rateLimit.enable ''
limit_req_zone $binary_remote_addr zone=global:10m rate=${toString cfg.rateLimit.requests}r/s;
limit_conn_zone $binary_remote_addr zone=connlimit:10m;
''
+ ''
map $http_upgrade $connection_upgrade {
default upgrade;
''' close;
}
'';
virtualHosts = lib.mapAttrs' (domain: opts: {
@ -161,7 +171,13 @@
locations = {
"/" = {
proxyPass = "http://127.0.0.1:${toString opts.port}";
extraConfig = opts.extraConfig + lib.optionalString (if opts.rateLimit.enable != null then
extraConfig = opts.extraConfig
+ lib.optionalString opts.websockets.enable ''
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
''
+ lib.optionalString (if opts.rateLimit.enable != null then
opts.rateLimit.enable else cfg.rateLimit.enable) ''
limit_req zone=global burst=${toString (if opts.rateLimit.burst != null then opts.rateLimit.burst
else cfg.rateLimit.burst)} nodelay;

View file

@ -50,6 +50,7 @@ in
environment = {
OLLAMA_API_BASE_URL = cfg.ollamaUrl;
WEBUI_URL = "https://${cfg.domain}";
OPENAI_API_BASE_URL = "https://api.tng-chimera.ai/v1/";
};
environmentFile = config.sops.templates."openwebui.env".path;
};
@ -58,10 +59,12 @@ in
sops.templates."openwebui.env" = {
content = ''
WEBUI_SECRET_KEY=${config.sops.placeholder.openwebui_secret_key}
OPENAI_API_KEY=${config.sops.placeholder.tng_api_key}
'';
};
sops.secrets.openwebui_secret_key = { };
sops.secrets.tng_api_key = { };
# Nginx configuration
myModules.nginx.domains.${cfg.domain} = {
@ -69,8 +72,12 @@ in
extraConfig = ''
client_max_body_size 100M;
'';
# Disable rate limiting for OpenWebUI (loads many assets at once)
rateLimit.enable = false;
# Enable WebSocket support for Socket.IO
websockets.enable = true;
# Relaxed CSP for OpenWeb UI — needs unsafe-eval for some JS, WebSockets, external images
contentSecurityPolicy = "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' wss: https:; frame-ancestors 'self'";
contentSecurityPolicy = "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' wss: https: ws:; frame-ancestors 'self'";
};
};
}

View file

@ -52,6 +52,7 @@ in
# Create directory for OpenClaw data
systemd.tmpfiles.rules = [
"d /var/lib/openclaw 0755 1000 1000 -" # Assuming node user is uid 1000
"d /var/lib/openclaw/local 0755 1000 1000 -" # For Go toolchain
];
# OpenClaw container (bridge network — isolated from host services)
@ -63,6 +64,7 @@ in
];
volumes = [
"/var/lib/openclaw:/home/node/.openclaw"
"/var/lib/openclaw/local:/home/node/.local"
] ++ lib.optionals cfg.superpowers.enable [
"${cfg.superpowers.src}:/home/node/superpowers-src:ro"
];
@ -71,7 +73,7 @@ in
# Copy the declarative config before starting the container
# This allows OpenClaw to safely write/rename the file at runtime without EBUSY errors
systemd.services."podman-openclaw".preStart = lib.mkBefore ''
mkdir -p /var/lib/openclaw
mkdir -p /var/lib/openclaw/local
cp -f ${./openclaw-config.json} /var/lib/openclaw/openclaw.json
chown -R 1000:1000 /var/lib/openclaw
chmod -R u+rwX /var/lib/openclaw
@ -100,13 +102,56 @@ in
''}
'';
# Go toolchain installation script
# Stored in /var/lib/openclaw and executed inside the container
environment.etc."openclaw/install-go.sh".source = pkgs.writeScript "install-go.sh" ''
#!/bin/bash
set -e
GO_URL="https://go.dev/dl/go1.24.1.linux-amd64.tar.gz"
GO_DIR="/home/node/.local/go"
if [ -d "$GO_DIR" ]; then
echo "Go already installed at $GO_DIR"
exit 0
fi
echo "Installing Go toolchain"
mkdir -p /home/node/.local
if command -v curl &> /dev/null; then
curl -fsSL "$GO_URL" | tar -C /home/node/.local -xzf -
elif command -v wget &> /dev/null; then
wget -qO- "$GO_URL" | tar -C /home/node/.local -xzf -
else
echo "ERROR - Neither curl nor wget available"
exit 1
fi
echo "Go installed successfully"
"$GO_DIR/bin/go" version
'';
# Go toolchain installation
# Downloads Go to a persistent volume for use inside the container
systemd.services."openclaw-go-setup" = {
description = "Install Go toolchain for OpenClaw";
after = [ "podman-openclaw.service" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";
# Copy script to container-accessible location, then execute
ExecStart = "${pkgs.bash}/bin/bash -c 'cp /etc/openclaw/install-go.sh /var/lib/openclaw/ && chmod +x /var/lib/openclaw/install-go.sh && ${pkgs.podman}/bin/podman exec -u node openclaw /home/node/.openclaw/install-go.sh'";
RemainAfterExit = true;
};
};
# Optional: Install PyYAML inside the container on startup
# We do this as a postStart or a simple background loop if needed,
# but a better way is to ensure the image has it.
# We do this as a postStart or a simple background loop if needed,
# but a better way is to ensure the image has it.
# Since we can't easily change the image here, we'll try to run a one-time pip install.
systemd.services."openclaw-superpowers-setup" = lib.mkIf cfg.superpowers.enable {
description = "One-time setup for OpenClaw superpowers (PyYAML and Cron)";
after = [ "podman-openclaw.service" ];
after = [ "podman-openclaw.service" "openclaw-go-setup.service" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";

View file

@ -28,5 +28,11 @@ in
# Give main user access to podman
users.users.${mainUser}.extraGroups = [ "podman" ];
# Enable IP forwarding for container networking
boot.kernel.sysctl = {
"net.ipv4.ip_forward" = 1;
"net.ipv6.conf.all.forwarding" = 1;
};
};
}