depot/ops/nixos/totoro/default.nix

638 lines
19 KiB
Nix
Raw Normal View History

2020-06-28 18:32:52 +00:00
# SPDX-FileCopyrightText: 2020 Luke Granger-Brown <depot@lukegb.com>
#
# SPDX-License-Identifier: Apache-2.0
{ depot, lib, pkgs, config, ... }:
2020-06-28 18:32:52 +00:00
let
inherit (depot.ops) secrets;
in {
2021-01-06 21:29:33 +00:00
imports = [
../../../third_party/nixpkgs/nixos/modules/installer/scan/not-detected.nix
../lib/client.nix
../lib/whitby-distributed.nix
2023-03-09 21:33:42 +00:00
../lib/nixbuild-distributed.nix
2021-01-06 21:29:33 +00:00
../lib/twitternuke.nix
2021-01-20 17:55:31 +00:00
../lib/quotes.bfob.gg.nix
2021-12-21 05:48:40 +00:00
../lib/baserow.nix
../lib/deluge.nix
../lib/plex.nix
2023-04-18 20:05:51 +00:00
../lib/tumblrandom.nix
2023-12-14 11:30:26 +00:00
../lib/freeswitch.nix
2024-10-20 17:01:51 +00:00
../lib/seaweedfs.nix
./home-assistant.nix
2022-05-12 22:55:10 +00:00
./authentik.nix
2023-01-09 02:09:04 +00:00
./adsb.nix
./barf.nix
2021-01-06 21:29:33 +00:00
];
2020-06-28 18:32:52 +00:00
boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usb_storage" "usbhid" "sd_mod" ];
boot.kernelModules = lib.mkAfter [ "kvm-intel" ];
boot.kernelParams = [ "mitigations=off" ];
fileSystems = let
zfs = device: {
device = device;
fsType = "zfs";
};
in {
"/" = zfs "zboot/safe/root";
"/nix" = zfs "zboot/local/nix";
"/home" = zfs "tank/safe/home";
2020-07-04 19:36:38 +00:00
"/export" = zfs "tank/safe/export";
2020-11-17 02:39:01 +00:00
"/srv" = zfs "tank/safe/srv";
"/srv/pancake" = zfs "tank/safe/srv/pancake";
2020-06-28 18:32:52 +00:00
2021-01-15 03:38:43 +00:00
"/persist" = zfs "tank/safe/persist";
2022-01-08 12:08:04 +00:00
"/persist/var/lib/containers" = zfs "tank/safe/persist/containers";
2021-01-15 03:38:43 +00:00
"/store" = zfs "tank/local/store";
2022-01-08 12:08:04 +00:00
"/store/run/containers" = zfs "tank/local/store/containers";
2021-01-15 03:38:43 +00:00
2024-10-20 17:01:51 +00:00
"/var/lib/private/seaweedfs-filer" = zfs "tank/safe/seaweedfs/filer";
"/var/lib/private/seaweedfs-master" = zfs "tank/safe/seaweedfs/master";
"/var/lib/private/seaweedfs-volume" = zfs "tank/safe/seaweedfs/volume";
"/var/lib/private/seaweedfs-volume/data" = zfs "tank/safe/seaweedfs/volume/data";
"/var/lib/private/seaweedfs-volume/idx" = zfs "tank/safe/seaweedfs/volume/idx";
2020-06-28 18:32:52 +00:00
"/boot" = {
device = "/dev/disk/by-uuid/D178-4E19";
fsType = "vfat";
};
};
boot.zfs.requestEncryptionCredentials = false;
2020-06-28 18:32:52 +00:00
# Use the systemd-boot EFI boot loader.
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
2021-04-25 21:44:05 +00:00
services.postgresql.package = pkgs.postgresql_13;
services.postgresql.settings.shared_buffers = "16GB";
services.postgresql.settings.work_mem = "1GB";
services.postgresql.settings.maintenance_work_mem = "1GB";
2021-04-25 21:44:05 +00:00
nix.settings.max-jobs = lib.mkDefault 8;
2020-06-28 18:32:52 +00:00
powerManagement.cpuFreqGovernor = lib.mkDefault "performance";
virtualisation = {
podman.enable = true;
2022-01-08 12:08:04 +00:00
containers.storage.settings.storage = {
driver = "zfs";
runroot = "/store/run/containers/storage";
graphroot = "/persist/var/lib/containers/storage";
};
};
2022-01-08 12:08:04 +00:00
systemd.services.podman.path = lib.mkAfter [
pkgs.zfs
];
2020-06-28 18:32:52 +00:00
services.openssh.settings.X11Forwarding = true;
# Extra packages.
environment.systemPackages = with pkgs; [
2020-10-15 13:22:18 +00:00
(depot.nix.pkgs.secretsync.configure {
workingDir = "/home/lukegb/depot";
gitlabAccessToken = secrets.deployer.gitlabAccessToken;
manifestVariable = "SECRETS_MANIFEST";
variablesToFile = {
"OPS_SECRETS_DEFAULT_NIX" = "ops/secrets/default.nix";
};
})
];
2020-06-28 18:32:52 +00:00
# Networking!
networking = {
hostName = "totoro"; # Define your hostname.
2021-04-10 20:15:30 +00:00
domain = "int.as205479.net";
2020-06-28 18:32:52 +00:00
hostId = "676c08c4";
2022-06-19 20:34:43 +00:00
useNetworkd = true;
2020-06-28 22:22:43 +00:00
bridges.br-ext.interfaces = [ "enp0s31f6" ];
2022-06-19 20:34:43 +00:00
interfaces.br-ext = {
ipv4.addresses = [
{ address = "192.168.1.40"; prefixLength = 24; }
];
2023-12-14 11:30:26 +00:00
ipv6.addresses = [
{ address = "2a09:a443::1000"; prefixLength = 128; }
];
2022-06-19 20:34:43 +00:00
};
2020-10-31 17:04:30 +00:00
interfaces.br-int = {
ipv4.addresses = [{ address = "10.0.0.2"; prefixLength = 24; }];
};
bridges.br-int.interfaces = [];
2021-01-15 03:39:36 +00:00
firewall.allowedTCPPorts = [
2021-01-15 03:42:38 +00:00
80 443 # web
2021-01-15 03:39:36 +00:00
4001 # ipfs
2022-03-05 11:56:22 +00:00
139 445 # SMB
5357 # samba-wsdd
2021-01-15 03:39:36 +00:00
];
firewall.allowedUDPPorts = [
4001 # ipfs
2022-03-05 11:56:22 +00:00
137 138 # SMB
3702 # samba-wsdd
2021-01-15 03:39:36 +00:00
];
2022-03-11 18:45:41 +00:00
firewall.checkReversePath = false; # breaks Lifx
2022-04-06 00:00:55 +00:00
firewall.extraCommands = ''
# Allow all inbound UDP from localnet for Lifx purposes...
iptables -A nixos-fw -p udp --src 192.168.1.0/24 --dst 192.168.1.40 -j nixos-fw-accept
'';
macvlans.mv-plex = { interface = "br-ext"; };
interfaces.mv-plex = {
ipv4.addresses = [
# plex-totoro
{ address = "92.118.30.20"; prefixLength = 32; }
];
ipv6.addresses = [
# plex-totoro
{ address = "2a09:a443::1:1000"; prefixLength = 128; }
];
};
interfaces.lo.ipv4.addresses = [
{ address = "92.118.30.19"; prefixLength = 32; }
];
2020-06-28 22:22:43 +00:00
};
2022-06-19 20:34:43 +00:00
systemd.network = {
networks."40-br-int" = {
linkConfig.RequiredForOnline = "no";
};
2022-06-25 17:43:30 +00:00
networks."40-br-ext" = {
gateway = [ "192.168.1.1" ];
};
2022-06-19 20:34:43 +00:00
};
my.ip.tailscale = "100.122.86.11";
2022-09-01 23:22:16 +00:00
my.ip.tailscale6 = "fd7a:115c:a1e0:ab12:4843:cd96:627a:560b";
2020-06-28 22:22:43 +00:00
# Virtualisation
virtualisation.libvirtd = {
enable = true;
allowedBridges = [ "virbr0" "br-ext" ];
2020-06-28 18:32:52 +00:00
};
2022-08-14 20:01:26 +00:00
security.polkit.enable = true;
2020-06-28 22:23:43 +00:00
users.users.lukegb = {
2020-07-08 18:35:48 +00:00
packages = with depot.pkgs; [ irssi ];
2022-01-08 12:08:04 +00:00
extraGroups = lib.mkAfter [ "libvirtd" "acme" "podman" ];
2020-06-28 22:23:43 +00:00
};
2020-11-17 03:14:04 +00:00
users.users.pancake = {
isSystemUser = true;
group = "pancake";
home = "/srv/pancake";
};
users.users.nginx.extraGroups = lib.mkAfter [ "acme" ];
users.groups.pancake = {
members = ["pancake" "nginx"];
};
2020-06-28 18:32:52 +00:00
systemd.tmpfiles.rules = [
"L /var/lib/export - - - - /export"
];
2020-11-17 03:14:04 +00:00
services.nginx = {
enable = true;
package = pkgs.nginxMainline;
additionalModules = with pkgs.nginxModules; [
rtmp
];
appendConfig = ''
rtmp {
server {
listen 1935;
chunk_size 4000;
application app {
live on;
record off;
allow publish all;
allow play all;
push rtmp://ingest.beam.bfob.gg/beam/thecakeisalie;
}
2022-03-14 21:28:58 +00:00
application live2 {
live on;
record off;
allow publish all;
allow play all;
push rtmp://ingest.beam.bfob.gg/beam/thecakeisalie;
2022-03-14 21:28:58 +00:00
}
}
}
'';
2020-11-17 03:14:04 +00:00
virtualHosts = {
"invoices.lukegb.com" = let
fastcgi = {
extraConfig = ''
rewrite ^(.*)$ /index.php break;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_index index.php;
fastcgi_pass unix:${config.services.phpfpm.pools.pancake.socket};
include ${pkgs.nginx}/conf/fastcgi_params;
include ${pkgs.nginx}/conf/fastcgi.conf;
'';
};
in {
root = "/srv/pancake/public_html";
forceSSL = true;
locations."/" = {
tryFiles = "$uri $uri/ @router";
index = "index.html index.php";
extraConfig = ''
error_page 403 = @router;
error_page 404 = @router;
'';
};
locations."~ (.php|\\/[^./]+)$" = fastcgi;
locations."@router" = fastcgi;
};
"plex-totoro.lukegb.com" = {
forceSSL = true;
locations."/" = {
proxyPass = "http://localhost:32400/";
proxyWebsockets = true;
};
};
2020-11-17 03:14:04 +00:00
};
};
services.phpfpm = let settingsBase = {
"listen.owner" = config.services.nginx.user;
"pm" = "dynamic";
"pm.max_children" = 32;
"pm.max_requests" = 500;
"pm.start_servers" = 2;
"pm.min_spare_servers" = 2;
"pm.max_spare_servers" = 5;
"php_admin_value[error_log]" = "stderr";
"php_admin_flag[log_errors]" = true;
"catch_workers_output" = true;
}; in {
pools.pancake = {
user = "pancake";
group = "pancake";
settings = settingsBase;
phpEnv."PATH" = lib.makeBinPath [ pkgs.php ];
};
};
services.mysql = {
enable = true;
package = pkgs.mariadb;
ensureDatabases = ["pancake"];
ensureUsers = [{
name = "pancake";
}];
};
services.prometheus = {
enable = true;
stateDir = "export/monitoring/prometheus";
2023-01-14 22:24:01 +00:00
webExternalUrl = "https://prometheus.int.lukegb.com";
alertmanagers = [{
scheme = "http";
static_configs = [{
targets = ["localhost:${toString config.services.prometheus.alertmanager.port}"];
}];
}];
globalConfig.scrape_interval = "15s";
scrapeConfigs = (builtins.attrValues depot.ops.nixos.systemExporters) ++ [{
2021-06-28 21:17:48 +00:00
job_name = "minotar/minotarproxy";
scheme = "https";
static_configs = [{
targets = ["minotarproxy.lukegb.xyz:443"];
}];
} {
job_name = "nixos/prometheus";
metrics_path = "/prometheus/federate";
honor_labels = true;
params = {
"match[]" = [
''hydra_job_failed{current="1"}''
''hydra_job_completion_time{current="1"}''
];
};
scheme = "https";
static_configs = [{
targets = ["monitoring.nixos.org:443"];
}];
} {
job_name = "emf/website";
metrics_path = "/metrics";
scheme = "https";
static_configs = [{
targets = ["www.emfcamp.org:443"];
}];
}];
pushgateway.enable = true;
rules = [
''
groups:
- name: alerting
rules:
# Blade power
2021-04-20 14:48:00 +00:00
# Systems
- alert: NodeExporterDown
2024-03-27 00:37:57 +00:00
expr: up{exporter="node", system=~"(rexxar|kusakabe|swann|totoro|clouvider-.*|etheroute-.*|bvm-.*)"} < 1
2021-04-20 14:48:00 +00:00
for: 30m
labels:
severity: page
annotations:
summary: "Node exporter no longer scrapable"
description: "{{ $labels.system }} is not reachable from totoro."
2021-04-20 14:48:00 +00:00
# Alert if the NixOS channels are broken
- alert: NixOSChannelBad
expr: hydra_job_failed{} == 1
for: 30m
labels:
severity: email
annotations:
summary: "NixOS Channel {{ $labels.channel }} failing"
description: "The channel {{ $labels.channel }} is failing - see https://hydra.nixos.org/job/{{ $labels.project }}/{{ $labels.jobset }}/tested"
2021-07-13 00:55:53 +00:00
# Packet loss
- alert: SmokepingAveragePacketLossHigh
2023-01-14 22:24:01 +00:00
expr: sum(clamp((rate(smokeping_requests_total{host=~"(([a-z0-9]+.)+[a-z]+|([0-9]+.){3}[0-9]+)"}[5m]) - rate(smokeping_response_duration_seconds_count[5m])) / rate(smokeping_requests_total[5m]) > 0.01, 1, 1)) by (system) > sum(clamp(smokeping_requests_total{host=~"(([a-z0-9]+.)+[a-z]+|([0-9]+.){3}[0-9]+)"}, 1, 1)) by (system) * 0.4
2021-07-13 00:55:53 +00:00
for: 10m
labels:
severity: page
annotations:
summary: "Average packet loss from {{ $labels.system }} high"
2023-01-14 22:24:01 +00:00
description: "Too many endpoints are failing packet loss checks from {{ $labels.system }} ({{ $value }} targets)."
2021-07-13 00:55:53 +00:00
- alert: SmokepingPacketLossVeryHigh
expr: ((rate(smokeping_requests_total{host=~"(([a-z0-9]+.)+[a-z]+|([0-9]+.){3}[0-9]+)"}[5m]) - rate(smokeping_response_duration_seconds_count[5m])) / rate(smokeping_requests_total[5m])) >= 0.10
for: 10m
labels:
severity: page
annotations:
summary: "Packet loss to {{ $labels.host }} from {{ $labels.system }} high"
description: "The packet loss from {{ $labels.system }} to {{ $labels.host }} (IP: {{ $labels.ip }}) is very high ({{ $value | humanizePercentage }}%)."
2021-07-13 00:55:53 +00:00
# Ping latency
- alert: Smokeping95LatencyHigh
expr: histogram_quantile(0.95, sum(rate(smokeping_response_duration_seconds_bucket{host=~"^(1.1.1.1|8.8.8.8)$"}[5m])) by (le, host, system)) > 0.1
2021-07-13 00:55:53 +00:00
for: 15m
labels:
severity: page
annotations:
summary: "Ping latency from {{ $labels.system }} to {{ $labels.host }} high"
description: "The 95th-percentile ping latency from {{ $labels.system }} to {{ $labels.host }} is {{ $value }}."
# Internet connectivity
- alert: MaldenRoadInternetConnectivityFailure
expr: sum(bird_bfd_session_state{state="Up"} * on(instance,name,neighbor_address,system) group_left(device) bird_bfd_session_device) by (instance,neighbor_address,device,state,system) < 1
2021-09-02 19:24:17 +00:00
for: 15m
labels:
severity: page
annotations:
summary: "Device {{ $labels.device }} on {{ $labels.system }} reports BFD down to neighbour {{ $labels.neighbor_address }}"
description: "Ruh roh, Raggy"
''
];
2021-02-23 00:16:41 +00:00
alertmanager = {
enable = true;
2023-01-14 22:24:01 +00:00
webExternalUrl = "https://alertmanager.int.lukegb.com";
configuration = {
global = {};
route = {
receiver = "default-receiver";
};
receivers = [{
name = "default-receiver";
2021-02-23 01:07:33 +00:00
webhook_configs = [{
url = "http://localhost:9997";
}];
pushover_configs = [{
user_key = secrets.pushover.userKey;
token = secrets.pushover.tokens.alertmanager;
}];
}];
};
};
exporters.snmp = {
enable = true;
configurationPath = depot.nix.pkgs.prometheus-snmp-config;
};
};
2020-12-29 20:08:55 +00:00
services.grafana = {
enable = true;
2022-10-31 21:41:42 +00:00
settings = {
server.root_url = "https://grafana.int.lukegb.com/";
server.http_addr = "0.0.0.0";
server.http_port = 3000;
server.domain = "grafana.int.lukegb.com";
2020-12-29 20:08:55 +00:00
"auth.proxy" = {
enabled = "true";
header_name = "X-Pomerium-Claim-Email";
header_property = "email";
headers = "username:X-Pomerium-Claim-User";
auto_sign_up = "true";
};
security.cookie_secure = true;
2020-12-29 20:08:55 +00:00
};
};
systemd.services.grafana.preStart = let
cfg = config.services.grafana;
plugins = with depot.pkgs.grafana-plugins; [
grafana-piechart-panel
2020-12-30 03:30:24 +00:00
grafana-clock-panel
grafana-worldmap-panel
grafana-polystat-panel
];
pluginLines = lib.concatMapStringsSep "\n" (pkg: ''
ln -sf ${pkg} ${cfg.dataDir}/plugins/${pkg.pname}
'') plugins;
in lib.mkAfter ''
rm -rf ${cfg.dataDir}/plugins
mkdir ${cfg.dataDir}/plugins
${pluginLines}
'';
services.kubo = {
2021-01-15 03:38:43 +00:00
enable = true;
dataDir = "/store/ipfs";
2022-10-31 21:41:42 +00:00
settings = {
Experimental.FilestoreEnabled = true;
};
2021-01-15 03:38:43 +00:00
};
2021-02-23 01:07:33 +00:00
systemd.services.alertmanager-discord = {
enable = true;
2021-07-17 01:45:31 +00:00
wantedBy = [ "multi-user.target" ];
2021-02-23 01:07:33 +00:00
serviceConfig = {
ExecStart = "${depot.pkgs.alertmanager-discord}/bin/alertmanager-discord -listen.address 127.0.0.1:9997";
EnvironmentFile = pkgs.writeText "discord-secret" ''
DISCORD_WEBHOOK=${secrets.monitoring.alertmanager.discord.api_url}
'';
DynamicUser = true;
MountAPIVFS = true;
PrivateTmp = true;
PrivateUsers = true;
ProtectControlGroups = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
};
};
2021-07-17 01:45:31 +00:00
systemd.services.sslrenew-raritan = {
enable = true;
after = [ "network-online.target" ];
2024-01-27 22:57:59 +00:00
wants = [ "network-online.target" ];
2021-07-17 01:45:31 +00:00
serviceConfig = {
Type = "oneshot";
ExecStart = "${depot.ops.raritan.ssl-renew}/lego.sh";
EnvironmentFile = pkgs.writeText "sslrenew-secret" ''
CERTIFICATE_DOMAIN=kvm.lukegb.xyz
2022-08-10 00:51:46 +00:00
CERTIFICATE_ROLE=google-cloudflare
2021-07-17 01:45:31 +00:00
RARITAN_IP=192.168.1.50
'';
DynamicUser = true;
User = "sslrenew-raritan";
2021-07-17 01:45:31 +00:00
StateDirectory = "sslrenew-raritan";
StateDirectoryMode = "0700";
WorkingDirectory = "/var/lib/sslrenew-raritan";
};
};
systemd.timers.sslrenew-raritan = {
enable = true;
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = "daily";
};
};
systemd.services.streetworks = {
enable = true;
after = [ "network-online.target" ];
2024-01-27 22:57:59 +00:00
wants = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = "${depot.go.streetworks}/bin/streetworks -postcode='NW5 4HS' -pushover_token='${secrets.pushover.tokens.depot}' -pushover_user='${secrets.pushover.userKey}'";
DynamicUser = true;
MountAPIVFS = true;
PrivateTmp = true;
PrivateUsers = true;
ProtectControlGroups = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
};
};
my.prometheus.additionalExporterPorts.trains = 2112;
2022-03-05 11:56:22 +00:00
services.samba-wsdd = {
enable = true;
workgroup = "WORKGROUP";
hostname = "TOTORO";
interface = "br-ext";
};
services.samba = {
enable = true;
2024-10-13 13:07:08 +00:00
nmbd.enable = false; # Eh, SMB1.0
2024-09-29 18:26:00 +00:00
settings.global = {
"server min protocol" = "SMB3_11";
"client min protocol" = "SMB3_11";
"restrict anonymous" = "1";
};
2024-10-13 13:07:08 +00:00
settings.content = {
comment = "Content";
browseable = "yes";
"read only" = "yes";
"guest ok" = "yes";
};
2024-10-13 13:07:08 +00:00
settings.homes = {
2022-03-05 11:56:22 +00:00
comment = "Home Directories";
browseable = "no";
"read only" = "no";
"create mask" = "0755";
"directory mask" = "0755";
"valid users" = "%S";
};
};
2023-03-09 21:33:22 +00:00
services.nfs.server = {
enable = true;
exports = ''
/export 192.168.1.0/24(rw,fsid=0,no_subtree_check,sync)
'';
};
my.vault.acmeCertificates = {
"plex-totoro.lukegb.com" = { hostnames = [ "plex-totoro.lukegb.com" ]; nginxVirtualHosts = [ "plex-totoro.lukegb.com" ]; };
"invoices.lukegb.com" = { hostnames = [ "invoices.lukegb.com" ]; nginxVirtualHosts = [ "invoices.lukegb.com" ]; };
};
2022-03-06 22:26:49 +00:00
2023-01-17 19:36:53 +00:00
boot.binfmt.emulatedSystems = [ "aarch64-linux" ];
2023-08-19 21:13:16 +00:00
services.openvscode-server = {
enable = true;
user = "lukegb";
withoutConnectionToken = true;
host = config.my.ip.tailscale6;
2023-08-19 21:13:16 +00:00
port = 3002;
};
2024-10-20 17:01:51 +00:00
my.services.seaweedfs = {
securitySettings = {
cors.allowed_origins.values = "*";
};
master = {
enable = true;
options = {
port = 21000;
ip = config.my.ip.tailscale6;
mdir = "/var/lib/seaweedfs-master/metadata";
defaultReplication = "000";
};
};
filer = {
enable = true;
earlyOptions = {
v = 4;
};
options = {
port = 21010;
ip = config.my.ip.tailscale6;
master = "[${config.my.ip.tailscale6}]:21000";
encryptVolumeData = true;
defaultReplicaPlacement = "000";
};
settings = {
leveldb2 = {
enabled = true;
dir = "/var/lib/seaweedfs-filer/leveldb2";
};
};
};
volume = {
enable = true;
earlyOptions = {
v = 4;
};
options = {
port = 21100;
ip = config.my.ip.tailscale6;
dataCenter = "home";
rack = "home";
max = 0;
mserver = "[${config.my.ip.tailscale6}]:21000";
};
};
cli.settings = {
cluster.default = "totoro";
cluster.totoro = {
master = "[${config.my.ip.tailscale6}]:21000";
};
};
2024-10-20 17:19:22 +00:00
sync.rexxar.options = {
a = "rexxar.int.as205479.net:21010";
b = "totoro.int.as205479.net:21010";
};
2024-10-20 17:01:51 +00:00
};
2022-10-08 21:05:50 +00:00
system.stateVersion = "22.11";
2020-06-28 18:32:52 +00:00
}