303 lines
No EOL
11 KiB
Nix
303 lines
No EOL
11 KiB
Nix
# SearXNG Module (Rootless Podman)
|
|
# Provides: Private meta-search engine running in a rootless container
|
|
#
|
|
# Usage:
|
|
# myModules.searxng = {
|
|
# enable = true;
|
|
# port = 8888;
|
|
# domain = "search.ashisgreat.xyz";
|
|
# };
|
|
|
|
{
|
|
config,
|
|
lib,
|
|
pkgs,
|
|
...
|
|
}:
|
|
|
|
let
|
|
cfg = config.myModules.searxng;
|
|
|
|
catppuccinCss = pkgs.writeText "searxng-catppuccin.css" ''
|
|
:root {
|
|
/* Mocha (Dark) */
|
|
--cat-rosewater: #f5e0dc;
|
|
--cat-flamingo: #f2cdcd;
|
|
--cat-pink: #f5c2e7;
|
|
--cat-mauve: #cba6f7;
|
|
--cat-red: #f38ba8;
|
|
--cat-maroon: #eba0ac;
|
|
--cat-peach: #fab387;
|
|
--cat-yellow: #f9e2af;
|
|
--cat-green: #a6e3a1;
|
|
--cat-teal: #94e2d5;
|
|
--cat-sky: #89dceb;
|
|
--cat-sapphire: #74c7ec;
|
|
--cat-blue: #89b4fa;
|
|
--cat-lavender: #b4befe;
|
|
--cat-text: #cdd6f4;
|
|
--cat-subtext1: #bac2de;
|
|
--cat-subtext0: #a6adc8;
|
|
--cat-overlay2: #9399b2;
|
|
--cat-overlay1: #7f849c;
|
|
--cat-overlay0: #6c7086;
|
|
--cat-surface2: #585b70;
|
|
--cat-surface1: #45475a;
|
|
--cat-surface0: #313244;
|
|
--cat-base: #1e1e2e;
|
|
--cat-mantle: #181825;
|
|
--cat-crust: #11111b;
|
|
}
|
|
|
|
@media (prefers-color-scheme: light) {
|
|
:root {
|
|
/* Latte (Light) */
|
|
--cat-rosewater: #dc8a78;
|
|
--cat-flamingo: #dd7878;
|
|
--cat-pink: #ea76cb;
|
|
--cat-mauve: #8839ef;
|
|
--cat-red: #d20f39;
|
|
--cat-maroon: #e64553;
|
|
--cat-peach: #fe640b;
|
|
--cat-yellow: #df8e1d;
|
|
--cat-green: #40a02b;
|
|
--cat-teal: #179287;
|
|
--cat-sky: #04a5e5;
|
|
--cat-sapphire: #209fb5;
|
|
--cat-blue: #1e66f5;
|
|
--cat-lavender: #7287fd;
|
|
--cat-text: #4c4f69;
|
|
--cat-subtext1: #5c5f77;
|
|
--cat-subtext0: #6c6f85;
|
|
--cat-overlay2: #7c7f93;
|
|
--cat-overlay1: #8c8fa1;
|
|
--cat-overlay0: #9ca0b0;
|
|
--cat-surface2: #acb0be;
|
|
--cat-surface1: #bcc0cc;
|
|
--cat-surface0: #ccd0da;
|
|
--cat-base: #eff1f5;
|
|
--cat-mantle: #e6e9ef;
|
|
--cat-crust: #dce0e8;
|
|
}
|
|
}
|
|
|
|
/* Apply variables */
|
|
:root {
|
|
--color-base-font: var(--cat-text);
|
|
--color-base-background: var(--cat-base);
|
|
--color-base-background-mobile: var(--cat-base);
|
|
--color-url-font: var(--cat-mauve);
|
|
--color-url-visited-font: var(--cat-mauve);
|
|
--color-header-background: var(--cat-mantle);
|
|
--color-header-border: var(--cat-mantle);
|
|
--color-footer-background: var(--cat-mantle);
|
|
--color-footer-border: var(--cat-mantle);
|
|
--color-sidebar-border: var(--cat-base);
|
|
--color-sidebar-font: var(--cat-text);
|
|
--color-sidebar-background: var(--cat-base);
|
|
--color-backtotop-font: var(--cat-subtext1);
|
|
--color-backtotop-border: var(--cat-surface0);
|
|
--color-backtotop-background: var(--cat-surface0);
|
|
--color-btn-background: var(--cat-mauve);
|
|
--color-btn-font: var(--cat-base);
|
|
--color-show-btn-background: var(--cat-mauve);
|
|
--color-show-btn-font: var(--cat-base);
|
|
--color-search-border: var(--cat-surface0);
|
|
--color-search-shadow: 0 2px 8px var(--cat-crust);
|
|
--color-search-background: var(--cat-surface0);
|
|
--color-search-font: var(--cat-text);
|
|
--color-search-background-hover: var(--cat-mauve);
|
|
--color-error: var(--cat-red);
|
|
--color-error-background: var(--cat-surface0);
|
|
--color-warning: var(--cat-yellow);
|
|
--color-warning-background: var(--cat-surface0);
|
|
--color-success: var(--cat-green);
|
|
--color-success-background: var(--cat-surface0);
|
|
--color-categories-item-selected-font: var(--cat-text);
|
|
--color-categories-item-border-selected: var(--cat-mauve);
|
|
--color-autocomplete-font: var(--cat-subtext1);
|
|
--color-autocomplete-border: var(--cat-surface0);
|
|
--color-autocomplete-shadow: 0 2px 8px var(--cat-crust);
|
|
--color-autocomplete-background: var(--cat-surface0);
|
|
--color-autocomplete-background-hover: var(--cat-surface1);
|
|
--color-answer-font: var(--cat-text);
|
|
--color-answer-background: var(--cat-mantle);
|
|
--color-result-background: var(--cat-mantle);
|
|
--color-result-border: var(--cat-base);
|
|
--color-result-url-font: var(--cat-subtext1);
|
|
--color-result-vim-selected: var(--cat-surface0);
|
|
--color-result-vim-arrow: var(--cat-mauve);
|
|
--color-result-description-highlight-font: var(--cat-text);
|
|
--color-result-link-font: var(--cat-mauve);
|
|
--color-result-link-font-highlight: var(--cat-mauve);
|
|
--color-result-link-visited-font: var(--cat-mauve);
|
|
--color-result-publishdate-font: var(--cat-surface2);
|
|
--color-result-engines-font: var(--cat-surface2);
|
|
--color-result-search-url-border: var(--cat-surface2);
|
|
--color-result-search-url-font: var(--cat-text);
|
|
--color-result-detail-font: var(--cat-text);
|
|
--color-result-detail-label-font: var(--cat-subtext0);
|
|
--color-result-detail-background: var(--cat-base);
|
|
--color-result-detail-hr: var(--cat-base);
|
|
--color-result-detail-link: var(--cat-mauve);
|
|
--color-result-detail-loader-border: rgba(255, 255, 255, 0.2);
|
|
--color-result-detail-loader-borderleft: var(--cat-crust);
|
|
--color-result-image-span-font: var(--cat-text);
|
|
--color-result-image-span-font-selected: var(--cat-base);
|
|
--color-result-image-background: var(--cat-mantle);
|
|
--color-settings-tr-hover: var(--cat-surface0);
|
|
--color-settings-engine-description-font: var(--cat-text);
|
|
--color-settings-engine-group-background: var(--cat-surface0);
|
|
--color-toolkit-badge-font: var(--cat-text);
|
|
--color-toolkit-badge-background: var(--cat-surface0);
|
|
--color-toolkit-kbd-font: var(--cat-text);
|
|
--color-toolkit-kbd-background: var(--cat-mantle);
|
|
--color-toolkit-dialog-border: var(--cat-mantle);
|
|
--color-toolkit-dialog-background: var(--cat-mantle);
|
|
--color-toolkit-tabs-label-border: var(--cat-base);
|
|
--color-toolkit-tabs-section-border: var(--cat-base);
|
|
--color-toolkit-select-background: var(--cat-surface0);
|
|
--color-toolkit-select-border: var(--cat-surface0);
|
|
--color-toolkit-select-background-hover: var(--cat-surface1);
|
|
--color-toolkit-input-text-font: var(--cat-text);
|
|
--color-toolkit-checkbox-onoff-off-background: var(--cat-surface0);
|
|
--color-toolkit-checkbox-onoff-on-background: var(--cat-surface0);
|
|
--color-toolkit-checkbox-onoff-on-mark-background: var(--cat-green);
|
|
--color-toolkit-checkbox-onoff-on-mark-color: var(--cat-mantle);
|
|
--color-toolkit-checkbox-onoff-off-mark-background: var(--cat-red);
|
|
--color-toolkit-checkbox-onoff-off-mark-color: var(--cat-mantle);
|
|
--color-toolkit-checkbox-label-background: var(--cat-base);
|
|
--color-toolkit-checkbox-label-border: var(--cat-mantle);
|
|
--color-toolkit-checkbox-input-border: var(--cat-mauve);
|
|
--color-toolkit-engine-tooltip-border: var(--cat-surface0);
|
|
--color-toolkit-engine-tooltip-background: var(--cat-surface0);
|
|
--color-toolkit-loader-border: rgba(255, 255, 255, 0.2);
|
|
--color-toolkit-loader-borderleft: var(--cat-crust);
|
|
--color-doc-code: var(--cat-rosewater);
|
|
--color-doc-code-background: var(--cat-mantle);
|
|
}
|
|
|
|
#search_logo svg :not([fill="none"]) {
|
|
fill: var(--cat-mauve) !important;
|
|
}
|
|
#search_logo svg :not([stroke="none"]) {
|
|
stroke: var(--cat-mauve) !important;
|
|
}
|
|
|
|
/* Additional cute tweaks */
|
|
article.result {
|
|
background-color: var(--color-result-background);
|
|
border-radius: 0.75em;
|
|
padding: 0.75em;
|
|
margin: 0.5em;
|
|
border: 1px solid var(--cat-surface0);
|
|
}
|
|
article.category-images {
|
|
padding-bottom: 4em;
|
|
}
|
|
input[type="text"] {
|
|
border-radius: 2em !important;
|
|
}
|
|
'';
|
|
in
|
|
{
|
|
options.myModules.searxng = {
|
|
enable = lib.mkEnableOption "SearXNG meta-search engine";
|
|
|
|
port = lib.mkOption {
|
|
type = lib.types.port;
|
|
default = 8888;
|
|
description = "Port to expose SearXNG on localhost";
|
|
};
|
|
|
|
domain = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "search.ashisgreat.xyz";
|
|
description = "Public domain name for SearXNG";
|
|
};
|
|
};
|
|
|
|
config = lib.mkIf cfg.enable {
|
|
# Ensure Podman is enabled
|
|
myModules.podman.enable = true;
|
|
|
|
# 1. Redis Container (Cache/Limiter)
|
|
virtualisation.oci-containers.containers."searxng-redis" = {
|
|
image = "docker.io/library/redis:alpine";
|
|
cmd = [ "redis-server" "--save" "" "--appendonly" "no" ]; # Ephemeral cache, no persistence needed
|
|
ports = [ "127.0.0.1:6379:6379" ];
|
|
};
|
|
|
|
# 2. SearXNG Container
|
|
virtualisation.oci-containers.containers."searxng" = {
|
|
image = "docker.io/searxng/searxng:latest";
|
|
ports = [ "127.0.0.1:${toString cfg.port}:8080" ];
|
|
environment = {
|
|
"SEARXNG_BASE_URL" = "https://${cfg.domain}";
|
|
"SEARXNG_REDIS_URL" = "redis://searxng-redis:6379"; # Talk to Redis directly via container DNS
|
|
"SEARXNG_URL_BASE" = "https://${cfg.domain}";
|
|
};
|
|
environmentFiles = [
|
|
# Contains SEARXNG_SECRET_KEY
|
|
config.sops.templates."searxng.env".path
|
|
];
|
|
extraOptions = [
|
|
"--cap-drop=ALL"
|
|
"--cap-add=CHOWN"
|
|
"--cap-add=SETGID"
|
|
"--cap-add=SETUID"
|
|
"--cap-add=DAC_OVERRIDE"
|
|
"--add-host=host.containers.internal:host-gateway"
|
|
];
|
|
volumes = [
|
|
"${config.sops.templates."searxng_settings.yml".path}:/etc/searxng/settings.yml:ro"
|
|
"${catppuccinCss}:/etc/searxng/custom.css:ro"
|
|
];
|
|
};
|
|
|
|
# 3. Secrets Configuration
|
|
# We generate the settings.yml dynamically using sops templates to inject secrets if needed,
|
|
# or just to manage the config declaratively.
|
|
sops.templates."searxng.env".content = ''
|
|
SEARXNG_SECRET_KEY=${config.sops.placeholder.searxng_secret_key}
|
|
'';
|
|
|
|
sops.templates."searxng_settings.yml".content = ''
|
|
use_default_settings: true
|
|
|
|
general:
|
|
debug: false
|
|
instance_name: "Ashie Search"
|
|
donations:
|
|
patreon: false
|
|
buymeacoffee: false
|
|
|
|
search:
|
|
safe_search: 0
|
|
autocomplete: "google"
|
|
default_lang: "en-US"
|
|
formats:
|
|
- html
|
|
- json
|
|
|
|
server:
|
|
port: 8080
|
|
bind_address: "0.0.0.0"
|
|
secret_key: "${config.sops.placeholder.searxng_secret_key}"
|
|
limiter: true
|
|
image_proxy: true
|
|
|
|
ui:
|
|
static_use_hash: true
|
|
custom_css: custom.css
|
|
theme_args:
|
|
simple_style: "auto"
|
|
|
|
redis:
|
|
url: redis://searxng-redis:6379/0
|
|
'';
|
|
|
|
# Placeholder secret definition (User must add this to secrets.yaml!)
|
|
sops.secrets.searxng_secret_key = { };
|
|
};
|
|
} |