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;
|
2022-12-12 12:34:23 +00:00
|
|
|
|
2022-11-27 16:41:44 +00:00
|
|
|
domain = config.networking.domain;
|
2022-12-19 12:30:30 +00:00
|
|
|
subdomain = prefix: "${prefix}.${domain}";
|
|
|
|
|
|
|
|
passwordManagerDomain = subdomain "pass";
|
|
|
|
codeForgeDomain = subdomain "code";
|
|
|
|
authDomain = subdomain "auth";
|
2022-12-26 05:23:40 +00:00
|
|
|
ldapDomain = subdomain "ldap";
|
2022-11-27 16:41:44 +00:00
|
|
|
|
2022-12-16 14:24:59 +00:00
|
|
|
certs = config.security.acme.certs;
|
|
|
|
|
2022-11-27 16:41:44 +00:00
|
|
|
# This should be set from service module from nixpkgs.
|
|
|
|
vaultwardenUser = config.users.users.vaultwarden.name;
|
|
|
|
|
|
|
|
# However, this is set on our own.
|
|
|
|
vaultwardenDbName = "vaultwarden";
|
2022-12-16 14:25:50 +00:00
|
|
|
|
2022-12-17 14:23:36 +00:00
|
|
|
# This is also set on our own.
|
|
|
|
keycloakUser = config.services.keycloak.database.username;
|
|
|
|
keycloakDbName = if config.services.keycloak.database.createLocally then keycloakUser else config.services.keycloak.database.username;
|
|
|
|
|
2022-12-16 14:25:50 +00:00
|
|
|
# The head of the Borgbase hostname.
|
|
|
|
borgbase-remote = "cr6pf13r";
|
2022-11-23 05:27:01 +00:00
|
|
|
in
|
|
|
|
{
|
|
|
|
imports = [
|
2022-11-25 13:27:23 +00:00
|
|
|
./hardware-configuration.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"
|
2022-11-23 05:27:01 +00:00
|
|
|
];
|
|
|
|
|
2023-01-04 11:53:44 +00:00
|
|
|
boot.loader.grub.enable = true;
|
|
|
|
|
2022-12-10 10:45:36 +00:00
|
|
|
networking = {
|
|
|
|
domain = "foodogsquared.one";
|
2022-12-11 10:10:10 +00:00
|
|
|
firewall.allowedTCPPorts = [
|
2022-12-10 10:45:36 +00:00
|
|
|
22 # Secure Shells.
|
2022-12-28 06:10:07 +00:00
|
|
|
|
2022-12-10 10:45:36 +00:00
|
|
|
80 # HTTP servers.
|
|
|
|
433 # HTTPS servers.
|
|
|
|
|
2022-12-26 05:23:40 +00:00
|
|
|
389 # LDAP servers.
|
|
|
|
636 # LDAPS servers.
|
2022-12-10 10:45:36 +00:00
|
|
|
];
|
|
|
|
};
|
2022-11-27 16:41:44 +00:00
|
|
|
|
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
|
|
|
|
|
|
|
giteaUserGroup = config.users.users."${config.services.gitea.user}".group;
|
|
|
|
|
|
|
|
# It is hardcoded but as long as the module is stable that way.
|
|
|
|
vaultwardenUserGroup = config.users.groups.vaultwarden.name;
|
|
|
|
postgresUserGroup = 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" = { };
|
|
|
|
"gitea/db/password".owner = giteaUserGroup;
|
|
|
|
"gitea/smtp/password".owner = giteaUserGroup;
|
|
|
|
"vaultwarden/env".owner = vaultwardenUserGroup;
|
|
|
|
"borg/patterns/keys" = { };
|
|
|
|
"borg/password" = { };
|
|
|
|
"keycloak/db/password".owner = postgresUserGroup;
|
|
|
|
};
|
2022-11-23 05:27:01 +00:00
|
|
|
|
2022-11-27 16:41:44 +00:00
|
|
|
# All of the keys required to deploy the secrets. Don't know how to make the
|
|
|
|
# GCP KMS key work though without manually going into the instance and
|
|
|
|
# configure it there.
|
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;
|
|
|
|
};
|
|
|
|
|
2022-12-03 00:09:26 +00:00
|
|
|
# DNS-related settings. This is nice for automating them putting DNS records
|
|
|
|
# and other types of stuff.
|
2022-12-29 02:26:15 +00:00
|
|
|
security.acme.defaults = {
|
|
|
|
dnsProvider = "porkbun";
|
|
|
|
credentialsFile = config.sops.secrets."plover/lego/env".path;
|
2022-12-03 00:09:26 +00:00
|
|
|
};
|
|
|
|
|
2022-12-02 04:33:51 +00:00
|
|
|
services.openssh.hostKeys = [{
|
|
|
|
path = config.sops.secrets."plover/ssh-key".path;
|
|
|
|
type = "ed25519";
|
|
|
|
}];
|
|
|
|
|
2022-11-27 16:41:44 +00:00
|
|
|
# The main server where it will tie all of the services in one neat little
|
|
|
|
# place.
|
2022-11-23 05:27:01 +00:00
|
|
|
services.nginx = {
|
|
|
|
enable = true;
|
|
|
|
enableReload = true;
|
2022-12-28 06:10:07 +00:00
|
|
|
|
2022-11-23 05:27:01 +00:00
|
|
|
package = pkgs.nginxMainline;
|
|
|
|
|
|
|
|
recommendedGzipSettings = true;
|
|
|
|
recommendedOptimisation = true;
|
|
|
|
recommendedProxySettings = true;
|
|
|
|
recommendedTlsSettings = true;
|
|
|
|
|
2022-11-26 06:13:17 +00:00
|
|
|
# Server blocks with no forcing of SSL are static sites so it is pretty
|
|
|
|
# much OK.
|
2022-11-23 05:27:01 +00:00
|
|
|
virtualHosts = {
|
|
|
|
# Vaultwarden instance.
|
|
|
|
"${passwordManagerDomain}" = {
|
|
|
|
forceSSL = true;
|
|
|
|
enableACME = true;
|
2022-12-11 10:11:07 +00:00
|
|
|
locations =
|
|
|
|
let
|
|
|
|
address = config.services.vaultwarden.config.ROCKET_ADDRESS;
|
|
|
|
port = config.services.vaultwarden.config.ROCKET_PORT;
|
|
|
|
websocketPort = config.services.vaultwarden.config.WEBSOCKET_PORT;
|
|
|
|
in
|
|
|
|
{
|
|
|
|
"/" = {
|
|
|
|
proxyPass = "http://${address}:${toString port}";
|
|
|
|
proxyWebsockets = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
"/notifications/hub" = {
|
|
|
|
proxyPass = "http://${address}:${toString websocketPort}";
|
|
|
|
proxyWebsockets = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
"/notifications/hub/negotiate" = {
|
|
|
|
proxyPass = "http://${address}:${toString port}";
|
|
|
|
proxyWebsockets = true;
|
|
|
|
};
|
2022-11-23 05:27:01 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2022-11-25 13:27:23 +00:00
|
|
|
# Gitea instance.
|
2022-12-10 10:45:36 +00:00
|
|
|
"${codeForgeDomain}" = {
|
2022-12-29 02:25:53 +00:00
|
|
|
forceSSL = true;
|
|
|
|
enableACME = true;
|
|
|
|
locations."/" = {
|
|
|
|
proxyPass = "http://localhost:${toString config.services.gitea.httpPort}";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
# Keycloak instance.
|
|
|
|
"${authDomain}" = {
|
2022-11-25 13:27:23 +00:00
|
|
|
forceSSL = true;
|
2022-11-23 05:27:01 +00:00
|
|
|
enableACME = true;
|
2023-01-01 07:47:06 +00:00
|
|
|
locations."/" = {
|
|
|
|
proxyPass = "http://localhost:${toString config.services.gitea.httpPort}";
|
2022-11-23 05:27:01 +00:00
|
|
|
};
|
|
|
|
};
|
2022-12-12 12:32:21 +00:00
|
|
|
|
2023-01-01 07:47:06 +00:00
|
|
|
# Portunus server which also has an OpenLDAP server running.
|
2022-12-29 02:26:15 +00:00
|
|
|
"${ldapDomain}" = {
|
2022-12-12 12:32:21 +00:00
|
|
|
forceSSL = true;
|
|
|
|
enableACME = true;
|
|
|
|
locations."/" = {
|
2023-01-01 07:47:06 +00:00
|
|
|
proxyPass = "http://localhost:${toString config.services.portunus.port}";
|
2022-12-12 12:32:21 +00:00
|
|
|
};
|
|
|
|
};
|
2022-11-23 05:27:01 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2022-11-27 16:41:44 +00:00
|
|
|
# Enable database services that is used in all of the services here so far.
|
|
|
|
services.postgresql = {
|
|
|
|
enable = true;
|
|
|
|
package = pkgs.postgresql_15;
|
2022-12-01 00:21:58 +00:00
|
|
|
enableTCPIP = true;
|
2022-11-27 16:41:44 +00:00
|
|
|
|
2022-12-04 00:55:55 +00:00
|
|
|
# Create per-user schema as documented from Usage Patterns. This is to make
|
|
|
|
# use of the secure schema usage pattern they encouraged to do.
|
|
|
|
#
|
|
|
|
# Now, you just have to keep in mind about applications making use of them.
|
|
|
|
# Most of them should have the setting to set the schema to be used. If
|
|
|
|
# not, then screw them (or just file an issue and politely ask for the
|
|
|
|
# feature).
|
2022-12-11 10:11:07 +00:00
|
|
|
initialScript =
|
|
|
|
let
|
2022-12-12 06:17:57 +00:00
|
|
|
# This will be run once anyways so it is acceptable to create users
|
|
|
|
# "forcibly".
|
2022-12-11 10:11:07 +00:00
|
|
|
perUserSchemas = lib.lists.map
|
2022-12-12 06:17:57 +00:00
|
|
|
(user: ''
|
|
|
|
CREATE USER ${user.name};
|
2022-12-22 05:58:20 +00:00
|
|
|
CREATE SCHEMA AUTHORIZATION ${user.name};
|
2022-12-12 06:17:57 +00:00
|
|
|
'')
|
2022-12-11 10:11:07 +00:00
|
|
|
config.services.postgresql.ensureUsers;
|
2022-12-12 06:17:57 +00:00
|
|
|
in pkgs.writeText "plover-initial-postgresql-script" ''
|
|
|
|
${lib.concatStringsSep "\n" perUserSchemas}
|
|
|
|
'';
|
2022-12-04 00:55:55 +00:00
|
|
|
|
|
|
|
settings = {
|
|
|
|
# Still doing the secure schema usage pattern.
|
|
|
|
search_path = "\"$user\"";
|
|
|
|
};
|
|
|
|
|
2022-11-27 16:41:44 +00:00
|
|
|
# There's no database and user checks for Vaultwarden service.
|
2022-12-17 14:23:36 +00:00
|
|
|
ensureDatabases = [ vaultwardenDbName keycloakDbName ];
|
2022-11-27 16:41:44 +00:00
|
|
|
ensureUsers = [
|
|
|
|
{
|
|
|
|
name = vaultwardenUser;
|
2022-12-02 04:33:51 +00:00
|
|
|
ensurePermissions = {
|
|
|
|
"DATABASE ${vaultwardenDbName}" = "ALL PRIVILEGES";
|
2022-12-04 00:55:55 +00:00
|
|
|
"SCHEMA ${vaultwardenDbName}" = "ALL PRIVILEGES";
|
2022-12-02 04:33:51 +00:00
|
|
|
};
|
2022-11-27 16:41:44 +00:00
|
|
|
}
|
2022-12-10 10:45:36 +00:00
|
|
|
{
|
|
|
|
name = config.services.gitea.user;
|
|
|
|
ensurePermissions = {
|
|
|
|
"SCHEMA ${config.services.gitea.user}" = "ALL PRIVILEGES";
|
|
|
|
};
|
|
|
|
}
|
2022-12-17 14:23:36 +00:00
|
|
|
{
|
|
|
|
name = keycloakUser;
|
|
|
|
ensurePermissions = {
|
|
|
|
"DATABASE ${keycloakDbName}" = "ALL PRIVILEGES";
|
|
|
|
"SCHEMA ${keycloakDbName}" = "ALL PRIVILEGES";
|
|
|
|
};
|
|
|
|
}
|
2022-11-27 16:41:44 +00:00
|
|
|
];
|
|
|
|
};
|
2022-12-12 12:32:21 +00:00
|
|
|
|
2023-01-01 07:47:06 +00:00
|
|
|
services.portunus = {
|
2022-12-26 05:23:40 +00:00
|
|
|
enable = true;
|
|
|
|
|
2023-01-01 07:47:06 +00:00
|
|
|
port = 8168;
|
|
|
|
domain = ldapDomain;
|
2022-12-26 05:23:40 +00:00
|
|
|
|
2023-01-01 07:47:06 +00:00
|
|
|
ldap = {
|
|
|
|
searchUserName = "admin";
|
|
|
|
suffix = "dc=foodogsquared,dc=one";
|
|
|
|
tls = true;
|
2022-12-26 05:23:40 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2022-12-12 12:32:21 +00:00
|
|
|
# Hey, the hub for your application sign-in.
|
|
|
|
services.keycloak = {
|
|
|
|
enable = true;
|
|
|
|
|
|
|
|
# Pls change at first login.
|
|
|
|
initialAdminPassword = "wow what is this thing";
|
|
|
|
|
|
|
|
database = {
|
|
|
|
type = "postgresql";
|
|
|
|
createLocally = true;
|
|
|
|
passwordFile = config.sops.secrets."plover/keycloak/db/password".path;
|
|
|
|
};
|
|
|
|
|
|
|
|
settings = {
|
2022-12-19 12:31:01 +00:00
|
|
|
host = "127.0.0.1";
|
|
|
|
|
2022-12-22 05:58:20 +00:00
|
|
|
db-schema = keycloakDbName;
|
|
|
|
|
2022-12-19 12:31:01 +00:00
|
|
|
http-enabled = true;
|
|
|
|
http-port = 8759;
|
|
|
|
https-port = 8760;
|
|
|
|
|
2022-12-19 12:30:30 +00:00
|
|
|
hostname = authDomain;
|
2022-12-12 12:32:21 +00:00
|
|
|
hostname-strict-backchannel = true;
|
2022-12-19 12:31:01 +00:00
|
|
|
proxy = "passthrough";
|
2022-12-12 12:32:21 +00:00
|
|
|
};
|
2022-12-19 12:31:01 +00:00
|
|
|
|
|
|
|
sslCertificate = "${certs."${authDomain}".directory}/fullchain.pem";
|
|
|
|
sslCertificateKey = "${certs."${authDomain}".directory}/key.pem";
|
2022-12-12 12:32:21 +00:00
|
|
|
};
|
2022-11-27 16:41:44 +00:00
|
|
|
|
2022-12-22 05:58:20 +00:00
|
|
|
# Modifying it a little bit for per-user schema.
|
|
|
|
systemd.services.keycloak = {
|
|
|
|
path = [ config.services.postgresql.package ];
|
|
|
|
preStart = ''
|
|
|
|
psql -tAc "SELECT 1 FROM information_schema.schemata WHERE schema_name='${keycloakDbName}';" \
|
|
|
|
grep -q 1 || psql -tAc "CREATE SCHEMA IF NOT EXISTS keycloak;"
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2022-12-11 10:09:49 +00:00
|
|
|
# With a database comes a dumping.
|
|
|
|
services.postgresqlBackup = {
|
|
|
|
enable = true;
|
|
|
|
compression = "zstd";
|
|
|
|
compressionLevel = 11;
|
|
|
|
|
|
|
|
# Start at every 3 days starting from the first day of the month.
|
|
|
|
startAt = "*-*-1/3";
|
|
|
|
};
|
|
|
|
|
2022-11-23 05:27:01 +00:00
|
|
|
# My code forge.
|
|
|
|
services.gitea = {
|
|
|
|
enable = true;
|
|
|
|
appName = "foodogsquared's code forge";
|
|
|
|
database = {
|
2022-11-27 16:41:44 +00:00
|
|
|
type = "postgres";
|
2022-12-02 04:33:51 +00:00
|
|
|
passwordFile = config.sops.secrets."plover/gitea/db/password".path;
|
2022-11-23 05:27:01 +00:00
|
|
|
};
|
2022-12-10 10:45:36 +00:00
|
|
|
domain = codeForgeDomain;
|
|
|
|
rootUrl = "https://${codeForgeDomain}";
|
2022-12-11 10:08:54 +00:00
|
|
|
|
|
|
|
# Allow Gitea to take a dump.
|
|
|
|
dump = {
|
|
|
|
enable = true;
|
2022-12-28 06:10:07 +00:00
|
|
|
interval = "weekly";
|
2022-12-11 10:08:54 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
# There are a lot of services in port 3000 so we'll change it.
|
2022-12-10 10:45:36 +00:00
|
|
|
httpPort = 8432;
|
2022-11-23 05:27:01 +00:00
|
|
|
lfs.enable = true;
|
2022-12-11 10:08:54 +00:00
|
|
|
|
2022-12-02 04:33:51 +00:00
|
|
|
mailerPasswordFile = config.sops.secrets."plover/gitea/smtp/password".path;
|
2022-11-23 05:27:01 +00:00
|
|
|
|
|
|
|
settings = {
|
|
|
|
"repository.pull_request" = {
|
|
|
|
WORK_IN_PROGRESS_PREFIXES = "WIP:,[WIP],DRAFT,[DRAFT]";
|
|
|
|
ADD_CO_COMMITTERS_TRAILERS = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
ui = {
|
2022-12-11 10:08:54 +00:00
|
|
|
DEFAULT_THEME = "auto";
|
2022-11-23 05:27:01 +00:00
|
|
|
EXPLORE_PAGING_SUM = 15;
|
|
|
|
GRAPH_MAX_COMMIT_NUM = 200;
|
|
|
|
};
|
|
|
|
|
|
|
|
"ui.meta" = {
|
|
|
|
AUTHOR = "foodogsquared's code forge";
|
2022-12-04 00:55:55 +00:00
|
|
|
DESCRIPTION = "foodogsquared's personal projects and some archived and mirrored codebases.";
|
2022-11-23 05:27:01 +00:00
|
|
|
KEYWORDS = "foodogsquared,gitea,self-hosted";
|
|
|
|
};
|
|
|
|
|
|
|
|
# It's a personal instance so nah...
|
|
|
|
service.DISABLE_REGISTRATION = true;
|
|
|
|
|
|
|
|
repository = {
|
|
|
|
ENABLE_PUSH_CREATE_USER = true;
|
|
|
|
DEFAULT_PRIVATE = "public";
|
|
|
|
DEFAULT_PRIVATE_PUSH_CREATE = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
"markup.asciidoc" = {
|
|
|
|
ENABLED = true;
|
|
|
|
NEED_POSTPROCESS = true;
|
|
|
|
FILE_EXTENSIONS = ".adoc,.asciidoc";
|
2022-12-04 00:55:55 +00:00
|
|
|
RENDER_COMMAND = "${pkgs.asciidoctor}/bin/asciidoctor --out-file=- -";
|
2022-11-23 05:27:01 +00:00
|
|
|
IS_INPUT_FILE = false;
|
|
|
|
};
|
|
|
|
|
2022-12-02 04:33:51 +00:00
|
|
|
# Mailer service.
|
|
|
|
mailer = {
|
|
|
|
ENABLED = true;
|
2022-12-11 10:08:54 +00:00
|
|
|
PROTOCOL = "smtp+starttls";
|
2022-12-02 04:33:51 +00:00
|
|
|
SMTP_ADDRESS = "smtp.sendgrid.net";
|
|
|
|
SMTP_PORT = 587;
|
|
|
|
USER = "apikey";
|
2022-12-11 10:08:54 +00:00
|
|
|
FROM = "bot+gitea@foodogsquared.one";
|
2022-12-02 04:33:51 +00:00
|
|
|
SEND_AS_PLAIN_TEXT = true;
|
2022-12-11 10:08:54 +00:00
|
|
|
SENDMAIL_PATH = "${pkgs.system-sendmail}/bin/sendmail";
|
2022-12-02 04:33:51 +00:00
|
|
|
};
|
|
|
|
|
2022-11-23 05:27:01 +00:00
|
|
|
# Well, collaboration between forges is nice...
|
|
|
|
federation.ENABLED = true;
|
|
|
|
|
|
|
|
# Enable mirroring feature...
|
|
|
|
mirror.ENABLED = true;
|
|
|
|
|
2022-12-04 00:55:55 +00:00
|
|
|
# Session configuration.
|
|
|
|
session.COOKIE_SECURE = true;
|
|
|
|
|
|
|
|
# Some more database configuration.
|
|
|
|
database.SCHEMA = config.services.gitea.user;
|
|
|
|
|
2022-12-11 10:08:54 +00:00
|
|
|
# Run various periodic services.
|
|
|
|
"cron.update_mirrors".SCHEDULE = "@every 12h";
|
|
|
|
|
2022-11-23 05:27:01 +00:00
|
|
|
other = {
|
|
|
|
SHOW_FOOTER_VERSION = true;
|
|
|
|
ENABLE_SITEMAP = true;
|
|
|
|
ENABLE_FEED = true;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2022-12-28 06:08:49 +00:00
|
|
|
# Disk space is always assumed to be limited so we're really only limited with 2 dumps.
|
|
|
|
systemd.services.gitea-dump.serviceConfig = {
|
|
|
|
ExecStartPre = pkgs.writeShellScript "gitea-dump-limit" ''
|
|
|
|
find ${config.services.gitea.dump.backupDir} -mtime 14 -maxdepth 1 -type f -delete
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2022-11-23 05:27:01 +00:00
|
|
|
# An alternative implementation of Bitwarden written in Rust. The project
|
|
|
|
# being written in Rust is a insta-self-hosting material right there.
|
|
|
|
services.vaultwarden = {
|
|
|
|
enable = true;
|
2022-11-27 16:41:44 +00:00
|
|
|
dbBackend = "postgresql";
|
2022-12-02 04:33:51 +00:00
|
|
|
environmentFile = config.sops.secrets."plover/vaultwarden/env".path;
|
2022-11-23 05:27:01 +00:00
|
|
|
config = {
|
|
|
|
DOMAIN = "https://${passwordManagerDomain}";
|
|
|
|
|
|
|
|
# Configuring the server.
|
|
|
|
ROCKET_ADDRESS = "127.0.0.1";
|
|
|
|
ROCKET_PORT = 8222;
|
|
|
|
ROCKET_LOG = "critical";
|
|
|
|
|
|
|
|
# Ehh... It's only a few (or even one) users anyways so nah. Since this
|
|
|
|
# instance will not configure SMTP server, this pretty much means
|
|
|
|
# invitation is only via email at this point.
|
|
|
|
SHOW_PASSWORD_HINT = false;
|
|
|
|
|
|
|
|
# Configuring some parts of account management which is almost
|
|
|
|
# nonexistent because this is just intended for me (at least right now).
|
|
|
|
SIGNUPS_ALLOWED = false;
|
|
|
|
SIGNUPS_VERIFY = true;
|
2022-12-11 10:08:54 +00:00
|
|
|
|
|
|
|
# Invitations...
|
2022-11-23 05:27:01 +00:00
|
|
|
INVITATIONS_ALLOWED = true;
|
2022-12-11 10:08:54 +00:00
|
|
|
INVITATION_ORG_NAME = "foodogsquared's Vaultwarden";
|
2022-11-23 05:27:01 +00:00
|
|
|
|
|
|
|
# Notifications...
|
|
|
|
WEBSOCKET_ENABLED = true;
|
|
|
|
WEBSOCKET_PORT = 3012;
|
|
|
|
WEBSOCKET_ADDRESS = "0.0.0.0";
|
|
|
|
|
|
|
|
# Enabling web vault with whatever nixpkgs comes in.
|
|
|
|
WEB_VAULT_ENABLED = true;
|
2022-11-27 16:41:44 +00:00
|
|
|
|
2022-12-28 06:10:07 +00:00
|
|
|
# Databasifications...
|
2022-12-10 10:45:36 +00:00
|
|
|
DATABASE_URL = "postgresql://${vaultwardenUser}@/${vaultwardenDbName}";
|
|
|
|
|
|
|
|
# Mailer service configuration (except the user and password).
|
|
|
|
SMTP_HOST = "smtp.sendgrid.net";
|
|
|
|
SMTP_PORT = 587;
|
|
|
|
SMTP_FROM_NAME = "Vaultwarden";
|
|
|
|
SMTP_FROM = "bot+vaultwarden@foodogsquared.one";
|
2022-11-23 05:27:01 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
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
|
|
|
|
jobCommonSettings = { patternFiles ? [ ], patterns ? [ ], paths ? [ ] }: {
|
|
|
|
inherit paths;
|
|
|
|
compression = "zstd,11";
|
|
|
|
dateFormat = "+%F-%H-%M-%S-%z";
|
|
|
|
doInit = true;
|
|
|
|
encryption = {
|
|
|
|
mode = "repokey-blake2";
|
|
|
|
passCommand = "cat ${config.sops.secrets."plover/borg/password".path}";
|
|
|
|
};
|
|
|
|
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;
|
|
|
|
};
|
2022-12-16 14:25:50 +00:00
|
|
|
repo = "${borgbase-remote}@${borgbase-remote}.repo.borgbase.com:repo";
|
2022-12-11 10:10:57 +00:00
|
|
|
startAt = "monthly";
|
|
|
|
environment.BORG_RSH = "ssh -i ${config.sops.secrets."plover/ssh-key".path}";
|
2022-12-02 23:40:21 +00:00
|
|
|
};
|
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 = [
|
|
|
|
config.sops.secrets."plover/borg/patterns/keys".path
|
|
|
|
];
|
|
|
|
};
|
|
|
|
|
|
|
|
# Backups for various services.
|
|
|
|
services-backup = jobCommonSettings
|
|
|
|
{
|
|
|
|
paths = [
|
|
|
|
# Vaultwarden
|
|
|
|
"/var/lib/bitwarden_rs"
|
|
|
|
|
|
|
|
# Gitea
|
|
|
|
config.services.gitea.dump.backupDir
|
|
|
|
|
|
|
|
# PostgreSQL database dumps
|
|
|
|
config.services.postgresqlBackup.location
|
|
|
|
];
|
|
|
|
} // { startAt = "weekly"; };
|
2022-12-02 23:40:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
programs.ssh.extraConfig = ''
|
2022-12-16 14:25:50 +00:00
|
|
|
Host ${borgbase-remote}.repo.borgbase.com
|
2022-12-02 23:40:21 +00:00
|
|
|
IdentityFile ${config.sops.secrets."plover/ssh-key".path}
|
|
|
|
'';
|
|
|
|
|
2022-12-11 10:08:54 +00:00
|
|
|
systemd.tmpfiles.rules = let
|
|
|
|
# To be used similarly to $GITEA_CUSTOM variable.
|
|
|
|
giteaCustomDir = "${config.services.gitea.stateDir}/custom";
|
|
|
|
in [
|
|
|
|
"L+ ${giteaCustomDir}/templates/home.tmpl - - - - ${./files/gitea/home.tmpl}"
|
|
|
|
"L+ ${giteaCustomDir}/public/img/logo.svg - - - - ${./files/gitea/logo.svg}"
|
|
|
|
"L+ ${giteaCustomDir}/public/img/logo.png - - - - ${./files/gitea/logo.png}"
|
|
|
|
];
|
|
|
|
|
2022-11-23 05:27:01 +00:00
|
|
|
system.stateVersion = "22.11";
|
|
|
|
}
|