feat: add searxng and factorio (#112)

* Create searxng.nix

* fix: folers

* factorio wip

* fix: remove stale locks

* feat: factorio and saerx

---------

Co-authored-by: Truxnell <9149206+truxnell@users.noreply.github.com>
This commit is contained in:
Truxnell 2024-04-20 21:24:13 +10:00 committed by GitHub
parent e3d3e338b6
commit f4ad1d51f4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 206 additions and 23 deletions

View file

@ -2,7 +2,7 @@
Nightly Backups are facilitated by NixOS's module for [restic](https://search.nixos.org/options?channel=23.11&from=0&size=50&sort=relevance&type=packages&query=services.restic.) module and a helper module ive written.
This does a nightly ZFS snapshot, in which apps and other mutable data is restic backed up to both a local folder on my NAS and also to Cloudflare R2 :octicons-info-16:{ title="R2 mainly due to the cheap cost and low egrees fees" }). Backing up from a ZFS snapshot ensures that the restic backup is consistent, as backing up files in use (especially a sqlite database) will cause corruption. Here, all restic jobs are backing up as per the 2.05 snapshot, regardless of when they run that night.
This does a nightly ZFS snapshot, in which apps and other mutable data is restic backed up to both a local folder on my NAS and also to Cloudflare R2 :octicons-info-16:{ title="R2 mainly due to the cheap cost and low egrees fees" }. Backing up from a ZFS snapshot ensures that the restic backup is consistent, as backing up files in use (especially a sqlite database) will cause corruption. Here, all restic jobs are backing up as per the 2.05 snapshot, regardless of when they run that night.
Another benefit of this approach is that it is service agnostic - containers, nixos services, qemu, whatever all have files in the same place on the filesystem (in the persistant folder) so they can all be backed up in the same fashion.

15
docs/network/dns_dhcp.md Normal file
View file

@ -0,0 +1,15 @@
# DNS & DHCP
!!! info "TLDR"
External DNS: Client -> Adguard Home (r->
My DNS has evolved and changed over time, especially with a personal desire to keep my entire internet backbone boring and standard off a trusted vendor. 'Why cant I connect to my Minecraft server' and 'Are you playing with the internet again' are questions I don't want to have to answer in this house.
Sadly, while I do love my Unifi Dream Machine Pro, its DNS opportunity is lackluster and I really prefer split-dns so I don't have to access everything with ip:port.
# General
<DNS IMAGE>
My devices all use the Unifi DHCP server to get addresses, which I much prefer so I maintain all my clients in the single-pane-of-glass the UDMP provides. In the DHCP options, I add the

View file

@ -19,6 +19,8 @@
plex.enable = true;
tautulli.enable = true;
syncthing.enable = true;
searxng.enable = true;
factorio.freight-forwarding.enable = true;
whoogle.enable = true;
@ -30,11 +32,11 @@
mySystem.system.motd.networkInterfaces = [ "eno1" ];
# Dev machine
mySystem.system.resticBackup =
{
local.enable = false;
remote.enable = false;
};
# mySystem.system.resticBackup =
# {
# local.enable = false;
# remote.enable = false;
# };
boot = {

View file

@ -8,6 +8,8 @@
./plex
./tautulli
./backrest
./searxng
./factorio
./whoogle
];
}

View file

@ -0,0 +1,73 @@
{ lib
, config
, pkgs
, ...
}:
with lib;
let
app = "factorio";
instance = "freight-forwarding";
image = "factoriotools/factorio:stable@sha256:e2e42bb597e5785ce99996c0ee074e009c79dd44dcb5dea01f4640288d7e5290";
user = "845"; #string
group = "845"; #string
port = 34203; #int
port_rcon = 27019; #int
cfg = config.mySystem.services.${app}.${instance};
appFolder = "containers/${app}/${instance}";
persistentFolder = "${config.mySystem.persistentFolder}/${appFolder}";
in
{
options.mySystem.services.${app}.${instance} =
{
enable = mkEnableOption "${app} - ${instance}";
addToHomepage = mkEnableOption "Add ${app} - ${instance} to homepage" // { default = true; };
openFirewall = mkEnableOption "Open firewall for ${app} - ${instance}" // {
default = true;
};
};
config = mkIf cfg.enable {
# ensure folder exist and has correct owner/group
systemd.tmpfiles.rules = [
"d ${persistentFolder} 0755 ${user} ${group} -" #The - disables automatic cleanup, so the file wont be removed after a period
];
virtualisation.oci-containers.containers."${app}-${instance}" = {
image = "${image}";
user = "${user}:${group}";
volumes = [
"${persistentFolder}:/factorio:rw"
"/etc/localtime:/etc/localtime:ro"
];
ports = [ (builtins.toString port) ]; # expose port
labels = config.lib.mySystem.mkTraefikLabels {
name = app;
inherit port;
};
};
networking.firewall = mkIf cfg.openFirewall {
allowedTCPPorts = [ port ]; # I dont use rcon so not opening that too.
};
mySystem.services.gatus.monitors = mkIf config.mySystem.services.gatus.enable [{
name = app;
group = "media";
url = "udp://${config.networking.hostName}:${builtins.toString port}";
interval = "30s";
conditions = [ "[CONNECTED] == true" "[RESPONSE_TIME] < 50" ];
}];
services.restic.backups = config.lib.mySystem.mkRestic
{
inherit app user;
paths = [ appFolder ];
inherit appFolder;
};
};
}

View file

@ -81,7 +81,7 @@ in
services.restic.backups = config.lib.mySystem.mkRestic
{
inherit app user;
excludePaths = [ "Backups" ];
# excludePaths = [ "Backups" ];
paths = [ appFolder ];
inherit appFolder;
};

View file

