mirror of
https://github.com/RGBCube/ncc
synced 2025-07-28 02:27:44 +00:00
chore: migrate cube host
This commit is contained in:
parent
dad68acf68
commit
f2ab446c48
45 changed files with 904 additions and 88 deletions
7
.gitignore
vendored
7
.gitignore
vendored
|
@ -6,6 +6,13 @@
|
||||||
|
|
||||||
!hosts/
|
!hosts/
|
||||||
|
|
||||||
|
!hosts/cube/
|
||||||
|
!hosts/cube/matrix/
|
||||||
|
!hosts/cube/nextcloud/
|
||||||
|
!hosts/cube/nextcloud/*.gif
|
||||||
|
!hosts/cube/grafana/
|
||||||
|
!hosts/cube/forgejo/
|
||||||
|
|
||||||
!hosts/disk/
|
!hosts/disk/
|
||||||
|
|
||||||
!hosts/nine/
|
!hosts/nine/
|
||||||
|
|
73
hosts/cube/default.nix
Normal file
73
hosts/cube/default.nix
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
lib: lib.nixosSystem ({ config, keys, lib, ... }: let
|
||||||
|
inherit (lib) collectNix remove;
|
||||||
|
in {
|
||||||
|
imports = collectNix ./. |> remove ./default.nix;
|
||||||
|
|
||||||
|
secrets.id.file = ./id.age;
|
||||||
|
services.openssh.hostKeys = [{
|
||||||
|
type = "ed25519";
|
||||||
|
path = config.secrets.id.path;
|
||||||
|
}];
|
||||||
|
|
||||||
|
services.openssh.banner = ''
|
||||||
|
_______________________________________
|
||||||
|
/ If God doesn't destroy San Francisco, \
|
||||||
|
| He should apologize to Sodom and |
|
||||||
|
\ Gomorrah. /
|
||||||
|
---------------------------------------
|
||||||
|
\ ^__^
|
||||||
|
\ (oo)\_______
|
||||||
|
(__)\ )\/\
|
||||||
|
||----w |
|
||||||
|
|| ||
|
||||||
|
'';
|
||||||
|
|
||||||
|
secrets.rgbPassword.file = ./password.rgb.age;
|
||||||
|
users.users = {
|
||||||
|
root.hashedPasswordFile = config.secrets.rgbPassword.path;
|
||||||
|
|
||||||
|
rgb = {
|
||||||
|
description = "RGB";
|
||||||
|
openssh.authorizedKeys.keys = keys.admins;
|
||||||
|
hashedPasswordFile = config.secrets.rgbPassword.path;
|
||||||
|
isNormalUser = true;
|
||||||
|
extraGroups = [ "wheel" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
backup = {
|
||||||
|
description = "Backup";
|
||||||
|
openssh.authorizedKeys.keys = keys.all;
|
||||||
|
hashedPasswordFile = config.secrets.rgbPassword.path;
|
||||||
|
isNormalUser = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
home-manager.users = {
|
||||||
|
root = {};
|
||||||
|
rgb = {};
|
||||||
|
backup = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
networking = let
|
||||||
|
interface = "ens18";
|
||||||
|
in {
|
||||||
|
hostName = "cube";
|
||||||
|
|
||||||
|
ipv4.address = "5.255.78.70";
|
||||||
|
ipv4.prefixLength = 24;
|
||||||
|
|
||||||
|
domain = "rgbcu.be";
|
||||||
|
|
||||||
|
defaultGateway = {
|
||||||
|
inherit interface;
|
||||||
|
|
||||||
|
address = "5.255.78.1";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
nixpkgs.hostPlatform = "x86_64-linux";
|
||||||
|
system.stateVersion = "23.05";
|
||||||
|
home-manager.sharedModules = [{
|
||||||
|
home.stateVersion = "23.11";
|
||||||
|
}];
|
||||||
|
})
|
161
hosts/cube/forgejo/default.nix
Normal file
161
hosts/cube/forgejo/default.nix
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
{ self, config, lib, pkgs, ... }: let
|
||||||
|
inherit (config.networking) domain;
|
||||||
|
inherit (lib) const enabled genAttrs head merge mkForce;
|
||||||
|
|
||||||
|
fqdn = "git.${domain}";
|
||||||
|
|
||||||
|
port = 8001;
|
||||||
|
in {
|
||||||
|
secrets.forgejoPasswordRunner = {
|
||||||
|
file = ./password.runner.age;
|
||||||
|
owner = "forgejo";
|
||||||
|
};
|
||||||
|
secrets.forgejoPasswordMail = {
|
||||||
|
file = self + /modules/mail/password.plain.age;
|
||||||
|
owner = "forgejo";
|
||||||
|
};
|
||||||
|
|
||||||
|
services.postgresql = let
|
||||||
|
users = [ "forgejo" ];
|
||||||
|
in {
|
||||||
|
ensureDatabases = users;
|
||||||
|
ensureUsers = map users (name: {
|
||||||
|
inherit name;
|
||||||
|
|
||||||
|
ensureDBOwnership = true;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
services.restic.backups = genAttrs config.services.restic.hosts <| const {
|
||||||
|
paths = [ "/var/lib/gitea-runner" "/var/lib/forgejo" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
users.groups.gitea-runner = {};
|
||||||
|
users.users.gitea-runner = {
|
||||||
|
extraGroups = [ "docker" ];
|
||||||
|
group = "gitea-runner";
|
||||||
|
home = "/var/lib/gitea-runner";
|
||||||
|
isSystemUser = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
services.gitea-actions-runner = {
|
||||||
|
package = pkgs.forgejo-actions-runner;
|
||||||
|
|
||||||
|
instances.runner-01 = enabled {
|
||||||
|
name = "runner-01";
|
||||||
|
url = fqdn;
|
||||||
|
|
||||||
|
labels = [
|
||||||
|
"debian-latest:docker://node:18-bullseye"
|
||||||
|
"ubuntu-latest:docker://node:18-bullseye"
|
||||||
|
"act:docker://ghcr.io/catthehacker/ubuntu:act-latest"
|
||||||
|
];
|
||||||
|
|
||||||
|
tokenFile = config.secrets.forgejoPasswordRunner.path;
|
||||||
|
|
||||||
|
settings = {
|
||||||
|
cache.enabled = true;
|
||||||
|
capacity = 4;
|
||||||
|
container.network = "host";
|
||||||
|
};
|
||||||
|
|
||||||
|
hostPackages = [
|
||||||
|
pkgs.bash
|
||||||
|
pkgs.uutils-coreutils-noprefix
|
||||||
|
pkgs.curl
|
||||||
|
pkgs.gitMinimal
|
||||||
|
pkgs.sudo
|
||||||
|
pkgs.wget
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.openssh.settings.AcceptEnv = mkForce "SHELLS COLOTERM GIT_PROTOCOL";
|
||||||
|
|
||||||
|
services.forgejo = enabled {
|
||||||
|
lfs = enabled;
|
||||||
|
|
||||||
|
secrets.mailer.PASSWD = config.secrets.forgejoPasswordMail.path;
|
||||||
|
|
||||||
|
database = {
|
||||||
|
socket = "/run/postgresql";
|
||||||
|
type = "postgres";
|
||||||
|
};
|
||||||
|
|
||||||
|
settings = let
|
||||||
|
description = "RGBCube's Forge of Shitty Software";
|
||||||
|
in {
|
||||||
|
default.APP_NAME = description;
|
||||||
|
|
||||||
|
actions = {
|
||||||
|
ENABLED = true;
|
||||||
|
DEFAULT_ACTIONS_URL = "https://${fqdn}";
|
||||||
|
};
|
||||||
|
|
||||||
|
attachment.ALLOWED_TYPES = "*/*";
|
||||||
|
|
||||||
|
cache.ENABLED = true;
|
||||||
|
|
||||||
|
mailer = {
|
||||||
|
ENABLED = true;
|
||||||
|
|
||||||
|
PROTOCOL = "smtps";
|
||||||
|
SMTP_ADDR = self.disk.mailserver.fqdn;
|
||||||
|
USER = "git@${domain}";
|
||||||
|
};
|
||||||
|
|
||||||
|
other = {
|
||||||
|
SHOW_FOOTER_TEMPLATE_LOAD_TIME = false;
|
||||||
|
SHOW_FOOTER_VERSION = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
packages.ENABLED = false;
|
||||||
|
|
||||||
|
repository = {
|
||||||
|
DEFAULT_BRANCH = "master";
|
||||||
|
DEFAULT_MERGE_STYLE = "rebase-merge";
|
||||||
|
DEFAULT_REPO_UNITS = "repo.code, repo.issues, repo.pulls, repo.actions";
|
||||||
|
|
||||||
|
DEFAULT_PUSH_CREATE_PRIVATE = false;
|
||||||
|
ENABLE_PUSH_CREATE_ORG = true;
|
||||||
|
ENABLE_PUSH_CREATE_USER = true;
|
||||||
|
|
||||||
|
DISABLE_STARS = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
"repository.upload" = {
|
||||||
|
FILE_MAX_SIZE = 100;
|
||||||
|
MAX_FILES = 10;
|
||||||
|
};
|
||||||
|
|
||||||
|
server = {
|
||||||
|
DOMAIN = domain;
|
||||||
|
ROOT_URL = "https://${fqdn}/";
|
||||||
|
LANDING_PAGE = "/explore";
|
||||||
|
|
||||||
|
HTTP_ADDR = "::1";
|
||||||
|
HTTP_PORT = port;
|
||||||
|
|
||||||
|
SSH_PORT = head config.services.openssh.ports;
|
||||||
|
|
||||||
|
DISABLE_ROUTER_LOG = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
service.DISABLE_REGISTRATION = true;
|
||||||
|
|
||||||
|
session = {
|
||||||
|
COOKIE_SECURE = true;
|
||||||
|
SAME_SITE = "strict";
|
||||||
|
};
|
||||||
|
|
||||||
|
"ui.meta" = {
|
||||||
|
AUTHOR = description;
|
||||||
|
DESCRIPTION = description;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.nginx.virtualHosts.${fqdn} = merge config.nginx.sslTemplate {
|
||||||
|
locations."/".proxyPass = "http://[::1]:${toString port}";
|
||||||
|
};
|
||||||
|
}
|
8
hosts/cube/forgejo/password.runner.age
Normal file
8
hosts/cube/forgejo/password.runner.age
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
age-encryption.org/v1
|
||||||
|
-> ssh-ed25519 +rZ0Tw w2DgM8xAXzEYvEPHwf2SKgG6UThGCsC9O5GJtBEmESA
|
||||||
|
ID5KL9YemWr93wy66VQzgzoidMSR9TQKZYgNJp6WAoc
|
||||||
|
-> ssh-ed25519 CzqbPQ U1lCAlt/cyCwbo4VaEv7edcwGdEGzdHRSoDjvYyWkxI
|
||||||
|
JWVcb5a3iNeJv75AHNHr/9nU6pE6SnmS/5N+oZbl/cg
|
||||||
|
--- qBV+LTrheqYtuHtzeDpZTPa96P1Q91wcf7pMcIKBzFM
|
||||||
|
¢5öïÐÉÿ§û=†¾gòãhÁS+îažºÿ•—ߪ‰Ä‹Ý<E280B9>_YeE
|
||||||
|
iBºæ5UWo"ÊJZ#(ríï`LàZÈüVŠúÅ
|
86
hosts/cube/grafana/default.nix
Normal file
86
hosts/cube/grafana/default.nix
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
{ self, config, lib, ... }: let
|
||||||
|
inherit (config.networking) domain;
|
||||||
|
inherit (lib) const enabled genAttrs merge;
|
||||||
|
|
||||||
|
fqdn = "metrics.${domain}";
|
||||||
|
|
||||||
|
port = 8000;
|
||||||
|
in {
|
||||||
|
secrets.grafanaPassword = {
|
||||||
|
file = ./password.age;
|
||||||
|
owner = "grafana";
|
||||||
|
};
|
||||||
|
secrets.grafanaPasswordMail = {
|
||||||
|
file = self + /modules/mail/password.plain.age;
|
||||||
|
owner = "grafana";
|
||||||
|
};
|
||||||
|
|
||||||
|
services.postgresql = let
|
||||||
|
users = [ "grafana" ];
|
||||||
|
in {
|
||||||
|
ensureDatabases = users;
|
||||||
|
ensureUsers = map users (name: {
|
||||||
|
inherit name;
|
||||||
|
|
||||||
|
ensureDBOwnership = true;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
services.restic.backups = genAttrs config.services.restic.hosts <| const {
|
||||||
|
paths = [ "/var/lib/grafana" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.grafana = {
|
||||||
|
after = [ "postgresql.service" ];
|
||||||
|
requires = [ "postgresql.service" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.grafana = enabled {
|
||||||
|
provision = enabled;
|
||||||
|
|
||||||
|
settings = {
|
||||||
|
analytics.reporting_enabled = false;
|
||||||
|
|
||||||
|
database.host = "/run/postgresql";
|
||||||
|
database.type = "postgres";
|
||||||
|
database.user = "grafana";
|
||||||
|
|
||||||
|
server.domain = fqdn;
|
||||||
|
server.http_addr = "[::1]";
|
||||||
|
server.http_port = port;
|
||||||
|
|
||||||
|
users.default_theme = "system";
|
||||||
|
};
|
||||||
|
|
||||||
|
settings.security = {
|
||||||
|
admin_email = "metrics@${domain}";
|
||||||
|
admin_password = "$__file{${config.secrets.grafanaPassword.path}}";
|
||||||
|
admin_user = "admin";
|
||||||
|
|
||||||
|
cookie_secure = true;
|
||||||
|
disable_gravatar = true;
|
||||||
|
|
||||||
|
disable_initial_admin_creation = true; # Just in case.
|
||||||
|
};
|
||||||
|
|
||||||
|
settings.smtp = {
|
||||||
|
enabled = true;
|
||||||
|
|
||||||
|
password = "$__file{${config.secrets.grafanaPasswordMail.path}}";
|
||||||
|
startTLS_policy = "MandatoryStartTLS";
|
||||||
|
|
||||||
|
ehlo_identity = "metrics@${domain}";
|
||||||
|
from_address = "metrics@${domain}";
|
||||||
|
from_name = "Metrics";
|
||||||
|
host = "${self.disk.mailserver.fqdn}:${toString self.disk.services.postfix.relayPort}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.nginx.virtualHosts.${fqdn} = merge config.nginx.sslTemplate {
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://[::1]:${toString port}";
|
||||||
|
proxyWebsockets = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
BIN
hosts/cube/grafana/password.age
Normal file
BIN
hosts/cube/grafana/password.age
Normal file
Binary file not shown.
23
hosts/cube/hardware.nix
Normal file
23
hosts/cube/hardware.nix
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{ lib, modulesPath, ... }: let
|
||||||
|
inherit (lib) enabled;
|
||||||
|
in {
|
||||||
|
imports = [(modulesPath + "/profiles/qemu-guest.nix")];
|
||||||
|
|
||||||
|
boot.loader.grub = enabled {
|
||||||
|
device = "/dev/vda";
|
||||||
|
};
|
||||||
|
|
||||||
|
boot.initrd.availableKernelModules = [
|
||||||
|
"ata_piix"
|
||||||
|
"sr_mod"
|
||||||
|
"uhci_hcd"
|
||||||
|
"virtio_blk"
|
||||||
|
"virtio_pci"
|
||||||
|
];
|
||||||
|
|
||||||
|
fileSystems."/" = {
|
||||||
|
device = "/dev/disk/by-label/root";
|
||||||
|
fsType = "ext4";
|
||||||
|
options = [ "noatime" ];
|
||||||
|
};
|
||||||
|
}
|
BIN
hosts/cube/id.age
Normal file
BIN
hosts/cube/id.age
Normal file
Binary file not shown.
136
hosts/cube/matrix/default.nix
Normal file
136
hosts/cube/matrix/default.nix
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
{ config, lib, ... }: let
|
||||||
|
inherit (config.networking) domain;
|
||||||
|
inherit (lib) const enabled genAttrs merge strings;
|
||||||
|
|
||||||
|
pathSite = "/var/www/site";
|
||||||
|
|
||||||
|
domainChat = "chat.${domain}";
|
||||||
|
domainSync = "sync.${domain}";
|
||||||
|
|
||||||
|
wellKnownResponse = data: ''
|
||||||
|
default_type application/json;
|
||||||
|
add_header Access-Control-Allow-Origin *;
|
||||||
|
return 200 '${strings.toJSON data}';
|
||||||
|
'';
|
||||||
|
|
||||||
|
configClient."m.homeserver".base_url = "https://${domainChat}";
|
||||||
|
configClient."org.matrix.msc3575.proxy".url = "https://${domainSync}";
|
||||||
|
|
||||||
|
configServer."m.server" = "${domainChat}:443";
|
||||||
|
|
||||||
|
configWellKnownResponse.locations = {
|
||||||
|
"= /.well-known/matrix/client".extraConfig = wellKnownResponse configClient;
|
||||||
|
"= /.well-known/matrix/server".extraConfig = wellKnownResponse configServer;
|
||||||
|
};
|
||||||
|
|
||||||
|
configNotFoundLocation = {
|
||||||
|
locations."/".extraConfig = "return 404;";
|
||||||
|
|
||||||
|
extraConfig = "error_page 404 /404.html;";
|
||||||
|
locations."/404".extraConfig = "internal;";
|
||||||
|
|
||||||
|
locations."/assets/".extraConfig = "return 301 https://${domain}$request_uri;";
|
||||||
|
};
|
||||||
|
|
||||||
|
portSynapse = 8002;
|
||||||
|
portSync = 8003;
|
||||||
|
in {
|
||||||
|
secrets.matrixSecret = {
|
||||||
|
file = ./password.secret.age;
|
||||||
|
owner = "matrix-synapse";
|
||||||
|
};
|
||||||
|
secrets.matrixSyncPassword = {
|
||||||
|
file = ./password.sync.age;
|
||||||
|
owner = "matrix-synapse";
|
||||||
|
};
|
||||||
|
|
||||||
|
services.postgresql = let
|
||||||
|
users = [ "matrix-synapse" "matrix-sliding-sync" ];
|
||||||
|
in {
|
||||||
|
ensureDatabases = users;
|
||||||
|
ensureUsers = map users (name: {
|
||||||
|
inherit name;
|
||||||
|
|
||||||
|
ensureDBOwnership = true;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
services.restic.backups = genAttrs config.services.restic.hosts <| const {
|
||||||
|
paths = [ "/var/lib/matrix-synapse" "/var/lib/matrix-sliding-sync" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.matrix-synapse = enabled {
|
||||||
|
withJemalloc = true;
|
||||||
|
|
||||||
|
configureRedisLocally = true;
|
||||||
|
settings.redis.enabled = true;
|
||||||
|
|
||||||
|
extras = [ "postgres" "url-preview" "user-search" ];
|
||||||
|
|
||||||
|
log.root.level = "WARNING"; # Shut the fuck up.
|
||||||
|
|
||||||
|
settings = {
|
||||||
|
server_name = domain;
|
||||||
|
# We are not setting web_client_location since the root is not accessible
|
||||||
|
# from the outside web at all. Only /_matrix is reverse proxied to.
|
||||||
|
|
||||||
|
database.name = "psycopg2";
|
||||||
|
|
||||||
|
report_stats = false;
|
||||||
|
|
||||||
|
enable_metrics = true;
|
||||||
|
metrics_flags.known_servers = true;
|
||||||
|
|
||||||
|
expire_access_token = true;
|
||||||
|
url_preview_enabled = true;
|
||||||
|
|
||||||
|
# Trusting Matrix.org.
|
||||||
|
suppress_key_server_warning = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Sets registration_shared_secret.
|
||||||
|
extraConfigFiles = [ config.secrets.matrixSecret.path ];
|
||||||
|
|
||||||
|
settings.listeners = [{
|
||||||
|
port = portSynapse;
|
||||||
|
|
||||||
|
bind_addresses = [ "::1" ];
|
||||||
|
tls = false;
|
||||||
|
type = "http";
|
||||||
|
x_forwarded = true;
|
||||||
|
|
||||||
|
resources = [{
|
||||||
|
compress = false;
|
||||||
|
names = [ "client" "federation" ];
|
||||||
|
}];
|
||||||
|
}];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.nginx.virtualHosts.${domain} = configWellKnownResponse;
|
||||||
|
|
||||||
|
services.nginx.virtualHosts.${domainChat} = merge config.nginx.sslTemplate configWellKnownResponse configNotFoundLocation {
|
||||||
|
root = "${pathSite}";
|
||||||
|
|
||||||
|
locations."/_matrix".proxyPass = "http://[::1]:${toString portSynapse}";
|
||||||
|
locations."/_synapse/client".proxyPass = "http://[::1]:${toString portSynapse}";
|
||||||
|
};
|
||||||
|
|
||||||
|
services.matrix-sliding-sync = enabled {
|
||||||
|
environmentFile = config.age.secrets.matrixSyncPassword.path;
|
||||||
|
settings = {
|
||||||
|
SYNCV3_SERVER = "https://${domainChat}";
|
||||||
|
SYNCV3_DB = "postgresql:///matrix-sliding-sync?host=/run/postgresql";
|
||||||
|
SYNCV3_BINDADDR = "[::1]:${toString portSync}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.nginx.virtualHosts.${domainSync} = merge config.nginx.sslTemplate configNotFoundLocation {
|
||||||
|
root = pathSite;
|
||||||
|
|
||||||
|
locations."~ ^/(client/|_matrix/client/unstable/org.matrix.msc3575/sync)"
|
||||||
|
.proxyPass = "http://[::1]:${toString portSynapse}";
|
||||||
|
|
||||||
|
locations."~ ^(\\/_matrix|\\/_synapse\\/client)"
|
||||||
|
.proxyPass = "http://[::1]:${toString portSync}";
|
||||||
|
};
|
||||||
|
}
|
7
hosts/cube/matrix/password.secret.age
Normal file
7
hosts/cube/matrix/password.secret.age
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
age-encryption.org/v1
|
||||||
|
-> ssh-ed25519 +rZ0Tw JrLJgFemnQUQpZ+SYnEs0gVfPYmLyVM0ibPzLa9UKU0
|
||||||
|
rZ9DtsOexcUGuPc4Rlfj9u0cbqU4z5R4M9MuKPyL/Zk
|
||||||
|
-> ssh-ed25519 CzqbPQ 5NibbW1CERCv8QTAuz5zeKxue1j23FyvQJn1ppjkXWg
|
||||||
|
oN12GPJsxJzRMrzUp34oLO0SvwT+Ed8CLCRqCtU0LrY
|
||||||
|
--- Y+OUAHyQ0irtOVcLDx1WvyIwp5VdkM2wqqhmeCMok6A
|
||||||
|
\Š{Z_?›’ËçÁqŽ—74ºŒÚðX˦+äƒd^‚$š4ä`B”3öûøŸ(êé^ãRi)$WÏÑyX=-"<$X$ލ<C5BD>ñâð:@Ì´ŸˆXHXgq
޹ʤOÈ ¾v›ž‘„Ó <[çúŸo&ÜCUÁíkWð|³e_ªÌº’
|
8
hosts/cube/matrix/password.sync.age
Normal file
8
hosts/cube/matrix/password.sync.age
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
age-encryption.org/v1
|
||||||
|
-> ssh-ed25519 +rZ0Tw txU8aL7ixRa9bTrV+FR5Vs8UrZ/JCNNblezCm/NJLWE
|
||||||
|
9ucwZW0qvCAc5EilV1B9XC+OA5Ro3FS6KBLGKT6NArI
|
||||||
|
-> ssh-ed25519 CzqbPQ 5DDlTXg4RIYcTcusedLRkuK3dbtccfQ0HiVFUH5B5XQ
|
||||||
|
6dW9qE5UMpOSohXIu559wBnPnOrTG/mqtrWvsy5CqYw
|
||||||
|
--- UO+CkdYt44UO16Yv3+sCJ5IoM2D+Pus7jEPbRFwGyKU
|
||||||
|
bs¶X¤
|
||||||
|
Pßt<C39F>å \Twêâ¸ÝŸq{±ÐÑó:ùlö<6C>¶9%˜ç(BdÃ]Øõhº<68>ǹÓ|Üþ…SþM¨ÆQ}¼ÿ^Œ<>/quüŒ]‡oXE@"Ü‘¨”ÝŸ|ÐH}«\p©åó€Þìmd«›
|
118
hosts/cube/nextcloud/default.nix
Normal file
118
hosts/cube/nextcloud/default.nix
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
{ config, lib, pkgs, ... }: let
|
||||||
|
inherit (config.networking) domain;
|
||||||
|
inherit (lib) const enabled genAttrs mkAfter;
|
||||||
|
|
||||||
|
fqdn = "cloud.${domain}";
|
||||||
|
|
||||||
|
packageNextcloud = pkgs.nextcloud29;
|
||||||
|
in {
|
||||||
|
secrets.nextcloudPassword = {
|
||||||
|
file = ./password.age;
|
||||||
|
owner = "nextcloud";
|
||||||
|
};
|
||||||
|
secrets.nextcloudPasswordExporter = {
|
||||||
|
file = ./password.age;
|
||||||
|
owner = "nextcloud-exporter";
|
||||||
|
};
|
||||||
|
|
||||||
|
services.prometheus.exporters.nextcloud = enabled {
|
||||||
|
listenAddress = "[::]";
|
||||||
|
|
||||||
|
username = "admin";
|
||||||
|
url = "https://${fqdn}";
|
||||||
|
passwordFile = config.secrets.nextcloudPasswordExporter.path;
|
||||||
|
};
|
||||||
|
|
||||||
|
services.postgresql = let
|
||||||
|
users = [ "nextcloud" ];
|
||||||
|
in {
|
||||||
|
ensureDatabases = users;
|
||||||
|
ensureUsers = map users (name: {
|
||||||
|
inherit name;
|
||||||
|
|
||||||
|
ensureDBOwnership = true;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
services.restic.backups = genAttrs config.services.restic.hosts <| const {
|
||||||
|
paths = [ "/var/lib/nextcloud" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.nextcloud-setup = {
|
||||||
|
after = [ "postgresql.service" ];
|
||||||
|
requires = [ "postgresql.service" ];
|
||||||
|
|
||||||
|
script = mkAfter ''
|
||||||
|
nextcloud-occ theming:config name "RGBCube's Depot"
|
||||||
|
nextcloud-occ theming:config slogan "RGBCube's storage of insignificant data."
|
||||||
|
|
||||||
|
nextcloud-occ theming:config color "#000000"
|
||||||
|
nextcloud-occ theming:config background backgroundColor
|
||||||
|
|
||||||
|
nextcloud-occ theming:config logo ${./icon.gif}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
services.nextcloud = enabled {
|
||||||
|
package = packageNextcloud;
|
||||||
|
|
||||||
|
hostName = fqdn;
|
||||||
|
https = true;
|
||||||
|
|
||||||
|
configureRedis = true;
|
||||||
|
|
||||||
|
config.adminuser = "admin";
|
||||||
|
config.adminpassFile = config.secrets.nextcloudPassword.path;
|
||||||
|
|
||||||
|
config.dbhost = "/run/postgresql";
|
||||||
|
config.dbtype = "pgsql";
|
||||||
|
|
||||||
|
settings = {
|
||||||
|
default_phone_region = "TR";
|
||||||
|
|
||||||
|
# Even with manual SMTP configuration, Nextcloud fails to communicate properly
|
||||||
|
# and fails to send mail. PHP moment?
|
||||||
|
# mail_smtphost = "::1"; # FIXME: Will need to use SMTP.
|
||||||
|
# mail_smtpmode = "sendmail";
|
||||||
|
# mail_from_address = "cloud";
|
||||||
|
|
||||||
|
maintenance_window_start = 1;
|
||||||
|
|
||||||
|
# No clue why it was syslog.
|
||||||
|
# What are the NixOS module authors on?
|
||||||
|
log_type = "file";
|
||||||
|
};
|
||||||
|
|
||||||
|
settings.enabledPreviewProviders = [
|
||||||
|
"OC\\Preview\\BMP"
|
||||||
|
"OC\\Preview\\GIF"
|
||||||
|
"OC\\Preview\\JPEG"
|
||||||
|
"OC\\Preview\\Krita"
|
||||||
|
"OC\\Preview\\MarkDown"
|
||||||
|
"OC\\Preview\\MP3"
|
||||||
|
"OC\\Preview\\OpenDocument"
|
||||||
|
"OC\\Preview\\PNG"
|
||||||
|
"OC\\Preview\\TXT"
|
||||||
|
"OC\\Preview\\XBitmap"
|
||||||
|
"OC\\Preview\\HEIC"
|
||||||
|
];
|
||||||
|
|
||||||
|
phpOptions = {
|
||||||
|
"opcache.interned_strings_buffer" = "16";
|
||||||
|
output_buffering = "off";
|
||||||
|
};
|
||||||
|
|
||||||
|
extraAppsEnable = true;
|
||||||
|
extraApps = {
|
||||||
|
inherit (packageNextcloud.packages.apps)
|
||||||
|
bookmarks calendar contacts deck
|
||||||
|
forms impersonate mail # groupfolders impersonate mail
|
||||||
|
maps notes polls previewgenerator; # tasks;
|
||||||
|
# Add: files_markdown files_texteditor memories news
|
||||||
|
};
|
||||||
|
|
||||||
|
nginx.recommendedHttpHeaders = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
services.nginx.virtualHosts.${fqdn} = config.ngnixSslTemplate;
|
||||||
|
}
|
BIN
hosts/cube/nextcloud/icon.gif
Normal file
BIN
hosts/cube/nextcloud/icon.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 767 KiB |
7
hosts/cube/nextcloud/password.age
Normal file
7
hosts/cube/nextcloud/password.age
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
age-encryption.org/v1
|
||||||
|
-> ssh-ed25519 +rZ0Tw B5yow6s83Ij7ymJ4DVisL/Q58+tewqii8SLknj+WDCI
|
||||||
|
lkD9VftG4FA8sIztdrlCfaiaaSiKIEThT8gvGPuYvto
|
||||||
|
-> ssh-ed25519 CzqbPQ eHxowar9M2Zw7DheC9Cj2jwtCFKuPHJiNTGNtJOc2Ek
|
||||||
|
2LMp4JqjbKbW1Sglf06h7ZtPTA0+qxNj8QJbz7drH1k
|
||||||
|
--- kCW5Y/0JPRigRjj3CNpr4ruLsG1f5tBXoEX1eVKjB7Q
|
||||||
|
M“¯£p¿íX1øùä&<0C>r‡€Cx 3N5Þ‘6‰æÖ5>W9W
|
BIN
hosts/cube/password.rgb.age
Normal file
BIN
hosts/cube/password.rgb.age
Normal file
Binary file not shown.
15
hosts/cube/podman.nix
Normal file
15
hosts/cube/podman.nix
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{ lib, ... }: let
|
||||||
|
inherit (lib) enabled;
|
||||||
|
in {
|
||||||
|
virtualisation.podman = enabled {
|
||||||
|
dockerCompat = true;
|
||||||
|
dockerSocket = enabled;
|
||||||
|
|
||||||
|
defaultNetwork.settings.dns_enabled = true;
|
||||||
|
|
||||||
|
autoPrune = enabled {
|
||||||
|
dates = "weekly";
|
||||||
|
flags = [ "--all" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
114
hosts/cube/postgresql.nix
Normal file
114
hosts/cube/postgresql.nix
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
{ config, lib, pkgs, ... }: let
|
||||||
|
inherit (lib) const enabled genAttrs mkForce mkOverride;
|
||||||
|
in {
|
||||||
|
environment.systemPackages = [
|
||||||
|
config.services.postgresql.package
|
||||||
|
];
|
||||||
|
|
||||||
|
services.prometheus.exporters.postgres = enabled {
|
||||||
|
listenAddress = "[::]";
|
||||||
|
runAsLocalSuperUser = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
services.restic.backups = genAttrs config.services.restic.hosts <| const {
|
||||||
|
paths = [ "/tmp/postgresql-dump.sql.gz" ];
|
||||||
|
|
||||||
|
backupPrepareCommand = ''
|
||||||
|
${config.services.postgresql.package}/bin/pg_dumpall --clean \
|
||||||
|
| ${lib.getExe pkgs.gzip} --rsyncable \
|
||||||
|
> /tmp/postgresql-dump.sql.gz
|
||||||
|
'';
|
||||||
|
|
||||||
|
backupCleanupCommand = ''
|
||||||
|
rm /tmp/postgresql-dump.sql.gz
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
services.postgresql = enabled {
|
||||||
|
package = pkgs.postgresql_14;
|
||||||
|
|
||||||
|
enableJIT = true;
|
||||||
|
|
||||||
|
initdbArgs = [ "--locale=C" "--encoding=UTF8" ];
|
||||||
|
initialScript = pkgs.writeText "grant-root-perms" ''
|
||||||
|
GRANT pg_read_all_data TO root;
|
||||||
|
GRANT pg_write_all_data TO root;
|
||||||
|
'';
|
||||||
|
|
||||||
|
authentication = mkOverride 10 ''
|
||||||
|
# Type Database DBUser Authentication
|
||||||
|
local all all peer
|
||||||
|
'';
|
||||||
|
|
||||||
|
ensureUsers = map [ "postgres" "root" ] (name: {
|
||||||
|
inherit name;
|
||||||
|
|
||||||
|
ensureClauses = {
|
||||||
|
createdb = true;
|
||||||
|
createrole = true;
|
||||||
|
login = true;
|
||||||
|
replication = true;
|
||||||
|
superuser = true;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
settings = {
|
||||||
|
listen_addresses = mkForce "";
|
||||||
|
|
||||||
|
# Generated by <https://pgconfigurator.cybertec.at/>
|
||||||
|
max_connections = 100;
|
||||||
|
superuser_reserved_connections = 3;
|
||||||
|
|
||||||
|
# Memory Settings
|
||||||
|
shared_buffers = "1024 MB";
|
||||||
|
work_mem = "32 MB";
|
||||||
|
maintenance_work_mem = "320 MB";
|
||||||
|
huge_pages = "off";
|
||||||
|
effective_cache_size = "3 GB";
|
||||||
|
effective_io_concurrency = 1; # Concurrent IO only really activated if OS supports posix_fadvise function.
|
||||||
|
random_page_cost = 4; # Speed of random disk access relative to sequential access (1.0).
|
||||||
|
|
||||||
|
# Monitoring
|
||||||
|
shared_preload_libraries = "pg_stat_statements"; # Per statement resource usage stats.
|
||||||
|
track_io_timing = "on"; # Measure exact block IO times.
|
||||||
|
track_functions = "pl"; # Track execution times of pl-language procedures if any.
|
||||||
|
|
||||||
|
# Replication
|
||||||
|
wal_level = "replica";
|
||||||
|
max_wal_senders = 0;
|
||||||
|
synchronous_commit = "on";
|
||||||
|
|
||||||
|
# Checkpointing
|
||||||
|
checkpoint_timeout = "15 min";
|
||||||
|
checkpoint_completion_target = 0.9;
|
||||||
|
max_wal_size = "1024 MB";
|
||||||
|
min_wal_size = "512 MB";
|
||||||
|
|
||||||
|
# WAL writing
|
||||||
|
wal_compression = "on";
|
||||||
|
wal_buffers = -1; # auto-tuned by Postgres till maximum of segment size (16MB by default).
|
||||||
|
wal_writer_delay = "200ms";
|
||||||
|
wal_writer_flush_after = "1MB";
|
||||||
|
|
||||||
|
# Background writer
|
||||||
|
bgwriter_delay = "200ms";
|
||||||
|
bgwriter_lru_maxpages = 100;
|
||||||
|
bgwriter_lru_multiplier = 2.0;
|
||||||
|
bgwriter_flush_after = 0;
|
||||||
|
|
||||||
|
# Parallel queries
|
||||||
|
max_worker_processes = 2;
|
||||||
|
max_parallel_workers_per_gather = 1;
|
||||||
|
max_parallel_maintenance_workers = 1;
|
||||||
|
max_parallel_workers = 2;
|
||||||
|
parallel_leader_participation = "on";
|
||||||
|
|
||||||
|
# Advanced features
|
||||||
|
enable_partitionwise_join = "on";
|
||||||
|
enable_partitionwise_aggregate = "on";
|
||||||
|
jit = "on";
|
||||||
|
max_slot_wal_keep_size = "1000 MB";
|
||||||
|
track_wal_io_timing = "on";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
42
hosts/cube/prometheus.nix
Normal file
42
hosts/cube/prometheus.nix
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
{ self, config, lib, ... }: let
|
||||||
|
inherit (lib) enabled filterAttrs flatten mapAttrsToList;
|
||||||
|
in {
|
||||||
|
services.grafana.provision.datasources.settings = {
|
||||||
|
datasources = [{
|
||||||
|
name = "Prometheus";
|
||||||
|
type = "prometheus";
|
||||||
|
url = "http://[::1]:${toString config.services.prometheus.port}";
|
||||||
|
|
||||||
|
orgId = 1;
|
||||||
|
}];
|
||||||
|
|
||||||
|
deleteDatasources = [{
|
||||||
|
name = "Prometheus";
|
||||||
|
orgId = 1;
|
||||||
|
}];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.prometheus = enabled {
|
||||||
|
listenAddress = "[::]";
|
||||||
|
retentionTime = "1w";
|
||||||
|
|
||||||
|
scrapeConfigs = let
|
||||||
|
configToScrapeConfig = hostName: { hostConfig, ... }:
|
||||||
|
hostConfig.services.prometheus.exporters
|
||||||
|
|> filterAttrs (exporterName: exporterConfig:
|
||||||
|
exporterName != "minio" &&
|
||||||
|
exporterName != "unifi-poller" &&
|
||||||
|
exporterConfig.enable or false)
|
||||||
|
|> mapAttrsToList (exporterName: exporterConfig: {
|
||||||
|
job_name = "${exporterName}-${hostName}";
|
||||||
|
|
||||||
|
static_configs = [{
|
||||||
|
targets = [ "${hostName}:${toString exporterConfig.port}" ];
|
||||||
|
}];
|
||||||
|
});
|
||||||
|
|
||||||
|
in self.nixosConfigurations
|
||||||
|
|> mapAttrsToList configToScrapeConfig
|
||||||
|
|> flatten;
|
||||||
|
};
|
||||||
|
}
|
|
@ -40,8 +40,8 @@ in {
|
||||||
in {
|
in {
|
||||||
hostName = "disk";
|
hostName = "disk";
|
||||||
|
|
||||||
ipv4 = "23.164.232.40";
|
ipv4.address = "23.164.232.40";
|
||||||
ipv6 = "2602:f9f7::40";
|
ipv6.address = "2602:f9f7::40";
|
||||||
|
|
||||||
domain = "rgbcu.be";
|
domain = "rgbcu.be";
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -1,7 +1,7 @@
|
||||||
age-encryption.org/v1
|
age-encryption.org/v1
|
||||||
-> ssh-ed25519 spFFQA pJguGLlB7R7iXrGfwKabGxmryMrfY57yvfaCytZG/Fs
|
-> ssh-ed25519 spFFQA YsTLrDcLvotgvQQJCD6DBH33gYQ9AqYaGcr190cG3TI
|
||||||
1USXbjiteoTrs7+KEFPTMVBNHpBWFXyHi/iLxFL7tls
|
3q4i1UfAG7EnjhIxZaeQWQY8vcJr6JK7/LM3yP2Gao0
|
||||||
-> ssh-ed25519 CzqbPQ IbK7nvEUn324R2zHDJzfgMV/FDqwLCU/jGZLSjrG4FY
|
-> ssh-ed25519 CzqbPQ e8RuAwnyVxk0Yuh7xHcrGYhhBH7GOJkJMxrIzgIcny8
|
||||||
naDshlcyrpvgLQydqxAXg/hhfFAFov568p163F7wrZ4
|
RCoXTagYrg7uX/XG9UCY794a4d+ClM8vYbkZCw6Sw0Q
|
||||||
--- MTj/7Zs1N348gDK+G1p01d6EZ21JzpPJnlaUc1ChcBo
|
--- 62b4Fu14qheY/e7ffDWERVQIrLrxl9yKdVWmuMD+ZSA
|
||||||
*°<>òluçM¹â=&Á÷à³Z<C2B3>¾›·×ü0•ï!<21>¶A3eí\ÙB0“ÎVêýÚš¢¦í¢R‹; \6Ö¹®¡ío’÷^ZRÎ}_³›ç%~›kÑ ™»Ão¹Œž$³O¸$É^…Aâ*¦Ù
|
<02>“†ù|aלóp6Â}ßÛ[ª<>TÛUË>ÔÊŽ{ÂV#‘7À"ë ûSû’óÓ<C3B3>M·¼žOúFæ“1¸ÿ) ‚3Ò@7Ì5ï°Ö‹>KtuŸõž°Õ2$Ü<>¤ÞW…"½Ñv
|
|
@ -40,8 +40,8 @@ in {
|
||||||
in {
|
in {
|
||||||
hostName = "nine";
|
hostName = "nine";
|
||||||
|
|
||||||
ipv4 = "152.53.2.105";
|
ipv4.address = "152.53.2.105";
|
||||||
ipv6 = "2a0a:4cc0:0:12d9::";
|
ipv6.address = "2a0a:4cc0:0:12d9::";
|
||||||
|
|
||||||
domain = "rgbcu.be";
|
domain = "rgbcu.be";
|
||||||
|
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -1,7 +1,7 @@
|
||||||
age-encryption.org/v1
|
age-encryption.org/v1
|
||||||
-> ssh-ed25519 dASlBQ jbiIxrysHZ21MCvz4L+lbmi3GMH32ZRy+q/pNBkSqW0
|
-> ssh-ed25519 dASlBQ QgmiZTOwtv6WXw/1tqHg53H7lH/ZYSYN932+desFFQo
|
||||||
j2j3uQhWnvrCRNg0+cSwCz3/NNhQ3845h2bzCWMv3kQ
|
p/1V5QZ9vrCOSvoSBKIPoIKAUXjdYXhovZkvRam2Yb0
|
||||||
-> ssh-ed25519 CzqbPQ u1JW2+Ti8JtHDLgvDFcKwVPPzSSQvNru4OOEMdGGhlQ
|
-> ssh-ed25519 CzqbPQ 7AN7/Dm9Iv4hQEELZyxKk74kJuDzv/veAHcPj3P3a0g
|
||||||
4AWUfqUzfT35ijv7rlqdnm0CGWOC4zQIpCWI+JYVWY4
|
miUBnlLKmwsbY/OirayxJO3VQrdn/6HDGwONlMoKWlQ
|
||||||
--- CtfGHevr6FqzOYK/REhFlxAy08LOgt+3+DJz9tZPNp0
|
--- trEYZUoukCFgpo/LwUW+0/ggQ0X0Chyyx/0TXRgsF58
|
||||||
CB1D§ËµQ¾C"¥îûB¼‚œ…<‰¬æ*ãø1UèÙp¦ù–¿EâÝ6No¨G–´½ªó½N¿ŸQú>Ÿ Ðô?ÛU#£¥59\ØpH\°q‰Ç+²å¢DYkÉ`k¢Ï‡uO½M
|
0zšÐÏ”³žUT“ÖúWÒª*ÌÄÄLt<4C>0SÖš‹ÐÁXø¶,«Ö1¤>5¬²»e‡sdK¨µE‰Uâ'ÈðžÅ|Á‰¨ŠžA"¬Q{„?ÕªjóðÆÅ}´‰ÃÔ}ª¸4^â&šå(<28>9È}
|
|
@ -1,9 +1,9 @@
|
||||||
inputs: self: super: let
|
inputs: self: super: let
|
||||||
inherit (self) attrValues filter getAttrFromPath hasAttrByPath collectNix;
|
inherit (self) attrValues filter getAttrFromPath hasAttrByPath collectNix;
|
||||||
|
|
||||||
commonModules = collectNix ../modules/common;
|
modulesCommon = collectNix ../modules/common;
|
||||||
nixosModules = collectNix ../modules/linux;
|
modulesLinux = collectNix ../modules/linux;
|
||||||
darwinModules = collectNix ../modules/darwin;
|
modulesDarwin = collectNix ../modules/darwin;
|
||||||
|
|
||||||
collectInputs = let
|
collectInputs = let
|
||||||
inputs' = attrValues inputs;
|
inputs' = attrValues inputs;
|
||||||
|
@ -11,8 +11,8 @@ inputs: self: super: let
|
||||||
|> filter (hasAttrByPath path)
|
|> filter (hasAttrByPath path)
|
||||||
|> map (getAttrFromPath path);
|
|> map (getAttrFromPath path);
|
||||||
|
|
||||||
inputNixosModules = collectInputs [ "nixosModules" "default" ];
|
inputModulesLinux = collectInputs [ "nixosModules" "default" ];
|
||||||
inputDarwinModules = collectInputs [ "darwinModules" "default" ];
|
inputModulesDarwin = collectInputs [ "darwinModules" "default" ];
|
||||||
|
|
||||||
inputOverlays = collectInputs [ "overlays" "default" ];
|
inputOverlays = collectInputs [ "overlays" "default" ];
|
||||||
overlayModule = { nixpkgs.overlays = inputOverlays; };
|
overlayModule = { nixpkgs.overlays = inputOverlays; };
|
||||||
|
@ -30,9 +30,9 @@ in {
|
||||||
modules = [
|
modules = [
|
||||||
module
|
module
|
||||||
overlayModule
|
overlayModule
|
||||||
] ++ commonModules
|
] ++ modulesCommon
|
||||||
++ nixosModules
|
++ modulesLinux
|
||||||
++ inputNixosModules;
|
++ inputModulesLinux;
|
||||||
};
|
};
|
||||||
|
|
||||||
darwinSystem = module: super.darwinSystem {
|
darwinSystem = module: super.darwinSystem {
|
||||||
|
@ -41,8 +41,8 @@ in {
|
||||||
modules = [
|
modules = [
|
||||||
module
|
module
|
||||||
overlayModule
|
overlayModule
|
||||||
] ++ commonModules
|
] ++ modulesCommon
|
||||||
++ darwinModules
|
++ modulesDarwin
|
||||||
++ inputDarwinModules;
|
++ inputModulesDarwin;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
inherit (config.networking) domain;
|
inherit (config.networking) domain;
|
||||||
inherit (lib) mkValue;
|
inherit (lib) mkValue;
|
||||||
in {
|
in {
|
||||||
options.acmeUsers = mkValue [];
|
options.security.acme.users = mkValue [];
|
||||||
|
|
||||||
config.secrets.acmeEnvironment.file = ./environment.age;
|
config.secrets.acmeEnvironment.file = ./environment.age;
|
||||||
|
|
||||||
config.users.groups.acme.members = config.acmeUsers;
|
config.users.groups.acme.members = config.security.acme.users;
|
||||||
|
|
||||||
config.security.acme = {
|
config.security.acme = {
|
||||||
acceptTerms = true;
|
acceptTerms = true;
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
age-encryption.org/v1
|
age-encryption.org/v1
|
||||||
-> ssh-ed25519 +rZ0Tw DMMzxXSIPSsRLkIvKJAiE6OzV1z3EZ0T+od2iIxMiA0
|
-> ssh-ed25519 +rZ0Tw 9CETPqa+HdfpR1kRho1QnotNGFsLCVh64oRzP6DoF3Q
|
||||||
OHVLHmVzeiWlsVI+DQ5M+iNik+nsdiQBz4zcquygC0A
|
nZ6qcscZQ3Auct11BaM0jsYLyGnseDQ7OwQgSvLqGDw
|
||||||
-> ssh-ed25519 spFFQA TVqArtAoudQlrgAqshCP8ZU0YlVZoKwkvUVh968NqC8
|
-> ssh-ed25519 spFFQA 3oJSVeOECqU6ZkxLWErgrfn/3pLEEaJGy64OiGLvsXM
|
||||||
Cy7+Y1rTFiAoWp6Gw8a1cljCjWPHtNwXjlXWQyu8A8U
|
dt7obdmMHz4rGJxqQuZm9ptbCbJmxk80s3ME0FNQWuI
|
||||||
-> ssh-ed25519 dASlBQ ui5a61Tg1JoJvR8okc8qKkDhrSE9dH84XZQWhLn7cCo
|
-> ssh-ed25519 dASlBQ A0OQkTL89cmKOhFlHerq98XxdEqn/EaXB+DlTbaGG2c
|
||||||
5ehK2bvVgLZSYr5AstV1dwW7/qaVGRxs8PdzAg7sk4w
|
X8sG3M7BEPrey204Bs2kLuiPI+r4LKvIVD+Xdz/Vfxk
|
||||||
-> ssh-ed25519 CzqbPQ wgktFhPRIAwX8BNJu8svEHDrpz0ZCOw94nR+M3FJCTY
|
-> ssh-ed25519 CzqbPQ ZU/Fb5/XYBD9RQjMC4IQwQPSouotxFNWVpKdCsetNQk
|
||||||
RAErTHg/g/voC7yPf2lB+ELmysNwQXre9jucw2y+ZVc
|
o97rTb0aofBUmjPyrY11NwE33az7+HxbYUlw6cjE9GU
|
||||||
--- AB7oiyhts6riNlp5xuWsFTzIx2y7Axn0CU4uCXHfVLo
|
--- 8wtobvBFTd1V1idugrE6xnI1/QW/StCrcO6IjrRl/cQ
|
||||||
ê`8³ô¡eß§J°SçT'ûBÄ›ýz÷gÖK‹‰Ÿ®üªÕ
¡zꚉWc¡Fݸ3ᇴGRÁ}’²¼R×™qü6Ä]¢òn€0bÖ<+ãÉdàÔ´ø\EƒC”•MìUͱÀØ¿3ü X{qé¶ö<C2B6>jÊ<6A>ŠEŠ0&MìÙë8x¸t‰öʈ¢°F Ç}/Oáqž_<C5BE>:ýªÝï¹ÒŸ0£ö±ßá(•I/hôËKH„Ÿ„K\ÊÏX\'(ÒgÀІb±A¶ßÜ<>
|
}¡KœzLþD(ÙÁÓøÑŸ¨€Â_̲ÇtV¾~NÖ¥^¥'5ˆ\ø†ŒH.7ŸŽÔ¹h<Uè‹cœA§qŒA¬`&j±{â<>‹àÆsž[Ä"êpÈ©KG³WaKôìÁ/ñM@èê^VUýØtAß"&ãU½ŸPœö¶°›`¿p€,ÿ~XØ<58>Ë·8s(æV¦ã`¡åþw.l»^…<>ýòu _IA¥öx€Sھé
|
||||||
|
_øÃ!NThŸÂZ¸%ˆi`ŒŸÎÝ
|
|
@ -1,14 +1,14 @@
|
||||||
{ lib, ... }: let
|
{ lib, ... }: let
|
||||||
inherit (lib) mkConst;
|
inherit (lib) mkConst;
|
||||||
in {
|
in {
|
||||||
options.dnsServers = mkConst [
|
options.networking.dns.servers = mkConst [
|
||||||
"45.90.28.0#7f2bf8.dns.nextdns.io"
|
"45.90.28.0#7f2bf8.dns.nextdns.io"
|
||||||
"2a07:a8c0::#7f2bf8.dns.nextdns.io"
|
"2a07:a8c0::#7f2bf8.dns.nextdns.io"
|
||||||
"45.90.30.0#7f2bf8.dns.nextdns.io"
|
"45.90.30.0#7f2bf8.dns.nextdns.io"
|
||||||
"2a07:a8c1::#7f2bf8.dns.nextdns.io"
|
"2a07:a8c1::#7f2bf8.dns.nextdns.io"
|
||||||
];
|
];
|
||||||
|
|
||||||
options.fallbackDnsServers = mkConst [
|
options.networking.dns.serversFallback = mkConst [
|
||||||
"1.1.1.1#one.one.one.one"
|
"1.1.1.1#one.one.one.one"
|
||||||
"2606:4700:4700::1111#one.one.one.one"
|
"2606:4700:4700::1111#one.one.one.one"
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,10 @@
|
||||||
inherit (lib) mkValue;
|
inherit (lib) mkValue;
|
||||||
in {
|
in {
|
||||||
options.networking = {
|
options.networking = {
|
||||||
ipv4 = mkValue null;
|
ipv4.address = mkValue null;
|
||||||
ipv6 = mkValue null;
|
ipv4.prefixLength = mkValue 22;
|
||||||
|
|
||||||
|
ipv6.address = mkValue null;
|
||||||
|
ipv6.prefixLength = mkValue 64;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
|
@ -34,20 +34,20 @@ in {
|
||||||
|
|
||||||
# TODO: Maybe autogenerate these?
|
# TODO: Maybe autogenerate these?
|
||||||
|
|
||||||
# cube = {
|
cube = {
|
||||||
# hostname = self.cube.networking.ipv4;
|
hostname = self.cube.networking.ipv4.address;
|
||||||
# user = "rgb";
|
user = "rgb";
|
||||||
# port = 2222;
|
port = 2222;
|
||||||
# };
|
};
|
||||||
|
|
||||||
disk = {
|
disk = {
|
||||||
hostname = self.disk.networking.ipv4;
|
hostname = self.disk.networking.ipv4.address;
|
||||||
user = "floppy";
|
user = "floppy";
|
||||||
port = 2222;
|
port = 2222;
|
||||||
};
|
};
|
||||||
|
|
||||||
nine = {
|
nine = {
|
||||||
hostname = self.nine.networking.ipv4;
|
hostname = self.nine.networking.ipv4.address;
|
||||||
user = "seven";
|
user = "seven";
|
||||||
port = 2222;
|
port = 2222;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
{ config, lib, ... }: let
|
{ config, lib, ... }: let
|
||||||
inherit (lib) head map splitString;
|
inherit (lib) head splitString;
|
||||||
in {
|
in {
|
||||||
# Yeah, no DNSSEC or DoT or anything.
|
# Yeah, no DNSSEC or DoT or anything.
|
||||||
# That's what you get for using Darwin I guess.
|
# That's what you get for using Darwin I guess.
|
||||||
networking.dns = config.dnsServers
|
networking.dns = config.networking.dns.servers
|
||||||
|> map (splitString "#")
|
|> map (splitString "#")
|
||||||
|> map head;
|
|> map head;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{ config, lib, pkgs, ... }: let
|
{ config, lib, pkgs, ... }: let
|
||||||
inherit (lib) enabled mkEnableOption mkIf mkOption types;
|
inherit (lib) enabled mkEnableOption mkIf mkOption types;
|
||||||
|
|
||||||
fakeSSHPort = 22;
|
portFakeSSH = 22;
|
||||||
in {
|
in {
|
||||||
config.services.prometheus.exporters.endlessh-go = mkIf config.isServer <| enabled {
|
config.services.prometheus.exporters.endlessh-go = mkIf config.isServer <| enabled {
|
||||||
listenAddress = "[::]";
|
listenAddress = "[::]";
|
||||||
|
@ -10,11 +10,11 @@ in {
|
||||||
# `services.endlessh-go.openFirewall` exposes both the Prometheus
|
# `services.endlessh-go.openFirewall` exposes both the Prometheus
|
||||||
# exporters port and the SSH port, and we don't want the metrics
|
# exporters port and the SSH port, and we don't want the metrics
|
||||||
# to leak, so we manually expose this like so.
|
# to leak, so we manually expose this like so.
|
||||||
config.networking.firewall.allowedTCPPorts = mkIf config.isServer <| [ fakeSSHPort ];
|
config.networking.firewall.allowedTCPPorts = mkIf config.isServer <| [ portFakeSSH ];
|
||||||
|
|
||||||
config.services.endlessh-go = mkIf config.isServer <| enabled {
|
config.services.endlessh-go = mkIf config.isServer <| enabled {
|
||||||
listenAddress = "[::]";
|
listenAddress = "[::]";
|
||||||
port = fakeSSHPort;
|
port = portFakeSSH;
|
||||||
|
|
||||||
extraOptions = [
|
extraOptions = [
|
||||||
"-alsologtostderr"
|
"-alsologtostderr"
|
||||||
|
|
|
@ -8,12 +8,12 @@ in merge <| mkIf config.isDesktop {
|
||||||
xdg.portal = enabled {
|
xdg.portal = enabled {
|
||||||
config.common.default = "*";
|
config.common.default = "*";
|
||||||
|
|
||||||
extraPortals = with pkgs; [
|
extraPortals = [
|
||||||
xdg-desktop-portal-hyprland
|
pkgs.xdg-desktop-portal-hyprland
|
||||||
];
|
];
|
||||||
|
|
||||||
configPackages = with pkgs; [
|
configPackages = [
|
||||||
hyprland
|
pkgs.hyprland
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ in merge <| mkIf config.isDesktop {
|
||||||
enableXdgAutostart = true;
|
enableXdgAutostart = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
# plugins = with pkgs; [ hyprcursors ];
|
# plugins = [ pkgs.hyprcursors ];
|
||||||
|
|
||||||
# settings.plugin.dynamic-cursors = {
|
# settings.plugin.dynamic-cursors = {
|
||||||
# mode = "rotate";
|
# mode = "rotate";
|
||||||
|
|
|
@ -3,14 +3,12 @@
|
||||||
inherit (lib) optionals;
|
inherit (lib) optionals;
|
||||||
in {
|
in {
|
||||||
networking.interfaces.${interface} = {
|
networking.interfaces.${interface} = {
|
||||||
ipv4.addresses = optionals (config.networking.ipv4 != null) [{
|
ipv4.addresses = optionals (config.networking.ipv4.address != null) [{
|
||||||
address = config.networking.ipv4;
|
inherit (config.networking.ipv4) address prefixLength;
|
||||||
prefixLength = 22;
|
|
||||||
}];
|
}];
|
||||||
|
|
||||||
ipv6.addresses = optionals (config.networking.ipv4 != null) [{
|
ipv6.addresses = optionals (config.networking.ipv4.address != null) [{
|
||||||
address = config.networking.ipv6;
|
inherit (config.networking.ipv6) address prefixLength;
|
||||||
prefixLength = 64;
|
|
||||||
}];
|
}];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
{ config, lib, ... }: let
|
{ config, lib, ... }: let
|
||||||
inherit (lib) enabled concatStringsSep map;
|
inherit (lib) enabled concatStringsSep;
|
||||||
in {
|
in {
|
||||||
services.resolved = enabled {
|
services.resolved = enabled {
|
||||||
dnssec = "true";
|
dnssec = "true";
|
||||||
dnsovertls = "true";
|
dnsovertls = "true";
|
||||||
|
|
||||||
extraConfig = config.dnsServers
|
extraConfig = config.networking.dns.servers
|
||||||
|> map (server: "DNS=${server}")
|
|> map (server: "DNS=${server}")
|
||||||
|> concatStringsSep "\n";
|
|> concatStringsSep "\n";
|
||||||
|
|
||||||
fallbackDns = config.fallbackDnsServers;
|
fallbackDns = config.networking.dns.serversFallback;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
{ config, lib, ... }: let
|
{ config, lib, ... }: let
|
||||||
inherit (lib) genAttrs mkConst mkIf remove;
|
inherit (lib) genAttrs mkConst mkIf remove;
|
||||||
in{
|
in{
|
||||||
options.resticHosts = mkConst <| remove config.networking.hostName [ "cube" "disk" "nine" ];
|
options.services.restic.hosts = mkConst <| remove config.networking.hostName [ "cube" "disk" "nine" ];
|
||||||
|
|
||||||
config.secrets.resticPassword.file = mkIf config.isServer ./password.age;
|
config.secrets.resticPassword.file = mkIf config.isServer ./password.age;
|
||||||
|
|
||||||
config.services.restic.backups = mkIf config.isServer <| genAttrs config.resticHosts (host: {
|
config.services.restic.backups = mkIf config.isServer <| genAttrs config.services.restic.hosts (host: {
|
||||||
repository = "sftp:backup@${host}:${config.networking.hostName}-backup";
|
repository = "sftp:backup@${host}:${config.networking.hostName}-backup";
|
||||||
passwordFile = config.secrets.resticPassword.path;
|
passwordFile = config.secrets.resticPassword.path;
|
||||||
initialize = true;
|
initialize = true;
|
||||||
|
|
Binary file not shown.
|
@ -10,11 +10,11 @@ in {
|
||||||
listenAddress = "[::]";
|
listenAddress = "[::]";
|
||||||
};
|
};
|
||||||
|
|
||||||
services.restic.backups = genAttrs config.resticHosts <| const {
|
services.restic.backups = genAttrs config.services.restic.hosts <| const {
|
||||||
paths = [ config.mailserver.dkimKeyDirectory config.mailserver.mailDirectory ];
|
paths = [ config.mailserver.dkimKeyDirectory config.mailserver.mailDirectory ];
|
||||||
};
|
};
|
||||||
|
|
||||||
acmeUsers = [ "mail" ];
|
security.acme.users = [ "mail" ];
|
||||||
|
|
||||||
mailserver = enabled {
|
mailserver = enabled {
|
||||||
domains = mkDefault [ domain ];
|
domains = mkDefault [ domain ];
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -2,13 +2,13 @@
|
||||||
inherit (config.networking) domain;
|
inherit (config.networking) domain;
|
||||||
inherit (lib) enabled mkConst;
|
inherit (lib) enabled mkConst;
|
||||||
in {
|
in {
|
||||||
options.nginxSslTemplate = mkConst {
|
options.nginx.sslTemplate = mkConst {
|
||||||
forceSSL = true;
|
forceSSL = true;
|
||||||
quic = true;
|
quic = true;
|
||||||
useACMEHost = config.networking.domain;
|
useACMEHost = config.networking.domain;
|
||||||
};
|
};
|
||||||
|
|
||||||
options.nginxHeaders = mkConst ''
|
options.nginx.headers = mkConst ''
|
||||||
# TODO: Not working for some reason.
|
# TODO: Not working for some reason.
|
||||||
add_header Access-Control-Allow-Origin $allow_origin;
|
add_header Access-Control-Allow-Origin $allow_origin;
|
||||||
add_header Access-Control-Allow-Methods $allow_methods;
|
add_header Access-Control-Allow-Methods $allow_methods;
|
||||||
|
@ -33,7 +33,7 @@ in {
|
||||||
listenAddress = "[::]";
|
listenAddress = "[::]";
|
||||||
};
|
};
|
||||||
|
|
||||||
config.acmeUsers = [ "nginx" ];
|
config.security.acme.users = [ "nginx" ];
|
||||||
|
|
||||||
config.services.nginx = enabled {
|
config.services.nginx = enabled {
|
||||||
package = pkgs.nginxQuic;
|
package = pkgs.nginxQuic;
|
||||||
|
@ -61,7 +61,7 @@ in {
|
||||||
~^https://.+\.${domain}$ "GET, HEAD, OPTIONS";
|
~^https://.+\.${domain}$ "GET, HEAD, OPTIONS";
|
||||||
}
|
}
|
||||||
|
|
||||||
${config.nginxHeaders}
|
${config.nginx.headers}
|
||||||
|
|
||||||
proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
|
proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
|
||||||
'';
|
'';
|
||||||
|
|
|
@ -2,22 +2,22 @@
|
||||||
inherit (config.networking) domain;
|
inherit (config.networking) domain;
|
||||||
inherit (lib) enabled merge;
|
inherit (lib) enabled merge;
|
||||||
|
|
||||||
sitePath = "/var/www/site";
|
pathSite = "/var/www/site";
|
||||||
|
|
||||||
notFoundLocationConfig = {
|
configNotFoundLocation = {
|
||||||
extraConfig = "error_page 404 /404.html;";
|
extraConfig = "error_page 404 /404.html;";
|
||||||
locations."/404".extraConfig = "internal;";
|
locations."/404".extraConfig = "internal;";
|
||||||
};
|
};
|
||||||
in {
|
in {
|
||||||
services.nginx = enabled {
|
services.nginx = enabled {
|
||||||
virtualHosts.${domain} = merge config.nginxSslTemplate notFoundLocationConfig {
|
virtualHosts.${domain} = merge config.nginx.sslTemplate configNotFoundLocation {
|
||||||
root = sitePath;
|
root = pathSite;
|
||||||
|
|
||||||
locations."/".tryFiles = "$uri $uri.html $uri/index.html =404";
|
locations."/".tryFiles = "$uri $uri.html $uri/index.html =404";
|
||||||
|
|
||||||
locations."/assets/".extraConfig = ''
|
locations."/assets/".extraConfig = ''
|
||||||
if ($request_method = OPTIONS) {
|
if ($request_method = OPTIONS) {
|
||||||
${config.nginxHeaders}
|
${config.nginx.headers}
|
||||||
add_header Content-Type text/plain;
|
add_header Content-Type text/plain;
|
||||||
add_header Content-Length 0;
|
add_header Content-Length 0;
|
||||||
return 204;
|
return 204;
|
||||||
|
@ -27,12 +27,12 @@ in {
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
virtualHosts."www.${domain}" = merge config.nginxSslTemplate {
|
virtualHosts."www.${domain}" = merge config.nginx.sslTemplate {
|
||||||
locations."/".extraConfig = "return 301 https://${domain}$request_uri;";
|
locations."/".extraConfig = "return 301 https://${domain}$request_uri;";
|
||||||
};
|
};
|
||||||
|
|
||||||
virtualHosts._ = merge config.nginxSslTemplate notFoundLocationConfig {
|
virtualHosts._ = merge config.nginx.sslTemplate configNotFoundLocation {
|
||||||
root = sitePath;
|
root = pathSite;
|
||||||
|
|
||||||
locations."/".extraConfig = "return 404;";
|
locations."/".extraConfig = "return 404;";
|
||||||
locations."/assets/".extraConfig = "return 301 https://${domain}$request_uri;";
|
locations."/assets/".extraConfig = "return 301 https://${domain}$request_uri;";
|
||||||
|
|
15
secrets.nix
15
secrets.nix
|
@ -1,14 +1,23 @@
|
||||||
let
|
let
|
||||||
inherit (import ./keys.nix) disk nine admins all;
|
inherit (import ./keys.nix) cube disk nine admins all;
|
||||||
in {
|
in {
|
||||||
|
# cube
|
||||||
|
"hosts/cube/forgejo/password.runner.age".publicKeys = [ cube ] ++ admins;
|
||||||
|
"hosts/cube/grafana/password.age".publicKeys = [ cube ] ++ admins;
|
||||||
|
"hosts/cube/id.age".publicKeys = [ cube ] ++ admins;
|
||||||
|
"hosts/cube/matrix/password.secret.age".publicKeys = [ cube ] ++ admins;
|
||||||
|
"hosts/cube/matrix/password.sync.age".publicKeys = [ cube ] ++ admins;
|
||||||
|
"hosts/cube/nextcloud/password.age".publicKeys = [ cube ] ++ admins;
|
||||||
|
"hosts/cube/password.rgb.age".publicKeys = [ cube ] ++ admins;
|
||||||
|
|
||||||
# disk
|
# disk
|
||||||
"hosts/disk/password.floppy.age".publicKeys = [ disk ] ++ admins;
|
|
||||||
"hosts/disk/id.age".publicKeys = [ disk ] ++ admins;
|
"hosts/disk/id.age".publicKeys = [ disk ] ++ admins;
|
||||||
|
"hosts/disk/password.floppy.age".publicKeys = [ disk ] ++ admins;
|
||||||
|
|
||||||
# nine
|
# nine
|
||||||
|
"hosts/nine/github2forgejo/environment.age".publicKeys = [ nine ] ++ admins;
|
||||||
"hosts/nine/id.age".publicKeys = [ nine ] ++ admins;
|
"hosts/nine/id.age".publicKeys = [ nine ] ++ admins;
|
||||||
"hosts/nine/password.seven.age".publicKeys = [ nine ] ++ admins;
|
"hosts/nine/password.seven.age".publicKeys = [ nine ] ++ admins;
|
||||||
"hosts/nine/github2forgejo/environment.age".publicKeys = [ nine ] ++ admins;
|
|
||||||
|
|
||||||
# shared
|
# shared
|
||||||
"modules/common/ssh/config.age".publicKeys = all;
|
"modules/common/ssh/config.age".publicKeys = all;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue