biotite: move services to new machines and new domain
- related services: forgejo, miniflux, vaultwarden - moved from xinyang.life to xiny.li - clean up modules
This commit is contained in:
parent
947e97ce4e
commit
ad9c205fc5
18 changed files with 263 additions and 670 deletions
|
@ -7,15 +7,10 @@
|
|||
./common-settings/mainland.nix
|
||||
./disk-partitions
|
||||
./restic.nix
|
||||
./vaultwarden.nix
|
||||
./monitor
|
||||
./hedgedoc.nix
|
||||
./sing-box.nix
|
||||
./kanidm-client.nix
|
||||
./ssh-tpm-agent.nix # FIXME: Waiting for upstream merge
|
||||
# ./ssh-tpm-agent.nix # FIXME: Waiting for upstream merge
|
||||
./forgejo-actions-runner.nix
|
||||
./oidc-agent.nix
|
||||
./miniflux.nix
|
||||
./immich.nix
|
||||
];
|
||||
}
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.custom.hedgedoc;
|
||||
in
|
||||
{
|
||||
options = {
|
||||
custom.hedgedoc = {
|
||||
enable = mkEnableOption "HedgeDoc Markdown Editor";
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
default = "docs.example.com";
|
||||
description = "Domain name of the HedgeDoc server";
|
||||
};
|
||||
caddy = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Enable Caddy as reverse proxy";
|
||||
};
|
||||
mediaPath = mkOption {
|
||||
type = types.path;
|
||||
default = /var/lib/hedgedoc/uploads;
|
||||
description = "Directory for storing medias";
|
||||
};
|
||||
oidc = {
|
||||
enable = mkEnableOption "OIDC support for HedgeDoc";
|
||||
baseURL = mkOption { type = types.str; };
|
||||
authorizationURL = mkOption { type = types.str; };
|
||||
tokenURL = mkOption { type = types.str; };
|
||||
userProfileURL = mkOption { type = types.str; };
|
||||
};
|
||||
environmentFile = mkOption { type = types.path; };
|
||||
};
|
||||
};
|
||||
config = mkIf cfg.enable {
|
||||
services.hedgedoc = {
|
||||
enable = true;
|
||||
environmentFile = cfg.environmentFile;
|
||||
settings = {
|
||||
domain = cfg.domain;
|
||||
protocolUseSSL = cfg.caddy;
|
||||
uploadsPath = cfg.mediaPath;
|
||||
path = "/run/hedgedoc/hedgedoc.sock";
|
||||
email = false;
|
||||
allowEmailRegister = false;
|
||||
oauth2 = mkIf cfg.oidc.enable {
|
||||
baseURL = cfg.oidc.baseURL;
|
||||
authorizationURL = cfg.oidc.authorizationURL;
|
||||
tokenURL = cfg.oidc.tokenURL;
|
||||
userProfileURL = cfg.oidc.userProfileURL;
|
||||
userProfileEmailAttr = "email";
|
||||
userProfileUsernameAttr = "name";
|
||||
userProfileDisplayNameAttr = "preferred_name";
|
||||
scope = "openid email profile";
|
||||
clientID = "$HEDGEDOC_CLIENT_ID";
|
||||
clientSecret = "$HEDGEDOC_CLIENT_SECRET";
|
||||
};
|
||||
allowAnonymous = false;
|
||||
defaultPermission = "private";
|
||||
};
|
||||
};
|
||||
services.caddy = mkIf cfg.caddy {
|
||||
enable = true;
|
||||
virtualHosts."https://${cfg.domain}".extraConfig = ''
|
||||
reverse_proxy unix/${config.services.hedgedoc.settings.path}
|
||||
'';
|
||||
};
|
||||
users.users.caddy.extraGroups = mkIf cfg.caddy [ "hedgedoc" ];
|
||||
|
||||
};
|
||||
}
|
|
@ -1,134 +0,0 @@
|
|||
{ config, lib, ... }:
|
||||
let
|
||||
cfg = config.custom.sing-box-server;
|
||||
|
||||
secretFileType = lib.types.submodule { _secret = lib.types.path; };
|
||||
singTls = {
|
||||
enabled = true;
|
||||
server_name = config.deployment.targetHost;
|
||||
key_path = config.security.acme.certs.${config.deployment.targetHost}.directory + "/key.pem";
|
||||
certificate_path =
|
||||
config.security.acme.certs.${config.deployment.targetHost}.directory + "/cert.pem";
|
||||
};
|
||||
in
|
||||
{
|
||||
options = {
|
||||
enable = lib.mkEnableOption "sing-box proxy server";
|
||||
users = lib.types.listOf lib.types.submodule {
|
||||
name = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "proxy";
|
||||
};
|
||||
password = lib.mkOption { type = secretFileType; };
|
||||
uuid = lib.mkOption { type = secretFileType; };
|
||||
};
|
||||
wgOut = {
|
||||
privKeyFile = lib.mkOption { type = lib.types.path; };
|
||||
pubkey = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo=";
|
||||
};
|
||||
};
|
||||
inbounds = {
|
||||
trojan = {
|
||||
enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
};
|
||||
};
|
||||
tuic = {
|
||||
enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
};
|
||||
ports = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.int;
|
||||
default = lib.range 6311 6313;
|
||||
};
|
||||
directPorts = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.int;
|
||||
default = [ 6314 ];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
config = lib.mkIf cfg.enable {
|
||||
services.sing-box = {
|
||||
enable = true;
|
||||
settings = {
|
||||
dns = {
|
||||
servers = [
|
||||
{
|
||||
address = "1.1.1.1";
|
||||
detour = "wg-out";
|
||||
}
|
||||
];
|
||||
};
|
||||
inbounds =
|
||||
[
|
||||
# TODO: Trojan and tuic enable
|
||||
{
|
||||
tag = "trojan-in";
|
||||
type = "trojan";
|
||||
listen = "::";
|
||||
listen_port = 8080;
|
||||
users = map (u: removeAttrs u [ "uuid" ]) cfg.users;
|
||||
tls = singTls;
|
||||
}
|
||||
]
|
||||
++ lib.forEach (cfg.tuic.ports ++ cfg.tuic.directPorts) (port: {
|
||||
tag = "tuic-in" + toString port;
|
||||
type = "tuic";
|
||||
listen = "::";
|
||||
listen_port = port;
|
||||
congestion_control = "bbr";
|
||||
users = cfg.users;
|
||||
tls = singTls;
|
||||
});
|
||||
outbounds = [
|
||||
{
|
||||
type = "wireguard";
|
||||
tag = "wg-out";
|
||||
private_key = cfg.wgOut.privKeyFile;
|
||||
local_address = [
|
||||
"172.16.0.2/32"
|
||||
"2606:4700:110:82ed:a443:3c62:6cbc:b59b/128"
|
||||
];
|
||||
peers = [
|
||||
{
|
||||
public_key = cfg.wgOut.pubkey;
|
||||
allowed_ips = [
|
||||
"0.0.0.0/0"
|
||||
"::/0"
|
||||
];
|
||||
server = "162.159.192.1";
|
||||
server_port = 500;
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
type = "direct";
|
||||
tag = "direct-out";
|
||||
}
|
||||
{
|
||||
type = "dns";
|
||||
tag = "dns-out";
|
||||
}
|
||||
];
|
||||
route = {
|
||||
rules =
|
||||
[
|
||||
{
|
||||
outbound = "dns-out";
|
||||
protocol = "dns";
|
||||
}
|
||||
]
|
||||
++ lib.forEach cfg.tuic.directPorts (port: {
|
||||
inbound = "tuic-in" + toString port;
|
||||
outbound = "direct-out";
|
||||
});
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -59,8 +59,6 @@ in
|
|||
PasswordAuthentication = false;
|
||||
KbdInteractiveAuthentication = false;
|
||||
PermitRootLogin = lib.mkForce "no";
|
||||
GSSAPIAuthentication = "no";
|
||||
KerberosAuthentication = "no";
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -1,165 +0,0 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib)
|
||||
mkEnableOption
|
||||
mkPackageOption
|
||||
mkOption
|
||||
types
|
||||
literalExpression
|
||||
mkIf
|
||||
mkDefault
|
||||
;
|
||||
cfg = config.custom.miniflux;
|
||||
|
||||
defaultAddress = "localhost:8080";
|
||||
|
||||
pgbin = "${config.services.postgresql.package}/bin";
|
||||
preStart = pkgs.writeScript "miniflux-pre-start" ''
|
||||
#!${pkgs.runtimeShell}
|
||||
${pgbin}/psql "miniflux" -c "CREATE EXTENSION IF NOT EXISTS hstore"
|
||||
'';
|
||||
in
|
||||
{
|
||||
options = {
|
||||
custom.miniflux = {
|
||||
enable = mkEnableOption "miniflux";
|
||||
|
||||
package = mkPackageOption pkgs "miniflux" { };
|
||||
|
||||
oauth2SecretFile = mkOption { type = types.path; };
|
||||
|
||||
environment = mkOption {
|
||||
type =
|
||||
with types;
|
||||
attrsOf (oneOf [
|
||||
int
|
||||
str
|
||||
]);
|
||||
};
|
||||
|
||||
createDatabaseLocally = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether a PostgreSQL database should be automatically created and
|
||||
configured on the local host. If set to `false`, you need provision a
|
||||
database yourself and make sure to create the hstore extension in it.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
services.miniflux.enable = false;
|
||||
custom.miniflux.environment = {
|
||||
LISTEN_ADDR = mkDefault defaultAddress;
|
||||
RUN_MIGRATIONS = mkDefault 1;
|
||||
DATABASE_URL = lib.mkIf cfg.createDatabaseLocally "user=miniflux host=/run/postgresql dbname=miniflux";
|
||||
OAUTH2_CLIENT_SECRET_FILE = "%d/oauth2_secret";
|
||||
WATCHDOG = mkDefault 1;
|
||||
};
|
||||
|
||||
services.postgresql = lib.mkIf cfg.createDatabaseLocally {
|
||||
enable = true;
|
||||
ensureUsers = [
|
||||
{
|
||||
name = "miniflux";
|
||||
ensureDBOwnership = true;
|
||||
}
|
||||
];
|
||||
ensureDatabases = [ "miniflux" ];
|
||||
};
|
||||
|
||||
systemd.services.miniflux-dbsetup = lib.mkIf cfg.createDatabaseLocally {
|
||||
description = "Miniflux database setup";
|
||||
requires = [ "postgresql.service" ];
|
||||
after = [
|
||||
"network.target"
|
||||
"postgresql.service"
|
||||
];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
User = config.services.postgresql.superUser;
|
||||
ExecStart = preStart;
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.miniflux = {
|
||||
description = "Miniflux service";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
requires = lib.optional cfg.createDatabaseLocally "miniflux-dbsetup.service";
|
||||
after =
|
||||
[ "network.target" ]
|
||||
++ lib.optionals cfg.createDatabaseLocally [
|
||||
"postgresql.service"
|
||||
"miniflux-dbsetup.service"
|
||||
];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "notify";
|
||||
ExecStart = lib.getExe cfg.package;
|
||||
User = "miniflux";
|
||||
DynamicUser = true;
|
||||
LoadCredential = [ "oauth2_secret:${cfg.oauth2SecretFile}" ];
|
||||
RuntimeDirectory = "miniflux";
|
||||
RuntimeDirectoryMode = "0750";
|
||||
WatchdogSec = 60;
|
||||
WatchdogSignal = "SIGKILL";
|
||||
Restart = "always";
|
||||
RestartSec = 5;
|
||||
|
||||
# Hardening
|
||||
CapabilityBoundingSet = [ "" ];
|
||||
DeviceAllow = [ "" ];
|
||||
LockPersonality = true;
|
||||
MemoryDenyWriteExecute = true;
|
||||
PrivateDevices = true;
|
||||
PrivateUsers = true;
|
||||
ProcSubset = "pid";
|
||||
ProtectClock = true;
|
||||
ProtectControlGroups = true;
|
||||
ProtectHome = true;
|
||||
ProtectHostname = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectProc = "invisible";
|
||||
RestrictAddressFamilies = [
|
||||
"AF_INET"
|
||||
"AF_INET6"
|
||||
"AF_UNIX"
|
||||
];
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
SystemCallArchitectures = "native";
|
||||
SystemCallFilter = [
|
||||
"@system-service"
|
||||
"~@privileged"
|
||||
];
|
||||
UMask = "0077";
|
||||
};
|
||||
|
||||
environment = lib.mapAttrs (_: toString) cfg.environment;
|
||||
};
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
|
||||
security.apparmor.policies."bin.miniflux".profile = ''
|
||||
include <tunables/global>
|
||||
${cfg.package}/bin/miniflux {
|
||||
include <abstractions/base>
|
||||
include <abstractions/nameservice>
|
||||
include <abstractions/ssl_certs>
|
||||
include "${pkgs.apparmorRulesFromClosure { name = "miniflux"; } cfg.package}"
|
||||
r ${cfg.package}/bin/miniflux,
|
||||
r @{sys}/kernel/mm/transparent_hugepage/hpage_pmd_size,
|
||||
rw /run/miniflux/**,
|
||||
}
|
||||
'';
|
||||
};
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
utils,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.custom.sing-box;
|
||||
settingsFormat = pkgs.formats.json { };
|
||||
in
|
||||
{
|
||||
options = {
|
||||
custom.sing-box = {
|
||||
enable = lib.mkEnableOption "sing-box";
|
||||
|
||||
package = lib.mkPackageOption pkgs "sing-box" { };
|
||||
|
||||
stateDir = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
default = "/var/lib/sing-box";
|
||||
};
|
||||
|
||||
configFile = {
|
||||
urlFile = lib.mkOption { type = lib.types.path; };
|
||||
name = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "config.json";
|
||||
};
|
||||
hash = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
example = "9a304bcb87d4c3f1e50f6281f25dd78635255ebde06cd4d2555729ecda43aed4";
|
||||
};
|
||||
};
|
||||
|
||||
overrideSettings = lib.mkOption {
|
||||
type = lib.types.submodule {
|
||||
freeformType = settingsFormat.type;
|
||||
options = {
|
||||
route = {
|
||||
geoip.path = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
default = "${pkgs.sing-geoip}/share/sing-box/geoip.db";
|
||||
defaultText = lib.literalExpression "\${pkgs.sing-geoip}/share/sing-box/geoip.db";
|
||||
description = lib.mdDoc ''
|
||||
The path to the sing-geoip database.
|
||||
'';
|
||||
};
|
||||
geosite.path = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
default = "${pkgs.sing-geosite}/share/sing-box/geosite.db";
|
||||
defaultText = lib.literalExpression "\${pkgs.sing-geosite}/share/sing-box/geosite.db";
|
||||
description = lib.mdDoc ''
|
||||
The path to the sing-geosite database.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
default = { };
|
||||
};
|
||||
};
|
||||
};
|
||||
config = lib.mkIf cfg.enable {
|
||||
networking.firewall.trustedInterfaces = [ "tun0" ];
|
||||
|
||||
systemd.packages = [ cfg.package ];
|
||||
|
||||
systemd.services.sing-box =
|
||||
let
|
||||
configFile = cfg.stateDir + "/${cfg.configFile.name}";
|
||||
in
|
||||
{
|
||||
preStart = ''
|
||||
umask 0077
|
||||
mkdir -p /etc/sing-box
|
||||
if ! [ -e ${configFile} ]; then
|
||||
${pkgs.curl}/bin/curl "$(${pkgs.coreutils}/bin/cat ${cfg.configFile.urlFile})" > '${configFile}'
|
||||
test "${cfg.configFile.hash}" $(${pkgs.coreutils}/bin/sha256sum '${configFile}' | ${pkgs.coreutils}/bin/cut -d ' ' -f 1)
|
||||
fi
|
||||
${utils.genJqSecretsReplacementSnippet cfg.overrideSettings "/etc/sing-box/config.json"}
|
||||
${cfg.package}/bin/sing-box merge -c '${configFile}' -c /etc/sing-box/config.json /etc/sing-box/config.json
|
||||
'';
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
};
|
||||
};
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue