Compare commits

..

1 commit

Author SHA1 Message Date
Tristan Daniël Maat aef71f548a
WIP: authelia: Add SSO 2024-06-14 01:01:39 +02:00
40 changed files with 1167 additions and 1064 deletions

View file

@ -1,11 +0,0 @@
# Run this command to always ignore formatting commits in `git blame`
# git config blame.ignoreRevsFile .git-blame-ignore-revs
# Switch to nixfmt formatting
04f7a7ef1d38906163afc9cddfa8ce2b0ebf3b45
# Switch to nixpkgs-fmt formatting
fd138d45e6a2cad89fead6e9f246ba282070d6b7
# Switch to alejandra formatting
046a88905ddfa7f9edc3291c310dbb985dee34f9

View file

@ -5,8 +5,7 @@
modulesPath,
flake-inputs,
...
}:
{
}: {
imports = [
flake-inputs.disko.nixosModules.disko
flake-inputs.sops-nix.nixosModules.sops
@ -16,6 +15,7 @@
(import ../modules)
./services/afvalcalendar.nix
./services/auth.nix
./services/backups.nix
./services/battery-manager.nix
./services/conduit.nix
@ -26,7 +26,7 @@
./services/nextcloud.nix
./services/webserver.nix
./services/wireguard.nix
# ./services/starbound.nix -- Not currently used
./services/starbound.nix
./services/postgres.nix
./nginx.nix
./sops.nix
@ -48,15 +48,15 @@
'';
# Enable remote builds from tlater
settings.trusted-users = [ "@wheel" ];
settings.trusted-users = ["@wheel"];
};
nixpkgs.config.allowUnfreePredicate = pkg:
builtins.elem (lib.getName pkg) ["steam-original" "steam-runtime" "steam-run" "steamcmd"];
# Optimization for minecraft servers, see:
# https://bugs.mojang.com/browse/MC-183518
boot.kernelParams = [
"highres=off"
"nohz=off"
];
boot.kernelParams = ["highres=off" "nohz=off"];
networking = {
usePredictableInterfaceNames = false;
@ -107,15 +107,15 @@
users.users.tlater = {
isNormalUser = true;
extraGroups = [ "wheel" ];
openssh.authorizedKeys.keyFiles = [ ../keys/tlater.pub ];
extraGroups = ["wheel"];
openssh.authorizedKeys.keyFiles = [../keys/tlater.pub];
};
services = {
openssh = {
enable = true;
allowSFTP = false;
ports = [ 2222 ];
ports = [2222];
startWhenNeeded = true;
settings = {
@ -134,14 +134,14 @@
pam = {
sshAgentAuth = {
enable = true;
authorizedKeysFiles = [ "/etc/ssh/authorized_keys.d/%u" ];
authorizedKeysFiles = ["/etc/ssh/authorized_keys.d/%u"];
};
services.sudo.sshAgentAuth = true;
};
};
# Remove some unneeded packages
environment.defaultPackages = [ ];
environment.defaultPackages = [];
system.stateVersion = "20.09";
}

View file

@ -8,7 +8,7 @@
# disables it by default.
#
# TODO(tlater): See if would be useful for anything?
boot.kernelParams = [ "nosgx" ];
boot.kernelParams = ["nosgx"];
networking.hostName = "hetzner-1";
services.nginx.domain = "tlater.net";
@ -25,7 +25,9 @@
};
}
# IPv6
{ addressConfig.Address = "2a01:4f8:10b:3c85::2/64"; }
{
addressConfig.Address = "2a01:4f8:10b:3c85::2/64";
}
];
networkConfig = {

View file

@ -1,95 +1,82 @@
{
disko.devices.disk =
let
bootPartition = {
size = "1M";
type = "EF02";
disko.devices.disk = let
bootPartition = {
size = "1M";
type = "EF02";
};
swapPartition = {
# 8G is apparently recommended for this much RAM, but we set up
# 4G on both disks for mirroring purposes.
#
# That'll still be 8G during normal operation, and it's probably
# not too bad to have slightly less swap if a disk dies.
size = "4G";
content = {
type = "swap";
randomEncryption = true;
};
};
swapPartition = {
# 8G is apparently recommended for this much RAM, but we set up
# 4G on both disks for mirroring purposes.
#
# That'll still be 8G during normal operation, and it's probably
# not too bad to have slightly less swap if a disk dies.
size = "4G";
content = {
type = "swap";
randomEncryption = true;
};
};
mountOptions = ["compress=zstd" "noatime"];
in {
sda = {
type = "disk";
device = "/dev/sda";
content = {
type = "gpt";
partitions = {
boot = bootPartition;
swap = swapPartition;
mountOptions = [
"compress=zstd"
"noatime"
];
in
{
sda = {
type = "disk";
device = "/dev/sda";
content = {
type = "gpt";
partitions = {
boot = bootPartition;
swap = swapPartition;
disk1 = {
size = "100%";
# Empty partition to combine in RAID0 with the other disk
};
disk1 = {
size = "100%";
# Empty partition to combine in RAID0 with the other disk
};
};
};
};
sdb = {
type = "disk";
device = "/dev/sdb";
content = {
type = "gpt";
partitions = {
boot = bootPartition;
swap = swapPartition;
sdb = {
type = "disk";
device = "/dev/sdb";
content = {
type = "gpt";
partitions = {
boot = bootPartition;
swap = swapPartition;
disk2 = {
size = "100%";
content = {
type = "btrfs";
# Hack to get multi-device btrfs going
# See https://github.com/nix-community/disko/issues/99
extraArgs = [
"-d"
"raid1"
"-m"
"raid1"
"--runtime-features"
"quota"
"/dev/sda3"
];
subvolumes = {
"/volume" = { };
"/volume/root" = {
inherit mountOptions;
mountpoint = "/";
};
"/volume/home" = {
inherit mountOptions;
mountpoint = "/home";
};
"/volume/var" = {
inherit mountOptions;
mountpoint = "/var";
};
"/volume/nix-store" = {
inherit mountOptions;
mountpoint = "/nix";
};
"/snapshots" = { };
disk2 = {
size = "100%";
content = {
type = "btrfs";
# Hack to get multi-device btrfs going
# See https://github.com/nix-community/disko/issues/99
extraArgs = ["-d" "raid1" "-m" "raid1" "--runtime-features" "quota" "/dev/sda3"];
subvolumes = {
"/volume" = {};
"/volume/root" = {
inherit mountOptions;
mountpoint = "/";
};
"/volume/home" = {
inherit mountOptions;
mountpoint = "/home";
};
"/volume/var" = {
inherit mountOptions;
mountpoint = "/var";
};
"/volume/nix-store" = {
inherit mountOptions;
mountpoint = "/nix";
};
"/snapshots" = {};
};
};
};
};
};
};
};
}

View file

@ -1,9 +1,8 @@
{ lib, ... }:
{
{lib, ...}: {
users.users.tlater.password = "insecure";
# Disable graphical tty so -curses works
boot.kernelParams = [ "nomodeset" ];
boot.kernelParams = ["nomodeset"];
networking.hostName = "testvm";
# Sets the base domain for nginx to a local domain so that we can

View file

@ -1,5 +1,8 @@
{ config, lib, ... }:
{
config,
lib,
...
}: {
services.nginx = {
enable = true;
recommendedTlsSettings = true;
@ -24,8 +27,7 @@
# Override the default, just keep fewer logs
nginx.rotate = 6;
}
// lib.mapAttrs' (
virtualHost: _:
// lib.mapAttrs' (virtualHost: _:
lib.nameValuePair "/var/log/nginx/${virtualHost}/access.log" {
frequency = "daily";
rotate = 2;
@ -33,21 +35,23 @@
delaycompress = true;
su = "${config.services.nginx.user} ${config.services.nginx.group}";
postrotate = "[ ! -f /var/run/nginx/nginx.pid ] || kill -USR1 `cat /var/run/nginx/nginx.pid`";
}
) config.services.nginx.virtualHosts;
})
config.services.nginx.virtualHosts;
systemd.tmpfiles.rules = lib.mapAttrsToList (
virtualHost: _:
#
"d /var/log/nginx/${virtualHost} 0750 ${config.services.nginx.user} ${config.services.nginx.group}"
) config.services.nginx.virtualHosts;
systemd.tmpfiles.rules =
lib.mapAttrsToList (
virtualHost: _:
#
"d /var/log/nginx/${virtualHost} 0750 ${config.services.nginx.user} ${config.services.nginx.group}"
)
config.services.nginx.virtualHosts;
security.acme = {
defaults.email = "tm@tlater.net";
acceptTerms = true;
certs."tlater.net" = {
extraDomainNames = [ "*.tlater.net" ];
extraDomainNames = ["*.tlater.net"];
dnsProvider = "hetzner";
group = "nginx";
credentialFiles."HETZNER_API_KEY_FILE" = config.sops.secrets."hetzner-api".path;
@ -56,8 +60,8 @@
services.backups.acme = {
user = "acme";
paths = lib.mapAttrsToList (
virtualHost: _: "/var/lib/acme/${virtualHost}"
) config.services.nginx.virtualHosts;
paths =
lib.mapAttrsToList (virtualHost: _: "/var/lib/acme/${virtualHost}")
config.services.nginx.virtualHosts;
};
}

View file

@ -1,9 +1,12 @@
{ pkgs, config, ... }:
{
pkgs,
config,
...
}: {
systemd.services.afvalcalendar = {
description = "Enschede afvalcalendar -> ical converter";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
wantedBy = ["multi-user.target"];
after = ["network.target"];
script = ''
${pkgs.local.afvalcalendar}/bin/afvalcalendar > /srv/afvalcalendar/afvalcalendar.ical
@ -23,23 +26,16 @@
ProtectKernelModules = true;
ProtectKernelLogs = true;
ProtectControlGroups = true;
RestrictAddressFamilies = [
"AF_UNIX"
"AF_INET"
"AF_INET6"
];
RestrictAddressFamilies = ["AF_UNIX" "AF_INET" "AF_INET6"];
RestrictNamespaces = true;
LockPersonality = true;
MemoryDenyWriteExecute = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"~@privileged @resources @setuid @keyring"
];
SystemCallFilter = ["@system-service" "~@privileged @resources @setuid @keyring"];
Umask = 2;
Umask = 0002;
SupplementaryGroups = "afvalcalendar-hosting";
ReadWritePaths = "/srv/afvalcalendar";
@ -54,7 +50,7 @@
root = "/srv/afvalcalendar";
};
users.groups.afvalcalendar-hosting = { };
users.groups.afvalcalendar-hosting = {};
systemd.tmpfiles.settings."10-afvalcalendar" = {
"/srv/afvalcalendar".d = {
user = "nginx";

View file

@ -0,0 +1,95 @@
{
pkgs,
config,
...
}: let
user = config.services.authelia.instances.main.user;
domain = "auth.${config.services.nginx.domain}";
in {
services.authelia.instances.main = {
enable = true;
settings = {
theme = "auto";
access_control.default_policy = "one_factor";
authentication_backend = {
password_reset.disable = true;
file.path = "/var/lib/authelia-main/users.yml";
};
notifier.filesystem.filename = "/var/lib/authelia-main/notification.txt";
session = {
domain = config.services.nginx.domain;
redis.host = config.services.redis.servers.authelia.unixSocket;
};
storage.postgres = {
host = "/run/postgresql";
port = 5432;
database = user;
username = user;
password = "unnecessary";
};
};
secrets = {
storageEncryptionKeyFile = config.sops.secrets."authelia/storageEncryptionKey".path; # Database
sessionSecretFile = config.sops.secrets."authelia/sessionSecret".path; # Redis
jwtSecretFile = config.sops.secrets."authelia/jwtSecret".path;
};
};
systemd.services.authelia-main.after = ["postgresql.service"];
services.nginx = {
# TODO(tlater): Possibly remove on next authelia release
additionalModules = with pkgs.nginxModules; [
develkit
set-misc
];
virtualHosts."${domain}" = {
forceSSL = true;
enableACME = true;
enableHSTS = true;
locations = {
"/" = {
proxyPass = "http://127.0.0.1:9091";
recommendedProxySettings = false;
enableAutheliaProxy = true;
};
"/api/verify" = {
proxyPass = "http://127.0.0.1:9091";
recommendedProxySettings = false;
};
};
};
};
services.redis.servers.authelia = {
inherit user;
enable = true;
};
sops.secrets = {
"authelia/storageEncryptionKey" = {
owner = user;
group = user;
};
"authelia/sessionSecret" = {
owner = user;
group = user;
};
"authelia/jwtSecret" = {
owner = user;
group = user;
};
};
}

View file

@ -3,33 +3,27 @@
pkgs,
lib,
...
}:
let
}: let
inherit (lib) types optional singleton;
mkShutdownScript =
service:
mkShutdownScript = service:
pkgs.writeShellScript "backup-${service}-shutdown" ''
if systemctl is-active --quiet '${service}'; then
touch '/tmp/${service}-was-active'
systemctl stop '${service}'
fi
'';
mkRestartScript =
service:
mkRestartScript = service:
pkgs.writeShellScript "backup-${service}-restart" ''
if [ -f '/tmp/${service}-was-active' ]; then
rm '/tmp/${service}-was-active'
systemctl start '${service}'
fi
'';
writeScript =
name: packages: text:
lib.getExe (
pkgs.writeShellApplication {
inherit name text;
runtimeInputs = packages;
}
);
writeScript = name: packages: text:
lib.getExe (pkgs.writeShellApplication {
inherit name text;
runtimeInputs = packages;
});
# *NOT* a TOML file, for some reason quotes are interpreted
# *literally
@ -48,98 +42,96 @@ let
RESTIC_REPOSITORY = "rclone:storagebox:backups";
RCLONE_CONFIG = rcloneConfig;
};
in
{
in {
options = {
services.backups = lib.mkOption {
description = lib.mdDoc ''
Configure restic backups with a specific tag.
'';
type = types.attrsOf (
types.submodule (
{ config, name, ... }:
{
options = {
user = lib.mkOption {
type = types.str;
description = ''
The user as which to run the backup.
'';
};
paths = lib.mkOption {
type = types.listOf types.str;
description = ''
The paths to back up.
'';
};
tag = lib.mkOption {
type = types.str;
description = ''
The restic tag to mark the backup with.
'';
default = name;
};
preparation = {
packages = lib.mkOption {
type = types.listOf types.package;
default = [ ];
description = ''
The list of packages to make available in the
preparation script.
'';
};
text = lib.mkOption {
type = types.nullOr types.str;
default = null;
description = ''
The preparation script to run before the backup.
This should include things like database dumps and
enabling maintenance modes. If a service needs to be
shut down for backups, use `pauseServices` instead.
'';
};
};
cleanup = {
packages = lib.mkOption {
type = types.listOf types.package;
default = [ ];
description = ''
The list of packages to make available in the
cleanup script.
'';
};
text = lib.mkOption {
type = types.nullOr types.str;
default = null;
description = ''
The cleanup script to run after the backup.
This should do things like cleaning up database dumps
and disabling maintenance modes.
'';
};
};
pauseServices = lib.mkOption {
type = types.listOf types.str;
default = [ ];
description = ''
The systemd services that need to be shut down before
the backup can run. Services will be restarted after the
backup is complete.
This is intended to be used for services that do not
support hot backups.
'';
};
type = types.attrsOf (types.submodule ({
config,
name,
...
}: {
options = {
user = lib.mkOption {
type = types.str;
description = ''
The user as which to run the backup.
'';
};
paths = lib.mkOption {
type = types.listOf types.str;
description = ''
The paths to back up.
'';
};
tag = lib.mkOption {
type = types.str;
description = ''
The restic tag to mark the backup with.
'';
default = name;
};
preparation = {
packages = lib.mkOption {
type = types.listOf types.package;
default = [];
description = ''
The list of packages to make available in the
preparation script.
'';
};
}
)
);
text = lib.mkOption {
type = types.nullOr types.str;
default = null;
description = ''
The preparation script to run before the backup.
This should include things like database dumps and
enabling maintenance modes. If a service needs to be
shut down for backups, use `pauseServices` instead.
'';
};
};
cleanup = {
packages = lib.mkOption {
type = types.listOf types.package;
default = [];
description = ''
The list of packages to make available in the
cleanup script.
'';
};
text = lib.mkOption {
type = types.nullOr types.str;
default = null;
description = ''
The cleanup script to run after the backup.
This should do things like cleaning up database dumps
and disabling maintenance modes.
'';
};
};
pauseServices = lib.mkOption {
type = types.listOf types.str;
default = [];
description = ''
The systemd services that need to be shut down before
the backup can run. Services will be restarted after the
backup is complete.
This is intended to be used for services that do not
support hot backups.
'';
};
};
}));
};
};
config = lib.mkIf (config.services.backups != { }) {
config = lib.mkIf (config.services.backups != {}) {
systemd.services =
{
restic-prune = {
@ -172,15 +164,16 @@ in
};
};
}
// lib.mapAttrs' (
name: backup:
// lib.mapAttrs' (name: backup:
lib.nameValuePair "backup-${name}" {
# Don't want to restart mid-backup
restartIfChanged = false;
environment = resticEnv // {
RESTIC_CACHE_DIR = "%C/backup-${name}";
};
environment =
resticEnv
// {
RESTIC_CACHE_DIR = "%C/backup-${name}";
};
path = with pkgs; [
coreutils
@ -203,60 +196,47 @@ in
PrivateTmp = true;
ExecStart = [
(lib.concatStringsSep " " (
[
"${pkgs.restic}/bin/restic"
"backup"
"--tag"
name
]
++ backup.paths
))
(lib.concatStringsSep " " (["${pkgs.restic}/bin/restic" "backup" "--tag" name] ++ backup.paths))
];
ExecStartPre =
map (service: "+${mkShutdownScript service}") backup.pauseServices
++ singleton (
writeScript "backup-${name}-repo-init" [ ] ''
restic snapshots || restic init
''
)
++ optional (backup.preparation.text != null) (
writeScript "backup-${name}-prepare" backup.preparation.packages backup.preparation.text
);
++ singleton (writeScript "backup-${name}-repo-init" [] ''
restic snapshots || restic init
'')
++ optional (backup.preparation.text != null)
(writeScript "backup-${name}-prepare" backup.preparation.packages backup.preparation.text);
# TODO(tlater): Add repo pruning/checking
ExecStopPost =
map (service: "+${mkRestartScript service}") backup.pauseServices
++ optional (backup.cleanup.text != null) (
writeScript "backup-${name}-cleanup" backup.cleanup.packages backup.cleanup.text
);
++ optional (backup.cleanup.text != null)
(writeScript "backup-${name}-cleanup" backup.cleanup.packages backup.cleanup.text);
};
}
) config.services.backups;
})
config.services.backups;
systemd.timers =
{
restic-prune = {
wantedBy = [ "timers.target" ];
wantedBy = ["timers.target"];
timerConfig.OnCalendar = "Thursday 03:00:00 UTC";
# Don't make this persistent, in case the server was offline
# for a while. This job cannot run at the same time as any
# of the backup jobs.
};
}
// lib.mapAttrs' (
name: backup:
// lib.mapAttrs' (name: backup:
lib.nameValuePair "backup-${name}" {
wantedBy = [ "timers.target" ];
wantedBy = ["timers.target"];
timerConfig = {
OnCalendar = "Wednesday 02:30:00 UTC";
RandomizedDelaySec = "1h";
FixedRandomDelay = true;
Persistent = true;
};
}
) config.services.backups;
})
config.services.backups;
users = {
# This user is only used to own the ssh key, because apparently
@ -265,7 +245,7 @@ in
group = "backup";
isSystemUser = true;
};
groups.backup = { };
groups.backup = {};
};
};
}

View file

@ -1,6 +1,11 @@
{ config, flake-inputs, ... }:
{
imports = [ flake-inputs.sonnenshift.nixosModules.default ];
config,
flake-inputs,
...
}: {
imports = [
flake-inputs.sonnenshift.nixosModules.default
];
services.batteryManager = {
enable = true;

View file

@ -3,15 +3,13 @@
config,
lib,
...
}:
let
}: let
inherit (lib.strings) concatMapStringsSep;
cfg = config.services.matrix-conduit;
domain = "matrix.${config.services.nginx.domain}";
turn-realm = "turn.${config.services.nginx.domain}";
in
{
in {
services.matrix-conduit = {
enable = true;
settings.global = {
@ -19,111 +17,98 @@ in
server_name = domain;
database_backend = "rocksdb";
# Set up delegation: https://docs.conduit.rs/delegation.html#automatic-recommended
# This is primarily to make sliding sync work
well_known = {
client = "https://${domain}";
server = "${domain}:443";
};
turn_uris =
let
address = "${config.services.coturn.realm}:${toString config.services.coturn.listening-port}";
tls-address = "${config.services.coturn.realm}:${toString config.services.coturn.tls-listening-port}";
in
[
"turn:${address}?transport=udp"
"turn:${address}?transport=tcp"
"turns:${tls-address}?transport=udp"
"turns:${tls-address}?transport=tcp"
];
turn_uris = let
address = "${config.services.coturn.realm}:${toString config.services.coturn.listening-port}";
tls-address = "${config.services.coturn.realm}:${toString config.services.coturn.tls-listening-port}";
in [
"turn:${address}?transport=udp"
"turn:${address}?transport=tcp"
"turns:${tls-address}?transport=udp"
"turns:${tls-address}?transport=tcp"
];
};
};
systemd.services.heisenbridge =
let
replaceSecretBin = "${pkgs.replace-secret}/bin/replace-secret";
registrationFile = builtins.toFile "heisenbridge-registration.yaml" (
builtins.toJSON {
id = "heisenbridge";
url = "http://127.0.0.1:9898";
as_token = "@AS_TOKEN@";
hs_token = "@HS_TOKEN@";
rate_limited = false;
sender_localpart = "heisenbridge";
namespaces = {
users = [
{
regex = "@irc_.*";
exclusive = true;
}
{
regex = "@heisenbridge:.*";
exclusive = true;
}
];
aliases = [ ];
rooms = [ ];
};
}
);
# TODO(tlater): Starting with systemd 253 it will become possible
# to do the credential setup as part of ExecStartPre/preStart
# instead.
#
# This will also make it possible to actually set caps on the
# heisenbridge process using systemd, so that we can run the
# identd process.
execScript = pkgs.writeShellScript "heisenbridge" ''
cp ${registrationFile} "$RUNTIME_DIRECTORY/heisenbridge-registration.yaml"
chmod 600 $RUNTIME_DIRECTORY/heisenbridge-registration.yaml
${replaceSecretBin} '@AS_TOKEN@' "$CREDENTIALS_DIRECTORY/heisenbridge_as-token" "$RUNTIME_DIRECTORY/heisenbridge-registration.yaml"
${replaceSecretBin} '@HS_TOKEN@' "$CREDENTIALS_DIRECTORY/heisenbridge_hs-token" "$RUNTIME_DIRECTORY/heisenbridge-registration.yaml"
chmod 400 $RUNTIME_DIRECTORY/heisenbridge-registration.yaml
${pkgs.heisenbridge}/bin/heisenbridge \
--config $RUNTIME_DIRECTORY/heisenbridge-registration.yaml \
--owner @tlater:matrix.tlater.net \
'http://localhost:${toString cfg.settings.global.port}'
'';
in
{
description = "Matrix<->IRC bridge";
wantedBy = [ "multi-user.target" ];
after = [ "conduit.service" ];
serviceConfig = {
Type = "simple";
LoadCredential = "heisenbridge:/run/secrets/heisenbridge";
ExecStart = execScript;
DynamicUser = true;
RuntimeDirectory = "heisenbridge";
RuntimeDirectoryMode = "0700";
RestrictNamespaces = true;
PrivateUsers = true;
ProtectHostname = true;
ProtectClock = true;
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectKernelLogs = true;
ProtectControlGroups = true;
RestrictAddressFamilies = [ "AF_INET AF_INET6" ];
LockPersonality = true;
RestrictRealtime = true;
ProtectProc = "invisible";
ProcSubset = "pid";
UMask = 77;
# For the identd port
# CapabilityBoundingSet = ["CAP_NET_BIND_SERVICE"];
# AmbientCapabilities = ["CAP_NET_BIND_SERVICE"];
systemd.services.heisenbridge = let
replaceSecretBin = "${pkgs.replace-secret}/bin/replace-secret";
registrationFile = builtins.toFile "heisenbridge-registration.yaml" (builtins.toJSON {
id = "heisenbridge";
url = "http://127.0.0.1:9898";
as_token = "@AS_TOKEN@";
hs_token = "@HS_TOKEN@";
rate_limited = false;
sender_localpart = "heisenbridge";
namespaces = {
users = [
{
regex = "@irc_.*";
exclusive = true;
}
{
regex = "@heisenbridge:.*";
exclusive = true;
}
];
aliases = [];
rooms = [];
};
});
# TODO(tlater): Starting with systemd 253 it will become possible
# to do the credential setup as part of ExecStartPre/preStart
# instead.
#
# This will also make it possible to actually set caps on the
# heisenbridge process using systemd, so that we can run the
# identd process.
execScript = pkgs.writeShellScript "heisenbridge" ''
cp ${registrationFile} "$RUNTIME_DIRECTORY/heisenbridge-registration.yaml"
chmod 600 $RUNTIME_DIRECTORY/heisenbridge-registration.yaml
${replaceSecretBin} '@AS_TOKEN@' "$CREDENTIALS_DIRECTORY/heisenbridge_as-token" "$RUNTIME_DIRECTORY/heisenbridge-registration.yaml"
${replaceSecretBin} '@HS_TOKEN@' "$CREDENTIALS_DIRECTORY/heisenbridge_hs-token" "$RUNTIME_DIRECTORY/heisenbridge-registration.yaml"
chmod 400 $RUNTIME_DIRECTORY/heisenbridge-registration.yaml
${pkgs.heisenbridge}/bin/heisenbridge \
--config $RUNTIME_DIRECTORY/heisenbridge-registration.yaml \
--owner @tlater:matrix.tlater.net \
'http://localhost:${toString cfg.settings.global.port}'
'';
in {
description = "Matrix<->IRC bridge";
wantedBy = ["multi-user.target"];
after = ["conduit.service"];
serviceConfig = {
Type = "simple";
LoadCredential = "heisenbridge:/run/secrets/heisenbridge";
ExecStart = execScript;
DynamicUser = true;
RuntimeDirectory = "heisenbridge";
RuntimeDirectoryMode = "0700";
RestrictNamespaces = true;
PrivateUsers = true;
ProtectHostname = true;
ProtectClock = true;
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectKernelLogs = true;
ProtectControlGroups = true;
RestrictAddressFamilies = ["AF_INET AF_INET6"];
LockPersonality = true;
RestrictRealtime = true;
ProtectProc = "invisible";
ProcSubset = "pid";
UMask = 0077;
# For the identd port
# CapabilityBoundingSet = ["CAP_NET_BIND_SERVICE"];
# AmbientCapabilities = ["CAP_NET_BIND_SERVICE"];
};
};
# Pass in the TURN secret via EnvironmentFile, not supported by
# upstream module currently.
@ -137,7 +122,9 @@ in
use-auth-secret = true;
static-auth-secret-file = config.sops.secrets."turn/secret".path;
realm = turn-realm;
relay-ips = [ "116.202.158.55" ];
relay-ips = [
"116.202.158.55"
];
# SSL config
#
@ -238,17 +225,30 @@ in
proxy_buffering off;
'';
};
"/.well-known/matrix" = {
proxyPass = "http://${cfg.settings.global.address}:${toString cfg.settings.global.port}";
# Add Element X support
# TODO(tlater): Remove when no longer required: https://github.com/vector-im/element-x-android/issues/1085
"=/.well-known/matrix/client" = {
alias = pkgs.writeText "well-known-matrix-client" (builtins.toJSON {
"m.homeserver".base_url = "https://${domain}";
"org.matrix.msc3575.proxy".url = "https://${domain}";
});
extraConfig = ''
default_type application/json;
add_header Access-Control-Allow-Origin "*";
'';
};
};
};
services.backups.conduit = {
user = "root";
paths = [ "/var/lib/private/matrix-conduit/" ];
paths = [
"/var/lib/private/matrix-conduit/"
];
# Other services store their data in conduit, so no other services
# need to be shut down currently.
pauseServices = [ "conduit.service" ];
pauseServices = ["conduit.service"];
};
}

View file

@ -1,8 +1,7 @@
{ pkgs, ... }:
{
{pkgs, ...}: {
services.fail2ban = {
enable = true;
extraPackages = [ pkgs.ipset ];
extraPackages = [pkgs.ipset];
banaction = "iptables-ipset-proto6-allports";
bantime-increment.enable = true;
@ -22,7 +21,7 @@
};
# Allow metrics services to connect to the socket as well
users.groups.fail2ban = { };
users.groups.fail2ban = {};
systemd.services.fail2ban.serviceConfig = {
ExecStartPost =
"+"

View file

@ -2,14 +2,11 @@
lib,
config,
flake-inputs,
pkgs,
...
}:
let
}: let
domain = "foundryvtt.${config.services.nginx.domain}";
in
{
imports = [ flake-inputs.foundryvtt.nixosModules.foundryvtt ];
in {
imports = [flake-inputs.foundryvtt.nixosModules.foundryvtt];
services.foundryvtt = {
enable = true;
@ -17,31 +14,30 @@ in
minifyStaticFiles = true;
proxySSL = true;
proxyPort = 443;
package = flake-inputs.foundryvtt.packages.${pkgs.system}.foundryvtt_11;
};
# Want to start it manually when I need it, not have it constantly
# running
systemd.services.foundryvtt.wantedBy = lib.mkForce [ ];
systemd.services.foundryvtt.wantedBy = lib.mkForce [];
services.nginx.virtualHosts."${domain}" =
let
inherit (config.services.foundryvtt) port;
in
{
forceSSL = true;
useACMEHost = "tlater.net";
enableHSTS = true;
services.nginx.virtualHosts."${domain}" = let
inherit (config.services.foundryvtt) port;
in {
forceSSL = true;
useACMEHost = "tlater.net";
enableHSTS = true;
locations."/" = {
proxyWebsockets = true;
proxyPass = "http://localhost:${toString port}";
};
locations."/" = {
proxyWebsockets = true;
proxyPass = "http://localhost:${toString port}";
};
};
services.backups.foundryvtt = {
user = "foundryvtt";
paths = [ config.services.foundryvtt.dataDir ];
pauseServices = [ "foundryvtt.service" ];
paths = [
config.services.foundryvtt.dataDir
];
pauseServices = ["foundryvtt.service"];
};
}

View file

@ -3,11 +3,9 @@
config,
lib,
...
}:
let
}: let
domain = "gitea.${config.services.nginx.domain}";
in
{
in {
services.forgejo = {
enable = true;
database.type = "postgres";
@ -29,35 +27,33 @@ in
};
};
systemd.services.forgejo.serviceConfig.ExecStartPre =
let
replaceSecretBin = "${pkgs.replace-secret}/bin/replace-secret";
secretPath = config.sops.secrets."forgejo/metrics-token".path;
runConfig = "${config.services.forgejo.customDir}/conf/app.ini";
in
[ "+${replaceSecretBin} '#metricstoken#' '${secretPath}' '${runConfig}'" ];
systemd.services.forgejo.serviceConfig.ExecStartPre = let
replaceSecretBin = "${pkgs.replace-secret}/bin/replace-secret";
secretPath = config.sops.secrets."forgejo/metrics-token".path;
runConfig = "${config.services.forgejo.customDir}/conf/app.ini";
in [
"+${replaceSecretBin} '#metricstoken#' '${secretPath}' '${runConfig}'"
];
# Set up SSL
services.nginx.virtualHosts."${domain}" =
let
httpAddress = config.services.forgejo.settings.server.HTTP_ADDR;
httpPort = config.services.forgejo.settings.server.HTTP_PORT;
in
{
forceSSL = true;
useACMEHost = "tlater.net";
enableHSTS = true;
services.nginx.virtualHosts."${domain}" = let
httpAddress = config.services.forgejo.settings.server.HTTP_ADDR;
httpPort = config.services.forgejo.settings.server.HTTP_PORT;
in {
forceSSL = true;
useACMEHost = "tlater.net";
enableHSTS = true;
locations."/".proxyPass = "http://${httpAddress}:${toString httpPort}";
locations."/metrics" = {
extraConfig = ''
access_log off;
allow 127.0.0.1;
${lib.optionalString config.networking.enableIPv6 "allow ::1;"}
deny all;
'';
};
locations."/".proxyPass = "http://${httpAddress}:${toString httpPort}";
locations."/metrics" = {
extraConfig = ''
access_log off;
allow 127.0.0.1;
${lib.optionalString config.networking.enableIPv6 "allow ::1;"}
deny all;
'';
};
};
# Block repeated failed login attempts
#
@ -87,13 +83,13 @@ in
# Conf is backed up via nix
];
preparation = {
packages = [ config.services.postgresql.package ];
packages = [config.services.postgresql.package];
text = "pg_dump ${config.services.forgejo.database.name} --file=/var/lib/forgejo/forgejo-db.sql";
};
cleanup = {
packages = [ pkgs.coreutils ];
packages = [pkgs.coreutils];
text = "rm /var/lib/forgejo/forgejo-db.sql";
};
pauseServices = [ "forgejo.service" ];
pauseServices = ["forgejo.service"];
};
}

View file

@ -3,25 +3,23 @@
pkgs,
lib,
...
}:
let
yaml = pkgs.formats.yaml { };
in
{
}: let
yaml = pkgs.formats.yaml {};
in {
services.prometheus = {
exporters = {
# Periodically check domain registration status
domain = {
enable = true;
listenAddress = "127.0.0.1";
extraFlags =
let
conf.domains = [
"tlater.net"
"tlater.com"
];
in
[ "--config=${yaml.generate "domains.yml" conf}" ];
extraFlags = let
conf.domains = [
"tlater.net"
"tlater.com"
];
in [
"--config=${yaml.generate "domains.yml" conf}"
];
};
# System statistics
@ -50,50 +48,48 @@ in
listenAddress = "127.0.0.1";
group = "nginx";
settings.namespaces = lib.mapAttrsToList (name: virtualHost: {
inherit name;
metrics_override.prefix = "nginxlog";
namespace_label = "vhost";
settings.namespaces =
lib.mapAttrsToList (name: virtualHost: {
inherit name;
metrics_override.prefix = "nginxlog";
namespace_label = "vhost";
format = lib.concatStringsSep " " [
"$remote_addr - $remote_user [$time_local]"
''"$request" $status $body_bytes_sent''
''"$http_referer" "$http_user_agent"''
''rt=$request_time uct="$upstream_connect_time"''
''uht="$upstream_header_time" urt="$upstream_response_time"''
];
format = lib.concatStringsSep " " [
"$remote_addr - $remote_user [$time_local]"
''"$request" $status $body_bytes_sent''
''"$http_referer" "$http_user_agent"''
''rt=$request_time uct="$upstream_connect_time"''
''uht="$upstream_header_time" urt="$upstream_response_time"''
];
source.files = [ "/var/log/nginx/${name}/access.log" ];
}) config.services.nginx.virtualHosts;
source.files = [
"/var/log/nginx/${name}/access.log"
];
})
config.services.nginx.virtualHosts;
};
};
extraExporters = {
fail2ban =
let
cfg = config.services.prometheus.extraExporters.fail2ban;
in
{
port = 9191;
serviceOpts = {
after = [ "fail2ban.service" ];
requires = [ "fail2ban.service" ];
serviceConfig = {
Group = "fail2ban";
RestrictAddressFamilies = [
"AF_UNIX"
"AF_INET"
"AF_INET6"
];
ExecStart = lib.concatStringsSep " " [
"${pkgs.local.prometheus-fail2ban-exporter}/bin/fail2ban-prometheus-exporter"
"--collector.f2b.socket=/var/run/fail2ban/fail2ban.sock"
"--web.listen-address='${cfg.listenAddress}:${toString cfg.port}'"
"--collector.f2b.exit-on-socket-connection-error=true"
];
};
fail2ban = let
cfg = config.services.prometheus.extraExporters.fail2ban;
in {
port = 9191;
serviceOpts = {
after = ["fail2ban.service"];
requires = ["fail2ban.service"];
serviceConfig = {
Group = "fail2ban";
RestrictAddressFamilies = ["AF_UNIX" "AF_INET" "AF_INET6"];
ExecStart = lib.concatStringsSep " " [
"${pkgs.local.prometheus-fail2ban-exporter}/bin/fail2ban-prometheus-exporter"
"--collector.f2b.socket=/var/run/fail2ban/fail2ban.sock"
"--web.listen-address='${cfg.listenAddress}:${toString cfg.port}'"
"--collector.f2b.exit-on-socket-connection-error=true"
];
};
};
};
};
# TODO(tlater):

View file

@ -1,8 +1,6 @@
{ config, ... }:
let
{config, ...}: let
domain = "metrics.${config.services.nginx.domain}";
in
{
in {
services.grafana = {
enable = true;
settings = {
@ -42,12 +40,7 @@ in
forceSSL = true;
useACMEHost = "tlater.net";
enableHSTS = true;
locations = {
"/".proxyPass = "http://localhost:${toString config.services.grafana.settings.server.http_port}";
"/api/live" = {
proxyWebsockets = true;
proxyPass = "http://localhost:${toString config.services.grafana.settings.server.http_port}";
};
};
enableAuthorization = true;
locations."/".proxyPass = "http://localhost:${toString config.services.grafana.settings.server.http_port}";
};
}

View file

@ -3,223 +3,202 @@
config,
lib,
...
}:
let
}: let
inherit (lib) types mkOption mkDefault;
yaml = pkgs.formats.yaml { };
in
{
yaml = pkgs.formats.yaml {};
in {
options = {
services.prometheus = {
extraExporters = mkOption {
type = types.attrsOf (
types.submodule {
options = {
port = mkOption {
type = types.int;
description = "The port on which this exporter listens.";
};
listenAddress = mkOption {
type = types.str;
default = "127.0.0.1";
description = "Address to listen on.";
};
serviceOpts = mkOption {
type = types.attrs;
description = "An attrset to be merged with the exporter's systemd service.";
};
type = types.attrsOf (types.submodule {
options = {
port = mkOption {
type = types.int;
description = "The port on which this exporter listens.";
};
}
);
listenAddress = mkOption {
type = types.str;
default = "127.0.0.1";
description = "Address to listen on.";
};
serviceOpts = mkOption {
type = types.attrs;
description = "An attrset to be merged with the exporter's systemd service.";
};
};
});
};
};
services.victoriametrics.scrapeConfigs = mkOption {
type = types.attrsOf (
types.submodule (
{ name, self, ... }:
{
options = {
job_name = mkOption {
type = types.str;
default = name;
type = types.attrsOf (types.submodule ({
name,
self,
...
}: {
options = {
job_name = mkOption {
type = types.str;
default = name;
};
extraSettings = mkOption {
type = types.anything;
description = ''
Other settings to set for this scrape config.
'';
default = {};
};
targets = mkOption {
type = types.listOf types.str;
description = lib.mdDoc ''
Addresses scrape targets for this config listen on.
Shortcut for `static_configs = lib.singleton {targets = [<targets>];}`
'';
default = [];
};
static_configs = mkOption {
default = [];
type = types.listOf (types.submodule {
options = {
targets = mkOption {
type = types.listOf types.str;
description = lib.mdDoc ''
The addresses scrape targets for this config listen on.
Must in `listenAddress:port` format.
'';
};
labels = mkOption {
type = types.attrsOf types.str;
description = lib.mdDoc ''
Labels to apply to all targets defined for this static config.
'';
default = {};
};
};
extraSettings = mkOption {
type = types.anything;
description = ''
Other settings to set for this scrape config.
'';
default = { };
};
targets = mkOption {
type = types.listOf types.str;
description = lib.mdDoc ''
Addresses scrape targets for this config listen on.
Shortcut for `static_configs = lib.singleton {targets = [<targets>];}`
'';
default = [ ];
};
static_configs = mkOption {
default = [ ];
type = types.listOf (
types.submodule {
options = {
targets = mkOption {
type = types.listOf types.str;
description = lib.mdDoc ''
The addresses scrape targets for this config listen on.
Must in `listenAddress:port` format.
'';
};
labels = mkOption {
type = types.attrsOf types.str;
description = lib.mdDoc ''
Labels to apply to all targets defined for this static config.
'';
default = { };
};
};
}
);
};
};
}
)
);
});
};
};
}));
};
};
config = {
systemd.services = lib.mkMerge [
(lib.mapAttrs' (
name: exporter:
lib.nameValuePair "prometheus-${name}-exporter" (
lib.mkMerge [
{
# Shamelessly copied from upstream because the upstream
# module is an intractable mess
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
serviceConfig.Restart = mkDefault "always";
serviceConfig.PrivateTmp = mkDefault true;
serviceConfig.WorkingDirectory = mkDefault /tmp;
serviceConfig.DynamicUser = mkDefault true;
# Hardening
serviceConfig.CapabilityBoundingSet = mkDefault [ "" ];
serviceConfig.DeviceAllow = [ "" ];
serviceConfig.LockPersonality = true;
serviceConfig.MemoryDenyWriteExecute = true;
serviceConfig.NoNewPrivileges = true;
serviceConfig.PrivateDevices = mkDefault true;
serviceConfig.ProtectClock = mkDefault true;
serviceConfig.ProtectControlGroups = true;
serviceConfig.ProtectHome = true;
serviceConfig.ProtectHostname = true;
serviceConfig.ProtectKernelLogs = true;
serviceConfig.ProtectKernelModules = true;
serviceConfig.ProtectKernelTunables = true;
serviceConfig.ProtectSystem = mkDefault "strict";
serviceConfig.RemoveIPC = true;
serviceConfig.RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
];
serviceConfig.RestrictNamespaces = true;
serviceConfig.RestrictRealtime = true;
serviceConfig.RestrictSUIDSGID = true;
serviceConfig.SystemCallArchitectures = "native";
serviceConfig.UMask = "0077";
}
exporter.serviceOpts
]
)
) config.services.prometheus.extraExporters)
(lib.mapAttrs' (name: exporter:
lib.nameValuePair "prometheus-${name}-exporter" (lib.mkMerge [
{
# Shamelessly copied from upstream because the upstream
# module is an intractable mess
wantedBy = ["multi-user.target"];
after = ["network.target"];
serviceConfig.Restart = mkDefault "always";
serviceConfig.PrivateTmp = mkDefault true;
serviceConfig.WorkingDirectory = mkDefault /tmp;
serviceConfig.DynamicUser = mkDefault true;
# Hardening
serviceConfig.CapabilityBoundingSet = mkDefault [""];
serviceConfig.DeviceAllow = [""];
serviceConfig.LockPersonality = true;
serviceConfig.MemoryDenyWriteExecute = true;
serviceConfig.NoNewPrivileges = true;
serviceConfig.PrivateDevices = mkDefault true;
serviceConfig.ProtectClock = mkDefault true;
serviceConfig.ProtectControlGroups = true;
serviceConfig.ProtectHome = true;
serviceConfig.ProtectHostname = true;
serviceConfig.ProtectKernelLogs = true;
serviceConfig.ProtectKernelModules = true;
serviceConfig.ProtectKernelTunables = true;
serviceConfig.ProtectSystem = mkDefault "strict";
serviceConfig.RemoveIPC = true;
serviceConfig.RestrictAddressFamilies = ["AF_INET" "AF_INET6"];
serviceConfig.RestrictNamespaces = true;
serviceConfig.RestrictRealtime = true;
serviceConfig.RestrictSUIDSGID = true;
serviceConfig.SystemCallArchitectures = "native";
serviceConfig.UMask = "0077";
}
exporter.serviceOpts
]))
config.services.prometheus.extraExporters)
{
vmagent-scrape-exporters =
let
listenAddress = config.services.victoriametrics.listenAddress;
vmAddr = (lib.optionalString (lib.hasPrefix ":" listenAddress) "127.0.0.1") + listenAddress;
promscrape = yaml.generate "prometheus.yml" {
scrape_configs = lib.mapAttrsToList (
_: scrape:
lib.recursiveUpdate {
inherit (scrape) job_name;
static_configs =
scrape.static_configs
++ lib.optional (scrape.targets != [ ]) { targets = scrape.targets; };
} scrape.extraSettings
) config.services.victoriametrics.scrapeConfigs;
};
in
{
enable = true;
path = [ pkgs.victoriametrics ];
wantedBy = [ "multi-user.target" ];
after = [
"network.target"
"victoriametrics.service"
];
serviceConfig = {
ExecStart = [
(lib.concatStringsSep " " [
"${pkgs.victoriametrics}/bin/vmagent"
"-promscrape.config=${promscrape}"
"-remoteWrite.url=http://${vmAddr}/api/v1/write"
"-remoteWrite.tmpDataPath=%t/vmagent"
])
];
SupplementaryGroups = "metrics";
DynamicUser = true;
RuntimeDirectory = "vmagent";
CapabilityBoundingSet = [ "" ];
DeviceAllow = [ "" ];
LockPersonality = true;
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
PrivateDevices = true;
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectSystem = "strict";
RemoveIPC = true;
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
UMask = "0077";
};
vmagent-scrape-exporters = let
listenAddress = config.services.victoriametrics.listenAddress;
vmAddr = (lib.optionalString (lib.hasPrefix ":" listenAddress) "127.0.0.1") + listenAddress;
promscrape = yaml.generate "prometheus.yml" {
scrape_configs = lib.mapAttrsToList (_: scrape:
lib.recursiveUpdate {
inherit (scrape) job_name;
static_configs =
scrape.static_configs
++ lib.optional (scrape.targets != []) {targets = scrape.targets;};
}
scrape.extraSettings)
config.services.victoriametrics.scrapeConfigs;
};
in {
enable = true;
path = [pkgs.victoriametrics];
wantedBy = ["multi-user.target"];
after = ["network.target" "victoriametrics.service"];
serviceConfig = {
ExecStart = [
(lib.concatStringsSep " " [
"${pkgs.victoriametrics}/bin/vmagent"
"-promscrape.config=${promscrape}"
"-remoteWrite.url=http://${vmAddr}/api/v1/write"
"-remoteWrite.tmpDataPath=%t/vmagent"
])
];
SupplementaryGroups = "metrics";
DynamicUser = true;
RuntimeDirectory = "vmagent";
CapabilityBoundingSet = [""];
DeviceAllow = [""];
LockPersonality = true;
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
PrivateDevices = true;
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectSystem = "strict";
RemoveIPC = true;
RestrictAddressFamilies = ["AF_INET" "AF_INET6"];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
UMask = "0077";
};
};
}
];
users.groups.metrics = { };
users.groups.metrics = {};
services.victoriametrics.scrapeConfigs =
let
allExporters = lib.mapAttrs (name: exporter: { inherit (exporter) listenAddress port; }) (
(lib.filterAttrs (
_: exporter: builtins.isAttrs exporter && exporter.enable
) config.services.prometheus.exporters)
// config.services.prometheus.extraExporters
);
in
services.victoriametrics.scrapeConfigs = let
allExporters =
lib.mapAttrs (name: exporter: {
inherit (exporter) listenAddress port;
}) ((lib.filterAttrs (_: exporter: builtins.isAttrs exporter && exporter.enable)
config.services.prometheus.exporters)
// config.services.prometheus.extraExporters);
in
lib.mapAttrs (_: exporter: {
targets = [ "${exporter.listenAddress}:${toString exporter.port}" ];
}) allExporters;
targets = ["${exporter.listenAddress}:${toString exporter.port}"];
})
allExporters;
};
}

View file

@ -1,15 +1,16 @@
{ config, ... }:
{
{config, ...}: {
config.services.victoriametrics = {
enable = true;
extraOptions = [ "-storage.minFreeDiskSpaceBytes=5GB" ];
extraOptions = [
"-storage.minFreeDiskSpaceBytes=5GB"
];
scrapeConfigs = {
forgejo = {
targets = [ "127.0.0.1:${toString config.services.forgejo.settings.server.HTTP_PORT}" ];
targets = ["127.0.0.1:${toString config.services.forgejo.settings.server.HTTP_PORT}"];
extraSettings.authorization.credentials_file = config.sops.secrets."forgejo/metrics-token".path;
};
coturn.targets = [ "127.0.0.1:9641" ];
coturn.targets = ["127.0.0.1:9641"];
};
};
}

View file

@ -1,35 +1,18 @@
{
pkgs,
config,
lib,
...
}:
let
}: let
# Update pending on rewrite of nextcloud news, though there is an
# alpha to switch to if it becomes necessary:
# https://github.com/nextcloud/news/issues/2610
nextcloud = pkgs.nextcloud28;
nextcloud = pkgs.nextcloud27;
hostName = "nextcloud.${config.services.nginx.domain}";
in
{
in {
services.nextcloud = {
inherit hostName;
package = nextcloud;
phpPackage = lib.mkForce (
pkgs.php.override {
packageOverrides = final: prev: {
extensions = prev.extensions // {
pgsql = prev.extensions.pgsql.overrideAttrs (old: {
configureFlags = [ "--with-pgsql=${config.services.postgresql.package}" ];
});
pdo_pgsql = prev.extensions.pdo_pgsql.overrideAttrs (old: {
configureFlags = [ "--with-pdo-pgsql=${config.services.postgresql.package}" ];
});
};
};
}
);
enable = true;
maxUploadSize = "2G";
https = true;
@ -54,19 +37,12 @@ in
};
extraApps = {
inherit (pkgs.local)
bookmarks
calendar
contacts
cookbook
news
notes
;
inherit (pkgs.local) bookmarks calendar contacts cookbook news notes;
};
};
# Ensure that this service doesn't start before postgres is ready
systemd.services.nextcloud-setup.after = [ "postgresql.service" ];
systemd.services.nextcloud-setup.after = ["postgresql.service"];
# Set up SSL
services.nginx.virtualHosts."${hostName}" = {

View file

@ -1,5 +1,8 @@
{ pkgs, ... }:
{
config,
pkgs,
...
}: {
services.postgresql = {
package = pkgs.postgresql_14;
enable = true;
@ -25,11 +28,16 @@
name = "nextcloud";
ensureDBOwnership = true;
}
{
name = config.services.authelia.instances.main.user;
ensureDBOwnership = true;
}
];
ensureDatabases = [
"grafana"
"nextcloud"
config.services.authelia.instances.main.user
];
};
}

View file

@ -1,14 +1,16 @@
{ pkgs, lib, ... }:
let
inherit (lib) concatStringsSep;
in
{
pkgs,
lib,
...
}: let
inherit (lib) concatStringsSep;
in {
# Sadly, steam-run requires some X libs
environment.noXlibs = false;
systemd.services.starbound = {
description = "Starbound";
after = [ "network.target" ];
after = ["network.target"];
serviceConfig = {
ExecStart = "${pkgs.local.starbound}/bin/launch-starbound ${./configs/starbound.json}";
@ -65,7 +67,7 @@ in
# Game servers shouldn't use cgroups themselves either
ProtectControlGroups = true;
# Most game servers will never need other socket types
RestrictAddressFamilies = [ "AF_UNIX AF_INET AF_INET6" ];
RestrictAddressFamilies = ["AF_UNIX AF_INET AF_INET6"];
# Also a no-brainer, no game server should ever need this
LockPersonality = true;
# Some game servers will probably try to set this, but they
@ -111,7 +113,9 @@ in
services.backups.starbound = {
user = "root";
paths = [ "/var/lib/private/starbound/storage/universe/" ];
pauseServices = [ "starbound.service" ];
paths = [
"/var/lib/private/starbound/storage/universe/"
];
pauseServices = ["starbound.service"];
};
}

View file

@ -1,8 +1,6 @@
{ config, ... }:
let
{config, ...}: let
domain = config.services.nginx.domain;
in
{
in {
services.tlaternet-webserver = {
enable = true;
listen = {
@ -12,17 +10,15 @@ in
};
# Set up SSL
services.nginx.virtualHosts."${domain}" =
let
inherit (config.services.tlaternet-webserver.listen) addr port;
in
{
serverAliases = [ "www.${domain}" ];
services.nginx.virtualHosts."${domain}" = let
inherit (config.services.tlaternet-webserver.listen) addr port;
in {
serverAliases = ["www.${domain}"];
forceSSL = true;
useACMEHost = "tlater.net";
enableHSTS = true;
forceSSL = true;
useACMEHost = "tlater.net";
enableHSTS = true;
locations."/".proxyPass = "http://${addr}:${toString port}";
};
locations."/".proxyPass = "http://${addr}:${toString port}";
};
}

View file

@ -1,5 +1,4 @@
{ config, ... }:
{
{config, ...}: {
# iptables needs to permit forwarding from wg0 to wg0
networking.firewall.extraCommands = ''
iptables -A FORWARD -i wg0 -o wg0 -j ACCEPT
@ -27,7 +26,7 @@
{
# yui
wireguardPeerConfig = {
AllowedIPs = [ "10.45.249.2/32" ];
AllowedIPs = ["10.45.249.2/32"];
PublicKey = "5mlnqEVJWks5OqgeFA2bLIrvST9TlCE81Btl+j4myz0=";
};
}
@ -35,7 +34,7 @@
{
# yuanyuan
wireguardPeerConfig = {
AllowedIPs = [ "10.45.249.10/32" ];
AllowedIPs = ["10.45.249.10/32"];
PublicKey = "0UsFE2atz/O5P3OKQ8UHyyyGQNJbp1MeIWUJLuoerwE=";
};
}

View file

@ -31,8 +31,8 @@
};
# Heisenbridge
"heisenbridge/as-token" = { };
"heisenbridge/hs-token" = { };
"heisenbridge/as-token" = {};
"heisenbridge/hs-token" = {};
"hetzner-api" = {
owner = "acme";
@ -62,10 +62,10 @@
};
# Steam
"steam/tlater" = { };
"steam/tlater" = {};
# Turn
"turn/env" = { };
"turn/env" = {};
"turn/secret" = {
owner = "turnserver";
};

View file

@ -7,11 +7,11 @@
"utils": "utils"
},
"locked": {
"lastModified": 1718194053,
"narHash": "sha256-FaGrf7qwZ99ehPJCAwgvNY5sLCqQ3GDiE/6uLhxxwSY=",
"lastModified": 1711973905,
"narHash": "sha256-UFKME/N1pbUtn+2Aqnk+agUt8CekbpuqwzljivfIme8=",
"owner": "serokell",
"repo": "deploy-rs",
"rev": "3867348fa92bc892eba5d9ddb2d7a97b9e127a8a",
"rev": "88b3059b020da69cbe16526b8d639bd5e0b51c8b",
"type": "github"
},
"original": {
@ -27,11 +27,11 @@
]
},
"locked": {
"lastModified": 1723685519,
"narHash": "sha256-GkXQIoZmW2zCPp1YFtAYGg/xHNyFH/Mgm79lcs81rq0=",
"lastModified": 1714103775,
"narHash": "sha256-kcBiIrmqzt3bNTr2GMBfAyA+on8BEKO1iKzzDFQZkjI=",
"owner": "nix-community",
"repo": "disko",
"rev": "276a0d055a720691912c6a34abb724e395c8e38a",
"rev": "285e26465a0bae510897ca04da26ce6307c652b4",
"type": "github"
},
"original": {
@ -47,11 +47,11 @@
"pyproject-nix": "pyproject-nix"
},
"locked": {
"lastModified": 1719685993,
"narHash": "sha256-04gy1icwnGO3ZXF6r96yBm/C0PNPzeLxA/8xzzq0dBI=",
"lastModified": 1702457430,
"narHash": "sha256-8NQiXtYCOiC7XFayy6GPGDudCBrPROry3mfWjpdVj5g=",
"owner": "nix-community",
"repo": "dream2nix",
"rev": "1b5e01219a32324c8f6889fe1f4db933ec7932f6",
"rev": "262198033e23e9ee832f0cc8133d38f07598f555",
"type": "github"
},
"original": {
@ -69,11 +69,11 @@
"rust-analyzer-src": "rust-analyzer-src"
},
"locked": {
"lastModified": 1719815435,
"narHash": "sha256-K2xFp142onP35jcx7li10xUxNVEVRWjAdY8DSuR7Naw=",
"lastModified": 1704003651,
"narHash": "sha256-bA3d4E1CX5G7TVbKwJOm9jZfVOGOPp6u5CKEUzNsE8E=",
"owner": "nix-community",
"repo": "fenix",
"rev": "ebfe2c639111d7e82972a12711206afaeeda2450",
"rev": "c6d82e087ac96f24b90c5787a17e29a72566c2b4",
"type": "github"
},
"original": {
@ -157,11 +157,11 @@
]
},
"locked": {
"lastModified": 1722661736,
"narHash": "sha256-0lujsK40JV/2PlqCjhZMGpHKL4vDKzJcnkFJYnG1WZA=",
"lastModified": 1712623723,
"narHash": "sha256-jPD5+M+QPyMRk52zfFMIeHdv7yXYJ/yNGqwS0PhYF+E=",
"owner": "reckenrode",
"repo": "nix-foundryvtt",
"rev": "699a175398410688214615a9d977354e9ef98d2d",
"rev": "6025615b431170558c3c13f16b549fc0126425e1",
"type": "github"
},
"original": {
@ -210,59 +210,59 @@
},
"nixpkgs-stable": {
"locked": {
"lastModified": 1721524707,
"narHash": "sha256-5NctRsoE54N86nWd0psae70YSLfrOek3Kv1e8KoXe/0=",
"lastModified": 1713638189,
"narHash": "sha256-q7APLfB6FmmSMI1Su5ihW9IwntBsk2hWNXh8XtSdSIk=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "556533a23879fc7e5f98dd2e0b31a6911a213171",
"rev": "74574c38577914733b4f7a775dd77d24245081dd",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "release-24.05",
"ref": "release-23.11",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-unstable": {
"locked": {
"lastModified": 1723957280,
"narHash": "sha256-J08Yqf2IJ73y7myI69qEKsQ048ibweG6FeJeCxbIdB4=",
"lastModified": 1714253743,
"narHash": "sha256-mdTQw2XlariysyScCv2tTE45QSU9v/ezLcHJ22f0Nxc=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "abcef4da4ebb72240bddc370a27263627e64877f",
"rev": "58a1abdbae3217ca6b702f03d3b35125d88a2994",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable-small",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1723920526,
"narHash": "sha256-USs6A60raDKZ/8BEpqja1XjZIsRzADX+NtWKH6wIxIw=",
"lastModified": 1718208800,
"narHash": "sha256-US1tAChvPxT52RV8GksWZS415tTS7PV42KTc2PNDBmc=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "1cbd3d585263dc620c483e138d352a39b9f0e3ec",
"rev": "cc54fb41d13736e92229c21627ea4f22199fee6b",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-24.05-small",
"ref": "nixos-24.05",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1719468428,
"narHash": "sha256-vN5xJAZ4UGREEglh3lfbbkIj+MPEYMuqewMn4atZFaQ=",
"lastModified": 1702272962,
"narHash": "sha256-D+zHwkwPc6oYQ4G3A1HuadopqRwUY/JkMwHz1YF7j4Q=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "1e3deb3d8a86a870d925760db1a5adecc64d329d",
"rev": "e97b3e4186bcadf0ef1b6be22b8558eab1cdeb5d",
"type": "github"
},
"original": {
@ -281,11 +281,11 @@
]
},
"locked": {
"lastModified": 1718252448,
"narHash": "sha256-xZZBdKqe1ByITzvx65pVgGQ5jeb73MybjgrcfI84lEo=",
"lastModified": 1713333471,
"narHash": "sha256-sIVQKOXzruxtTYiBRHZa8UQH+CSIa9K5MZlY6vavYfA=",
"owner": "berberman",
"repo": "nvfetcher",
"rev": "fa7609950023462c6f91c425de7610c0bb6b86ba",
"rev": "2a824322dc6a755ffda83a13b948d42304521e4d",
"type": "github"
},
"original": {
@ -375,11 +375,11 @@
"rust-analyzer-src": {
"flake": false,
"locked": {
"lastModified": 1719760370,
"narHash": "sha256-fsxAuW6RxKZYjAP3biUC6C4vaYFhDfWv8lp1Tmx3ZCY=",
"lastModified": 1703965384,
"narHash": "sha256-3iyouqkBvhh/E48TkBlt4JmmcIEyfQwY7pokKBx9WNg=",
"owner": "rust-lang",
"repo": "rust-analyzer",
"rev": "ea7fdada6a0940b239ddbde2048a4d7dac1efe1e",
"rev": "e872f5085cf5b0e44558442365c1c033d486eff2",
"type": "github"
},
"original": {
@ -442,11 +442,11 @@
"nixpkgs-stable": "nixpkgs-stable"
},
"locked": {
"lastModified": 1723501126,
"narHash": "sha256-N9IcHgj/p1+2Pvk8P4Zc1bfrMwld5PcosVA0nL6IGdE=",
"lastModified": 1713892811,
"narHash": "sha256-uIGmA2xq41vVFETCF1WW4fFWFT2tqBln+aXnWrvjGRE=",
"owner": "Mic92",
"repo": "sops-nix",
"rev": "be0eec2d27563590194a9206f551a6f73d52fa34",
"rev": "f1b0adc27265274e3b0c9b872a8f476a098679bd",
"type": "github"
},
"original": {
@ -523,11 +523,11 @@
]
},
"locked": {
"lastModified": 1719851829,
"narHash": "sha256-M5miiIbiwP4uArTyeIr/RKA857rP14AEJUe11AZsKAc=",
"lastModified": 1704840002,
"narHash": "sha256-ik2LeuRjcnRXwBLoRSOyGEMXscE+coO8G79IFhZhdJk=",
"ref": "refs/heads/master",
"rev": "4a099f27a27f4107ceb14969e2158eaabebcf1d4",
"revCount": 74,
"rev": "d14f50c8dcc8ab30a5e5fa907b392ac0df6c7b52",
"revCount": 73,
"type": "git",
"url": "https://gitea.tlater.net/tlaternet/tlaternet.git"
},

250
flake.nix
View file

@ -2,8 +2,8 @@
description = "tlater.net host configuration";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-24.05-small";
nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable-small";
nixpkgs.url = "github:nixos/nixpkgs/nixos-24.05";
nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable";
disko = {
url = "github:nix-community/disko";
inputs.nixpkgs.follows = "nixpkgs";
@ -32,144 +32,126 @@
};
};
outputs =
{
self,
nixpkgs,
sops-nix,
nvfetcher,
deploy-rs,
...
}@inputs:
let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
vm = nixpkgs.lib.nixosSystem {
outputs = {
self,
nixpkgs,
sops-nix,
nvfetcher,
deploy-rs,
...
} @ inputs: let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
in {
##################
# Configurations #
##################
nixosConfigurations = {
# The actual system definition
hetzner-1 = nixpkgs.lib.nixosSystem {
inherit system;
specialArgs.flake-inputs = inputs;
modules = [
./configuration
./configuration/hardware-specific/vm.nix
];
};
in
{
##################
# Configurations #
##################
nixosConfigurations = {
# The actual system definition
hetzner-1 = nixpkgs.lib.nixosSystem {
inherit system;
specialArgs.flake-inputs = inputs;
modules = [
./configuration
./configuration/hardware-specific/hetzner
];
};
};
############################
# Deployment configuration #
############################
deploy.nodes = {
hetzner-1 = {
hostname = "116.202.158.55";
profiles.system = {
user = "root";
path = deploy-rs.lib.${system}.activate.nixos self.nixosConfigurations.hetzner-1;
};
sshUser = "tlater";
sshOpts = [
"-p"
"2222"
"-o"
"ForwardAgent=yes"
];
};
};
#########
# Tests #
#########
checks = builtins.mapAttrs (system: deployLib: deployLib.deployChecks self.deploy) deploy-rs.lib;
###########################
# Garbage collection root #
###########################
packages.${system}.default = vm.config.system.build.vm;
###################
# Utility scripts #
###################
apps.${system} = {
default = self.apps.${system}.run-vm;
run-vm = {
type = "app";
program =
let
in
(pkgs.writeShellScript "" ''
${vm.config.system.build.vm.outPath}/bin/run-testvm-vm
'').outPath;
};
update-pkgs = {
type = "app";
program =
let
nvfetcher-bin = "${nvfetcher.packages.${system}.default}/bin/nvfetcher";
in
(pkgs.writeShellScript "update-pkgs" ''
cd "$(git rev-parse --show-toplevel)/pkgs"
${nvfetcher-bin} -o _sources_pkgs -c nvfetcher.toml
'').outPath;
};
update-nextcloud-apps = {
type = "app";
program =
let
nvfetcher-bin = "${nvfetcher.packages.${system}.default}/bin/nvfetcher";
in
(pkgs.writeShellScript "update-nextcloud-apps" ''
cd "$(git rev-parse --show-toplevel)/pkgs"
${nvfetcher-bin} -o _sources_nextcloud -c nextcloud-apps.toml
'').outPath;
};
};
###########################
# Development environment #
###########################
devShells.${system}.default = nixpkgs.legacyPackages.${system}.mkShell {
sopsPGPKeyDirs = [
"./keys/hosts/"
"./keys/users/"
];
nativeBuildInputs = [ sops-nix.packages.${system}.sops-import-keys-hook ];
packages = with pkgs; [
sops-nix.packages.${system}.sops-init-gpg-key
deploy-rs.packages.${system}.default
nixpkgs-fmt
cargo
clippy
rustc
rustfmt
rust-analyzer
pkg-config
openssl
./configuration/hardware-specific/hetzner
];
};
};
############################
# Deployment configuration #
############################
deploy.nodes = {
hetzner-1 = {
hostname = "116.202.158.55";
profiles.system = {
user = "root";
path = deploy-rs.lib.${system}.activate.nixos self.nixosConfigurations.hetzner-1;
};
sshUser = "tlater";
sshOpts = ["-p" "2222" "-o" "ForwardAgent=yes"];
};
};
#########
# Tests #
#########
checks = builtins.mapAttrs (system: deployLib: deployLib.deployChecks self.deploy) deploy-rs.lib;
###################
# Utility scripts #
###################
apps.${system} = {
default = self.apps.${system}.run-vm;
run-vm = {
type = "app";
program = let
vm = nixpkgs.lib.nixosSystem {
inherit system;
specialArgs.flake-inputs = inputs;
modules = [
./configuration
./configuration/hardware-specific/vm.nix
];
};
in
(pkgs.writeShellScript "" ''
${vm.config.system.build.vm.outPath}/bin/run-testvm-vm
'')
.outPath;
};
update-pkgs = {
type = "app";
program = let
nvfetcher-bin = "${nvfetcher.packages.${system}.default}/bin/nvfetcher";
in
(pkgs.writeShellScript "update-pkgs" ''
cd "$(git rev-parse --show-toplevel)/pkgs"
${nvfetcher-bin} -o _sources_pkgs -c nvfetcher.toml
'')
.outPath;
};
update-nextcloud-apps = {
type = "app";
program = let
nvfetcher-bin = "${nvfetcher.packages.${system}.default}/bin/nvfetcher";
in
(pkgs.writeShellScript "update-nextcloud-apps" ''
cd "$(git rev-parse --show-toplevel)/pkgs"
${nvfetcher-bin} -o _sources_nextcloud -c nextcloud-apps.toml
'')
.outPath;
};
};
###########################
# Development environment #
###########################
devShells.${system}.default = nixpkgs.legacyPackages.${system}.mkShell {
sopsPGPKeyDirs = ["./keys/hosts/" "./keys/users/"];
nativeBuildInputs = [
sops-nix.packages.${system}.sops-import-keys-hook
];
packages = with pkgs; [
sops-nix.packages.${system}.sops-init-gpg-key
deploy-rs.packages.${system}.default
cargo
clippy
rustc
rustfmt
rust-analyzer
pkg-config
openssl
];
};
};
}

View file

@ -1,4 +1,6 @@
hetzner-api: ENC[AES256_GCM,data:OsUfo86AzcBe/OELkfB5brEfsZ4gkbeehxwIVUBwQgE=,iv:Bt/cjlZ6oZEVUOQjWMDL7/mfL3HWLFAw1tEGeLMgeKg=,tag:TMU2XiHlMgP4aes10mIQYQ==,type:str]
authelia:
storageEncryptionKey: ENC[AES256_GCM,data:OUCC+6Gcr6U7Mub1+DaIyswTV6da1wd1u0WGEm4wpJ8L0mi7WSpEmVjH79YyRhp7AmiZhdFFDXFeEYthBb2AZl+xoS9gqs6rWyfU4ezaCbXBiS/dIhsA5foPg13wq5A33qJWtPTy7DJEgqHaIonnaBuVJIBwH3wzPTHc3bDvBo4=,iv:intiZzngz5cMTtjEI9rTKMW0Xv3KB3ZEgtYN3amwKCE=,tag:AKxfbeZlPs54esHCsVnNCg==,type:str]
sessionSecret: ENC[AES256_GCM,data:GEMWhBltOIOs0g9FsWk3OQGs6dMcbwz3ZuhlyBFYROylsIZb4xTXWLgNwIpHwQukQU3TgvIxbCW/fGRWiALPanE2koSVAHNx0UU0hj1mVNRFQGK4H3EL10tPp7l4PofrcdeCbLPrOwM/xLOuPt+52sKlcbL2Awz5/MmpUVpCKXc=,iv:kWX2ptOpTgW3obBgri0MvVv6gCEPR3o77sldOXFQeks=,tag:je4pqLcEOhuBTQkoZHYNCw==,type:str]
battery-manager:
email: ENC[AES256_GCM,data:rYLUACXR/n+bLBmZ,iv:sUBEkh2+7qGjHZ5R23e/hoCiyTA7GTL4bJvXmxjZ5Sw=,tag:fdPMllaQQfRgX0WZKIre4g==,type:str]
password: ENC[AES256_GCM,data:7cokZa6Q6ahSeiFPz+cV,iv:vz405P0IcG9FsAQXlY7mi78GuushQUKJm2irG6buGzc=,tag:JLHG2jTkJDGbinAq9dXRsQ==,type:str]
@ -32,8 +34,8 @@ sops:
azure_kv: []
hc_vault: []
age: []
lastmodified: "2024-04-15T23:13:18Z"
mac: ENC[AES256_GCM,data:3/v+WgSWJ+VcBSBe1Wkis3z+tMmSjbKzLFqBB8xugc6DvgQG8J+1HRrPucLnpNNtEdmpyoTa72U6fPm6JnyUsuj5pLEghLprOJkqQNdRI06fllhw+9d3e3twx6D4oIIsVH6/io4ElXrGsGQTsfNbYhgn+987wa3WP5N25fBac3U=,iv:FL3tzPutOMN6IPkQfXIu/JOZT+OzUSqpMSQrUeXZQHE=,tag:jL1BTsYTA9XjrsjFszxZhA==,type:str]
lastmodified: "2024-04-11T23:38:56Z"
mac: ENC[AES256_GCM,data:GjIB0EbWsh4o+QoFSyIXgGYnNhRlvfSmue1LyTt6oUlIjNgODhdIB8px8LnRo0rmm/f1YHbDq2MFOxlgdm3PTNaqm/MoKyW3r/wuAeWADsYayQszLNxyhTMXcjWtfm6zCRIuc/+YyM44pXRfVrOZRAin9B6pmJZsRJwBAZpogbU=,iv:r/ZQZvrP0E9dOW5fhBH2I21Z0uv2e3njdEGmadxEALg=,tag:iZvbGTvRJFo80n8aoKSSmQ==,type:str]
pgp:
- created_at: "2024-03-18T04:02:00Z"
enc: |-

View file

@ -1,4 +1,7 @@
hetzner-api: ENC[AES256_GCM,data:1Zjp003j60g=,iv:+vDcyiqYm4A9CMIrW4oGZKdZiczatBcvfL4qYYhKwCg=,tag:Xeu8JuRm+b+5RO+wFR2M8w==,type:str]
authelia:
storageEncryptionKey: ENC[AES256_GCM,data:8X6Zvq7ct1MkMH+lc5kTTHXOo6rGyhSzc3aWxGRA5tnBet+TGcENo0RYTYmactsPGVpTIUGGplaG7B7dqRPhkdDHhbCCZCm2nLaYjpVJ241DrpUNKHn8lvg/bMxUQ/Dvw76ByYuWN6bREr3XRaBztBSPzld8zTSYx71I0CKY7vk=,iv:cJSwfuVWO39qqKCGt2Mvw7pN8+hD6kRH9v4c/u4hLuk=,tag:YhdlXuX2ETxjb443RI8MsA==,type:str]
sessionSecret: ENC[AES256_GCM,data:dnoWmc4HND62w3jMXL+akncAEb61c/I70DgRytx55Wxcn4rMiswp6zCkRdsP4CkouTQ1lyAcQrubp5I8M9Kyow/KBMYz9dPkr4+2xJ9w0SEmAVhyPe2DFvYos3x0Uvx5S0B3o1mXoXqbg78e4w5yEIbALiJT8VPGrWK8Cl4nVPo=,iv:FHDXUW2DWUmEZzWUYkYduogdVOtvMlRH4/fVg05cZaI=,tag:u282WQnHpBsZGYJH7mFFKA==,type:str]
jwtSecret: ENC[AES256_GCM,data:0M3AyoMp+orrljl5NsxmthzrHMmu0REcz7+9fpFKbwwqV6KqlpgGddjYZIsTpHEWEq9zhZ2YWLJkMxKdDgROVHUFZGKut28JPSAjjY+1V0wxNBnfSCnxEv5BUw2+cCxcpCwYQyNfRK6SotTt8aqpxvda4oRXpzxV6SW7ogDjc6E=,iv:D57SynZkW2JuFyX6bpZYkxpR2KtkOmKaySg1Bxim0r8=,tag:JCPGZaumdHrtgcH16A7b+g==,type:str]
battery-manager:
email: ENC[AES256_GCM,data:LM/EGzWHfVQ=,iv:jFaoUQuUfuGoOyj/GFpdI8TerH/c8D9fjvio+IEt2Tc=,tag:IWLiN011JEnHRLIXWQgfmA==,type:str]
password: ENC[AES256_GCM,data:SUxjqS7SJHM=,iv:LvdKk88S+nSImh6/ZezbFGLCUBu1Lpdu+neF2xyHdBg=,tag:rcMyZuW4FVNbcbz00wQKBg==,type:str]
@ -32,8 +35,8 @@ sops:
azure_kv: []
hc_vault: []
age: []
lastmodified: "2024-04-15T23:13:27Z"
mac: ENC[AES256_GCM,data:JhEVrKF2Jsqpdztcr3g5lMrgEFeLXfBRQTwQJ6PmLSNyDORcTU09TJPNWTPDnR5okDrvIU/wlzi5DZ8A0ebNhrKf6l0tNFBT9LSvQFHU5SBxqY/m8uEJKSrEC4IL5lugOOISDka2KSvYXVCXrumMHE5FnmOS/CgOZaZk6LUjPYA=,iv:ygygnSedcTo2Vsc56s2qrz1qkWchvSgvoiMTebRxQQ8=,tag:vf6z8rxsXmqzwpDy9Avifw==,type:str]
lastmodified: "2024-04-12T01:00:31Z"
mac: ENC[AES256_GCM,data:fVnMwfvGi7vtP1Fg4NLrhGvLF2PcIgZPOcwk4Ssm4iw5iSj0K1npOX3pd5BWzyszqchfYYRHY99GllAump0bZmprVAld9rf70B2HZIVvowBPuUXfc9Cz/5q0z+s8bQ5vCdElW1Bh7h8W/POePdc8cFGAyBS4i1ZVNheIDOHdDjI=,iv:Bi6rekXOx3/dwwPRryF3CoAoQi3D06ABysRF1oBeG5A=,tag:0TCra+AkhBDczj4uvAzKMw==,type:str]
pgp:
- created_at: "2023-12-29T15:25:27Z"
enc: |

View file

@ -1 +1,5 @@
{ imports = [ ./nginxExtensions.nix ]; }
{
imports = [
./nginxExtensions.nix
];
}

View file

@ -3,57 +3,156 @@
pkgs,
lib,
...
}:
{
}: {
options = {
services.nginx.domain = lib.mkOption {
type = lib.types.str;
description = "The base domain name to append to virtual domain names";
};
services.nginx.virtualHosts =
let
extraVirtualHostOptions =
{ name, config, ... }:
{
options = {
enableHSTS = lib.mkEnableOption "Enable HSTS";
services.nginx.virtualHosts = let
autheliaDomain = "auth.${config.services.nginx.domain}";
extraLocationOptions = {config, ...}: {
options = {
enableAutheliaProxy = lib.mkEnableOption "Enable recommended authelia proxy settings";
enableAuthorization = lib.mkEnableOption "Enable authorization via authelia";
};
addAccessLog = lib.mkOption {
type = lib.types.bool;
default = true;
description = ''
Add special logging to `/var/log/nginx/''${serverName}`
'';
};
};
config = {
recommendedProxySettings = lib.mkIf config.enableAutheliaProxy false;
config = {
extraConfig = lib.concatStringsSep "\n" [
(lib.optionalString config.enableHSTS ''
add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
'')
(lib.optionalString config.addAccessLog ''
access_log /var/log/nginx/${name}/access.log upstream_time;
'')
];
extraConfig = lib.concatStringsSep "\n" [
(lib.optionalString config.enableAutheliaProxy ''
proxy_set_header Host $host;
proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-URI $request_uri;
proxy_set_header X-Forwarded-Ssl on;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Connection "";
client_body_buffer_size 128k;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
proxy_redirect http:// $scheme://;
proxy_http_version 1.1;
proxy_cache_bypass $cookie_session;
proxy_no_cache $cookie_session;
proxy_buffers 64 256k;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
send_timeout 5m;
proxy_read_timeout 360;
proxy_send_timeout 360;
proxy_connect_timeout 360;
'')
(lib.optionalString config.enableAuthorization ''
auth_request /authelia;
set_escape_uri $target_url $scheme://$http_host$request_uri;
auth_request_set $user $upstream_http_remote_user;
auth_request_set $groups $upstream_http_remote_groups;
auth_request_set $name $upstream_http_remote_name;
auth_request_set $email $upstream_http_remote_email;
proxy_set_header Remote-User $user;
proxy_set_header Remote-Groups $groups;
proxy_set_header Remote-Email $email;
proxy_set_header Remote-Name $name;
error_page 401 =302 https://${autheliaDomain}/?rd=$target_url;
'')
];
};
};
extraVirtualHostOptions = {
name,
config,
...
}: {
options = {
enableAuthorization = lib.mkEnableOption "Enable authorization via authelia";
enableHSTS = lib.mkEnableOption "Enable HSTS";
addAccessLog = lib.mkOption {
type = lib.types.bool;
default = true;
description = ''
Add special logging to `/var/log/nginx/''${serverName}`
'';
};
locations = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule extraLocationOptions);
};
};
config = {
extraConfig = lib.concatStringsSep "\n" [
(lib.optionalString config.enableHSTS ''
add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
'')
(lib.optionalString config.addAccessLog ''
access_log /var/log/nginx/${name}/access.log upstream_time;
'')
];
locations = lib.mkIf config.enableAuthorization {
"/".enableAuthorization = true;
"/authelia" = {
proxyPass = "http://127.0.0.1:9091/api/verify";
recommendedProxySettings = false;
extraConfig = ''
internal;
proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
proxy_set_header X-Original-Method $request_method;
proxy_set_header X-Forwarded-Method $request_method;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Uri $request_uri;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Content-Length "";
proxy_set_header Connection "";
proxy_pass_request_body off;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
proxy_redirect http:// $scheme://;
proxy_http_version 1.1;
proxy_cache_bypass $cookie_session;
proxy_no_cache $cookie_session;
proxy_buffers 4 32k;
client_body_buffer_size 128k;
send_timeout 5m;
proxy_read_timeout 240;
proxy_send_timeout 240;
proxy_connect_timeout 240;
'';
};
};
in
lib.mkOption { type = lib.types.attrsOf (lib.types.submodule extraVirtualHostOptions); };
};
};
in
lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule extraVirtualHostOptions);
};
};
config = {
# Don't attempt to run acme if the domain name is not tlater.net
systemd.services =
let
confirm = ''[[ "tlater.net" = ${config.services.nginx.domain} ]]'';
in
lib.mapAttrs' (
cert: _:
systemd.services = let
confirm = ''[[ "tlater.net" = ${config.services.nginx.domain} ]]'';
in
lib.mapAttrs' (cert: _:
lib.nameValuePair "acme-${cert}" {
serviceConfig.ExecCondition = ''${pkgs.runtimeShell} -c '${confirm}' '';
}
) config.security.acme.certs;
})
config.security.acme.certs;
};
}

View file

@ -7,11 +7,11 @@
"passthru": null,
"pinned": false,
"src": {
"sha256": "sha256-V4zZsAwPn8QiCXEDqOgNFHaXqMOcHMpMbJ1Oz3Db0pc=",
"sha256": "sha256-JXNQNnWXoii71QhtKktuEBEIqzmONVetULBhpSjM9xo=",
"type": "tarball",
"url": "https://github.com/nextcloud/bookmarks/releases/download/v14.2.4/bookmarks-14.2.4.tar.gz"
"url": "https://github.com/nextcloud/bookmarks/releases/download/v13.1.3/bookmarks-13.1.3.tar.gz"
},
"version": "14.2.4"
"version": "13.1.3"
},
"calendar": {
"cargoLocks": null,
@ -21,11 +21,11 @@
"passthru": null,
"pinned": false,
"src": {
"sha256": "sha256-sipXeyOL4OhENz7V2beFeSYBAoFZdCWtqftIy0lsqEY=",
"sha256": "sha256-hZfjWAMi/0qs5xMMgOlcoSXG6kcZ2aeDaez+NqSZFKI=",
"type": "tarball",
"url": "https://github.com/nextcloud-releases/calendar/releases/download/v4.7.15/calendar-v4.7.15.tar.gz"
"url": "https://github.com/nextcloud-releases/calendar/releases/download/v4.6.7/calendar-v4.6.7.tar.gz"
},
"version": "v4.7.15"
"version": "v4.6.7"
},
"contacts": {
"cargoLocks": null,
@ -49,11 +49,11 @@
"passthru": null,
"pinned": false,
"src": {
"sha256": "sha256-a8ekMnEzudHGiqHF53jPtgsVTOTc2QLuPg6YtTw5h68=",
"sha256": "sha256-TE/w8SgyIPaGl5wZUAsG234nxoPj25QoRPF3zjbMoRk=",
"type": "tarball",
"url": "https://github.com/christianlupus-nextcloud/cookbook-releases/releases/download/v0.11.1/Cookbook-0.11.1.tar.gz"
"url": "https://github.com/christianlupus-nextcloud/cookbook-releases/releases/download/v0.10.5/Cookbook-0.10.5.tar.gz"
},
"version": "0.11.1"
"version": "0.10.5"
},
"news": {
"cargoLocks": null,
@ -63,11 +63,11 @@
"passthru": null,
"pinned": false,
"src": {
"sha256": "sha256-AhTZGQCLeNgsRBF5w3+Lf9JtNN4D1QncB5t+odU+XUc=",
"sha256": "sha256-cfJkKRNSz15L4E3w1tnEb+t4MrVwVzb8lb6vCOA4cK4=",
"type": "tarball",
"url": "https://github.com/nextcloud/news/releases/download/25.0.0-alpha8/news.tar.gz"
"url": "https://github.com/nextcloud/news/releases/download/24.0.0/news.tar.gz"
},
"version": "25.0.0-alpha8"
"version": "24.0.0"
},
"notes": {
"cargoLocks": null,
@ -77,10 +77,10 @@
"passthru": null,
"pinned": false,
"src": {
"sha256": "sha256-A3QNWGWeC2OcZngMrh9NpYbU5qp5x9xiDcRfB9cRXBo=",
"sha256": "sha256-ydpxatwuZUz7XIgK8FMklZlxNQklpsP8Uqpxvt3iK0k=",
"type": "tarball",
"url": "https://github.com/nextcloud-releases/notes/releases/download/v4.10.1/notes-v4.10.1.tar.gz"
"url": "https://github.com/nextcloud/notes/releases/download/v4.10.0/notes.tar.gz"
},
"version": "v4.10.1"
"version": "v4.10.0"
}
}

View file

@ -3,18 +3,18 @@
{
bookmarks = {
pname = "bookmarks";
version = "14.2.4";
version = "13.1.3";
src = fetchTarball {
url = "https://github.com/nextcloud/bookmarks/releases/download/v14.2.4/bookmarks-14.2.4.tar.gz";
sha256 = "sha256-V4zZsAwPn8QiCXEDqOgNFHaXqMOcHMpMbJ1Oz3Db0pc=";
url = "https://github.com/nextcloud/bookmarks/releases/download/v13.1.3/bookmarks-13.1.3.tar.gz";
sha256 = "sha256-JXNQNnWXoii71QhtKktuEBEIqzmONVetULBhpSjM9xo=";
};
};
calendar = {
pname = "calendar";
version = "v4.7.15";
version = "v4.6.7";
src = fetchTarball {
url = "https://github.com/nextcloud-releases/calendar/releases/download/v4.7.15/calendar-v4.7.15.tar.gz";
sha256 = "sha256-sipXeyOL4OhENz7V2beFeSYBAoFZdCWtqftIy0lsqEY=";
url = "https://github.com/nextcloud-releases/calendar/releases/download/v4.6.7/calendar-v4.6.7.tar.gz";
sha256 = "sha256-hZfjWAMi/0qs5xMMgOlcoSXG6kcZ2aeDaez+NqSZFKI=";
};
};
contacts = {
@ -27,26 +27,26 @@
};
cookbook = {
pname = "cookbook";
version = "0.11.1";
version = "0.10.5";
src = fetchTarball {
url = "https://github.com/christianlupus-nextcloud/cookbook-releases/releases/download/v0.11.1/Cookbook-0.11.1.tar.gz";
sha256 = "sha256-a8ekMnEzudHGiqHF53jPtgsVTOTc2QLuPg6YtTw5h68=";
url = "https://github.com/christianlupus-nextcloud/cookbook-releases/releases/download/v0.10.5/Cookbook-0.10.5.tar.gz";
sha256 = "sha256-TE/w8SgyIPaGl5wZUAsG234nxoPj25QoRPF3zjbMoRk=";
};
};
news = {
pname = "news";
version = "25.0.0-alpha8";
version = "24.0.0";
src = fetchTarball {
url = "https://github.com/nextcloud/news/releases/download/25.0.0-alpha8/news.tar.gz";
sha256 = "sha256-AhTZGQCLeNgsRBF5w3+Lf9JtNN4D1QncB5t+odU+XUc=";
url = "https://github.com/nextcloud/news/releases/download/24.0.0/news.tar.gz";
sha256 = "sha256-cfJkKRNSz15L4E3w1tnEb+t4MrVwVzb8lb6vCOA4cK4=";
};
};
notes = {
pname = "notes";
version = "v4.10.1";
version = "v4.10.0";
src = fetchTarball {
url = "https://github.com/nextcloud-releases/notes/releases/download/v4.10.1/notes-v4.10.1.tar.gz";
sha256 = "sha256-A3QNWGWeC2OcZngMrh9NpYbU5qp5x9xiDcRfB9cRXBo=";
url = "https://github.com/nextcloud/notes/releases/download/v4.10.0/notes.tar.gz";
sha256 = "sha256-ydpxatwuZUz7XIgK8FMklZlxNQklpsP8Uqpxvt3iK0k=";
};
};
}

View file

@ -13,7 +13,6 @@
"name": null,
"rev": "v0.10.1",
"sha256": "sha256-zGEhDy3uXIbvx4agSA8Mx7bRtiZZtoDZGbNbHc9L+yI=",
"sparseCheckout": [],
"type": "git",
"url": "https://gitlab.com/hectorjsmith/fail2ban-prometheus-exporter"
},

View file

@ -10,7 +10,6 @@
fetchSubmodules = false;
deepClone = false;
leaveDotGit = false;
sparseCheckout = [ ];
sha256 = "sha256-zGEhDy3uXIbvx4agSA8Mx7bRtiZZtoDZGbNbHc9L+yI=";
};
};

View file

@ -1,12 +1,20 @@
{ pkgs, rustPlatform, ... }:
{
pkgs,
rustPlatform,
...
}:
rustPlatform.buildRustPackage {
pname = "afvalcalendar";
version = "0.1.0";
src = ./.;
nativeBuildInputs = with pkgs; [ pkg-config ];
nativeBuildInputs = with pkgs; [
pkg-config
];
buildInputs = with pkgs; [ openssl ];
buildInputs = with pkgs; [
openssl
];
cargoHash = "sha256-JXx6aUKdKbUTBCwlBw5i1hZy8ofCfSrhLCwFzqdA8cI=";
}

View file

@ -1,20 +1,22 @@
{ pkgs, lib }:
let
{
pkgs,
lib,
}: let
inherit (builtins) fromJSON mapAttrs readFile;
inherit (pkgs) callPackage;
in
{
starbound = callPackage ./starbound { };
prometheus-fail2ban-exporter = callPackage ./prometheus/fail2ban-exporter.nix {
sources = pkgs.callPackage ./_sources_pkgs/generated.nix { };
};
afvalcalendar = callPackage ./afvalcalendar { };
}
// (
# Add nextcloud apps
let
mkNextcloudApp = pkgs.callPackage ./mkNextcloudApp.nix { };
sources = fromJSON (readFile ./_sources_nextcloud/generated.json);
in
mapAttrs (_: source: mkNextcloudApp source) sources
)
{
starbound = callPackage ./starbound {};
prometheus-fail2ban-exporter = callPackage ./prometheus/fail2ban-exporter.nix {
sources = pkgs.callPackage ./_sources_pkgs/generated.nix {};
};
afvalcalendar = callPackage ./afvalcalendar {};
}
// (
# Add nextcloud apps
let
mkNextcloudApp = pkgs.callPackage ./mkNextcloudApp.nix {};
sources = fromJSON (readFile ./_sources_nextcloud/generated.json);
in
mapAttrs (_: source: mkNextcloudApp source) sources
)

