1
1
Fork 1
mirror of https://github.com/oddlama/nix-config.git synced 2025-10-11 07:10:39 +02:00

feat: wip: add container backend to guests

This commit is contained in:
oddlama 2023-12-17 02:04:20 +01:00
parent 83f1908e21
commit abb8330d86
No known key found for this signature in database
GPG key ID: 14EFE510775FE39A
23 changed files with 256 additions and 208 deletions

View file

@ -0,0 +1,84 @@
{
config,
lib,
nodes,
pkgs,
...
}: let
sentinelCfg = nodes.sentinel.config;
adguardhomeDomain = "adguardhome.${sentinelCfg.repo.secrets.local.personalDomain}";
in {
meta.wireguard-proxy.sentinel.allowedTCPPorts = [config.services.adguardhome.settings.bind_port];
nodes.sentinel = {
networking.providedDomains.adguard = adguardhomeDomain;
services.nginx = {
upstreams.adguardhome = {
servers."${config.meta.wireguard.proxy-sentinel.ipv4}:${toString config.services.adguardhome.settings.bind_port}" = {};
extraConfig = ''
zone adguardhome 64k;
keepalive 2;
'';
};
virtualHosts.${adguardhomeDomain} = {
forceSSL = true;
useACMEWildcardHost = true;
oauth2.enable = true;
oauth2.allowedGroups = ["access_adguardhome"];
locations."/" = {
proxyPass = "http://adguardhome";
proxyWebsockets = true;
};
};
};
};
networking.firewall = {
allowedTCPPorts = [53];
allowedUDPPorts = [53];
};
services.adguardhome = {
enable = true;
# TODO allow mutable settings, replace 123.123.123.123 with
# simpler sed dns.host_addr logic.
mutableSettings = false;
settings = {
bind_host = "0.0.0.0";
bind_port = 3000;
dns = {
bind_hosts = [
# This dummy address passes the configuration check and will
# later be replaced by the actual interface address.
"123.123.123.123"
];
# allowed_clients = [
# ];
#trusted_proxied = [];
ratelimit = 60;
upstream_dns = [
"1.1.1.1"
"2606:4700:4700::1111"
"8.8.8.8"
"2001:4860:4860::8844"
];
bootstrap_dns = [
"1.1.1.1"
"2606:4700:4700::1111"
"8.8.8.8"
"2001:4860:4860::8844"
];
dhcp.enabled = false;
};
};
};
systemd.services.adguardhome = {
preStart = lib.mkAfter ''
INTERFACE_ADDR=$(${pkgs.iproute2}/bin/ip -family inet -brief addr show wan | grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+")
sed -i -e "s/123.123.123.123/$INTERFACE_ADDR/" "$STATE_DIRECTORY/AdGuardHome.yaml"
'';
serviceConfig.RestartSec = lib.mkForce "600"; # Retry every 10 minutes
};
}

View file

@ -0,0 +1,22 @@
{nodes, ...}: let
sentinelCfg = nodes.sentinel.config;
in {
meta.wireguard-proxy.sentinel = {};
meta.promtail = {
enable = true;
proxy = "sentinel";
};
# Connect safely via wireguard to skip http authentication
networking.hosts.${sentinelCfg.meta.wireguard.proxy-sentinel.ipv4} = [sentinelCfg.networking.providedDomains.influxdb];
meta.telegraf = {
enable = true;
scrapeSensors = false;
influxdb2 = {
domain = sentinelCfg.networking.providedDomains.influxdb;
organization = "servers";
bucket = "telegraf";
node = "ward-influxdb";
};
};
}

View file

@ -0,0 +1,168 @@
{
config,
lib,
nodes,
pkgs,
...
}: let
sentinelCfg = nodes.sentinel.config;
# XXX: other domain on other proxy?
forgejoDomain = "git.${sentinelCfg.repo.secrets.local.personalDomain}";
in {
# TODO forward ssh port
meta.wireguard-proxy.sentinel.allowedTCPPorts = [
config.services.gitea.settings.server.HTTP_PORT
];
age.secrets.forgejo-mailer-password = {
rekeyFile = config.node.secretsDir + "/forgejo-mailer-password.age";
mode = "440";
inherit (config.services.gitea) group;
};
# Mirror the original oauth2 secret
age.secrets.forgejo-oauth2-client-secret = {
inherit (nodes.ward-kanidm.config.age.secrets.kanidm-oauth2-forgejo) rekeyFile;
mode = "440";
inherit (config.services.gitea) group;
};
nodes.sentinel = {
networking.providedDomains.forgejo = forgejoDomain;
services.nginx = {
upstreams.forgejo = {
servers."${config.meta.wireguard.proxy-sentinel.ipv4}:${toString config.services.gitea.settings.server.HTTP_PORT}" = {};
extraConfig = ''
zone forgejo 64k;
keepalive 2;
'';
};
virtualHosts.${forgejoDomain} = {
forceSSL = true;
useACMEWildcardHost = true;
extraConfig = ''
client_max_body_size 512M;
'';
locations."/".proxyPass = "http://forgejo";
locations."/metrics" = {
proxyPass = "http://forgejo/metrics";
extraConfig = ''
allow 127.0.0.0/8;
allow ::1;
deny all;
access_log off;
'';
};
};
};
};
# Recommended by forgejo: https://forgejo.org/docs/latest/admin/recommendations/#git-over-ssh
services.openssh.settings.AcceptEnv = "GIT_PROTOCOL";
services.gitea = {
enable = true;
package = pkgs.forgejo;
appName = "Redlew Git"; # tungsten inert gas?
stateDir = "/var/lib/forgejo";
# TODO db backups
# dump.enable = true;
lfs.enable = true;
mailerPasswordFile = config.age.secrets.forgejo-mailer-password.path;
settings = {
actions = {
ENABLED = true;
DEFAULT_ACTIONS_URL = "https://gitea.com";
};
database = {
SQLITE_JOURNAL_MODE = "WAL";
LOG_SQL = false; # Leaks secrets
};
# federation.ENABLED = true;
mailer = {
ENABLED = true;
HOST = config.repo.secrets.local.forgejo.mail.host;
FROM = config.repo.secrets.local.forgejo.mail.from;
USER = config.repo.secrets.local.forgejo.mail.user;
SEND_AS_PLAIN_TEXT = true;
};
metrics = {
# XXX: query with local telegraf
ENABLED = true;
ENABLED_ISSUE_BY_REPOSITORY = true;
ENABLED_ISSUE_BY_LABEL = true;
};
oauth2_client = {
ACCOUNT_LINKING = "auto";
ENABLE_AUTO_REGISTRATION = true;
OPENID_CONNECT_SCOPES = "email profile";
REGISTER_EMAIL_CONFIRM = false;
UPDATE_AVATAR = true;
};
# packages.ENABLED = true;
repository = {
DEFAULT_PRIVATE = false;
ENABLE_PUSH_CREATE_USER = true;
ENABLE_PUSH_CREATE_ORG = true;
};
server = {
HTTP_ADDR = "0.0.0.0";
HTTP_PORT = 3000;
DOMAIN = forgejoDomain;
ROOT_URL = "https://${forgejoDomain}/";
LANDING_PAGE = "login";
SSH_PORT = 9922;
};
service = {
DISABLE_REGISTRATION = false;
ALLOW_ONLY_INTERNAL_REGISTRATION = false;
ALLOW_ONLY_EXTERNAL_REGISTRATION = true;
SHOW_REGISTRATION_BUTTON = false;
REGISTER_EMAIL_CONFIRM = false;
ENABLE_NOTIFY_MAIL = true;
};
session.COOKIE_SECURE = true;
ui.DEFAULT_THEME = "forgejo-auto";
"ui.meta" = {
AUTHOR = "Redlew Git";
DESCRIPTION = "Tungsten Inert Gas?";
};
};
};
# XXX: PKCE is currently not supported by gitea/forgejo,
# see https://github.com/go-gitea/gitea/issues/21376.
# Disable PKCE manually in kanidm for now.
# `kanidm system oauth2 warning-insecure-client-disable-pkce forgejo`
systemd.services.gitea = {
serviceConfig.RestartSec = "600"; # Retry every 10 minutes
preStart = let
exe = lib.getExe config.services.gitea.package;
providerName = "kanidm";
clientId = "forgejo";
args = lib.escapeShellArgs [
"--name"
providerName
"--provider"
"openidConnect"
"--key"
clientId
"--auto-discover-url"
"https://${sentinelCfg.networking.providedDomains.kanidm}/oauth2/openid/${clientId}/.well-known/openid-configuration"
#"--required-claim-name" "groups"
#"--group-claim-name" "groups"
#"--admin-group" "/forge_admins@${domain}"
"--skip-local-2fa"
];
in
lib.mkAfter ''
provider_id=$(${exe} admin auth list | ${pkgs.gnugrep}/bin/grep -w '${providerName}' | cut -f1)
if [[ -z "$provider_id" ]]; then
FORGEJO_ADMIN_OAUTH2_SECRET="$(< ${config.age.secrets.forgejo-oauth2-client-secret.path})" ${exe} admin auth add-oauth ${args}
else
FORGEJO_ADMIN_OAUTH2_SECRET="$(< ${config.age.secrets.forgejo-oauth2-client-secret.path})" ${exe} admin auth update-oauth --id "$provider_id" ${args}
fi
'';
};
}

View file

@ -0,0 +1,152 @@
{
config,
nodes,
...
}: let
sentinelCfg = nodes.sentinel.config;
grafanaDomain = "grafana.${sentinelCfg.repo.secrets.local.personalDomain}";
in {
meta.wireguard-proxy.sentinel.allowedTCPPorts = [config.services.grafana.settings.server.http_port];
age.secrets.grafana-secret-key = {
rekeyFile = config.node.secretsDir + "/grafana-secret-key.age";
mode = "440";
group = "grafana";
};
age.secrets.grafana-loki-basic-auth-password = {
generator.script = "alnum";
mode = "440";
group = "grafana";
};
age.secrets.grafana-influxdb-token = {
generator.script = "alnum";
generator.tags = ["influxdb"];
mode = "440";
group = "grafana";
};
# Mirror the original oauth2 secret
age.secrets.grafana-oauth2-client-secret = {
inherit (nodes.ward-kanidm.config.age.secrets.kanidm-oauth2-grafana) rekeyFile;
mode = "440";
group = "grafana";
};
nodes.ward-influxdb = {
# Mirror the original secret on the influx host
age.secrets."grafana-influxdb-token-${config.node.name}" = {
inherit (config.age.secrets.grafana-influxdb-token) rekeyFile;
mode = "440";
group = "influxdb2";
};
services.influxdb2.provision.organization.servers.auths."grafana servers:telegraf (${config.node.name})" = {
readBuckets = ["telegraf"];
writeBuckets = ["telegraf"];
tokenFile = nodes.ward-influxdb.config.age.secrets."grafana-influxdb-token-${config.node.name}".path;
};
};
nodes.sentinel = {
age.secrets.loki-basic-auth-hashes.generator.dependencies = [
config.age.secrets.grafana-loki-basic-auth-password
];
networking.providedDomains.grafana = grafanaDomain;
services.nginx = {
upstreams.grafana = {
servers."${config.meta.wireguard.proxy-sentinel.ipv4}:${toString config.services.grafana.settings.server.http_port}" = {};
extraConfig = ''
zone grafana 64k;
keepalive 2;
'';
};
virtualHosts.${grafanaDomain} = {
forceSSL = true;
useACMEWildcardHost = true;
locations."/" = {
proxyPass = "http://grafana";
proxyWebsockets = true;
};
};
};
};
services.grafana = {
enable = true;
settings = {
analytics.reporting_enabled = false;
users.allow_sign_up = false;
server = {
domain = grafanaDomain;
root_url = "https://${grafanaDomain}";
enforce_domain = true;
enable_gzip = true;
http_addr = "0.0.0.0";
http_port = 3001;
};
security = {
disable_initial_admin_creation = true;
secret_key = "$__file{${config.age.secrets.grafana-secret-key.path}}";
cookie_secure = true;
disable_gravatar = true;
hide_version = true;
};
auth.disable_login_form = true;
"auth.generic_oauth" = {
enabled = true;
name = "Kanidm";
icon = "signin";
allow_sign_up = true;
#auto_login = true;
client_id = "grafana";
client_secret = "$__file{${config.age.secrets.grafana-oauth2-client-secret.path}}";
scopes = "openid email profile";
login_attribute_path = "prefered_username";
auth_url = "https://${sentinelCfg.networking.providedDomains.kanidm}/ui/oauth2";
token_url = "https://${sentinelCfg.networking.providedDomains.kanidm}/oauth2/token";
api_url = "https://${sentinelCfg.networking.providedDomains.kanidm}/oauth2/openid/grafana/userinfo";
use_pkce = true;
# Allow mapping oauth2 roles to server admin
allow_assign_grafana_admin = true;
role_attribute_path = "contains(scopes[*], 'server_admin') && 'GrafanaAdmin' || contains(scopes[*], 'admin') && 'Admin' || contains(scopes[*], 'editor') && 'Editor' || 'Viewer'";
};
};
provision = {
enable = true;
datasources.settings.datasources = [
{
name = "InfluxDB (servers)";
type = "influxdb";
access = "proxy";
url = "https://${sentinelCfg.networking.providedDomains.influxdb}";
orgId = 1;
secureJsonData.token = "$__file{${config.age.secrets.grafana-influxdb-token.path}}";
jsonData.version = "Flux";
jsonData.organization = "servers";
jsonData.defaultBucket = "telegraf";
}
# TODO duplicate above influxdb source (with scoped read tokens??) for each organization
{
name = "Loki";
type = "loki";
access = "proxy";
url = "https://${sentinelCfg.networking.providedDomains.loki}";
orgId = 1;
basicAuth = true;
basicAuthUser = "${config.node.name}+grafana-loki-basic-auth-password";
secureJsonData.basicAuthPassword = "$__file{${config.age.secrets.grafana-loki-basic-auth-password.path}}";
}
];
};
};
systemd.services.grafana.serviceConfig.RestartSec = "600"; # Retry every 10 minutes
}

View file

@ -0,0 +1,40 @@
{
config,
nodes,
...
}: let
sentinelCfg = nodes.sentinel.config;
immichDomain = "immich.${sentinelCfg.repo.secrets.local.personalDomain}";
in {
meta.wireguard-proxy.sentinel.allowedTCPPorts = [config.services.immich.web_port];
nodes.sentinel = {
networking.providedDomains.immich = immichDomain;
services.nginx = {
upstreams.immich = {
servers."${config.meta.wireguard.proxy-sentinel.ipv4}:${toString config.services.immich.settings.bind_port}" = {};
extraConfig = ''
zone immich 64k;
keepalive 2;
'';
};
virtualHosts.${immichDomain} = {
forceSSL = true;
useACMEWildcardHost = true;
oauth2.enable = true;
oauth2.allowedGroups = ["access_immich"];
locations."/" = {
proxyPass = "http://immich";
proxyWebsockets = true;
};
};
};
};
services.immich = {
enable = true;
};
systemd.services.grafana.serviceConfig.RestartSec = "600"; # Retry every 10 minutes
}

View file

@ -0,0 +1,92 @@
{
config,
lib,
nodes,
pkgs,
...
}: let
sentinelCfg = nodes.sentinel.config;
influxdbDomain = "influxdb.${sentinelCfg.repo.secrets.local.personalDomain}";
influxdbPort = 8086;
in {
meta.wireguard-proxy.sentinel.allowedTCPPorts = [influxdbPort];
nodes.sentinel = {
networking.providedDomains.influxdb = influxdbDomain;
services.nginx = {
upstreams.influxdb = {
servers."${config.meta.wireguard.proxy-sentinel.ipv4}:${toString influxdbPort}" = {};
extraConfig = ''
zone influxdb 64k;
keepalive 2;
'';
};
virtualHosts.${influxdbDomain} = let
accessRules = ''
satisfy any;
${lib.concatMapStrings (ip: "allow ${ip};\n") sentinelCfg.meta.wireguard.proxy-sentinel.server.reservedAddresses}
deny all;
'';
in {
forceSSL = true;
useACMEWildcardHost = true;
oauth2.enable = true;
oauth2.allowedGroups = ["access_influxdb"];
locations."/" = {
proxyPass = "http://influxdb";
proxyWebsockets = true;
extraConfig = accessRules;
};
locations."/api/v2/write" = {
proxyPass = "http://influxdb/api/v2/write";
proxyWebsockets = true;
extraConfig = ''
${accessRules}
access_log off;
'';
};
};
};
};
age.secrets.influxdb-admin-password = {
generator.script = "alnum";
mode = "440";
group = "influxdb2";
};
age.secrets.influxdb-admin-token = {
generator.script = "alnum";
mode = "440";
group = "influxdb2";
};
age.secrets.influxdb-user-telegraf-token = {
generator.script = "alnum";
mode = "440";
group = "influxdb2";
};
services.influxdb2 = {
enable = true;
settings = {
reporting-disabled = true;
http-bind-address = "0.0.0.0:${toString influxdbPort}";
};
provision = {
enable = true;
initialSetup = {
organization = "default";
bucket = "default";
passwordFile = config.age.secrets.influxdb-admin-password.path;
tokenFile = config.age.secrets.influxdb-admin-token.path;
};
organizations.servers.buckets.telegraf = {};
};
};
environment.systemPackages = [pkgs.influxdb2-cli];
systemd.services.grafana.serviceConfig.RestartSec = "600"; # Retry every 10 minutes
}

View file

@ -0,0 +1,157 @@
{
config,
nodes,
pkgs,
...
}: let
inherit (sentinelCfg.repo.secrets.local) personalDomain;
sentinelCfg = nodes.sentinel.config;
kanidmDomain = "auth.${personalDomain}";
kanidmPort = 8300;
in {
meta.wireguard-proxy.sentinel.allowedTCPPorts = [kanidmPort];
age.secrets."kanidm-self-signed.crt" = {
rekeyFile = config.node.secretsDir + "/kanidm-self-signed.crt.age";
mode = "440";
group = "kanidm";
};
age.secrets."kanidm-self-signed.key" = {
rekeyFile = config.node.secretsDir + "/kanidm-self-signed.key.age";
mode = "440";
group = "kanidm";
};
age.secrets.kanidm-admin-password = {
generator.script = "alnum";
mode = "440";
group = "kanidm";
};
age.secrets.kanidm-idm-admin-password = {
generator.script = "alnum";
mode = "440";
group = "kanidm";
};
age.secrets.kanidm-oauth2-grafana = {
generator.script = "alnum";
generator.tags = ["oauth2"];
mode = "440";
group = "kanidm";
};
age.secrets.kanidm-oauth2-forgejo = {
generator.script = "alnum";
generator.tags = ["oauth2"];
mode = "440";
group = "kanidm";
};
age.secrets.kanidm-oauth2-web-sentinel = {
generator.script = "alnum";
generator.tags = ["oauth2"];
mode = "440";
group = "kanidm";
};
nodes.sentinel = {
networking.providedDomains.kanidm = kanidmDomain;
services.nginx = {
upstreams.kanidm = {
servers."${config.meta.wireguard.proxy-sentinel.ipv4}:${toString kanidmPort}" = {};
extraConfig = ''
zone kanidm 64k;
keepalive 2;
'';
};
virtualHosts.${kanidmDomain} = {
forceSSL = true;
useACMEWildcardHost = true;
locations."/".proxyPass = "https://kanidm";
# Allow using self-signed certs to satisfy kanidm's requirement
# for TLS connections. (Although this is over wireguard anyway)
extraConfig = ''
proxy_ssl_verify off;
'';
};
};
};
services.kanidm = {
enableServer = true;
serverSettings = {
domain = kanidmDomain;
origin = "https://${kanidmDomain}";
tls_chain = config.age.secrets."kanidm-self-signed.crt".path;
tls_key = config.age.secrets."kanidm-self-signed.key".path;
bindaddress = "0.0.0.0:${toString kanidmPort}";
trust_x_forward_for = true;
};
enableClient = true;
clientSettings = {
uri = config.services.kanidm.serverSettings.origin;
verify_ca = true;
verify_hostnames = true;
};
provision = {
enable = true;
adminPasswordFile = config.age.secrets.kanidm-admin-password.path;
idmAdminPasswordFile = config.age.secrets.kanidm-idm-admin-password.path;
inherit (config.repo.secrets.global.kanidm) persons;
# Grafana
groups.grafana = {};
groups."grafana.admins" = {};
groups."grafana.editors" = {};
groups."grafana.server-admins" = {};
systems.oauth2.grafana = {
displayName = "Grafana";
originUrl = "https://${sentinelCfg.networking.providedDomains.grafana}";
basicSecretFile = config.age.secrets.kanidm-oauth2-grafana.path;
scopeMaps.grafana = ["openid" "email" "profile"];
supplementaryScopeMaps = {
"grafana.admins" = ["admin"];
"grafana.editors" = ["editor"];
"grafana.server-admins" = ["server_admin"];
};
};
# Forgejo
groups.forgejo = {};
groups."forgejo.admins" = {};
systems.oauth2.forgejo = {
displayName = "Forgejo";
originUrl = "https://${sentinelCfg.networking.providedDomains.forgejo}";
basicSecretFile = config.age.secrets.kanidm-oauth2-forgejo.path;
scopeMaps.forgejo = ["openid" "email" "profile"];
supplementaryScopeMaps = {
"forgejo.admins" = ["admin"];
};
};
# Web Sentinel
groups.web-sentinel = {};
groups."web-sentinel.adguardhome" = {};
groups."web-sentinel.influxdb" = {};
systems.oauth2.web-sentinel = {
displayName = "Web Sentinel";
originUrl = "https://oauth2.${personalDomain}";
basicSecretFile = config.age.secrets.kanidm-oauth2-web-sentinel.path;
scopeMaps.web-sentinel = ["openid" "email"];
supplementaryScopeMaps = {
"web-sentinel.adguardhome" = ["access_adguardhome"];
"web-sentinel.influxdb" = ["access_influxdb"];
};
};
};
};
environment.systemPackages = [pkgs.kanidm];
systemd.services.kanidm.serviceConfig.RestartSec = "60"; # Retry every minute
}

126
hosts/ward/guests/loki.nix Normal file
View file

@ -0,0 +1,126 @@
{
config,
nodes,
...
}: let
sentinelCfg = nodes.sentinel.config;
lokiDomain = "loki.${sentinelCfg.repo.secrets.local.personalDomain}";
in {
meta.wireguard-proxy.sentinel.allowedTCPPorts = [config.services.loki.configuration.server.http_listen_port];
nodes.sentinel = {
networking.providedDomains.loki = lokiDomain;
age.secrets.loki-basic-auth-hashes = {
generator.script = "basic-auth";
mode = "440";
group = "nginx";
};
services.nginx = {
upstreams.loki = {
servers."${config.meta.wireguard.proxy-sentinel.ipv4}:${toString config.services.loki.configuration.server.http_listen_port}" = {};
extraConfig = ''
zone loki 64k;
keepalive 2;
'';
};
virtualHosts.${lokiDomain} = {
forceSSL = true;
useACMEWildcardHost = true;
locations."/" = {
proxyPass = "http://loki";
proxyWebsockets = true;
extraConfig = ''
auth_basic "Authentication required";
auth_basic_user_file ${sentinelCfg.age.secrets.loki-basic-auth-hashes.path};
proxy_read_timeout 1800s;
proxy_connect_timeout 1600s;
access_log off;
'';
};
locations."= /ready" = {
proxyPass = "http://loki";
extraConfig = ''
auth_basic off;
access_log off;
'';
};
};
};
};
services.loki = let
lokiDir = "/var/lib/loki";
in {
enable = true;
configuration = {
analytics.reporting_enabled = false;
auth_enabled = false;
server = {
http_listen_address = "0.0.0.0";
http_listen_port = 3100;
log_level = "warn";
};
ingester = {
lifecycler = {
address = "127.0.0.1";
ring = {
kvstore.store = "inmemory";
replication_factor = 1;
};
final_sleep = "0s";
};
chunk_idle_period = "5m";
chunk_retain_period = "30s";
};
schema_config.configs = [
{
from = "2023-06-01";
store = "tsdb";
object_store = "filesystem";
schema = "v12";
index = {
prefix = "index_";
period = "24h";
};
}
];
storage_config = {
tsdb_shipper = {
active_index_directory = "${lokiDir}/tsdb-index";
cache_location = "${lokiDir}/tsdb-cache";
cache_ttl = "24h";
shared_store = "filesystem";
};
filesystem.directory = "${lokiDir}/chunks";
};
# Do not accept new logs that are ingressed when they are actually already old.
limits_config = {
reject_old_samples = true;
reject_old_samples_max_age = "168h";
};
# Do not delete old logs automatically
table_manager = {
retention_deletes_enabled = false;
retention_period = "0s";
};
compactor = {
working_directory = lokiDir;
shared_store = "filesystem";
compactor_ring.kvstore.store = "inmemory";
};
};
};
systemd.services.loki.serviceConfig.RestartSec = "600"; # Retry every 10 minutes
}

View file

@ -0,0 +1,68 @@
{
config,
nodes,
...
}: let
sentinelCfg = nodes.sentinel.config;
paperlessDomain = "paperless.${sentinelCfg.repo.secrets.local.personalDomain}";
in {
# XXX: remove microvm.mem = 1024 * 12;
# XXX: remove microvm.vcpu = 4;
meta.wireguard-proxy.sentinel.allowedTCPPorts = [
config.services.paperless.port
];
age.secrets.paperless-admin-password = {
rekeyFile = config.node.secretsDir + "/paperless-admin-password.age";
generator.script = "alnum";
mode = "440";
group = "paperless";
};
nodes.sentinel = {
networking.providedDomains.paperless = paperlessDomain;
services.nginx = {
upstreams.paperless = {
servers."${config.meta.wireguard.proxy-sentinel.ipv4}:${toString config.services.paperless.port}" = {};
extraConfig = ''
zone paperless 64k;
keepalive 2;
'';
};
virtualHosts.${paperlessDomain} = {
forceSSL = true;
useACMEWildcardHost = true;
extraConfig = ''
client_max_body_size 512M;
'';
locations."/" = {
proxyPass = "http://paperless";
proxyWebsockets = true;
X-Frame-Options = "SAMEORIGIN";
};
};
};
};
services.paperless = {
enable = true;
address = "0.0.0.0";
passwordFile = config.age.secrets.paperless-admin-password.path;
extraConfig = {
PAPERLESS_URL = "https://${paperlessDomain}";
PAPERLESS_CONSUMER_ENABLE_BARCODES = true;
PAPERLESS_CONSUMER_ENABLE_ASN_BARCODE = true;
PAPERLESS_CONSUMER_BARCODE_SCANNER = "ZXING";
PAPERLESS_FILENAME_FORMAT = "{created_year}-{created_month}-{created_day}_{asn}_{title}";
#PAPERLESS_IGNORE_DATES = concatStringsSep "," ignoreDates;
PAPERLESS_NUMBER_OF_SUGGESTED_DATES = 4;
PAPERLESS_OCR_LANGUAGE = "deu+eng";
PAPERLESS_TASK_WORKERS = 4;
PAPERLESS_WEBSERVER_WORKERS = 4;
};
};
systemd.services.paperless.serviceConfig.RestartSec = "600"; # Retry every 10 minutes
}

View file

@ -0,0 +1,93 @@
{
config,
lib,
nodes,
...
}: let
sentinelCfg = nodes.sentinel.config;
vaultwardenDomain = "pw.${sentinelCfg.repo.secrets.local.personalDomain}";
in {
meta.wireguard-proxy.sentinel.allowedTCPPorts = [
config.services.vaultwarden.config.rocketPort
config.services.vaultwarden.config.websocketPort
];
age.secrets.vaultwarden-env = {
rekeyFile = config.node.secretsDir + "/vaultwarden-env.age";
mode = "440";
group = "vaultwarden";
};
nodes.sentinel = {
networking.providedDomains.vaultwarden = vaultwardenDomain;
services.nginx = {
upstreams.vaultwarden = {
servers."${config.meta.wireguard.proxy-sentinel.ipv4}:${toString config.services.vaultwarden.config.rocketPort}" = {};
extraConfig = ''
zone vaultwarden 64k;
keepalive 2;
'';
};
upstreams.vaultwarden-websocket = {
servers."${config.meta.wireguard.proxy-sentinel.ipv4}:${toString config.services.vaultwarden.config.websocketPort}" = {};
extraConfig = ''
zone vaultwarden-websocket 64k;
keepalive 2;
'';
};
virtualHosts.${vaultwardenDomain} = {
forceSSL = true;
useACMEWildcardHost = true;
extraConfig = ''
client_max_body_size 256M;
'';
locations."/".proxyPass = "http://vaultwarden";
locations."/notifications/hub" = {
proxyPass = "http://vaultwarden-websocket";
proxyWebsockets = true;
};
locations."/notifications/hub/negotiate" = {
proxyPass = "http://vaultwarden";
proxyWebsockets = true;
};
};
};
};
services.vaultwarden = {
enable = true;
dbBackend = "sqlite";
config = {
dataFolder = lib.mkForce "/var/lib/vaultwarden";
extendedLogging = true;
useSyslog = true;
webVaultEnabled = true;
websocketEnabled = true;
websocketAddress = "0.0.0.0";
websocketPort = 3012;
rocketAddress = "0.0.0.0";
rocketPort = 8012;
signupsAllowed = false;
passwordIterations = 1000000;
invitationsAllowed = true;
invitationOrgName = "Vaultwarden";
domain = "https://${vaultwardenDomain}";
smtpEmbedImages = true;
smtpSecurity = "force_tls";
smtpPort = 465;
};
#backupDir = "/data/backup";
environmentFile = config.age.secrets.vaultwarden-env.path;
};
# Replace uses of old name
systemd.services.backup-vaultwarden.environment.DATA_FOLDER = lib.mkForce "/var/lib/vaultwarden";
systemd.services.vaultwarden.serviceConfig = {
StateDirectory = lib.mkForce "vaultwarden";
RestartSec = "600"; # Retry every 10 minutes
};
}