Compare commits

..

No commits in common. "042820fb2a88c46389e477abf5181b78d02222a3" and "66928072293bf73596690d578ec6f3be6675ebe9" have entirely different histories.

8 changed files with 53 additions and 97 deletions

View file

@ -0,0 +1,9 @@
{
"permissions": {
"allow": [
"WebSearch",
"WebFetch(domain:forgejo.org)",
"Bash(ssh:*)"
]
}
}

1
.gitignore vendored
View file

@ -1,4 +1,3 @@
*.qcow2
result
.direnv
.claude

View file

@ -12,19 +12,13 @@ creation_rules:
key_groups:
- age:
- *desktop
# Shared secrets (desktop + server)
- path_regex: secrets/system/llama\.yaml$ # llama.cpp API key
key_groups:
- age:
- *desktop
- *server
# Server secrets (cameras)
- path_regex: secrets/system/cameras\.yaml$ # RTSP Feed
key_groups:
- age:
- *server
# Server secrets (searxng)
- path_regex: secrets/system/searxng\.yaml$ # searxng token
- path_regex: secrets/system/searxng\.yaml$
key_groups:
- age:
- *server

View file

@ -1,25 +0,0 @@
LLAMA_API_KEY: ENC[AES256_GCM,data:ZVDpwGAxnHbHxt+JW3mYGyyBU5JfFAbjc/byq6Ok9wTlpQZBx969Z0wV74F5pR4axmpdGs7XlZDh1rJaQTn7lg==,iv:oAG9G25x+1FRkRNBRzLW2UJmbSxgx5Cu64Qo/6VzAyw=,tag:nkO/SdzjjLxH4fkgIdwUYQ==,type:str]
sops:
age:
- recipient: age17ejyzyk52unr6eyaa9rpunxpmf7u9726v6sx7me3ww3mdu5xzgjqsgj9gl
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBzUmV6Q2dCMWU3TUFkZ0I0
dHA3dXd2U0RSRzNtL3YvdG8rYWdnOTZoTkMwCkNnYnVlVmMyRDNnS1FmWktlNU9N
UW1OMlJYODVzSHNIZWZMRkpPY05Ed3cKLS0tIDg0b0VkT0NrS3NIWE9EdWtWYXc1
NjNESHpYbVptcnVRYWFKb3RlYkJ6OWMK3JsRXPDvJdKv2UyYIH8kr/WKbXgUDXbc
fYOD0Huo73BA0vr8PlrsF4STVgJr/arKCMdI1C0bDdcwjExKnR1tIw==
-----END AGE ENCRYPTED FILE-----
- recipient: age198jg29ryg3c0qj3yg6y9ha4ce2ue4hjdaa9kalf49fxju74dhchsquvjzp
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBFTGNKOWczaityaXowWi9I
dmh0MjJoelV3bVlzeGpLZmVTVzJjckwwQUFzCk81ZHlTcm5oWHRQNklreUR4bWNS
OVdQelQ4YXkzeWZqOWZoNWlOVkZpWUkKLS0tIDZKQUU3LzV0UUhnRHVHQkFadkxm
djRyUEYyZ2srMlVxR0JtQlFqSWV1QWcKMIF9Sq4TUUmpVZAukjTjFbIrMxcE3+el
QSrHIm1HXLXwCKLDQ2N6b8Q9iUo/XMV0wsD3TLxdnUfegpQpfsDhag==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2026-04-14T05:45:37Z"
mac: ENC[AES256_GCM,data:G+o6OhNF5AFBDKQEU3f1MZ+GOkxQj/m7NNk4Ti8PxPPOHdByoCrauvgB78SdQf5ubcfupElcNB0yF5QsG3/m7eGaSA+8J0cDL6jB3NEE5EUbW1Fuzzg2Ez1JnFu4BstkLiDRD/TribXMNFAjykmNrHt4zee6fhU3H0MOn7+Acok=,iv:IqBLSBq1kOMRHQn1IvU8OgmWGn6EFJcef/rNr38txmY=,tag:/mSWgbPbhUNoIm3x+6zyRA==,type:str]
unencrypted_suffix: _unencrypted
version: 3.12.1

View file

@ -5,10 +5,6 @@ let
(user: user.modules.user.security.gpg.enable or false)
(lib.attrValues config.home-manager.users);
devEnabled = lib.any
(user: user.modules.user.utils.dev.enable or false)
(lib.attrValues config.home-manager.users);
sysModules = config.modules.system;
in
@ -23,11 +19,6 @@ in
"WIFI_HOME_PSK" = wifi;
"WIFI_CAMS_SSID" = wifi;
"WIFI_CAMS_PSK" = wifi;
} // lib.optionalAttrs devEnabled {
"LLAMA_API_KEY" = {
sopsFile = ../../../secrets/system/llama.yaml;
owner = config.user.name;
};
};
sops.templates."wifi-env".content = ''