View file

@ -1,5 +1,7 @@
{ fetchNextcloudApp, lib }:
source:
{
fetchNextcloudApp,
lib,
}: source:
fetchNextcloudApp {
url = source.src.url;
sha256 = source.src.sha256;

View file

@ -1,10 +1,12 @@
[bookmarks]
src.github = "nextcloud/bookmarks"
# src.github = "nextcloud/bookmarks"
src.prefix = "v"
src.manual = "v13.1.3"
fetch.tarball = "https://github.com/nextcloud/bookmarks/releases/download/v$ver/bookmarks-$ver.tar.gz"
[calendar]
src.github = "nextcloud-releases/calendar"
# src.github = "nextcloud-releases/calendar"
src.manual = "v4.6.7"
fetch.tarball = "https://github.com/nextcloud-releases/calendar/releases/download/$ver/calendar-$ver.tar.gz"
[contacts]
@ -13,16 +15,17 @@ src.manual = "v5.5.3"
fetch.tarball = "https://github.com/nextcloud-releases/contacts/releases/download/$ver/contacts-$ver.tar.gz"
[cookbook]
src.github = "christianlupus-nextcloud/cookbook-releases"
# src.github = "christianlupus-nextcloud/cookbook-releases"
src.prefix = "v"
src.manual = "0.10.5"
fetch.tarball = "https://github.com/christianlupus-nextcloud/cookbook-releases/releases/download/v$ver/Cookbook-$ver.tar.gz"
[news]
# Update manually until angular rewrite is done
# src.github = "nextcloud/news"
src.manual = "25.0.0-alpha8"
# Update to 25 when angular rewrite is done/the alpha when I need to switch to nextcloud 28+
src.manual = "24.0.0"
fetch.tarball = "https://github.com/nextcloud/news/releases/download/$ver/news.tar.gz"
[notes]
src.github = "nextcloud-releases/notes"
fetch.tarball = "https://github.com/nextcloud-releases/notes/releases/download/$ver/notes-$ver.tar.gz"
src.github = "nextcloud/notes"
fetch.tarball = "https://github.com/nextcloud/notes/releases/download/$ver/notes.tar.gz"

View file

@ -1,4 +1,7 @@
{ buildGoModule, sources }:
{
buildGoModule,
sources,
}:
buildGoModule {
inherit (sources.prometheus-fail2ban-exporter) pname src version;
vendorHash = "sha256-5o8p5p0U/c0WAIV5dACnWA3ThzSh2tt5LIFMb59i9GY=";

View file

@ -5,33 +5,30 @@
patchelf,
steamPackages,
replace-secret,
}:
let
}: let
# Use the directory in which starbound is installed so steamcmd
# doesn't have to be reinstalled constantly (we're using DynamicUser
# with StateDirectory to persist this).
steamcmd = steamPackages.steamcmd.override { steamRoot = "/var/lib/starbound/.steamcmd"; };
wrapperPath = lib.makeBinPath [
patchelf
steamcmd
replace-secret
];
steamcmd = steamPackages.steamcmd.override {
steamRoot = "/var/lib/starbound/.steamcmd";
};
wrapperPath = lib.makeBinPath [patchelf steamcmd replace-secret];
in
stdenv.mkDerivation {
name = "starbound-update-script";
nativeBuildInputs = [ makeWrapper ];
dontUnpack = true;
patchPhase = ''
interpreter="$(cat $NIX_CC/nix-support/dynamic-linker)"
substitute ${./launch-starbound.sh} launch-starbound --subst-var interpreter
'';
installPhase = ''
mkdir -p $out/bin
cp launch-starbound $out/bin/launch-starbound
chmod +x $out/bin/launch-starbound
'';
postFixup = ''
wrapProgram $out/bin/launch-starbound \
--prefix PATH : "${wrapperPath}"
'';
}
stdenv.mkDerivation {
name = "starbound-update-script";
nativeBuildInputs = [makeWrapper];
dontUnpack = true;
patchPhase = ''
interpreter="$(cat $NIX_CC/nix-support/dynamic-linker)"
substitute ${./launch-starbound.sh} launch-starbound --subst-var interpreter
'';
installPhase = ''
mkdir -p $out/bin
cp launch-starbound $out/bin/launch-starbound
chmod +x $out/bin/launch-starbound
'';
postFixup = ''
wrapProgram $out/bin/launch-starbound \
--prefix PATH : "${wrapperPath}"
'';
}