2022-12-03 03:11:48 +00:00
|
|
|
{ config, options, lib, pkgs, modulesPath, ... }:
|
2022-11-23 05:27:01 +00:00
|
|
|
|
|
|
|
let
|
2022-11-25 13:27:23 +00:00
|
|
|
inherit (builtins) toString;
|
2023-01-25 03:38:45 +00:00
|
|
|
inherit (import ./modules/hardware/networks.nix) interfaces;
|
2022-12-12 12:34:23 +00:00
|
|
|
|
2022-12-16 14:25:50 +00:00
|
|
|
# The head of the Borgbase hostname.
|
2023-01-07 02:51:49 +00:00
|
|
|
hetzner-boxes-user = "u332477";
|
|
|
|
hetzner-boxes-server = "${hetzner-boxes-user}.your-storagebox.de";
|
2022-11-23 05:27:01 +00:00
|
|
|
in
|
|
|
|
{
|
|
|
|
imports = [
|
2023-01-14 07:55:30 +00:00
|
|
|
# Since this will be rarely configured, make sure to import the appropriate
|
|
|
|
# hardware modules depending on the hosting provider (and even just the
|
|
|
|
# server).
|
|
|
|
./modules/hardware/hetzner-cloud-cx21.nix
|
2022-11-26 06:13:17 +00:00
|
|
|
|
2022-12-03 05:46:46 +00:00
|
|
|
# The users for this host.
|
|
|
|
(lib.getUser "nixos" "admin")
|
2022-11-26 06:13:17 +00:00
|
|
|
(lib.getUser "nixos" "plover")
|
2022-12-03 03:11:48 +00:00
|
|
|
|
2022-12-03 07:46:22 +00:00
|
|
|
# Hardened profile from nixpkgs.
|
2022-12-03 03:11:48 +00:00
|
|
|
"${modulesPath}/profiles/hardened.nix"
|
2023-01-12 13:22:55 +00:00
|
|
|
|
2023-02-08 10:00:35 +00:00
|
|
|
# The primary DNS server that is completely hidden.
|
2023-06-22 09:56:47 +00:00
|
|
|
./modules/services/bind.nix
|
2023-02-08 10:00:35 +00:00
|
|
|
|
2023-02-08 10:03:20 +00:00
|
|
|
# The reverse proxy of choice.
|
2023-01-12 13:22:55 +00:00
|
|
|
./modules/services/nginx.nix
|
|
|
|
|
2023-01-13 07:26:32 +00:00
|
|
|
# The database of choice which is used by most self-managed services on
|
|
|
|
# this server.
|
|
|
|
./modules/services/postgresql.nix
|
|
|
|
|
2023-01-12 13:22:55 +00:00
|
|
|
# The application services for this server. They are modularized since
|
|
|
|
# configuring it here will make it too big.
|
|
|
|
./modules/services/atuin.nix
|
|
|
|
./modules/services/gitea.nix
|
|
|
|
./modules/services/keycloak.nix
|
|
|
|
./modules/services/portunus.nix
|
|
|
|
./modules/services/vaultwarden.nix
|
2023-01-17 08:05:11 +00:00
|
|
|
./modules/services/wireguard.nix
|
2022-11-23 05:27:01 +00:00
|
|
|
];
|
|
|
|
|
2023-06-30 05:38:38 +00:00
|
|
|
# Automatic format and partitioning.
|
|
|
|
disko.devices = import ./disko.nix {
|
|
|
|
disks = [ "/dev/sda" ];
|
|
|
|
};
|
|
|
|
|
2022-12-10 10:45:36 +00:00
|
|
|
networking = {
|
2023-01-06 12:26:57 +00:00
|
|
|
nftables.enable = true;
|
2022-12-10 10:45:36 +00:00
|
|
|
domain = "foodogsquared.one";
|
2023-01-05 11:48:54 +00:00
|
|
|
firewall = {
|
2023-02-06 08:09:09 +00:00
|
|
|
enable = true;
|
2023-01-05 11:48:54 +00:00
|
|
|
allowedTCPPorts = [
|
|
|
|
22 # Secure Shells.
|
|
|
|
];
|
|
|
|
};
|
2022-12-10 10:45:36 +00:00
|
|
|
};
|
2022-11-27 16:41:44 +00:00
|
|
|
|
2023-02-09 06:17:59 +00:00
|
|
|
services.fail2ban = {
|
|
|
|
ignoreIP = [
|
|
|
|
# VPN clients.
|
|
|
|
"${interfaces.wireguard0.IPv4.address}/13"
|
|
|
|
"${interfaces.wireguard0.IPv6.address}/64"
|
|
|
|
];
|
2023-01-25 03:38:45 +00:00
|
|
|
|
2023-02-09 06:17:59 +00:00
|
|
|
# We're going to be unforgiving with this one since we only have key
|
|
|
|
# authentication and password authentication is disabled anyways.
|
|
|
|
jails.sshd = ''
|
|
|
|
enabled = true
|
|
|
|
maxretry = 1
|
|
|
|
port = 22
|
|
|
|
'';
|
|
|
|
};
|
2023-01-17 08:05:11 +00:00
|
|
|
|
2023-01-12 13:22:55 +00:00
|
|
|
# TODO: Put the secrets to the respective service module.
|
2022-11-23 05:27:01 +00:00
|
|
|
sops.secrets =
|
|
|
|
let
|
|
|
|
getKey = key: {
|
|
|
|
inherit key;
|
|
|
|
sopsFile = ./secrets/secrets.yaml;
|
|
|
|
};
|
2022-12-02 04:33:51 +00:00
|
|
|
getSecrets = secrets:
|
|
|
|
lib.mapAttrs'
|
|
|
|
(secret: config:
|
2022-11-23 05:27:01 +00:00
|
|
|
lib.nameValuePair
|
|
|
|
"plover/${secret}"
|
2022-12-02 04:33:51 +00:00
|
|
|
((getKey secret) // config))
|
|
|
|
secrets;
|
2022-12-26 09:45:54 +00:00
|
|
|
|
2023-01-17 08:55:25 +00:00
|
|
|
giteaUser = config.users.users."${config.services.gitea.user}".name;
|
|
|
|
portunusUser = config.users.users."${config.services.portunus.user}".name;
|
2022-12-26 09:45:54 +00:00
|
|
|
|
|
|
|
# It is hardcoded but as long as the module is stable that way.
|
2023-01-17 08:55:25 +00:00
|
|
|
vaultwardenUser = config.users.groups.vaultwarden.name;
|
|
|
|
postgresUser = config.users.groups.postgres.name;
|
2022-11-23 05:27:01 +00:00
|
|
|
in
|
2022-12-26 09:45:54 +00:00
|
|
|
getSecrets {
|
|
|
|
"ssh-key" = { };
|
|
|
|
"lego/env" = { };
|
2023-01-17 08:55:25 +00:00
|
|
|
"gitea/db/password".owner = giteaUser;
|
|
|
|
"gitea/smtp/password".owner = giteaUser;
|
|
|
|
"vaultwarden/env".owner = vaultwardenUser;
|
2023-06-27 14:49:49 +00:00
|
|
|
|
2023-01-07 09:15:45 +00:00
|
|
|
"borg/repos/host/patterns/keys" = { };
|
|
|
|
"borg/repos/host/password" = { };
|
|
|
|
"borg/repos/services/password" = { };
|
2023-01-07 02:51:49 +00:00
|
|
|
"borg/ssh-key" = { };
|
2023-06-27 14:49:49 +00:00
|
|
|
|
2023-01-17 08:55:25 +00:00
|
|
|
"keycloak/db/password".owner = postgresUser;
|
|
|
|
"ldap/users/foodogsquared/password".owner = portunusUser;
|
2022-12-26 09:45:54 +00:00
|
|
|
};
|
2022-11-23 05:27:01 +00:00
|
|
|
|
2023-01-12 13:22:55 +00:00
|
|
|
# All of the keys required to deploy the secrets.
|
2022-11-23 05:27:01 +00:00
|
|
|
sops.age.keyFile = "/var/lib/sops-nix/key.txt";
|
|
|
|
|
2022-12-02 04:33:51 +00:00
|
|
|
profiles.server = {
|
|
|
|
enable = true;
|
|
|
|
headless.enable = true;
|
|
|
|
hardened-config.enable = true;
|
|
|
|
cleanup.enable = true;
|
|
|
|
};
|
|
|
|
|
2023-01-12 13:22:55 +00:00
|
|
|
# DNS-related settings. We're settling by configuring the ACME setup with a
|
2023-06-22 09:56:47 +00:00
|
|
|
# self-hosted DNS server.
|
2022-12-29 02:26:15 +00:00
|
|
|
security.acme.defaults = {
|
2023-06-27 14:56:18 +00:00
|
|
|
email = "admin+acme@foodogsquared.one";
|
2023-06-22 09:56:47 +00:00
|
|
|
dnsProvider = "rfc2136";
|
2023-06-27 14:56:18 +00:00
|
|
|
dnsResolver = "1.1.1.1";
|
2022-12-29 02:26:15 +00:00
|
|
|
credentialsFile = config.sops.secrets."plover/lego/env".path;
|
2022-12-03 00:09:26 +00:00
|
|
|
};
|
|
|
|
|
2023-06-30 02:46:43 +00:00
|
|
|
# Enable generating new DH params.
|
|
|
|
security.dhparams.enable = true;
|
|
|
|
|
|
|
|
# !!! The keys should be rotated at an interval here.
|
2022-12-02 04:33:51 +00:00
|
|
|
services.openssh.hostKeys = [{
|
|
|
|
path = config.sops.secrets."plover/ssh-key".path;
|
|
|
|
type = "ed25519";
|
|
|
|
}];
|
|
|
|
|
2022-12-02 23:40:21 +00:00
|
|
|
# Of course, what is a server without a backup? A professionally-handled
|
2022-12-16 14:25:50 +00:00
|
|
|
# production system. However, we're not professionals so we do have backups.
|
2022-12-11 10:10:57 +00:00
|
|
|
services.borgbackup.jobs =
|
|
|
|
let
|
2023-01-07 09:15:45 +00:00
|
|
|
jobCommonSettings = { patternFiles ? [ ], patterns ? [ ], paths ? [ ], repo, passCommand }: {
|
2023-01-07 08:58:47 +00:00
|
|
|
inherit paths repo;
|
2022-12-11 10:10:57 +00:00
|
|
|
compression = "zstd,11";
|
|
|
|
dateFormat = "+%F-%H-%M-%S-%z";
|
|
|
|
doInit = true;
|
|
|
|
encryption = {
|
2023-01-07 09:15:45 +00:00
|
|
|
inherit passCommand;
|
2022-12-11 10:10:57 +00:00
|
|
|
mode = "repokey-blake2";
|
|
|
|
};
|
|
|
|
extraCreateArgs =
|
|
|
|
let
|
2022-12-12 06:19:55 +00:00
|
|
|
args = lib.flatten [
|
|
|
|
(builtins.map
|
|
|
|
(patternFile: "--patterns-from ${lib.escapeShellArg patternFile}")
|
|
|
|
patternFiles)
|
|
|
|
(builtins.map
|
|
|
|
(pattern: "--pattern ${lib.escapeShellArg pattern}")
|
|
|
|
patterns)
|
2022-12-11 10:10:57 +00:00
|
|
|
];
|
|
|
|
in
|
|
|
|
lib.concatStringsSep " " args;
|
|
|
|
extraInitArgs = "--make-parent-dirs";
|
|
|
|
persistentTimer = true;
|
|
|
|
preHook = ''
|
|
|
|
extraCreateArgs="$extraCreateArgs --stats"
|
|
|
|
'';
|
|
|
|
prune.keep = {
|
|
|
|
weekly = 4;
|
|
|
|
monthly = 12;
|
|
|
|
yearly = 6;
|
|
|
|
};
|
|
|
|
startAt = "monthly";
|
2023-01-07 02:51:49 +00:00
|
|
|
environment.BORG_RSH = "ssh -i ${config.sops.secrets."plover/borg/ssh-key".path}";
|
2022-12-02 23:40:21 +00:00
|
|
|
};
|
2023-01-07 03:39:17 +00:00
|
|
|
|
|
|
|
borgRepo = path: "ssh://${hetzner-boxes-user}@${hetzner-boxes-server}:23/./borg/plover/${path}";
|
2022-12-11 10:10:57 +00:00
|
|
|
in
|
|
|
|
{
|
|
|
|
# Backup for host-specific files. They don't change much so it is
|
|
|
|
# acceptable for it to be backed up monthly.
|
|
|
|
host-backup = jobCommonSettings {
|
|
|
|
patternFiles = [
|
2023-01-07 09:15:45 +00:00
|
|
|
config.sops.secrets."plover/borg/repos/host/patterns/keys".path
|
2022-12-11 10:10:57 +00:00
|
|
|
];
|
2023-01-07 03:39:17 +00:00
|
|
|
repo = borgRepo "host";
|
2023-01-07 09:15:45 +00:00
|
|
|
passCommand = "cat ${config.sops.secrets."plover/borg/repos/host/password".path}";
|
2022-12-11 10:10:57 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
# Backups for various services.
|
|
|
|
services-backup = jobCommonSettings
|
|
|
|
{
|
|
|
|
paths = [
|
2023-06-27 14:49:49 +00:00
|
|
|
# Vaultwarden.
|
2022-12-11 10:10:57 +00:00
|
|
|
"/var/lib/bitwarden_rs"
|
|
|
|
|
2023-06-27 14:49:49 +00:00
|
|
|
# Gitea.
|
2022-12-11 10:10:57 +00:00
|
|
|
config.services.gitea.dump.backupDir
|
|
|
|
|
2023-06-27 14:49:49 +00:00
|
|
|
# PostgreSQL database dumps.
|
2022-12-11 10:10:57 +00:00
|
|
|
config.services.postgresqlBackup.location
|
2023-02-10 13:09:05 +00:00
|
|
|
|
2023-06-27 14:49:49 +00:00
|
|
|
# ACME accounts.
|
|
|
|
"/var/lib/acme/.lego/accounts"
|
|
|
|
|
|
|
|
# Zone files.
|
|
|
|
"/etc/bind/zones"
|
2022-12-11 10:10:57 +00:00
|
|
|
];
|
2023-01-07 03:39:17 +00:00
|
|
|
repo = borgRepo "services";
|
2023-01-07 09:15:45 +00:00
|
|
|
passCommand = "cat ${config.sops.secrets."plover/borg/repos/services/password".path}";
|
2022-12-11 10:10:57 +00:00
|
|
|
} // { startAt = "weekly"; };
|
2022-12-02 23:40:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
programs.ssh.extraConfig = ''
|
2023-01-07 02:51:49 +00:00
|
|
|
Host ${hetzner-boxes-server}
|
|
|
|
IdentityFile ${config.sops.secrets."plover/borg/ssh-key".path}
|
2022-12-02 23:40:21 +00:00
|
|
|
'';
|
|
|
|
|
2023-05-15 14:13:51 +00:00
|
|
|
system.stateVersion = "23.05";
|
2022-11-23 05:27:01 +00:00
|
|
|
}
|