View file

@ -22,6 +22,7 @@ in
'';
};
searxng.enable = mkEnableOption "Publicly exposed SearXNG endpoint with secret path via sops";
};
config = mkIf cfg.enable {
@ -91,6 +92,17 @@ in
};
};
virtualHosts."test.${domain}" = {
useACMEHost = domain;
forceSSL = true;
locations."/" = {
return = "200 'nginx is working'";
extraConfig = ''
add_header Content-Type text/plain;
'';
};
};
virtualHosts."wg.${domain}" = {
useACMEHost = domain;
forceSSL = true;
@ -104,49 +116,32 @@ in
};
};
virtualHosts."ai.${domain}" = let
apiKeyAuth = ''
set $api_key "";
if ($http_authorization ~* "^Bearer (.+)$") {
set $api_key $1;
}
if ($api_key = "") {
return 401 '{"error": "Missing Authorization header"}';
}
include ${config.sops.templates."nginx-ai-auth.conf".path};
'';
in {
virtualHosts."searxng.${domain}" = mkIf cfg.searxng.enable {
useACMEHost = domain;
forceSSL = true;
locations."/".return = "404";
extraConfig = ''
include ${config.sops.templates."nginx-searxng-location.conf".path};
'';
};
# Web UI + llama.cpp API (browser, /v1/* calls from the UI)
# Auth handled by llama.cpp itself (--api-key flag)
virtualHosts."chat.${domain}" = {
useACMEHost = domain;
forceSSL = true;
locations."/" = {
proxyPass = "http://192.168.0.23:3080";
proxyWebsockets = true;
extraConfig = privateAccessRules;
};
};
virtualHosts."ai.${domain}" = {
useACMEHost = domain;
forceSSL = true;
locations."/" = {
proxyPass = "http://192.168.0.23:8000";
proxyWebsockets = true;
};
# Llama Stack API (opencode, programmatic clients)
# Clients use baseURL: https://ai.ramos.codes/stack/v1
locations."/stack/v1/" = {
proxyPass = "http://192.168.0.23:8321/v1/";
proxyWebsockets = true;
extraConfig = apiKeyAuth + ''
proxy_read_timeout 300s;
proxy_send_timeout 300s;
'';
};
# MCP servers (namespaced, for llama.cpp web UI + direct access)
locations."/mcp/web_search/" = {
proxyPass = "http://192.168.0.23:8002/";
proxyWebsockets = true;
extraConfig = ''
include ${config.sops.templates."nginx-mcp-auth.conf".path};
proxy_read_timeout 300s;
proxy_send_timeout 300s;
'';
};
};
virtualHosts."comfy.${domain}" = {

View file

@ -9,28 +9,20 @@
# Camera RTSP credentials (used by frigate/go2rtc)
sops.secrets = let
cameras = { sopsFile = ../../../secrets/system/cameras.yaml; };
llama = { sopsFile = ../../../secrets/system/llama.yaml; };
searxng = { sopsFile = ../../../secrets/system/searxng.yaml; };
in {
"RTSP_USER" = cameras;
"RTSP_PASS" = cameras;
"LLAMA_API_KEY" = llama // { owner = config.user.name; };
"SEARXNG_TOKEN" = searxng;
};
# API key auth for ai.ramos.codes — nginx validates Bearer token against sops secret
sops.templates."nginx-ai-auth.conf" = {
sops.templates."nginx-searxng-location.conf" = {
content = ''
if ($api_key != "${config.sops.placeholder."LLAMA_API_KEY"}") {
return 401 '{"error": "Invalid API key"}';
}
'';
owner = "nginx";
};
# MCP endpoint auth — validates X-API-Key header
sops.templates."nginx-mcp-auth.conf" = {
content = ''
if ($http_x_api_key != "${config.sops.placeholder."LLAMA_API_KEY"}") {
return 401 '{"error": "Unauthorized"}';
location /${config.sops.placeholder."SEARXNG_TOKEN"}/ {
proxy_pass http://192.168.0.23:8080/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
'';
owner = "nginx";
@ -39,6 +31,7 @@
modules.system = {
nginx = {
enable = true;
searxng.enable = true;
};
sandpack.enable = true;
forgejo.enable = true;

View file

@ -30,9 +30,9 @@ in
];
programs = {
bash = {
initExtra = "export LLAMA_API_KEY=$(cat /run/secrets/LLAMA_API_KEY)";
};
#bash = {
# initExtra = import ./config/penpot.nix;
#};
direnv = {
enable = true;
enableBashIntegration = true;