@ -6,13 +6,15 @@
with lib;
let
app = "searxng";
image = "ghcr.io/benbusby/whoogle-search:0.8.4@sha256:93977c3aec8a039df94745a6e960d1b590a897e451b874c90ce484fbdbc3630f";
user = "568"; #string
group = "568"; #string
port = 5000; #int
image = "docker.io/searxng/searxng:2023.11.1-b5a8ddfec";
user = "977"; #string
group = "977"; #string
port = 8080; #int
cfg = config.mySystem.services.${app};
appFolder = "containers/${app}";
persistentFolder = "${config.mySystem.persistentFolder}/${appFolder}";
configNix = { use_default_settings = { engines = { keep_only = [ "arch linux wiki" "google" "google images" "google news" "google videos" "google scholar" "google play apps" "duckduckgo" "brave" "startpage" "gitlab" "github" "codeberg" "sourcehut" "bitbucket" "apple app store" "wikipedia" "currency" "docker hub" "ddg definitions" "duckduckgo images" "bandcamp" "deviantart" "tineye" "apple maps" "fdroid" "flickr" "free software directory" "z-library" "lobste.rs" "azlyrics" "openstreetmap" "npm" "pypi" "lib.rs" "nyaa" "reddit" "sepiasearch" "soundcloud" "stackoverflow" "askubuntu" "superuser" "searchcode code" "unsplash" "youtube" "wolframalpha" "mojeek" ]; }; }; engines = [{ name = "brave"; disabled = false; } { name = "startpage"; disabled = false; } { name = "apple app store"; disabled = false; } { name = "ddg definitions"; disabled = false; } { name = "tineye"; disabled = false; } { name = "apple maps"; disabled = false; } { name = "duckduckgo images"; disabled = false; } { name = "fdroid"; disabled = false; } { name = "free software directory"; disabled = false; } { name = "bitbucket"; disabled = false; } { name = "gitlab"; disabled = false; } { name = "codeberg"; disabled = false; } { name = "google play apps"; disabled = false; } { name = "lobste.rs"; disabled = false; } { name = "azlyrics"; disabled = false; } { name = "npm"; disabled = false; } { name = "nyaa"; disabled = false; categories = "videos"; } { name = "searchcode code"; disabled = false; } { name = "mojeek"; disabled = false; } { name = "lib.rs"; disabled = false; } { name = "sourcehut"; disabled = false; }]; general = { instance_name = "NatFlix Search"; enable_metrics = false; }; brand = { new_issue_url = ""; docs_url = ""; public_instances = ""; wiki_url = ""; issue_url = ""; }; search = { safe_search = 0; autocomplete = "duckduckgo"; autocomplete_min = 2; default_lang = "en"; max_page = 0; }; server = { base_url = "https://searxng.\${EXTERNAL_DOMAIN}/"; image_proxy = true; http_protocol_version = "1.1"; method = "GET"; }; ui = { static_use_hash = true; infinite_scroll = true; default_theme = "simple"; theme_args = { simple_style = "dark"; }; }; enabled_plugins = [ "Hash plugin" "Search on category select" "Self Information" "Tracker URL remover" "Open Access DOI rewrite" "Vim-like hotkeys" ]; };
configFile = builtins.toFile "config.yaml" (builtins.toJSON configNix);
in
{
options.mySystem.services.${app} =
@ -26,32 +28,49 @@ in
virtualisation.oci-containers.containers.${app} = {
image = "${image}";
user = "${user}:${group}";
ports = [ (builtins.toString port) ]; # expose port
volumes = [
"${configFile}:/config/config.yaml:ro"
"/etc/localtime:/etc/localtime:ro"
];
environment = {
TZ = "${config.time.timeZone}";
SEARXNG_BASE_URL = "https://searxng.${config.mySystem.domain}/";
SEARXNG_URL = "https://searxng.${config.mySystem.domain}";
};
labels = config.lib.mySystem.mkTraefikLabels {
name = app;
inherit port;
};
extraOptions = [
"--read-only"
"--tmpfs=/etc/searxng/"
"--cap-add=CHOWN"
"--cap-add=SETGID"
"--cap-add=SETUID"
"--cap-add=DAC_OVERRIDE"
];
};
mySystem.services.homepage.home-services = mkIf cfg.addToHomepage [
mySystem.services.homepage.media-services = mkIf cfg.addToHomepage [
{
Whoogle = {
icon = "whooglesearch.png";
Tautulli = {
icon = "${app}.png";
href = "https://${app}.${config.mySystem.domain}";
description = "Google frontend";
container = "${app}";
ping = "https://${app}.${config.mySystem.domain}";
description = "Private meta search engine";
};
}
];
mySystem.services.gatus.monitors = [{
mySystem.services.gatus.monitors = mkIf config.mySystem.services.gatus.enable [{
name = app;
group = "media";
url = "https://${app}.${config.mySystem.domain}";
interval = "1m";
interval = "30s";
conditions = [ "[CONNECTED] == true" "[STATUS] == 200" "[RESPONSE_TIME] < 50" ];
}];

View file

@ -0,0 +1,70 @@
{ lib
, config
, pkgs
, ...
}:
with lib;
let
app = "searxng";
image = "docker.io/searxng/searxng:2023.11.1-b5a8ddfec";
user = "568"; #string
group = "568"; #string
port = 8080; #int
cfg = config.mySystem.services.${app};
appFolder = "containers/${app}";
persistentFolder = "${config.mySystem.persistentFolder}/${appFolder}";
config = { use_default_settings = { engines = { keep_only = [ "arch linux wiki" "google" "google images" "google news" "google videos" "google scholar" "google play apps" "duckduckgo" "brave" "startpage" "gitlab" "github" "codeberg" "sourcehut" "bitbucket" "apple app store" "wikipedia" "currency" "docker hub" "ddg definitions" "duckduckgo images" "bandcamp" "deviantart" "tineye" "apple maps" "fdroid" "flickr" "free software directory" "z-library" "lobste.rs" "azlyrics" "openstreetmap" "npm" "pypi" "lib.rs" "nyaa" "reddit" "sepiasearch" "soundcloud" "stackoverflow" "askubuntu" "superuser" "searchcode code" "unsplash" "youtube" "wolframalpha" "mojeek" ]; }; }; engines = [{ name = "brave"; disabled = false; } { name = "startpage"; disabled = false; } { name = "apple app store"; disabled = false; } { name = "ddg definitions"; disabled = false; } { name = "tineye"; disabled = false; } { name = "apple maps"; disabled = false; } { name = "duckduckgo images"; disabled = false; } { name = "fdroid"; disabled = false; } { name = "free software directory"; disabled = false; } { name = "bitbucket"; disabled = false; } { name = "gitlab"; disabled = false; } { name = "codeberg"; disabled = false; } { name = "google play apps"; disabled = false; } { name = "lobste.rs"; disabled = false; } { name = "azlyrics"; disabled = false; } { name = "npm"; disabled = false; } { name = "nyaa"; disabled = false; categories = "videos"; } { name = "searchcode code"; disabled = false; } { name = "mojeek"; disabled = false; } { name = "lib.rs"; disabled = false; } { name = "sourcehut"; disabled = false; }]; general = { instance_name = "NatFlix Search"; enable_metrics = false; }; brand = { new_issue_url = ""; docs_url = ""; public_instances = ""; wiki_url = ""; issue_url = ""; }; search = { safe_search = 0; autocomplete = "duckduckgo"; autocomplete_min = 2; default_lang = "en"; max_page = 0; }; server = { base_url = "https://searxng.\${EXTERNAL_DOMAIN}/"; image_proxy = true; http_protocol_version = "1.1"; method = "GET"; }; ui = { static_use_hash = true; infinite_scroll = true; default_theme = "simple"; theme_args = { simple_style = "dark"; }; }; enabled_plugins = [ "Hash plugin" "Search on category select" "Self Information" "Tracker URL remover" "Open Access DOI rewrite" "Vim-like hotkeys" ]; };
in
{
options.mySystem.services.${app} =
{
enable = mkEnableOption "${app}";
addToHomepage = mkEnableOption "Add ${app} to homepage" // { default = true; };
};
config = mkIf cfg.enable {
virtualisation.oci-containers.containers.${app} = {
image = "${image}";
user = "${user}:${group}";
volumes = [
"${configFile}:/etc/searxng/settings.yml:ro"
"/etc/localtime:/etc/localtime:ro"
];
environment = {
TZ = "${config.time.timeZone}";
SEARXNG_BASE_URL = "https://searxng.${config.mySystem.domain}/";
SEARXNG_URL = "https://searxng.${config.mySystem.domain}";
};
labels = config.lib.mySystem.mkTraefikLabels {
name = app;
inherit port;
};
extraOptions = [
"--read-only"
"--tmpfs=/etc/searxng/"
];
};
mySystem.services.homepage.media-services = mkIf cfg.addToHomepage [
{
Searxng = {
icon = "${app}.svg";
href = "https://${app}.${config.mySystem.domain}";
ping = "https://${app}.${config.mySystem.domain}";
description = "Private Search Engine";
};
}
];
mySystem.services.gatus.monitors = mkIf config.mySystem.services.gatus.enable [{
name = app;
group = "services";
url = "https://${app}.${config.mySystem.domain}";
interval = "1m";
conditions = [ "[CONNECTED] == true" "[STATUS] == 200" "[RESPONSE_TIME] < 50" ];
}];
};
}

View file

@ -61,6 +61,7 @@ in
url = "https://${app}.${config.mySystem.domain}";
interval = "1m";
conditions = [ "[CONNECTED] == true" "[STATUS] == 200" "[RESPONSE_TIME] < 50" ];
}];
services.restic.backups = config.lib.mySystem.mkRestic

View file

@ -45,7 +45,8 @@ with lib;
initialize = true;
backupPrepareCommand = ''
# remove stale locks - this avoids some annoyance
${pkgs.restic}/bin/restic unlock || true
#
${pkgs.restic}/bin/restic unlock --remove-all || true
'';
in
{
@ -55,7 +56,7 @@ with lib;
# Move the path to the zfs snapshot path
paths = map (x: "${config.mySystem.persistentFolder}/.zfs/snapshot/restic_nightly_snap/${x}") options.paths;
passwordFile = config.sops.secrets."services/restic/password".path;
exclude = options.excludePaths;
exclude = excludePath;
repository = "${config.mySystem.system.resticBackup.local.location}/${options.appFolder}";
inherit (options) user;
};
@ -68,7 +69,7 @@ with lib;
environmentFile = config.sops.secrets."services/restic/env".path;
passwordFile = config.sops.secrets."services/restic/password".path;
repository = "${config.mySystem.system.resticBackup.remote.location}/${options.appFolder}";
exclude = options.excludePaths;
exclude = excludePath;
inherit (options) user;
};