# SPDX-FileCopyrightText: 2020 Luke Granger-Brown # # SPDX-License-Identifier: Apache-2.0 { depot, lib, pkgs, rebuilder, config, ... }: let inherit (depot.ops) secrets; machineSecrets = secrets.machineSpecific.clouvider-lon01; in { imports = [ ../lib/zfs.nix ../lib/bgp.nix ../lib/whitby-distributed.nix ]; boot.initrd = { availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usbhid" "usb_storage" "sd_mod" "sr_mod" "igb" ]; network = { enable = true; ssh = { enable = true; hostKeys = ["/persist/etc/ssh/ssh_host_ed25519_key"]; authorizedKeys = map builtins.readFile config.users.users.lukegb.openssh.authorizedKeys.keyFiles; }; postCommands = '' echo "zfs load-key -a; killall zfs" >> /root/.profile ''; }; }; boot.kernelParams = [ "ip=185.198.188.29::185.198.188.28:255.255.255.254:clouvider-lon01:enp1s0f0:none" ]; boot.kernelModules = [ "kvm-intel" ]; powerManagement.cpuFreqGovernor = lib.mkDefault "performance"; fileSystems = let zfs = device: { device = device; fsType = "zfs"; }; in { "/" = zfs "tank/local/root"; "/nix" = zfs "tank/local/nix"; "/persist" = zfs "tank/safe/persist"; "/home" = zfs "tank/safe/home"; "/boot1" = { device = "/dev/disk/by-partlabel/boota"; fsType = "vfat"; }; "/boot2" = { device = "/dev/disk/by-partlabel/bootb"; fsType = "vfat"; }; }; nix.maxJobs = lib.mkDefault 8; # Use GRUB, so we can have mirrored bootloaders. boot.loader.efi.canTouchEfiVariables = true; boot.loader.grub = { enable = true; version = 2; zfsSupport = true; efiSupport = true; mirroredBoots = map (path: { inherit path; devices = ["nodev"]; efiSysMountPoint = path; }) ["/boot1" "/boot2"]; }; # Networking! networking = { hostName = "clouvider-lon01"; domain = "as205479.net"; hostId = "29aaa324"; nameservers = [ "2001:4860:4860::8888" "2001:4860:4860::8844" "8.8.8.8" "8.8.4.4" ]; useDHCP = false; defaultGateway = { address = "185.198.188.28"; interface = "br-ext"; }; defaultGateway6 = { address = "2a0a:54c0:0:17::1"; interface = "br-ext"; }; bridges.br-ext.interfaces = ["enp1s0f0"]; interfaces.br-ext = { ipv4.addresses = [{ address = "185.198.188.29"; prefixLength = 31; }]; ipv6.addresses = [{ address = "2a0a:54c0:0:17::2"; prefixLength = 126; }]; }; interfaces.lo = { ipv4.addresses = [{ address = "127.0.0.1"; prefixLength = 8; }] ++ ( map (n: { address = "92.118.29.${toString n}"; prefixLength = 32; }) (lib.range 225 253)); ipv6.addresses = [{ address = "::1"; prefixLength = 128; }]; }; firewall = { allowPing = true; allowedTCPPorts = [ 80 443 # HTTP/nginx 6697 # znc 34197 # factorio ]; allowedUDPPorts = [ 34197 # factorio ]; }; }; my.ip.tailscale = "100.79.173.25"; services.openssh.listenAddresses = [{ addr = config.my.ip.tailscale; port = 22; }] ++ (let inherit (builtins) map concatMap; in map (addr: { inherit addr; port = 22; }) (concatMap (intf: (map (addr: addr.address) (intf.ipv4.addresses)) ++ (map (addr: "[${addr.address}]") (intf.ipv6.addresses))) (with config.networking.interfaces; [ br-ext ]))); services.openssh.hostKeys = [ { path = "/persist/etc/ssh/ssh_host_ed25519_key"; type = "ed25519"; } { path = "/persist/etc/ssh/ssh_host_rsa_key"; type = "rsa"; bits = 4096; } ]; users.users = { lukegb.extraGroups = [ "bird2" ]; minotarproxy = { isSystemUser = true; }; }; users.groups = { znc-acme = { members = [ "znc" "nginx" ]; }; }; services.lukegbgp = let local = { asn = 205479; }; in { enable = true; config = { local = { routerID = "185.198.188.29"; }; export = { v4 = ["92.118.28.0/24" "92.118.29.0/24"]; }; peering = { clouvider = { local = local // { v4 = "185.198.188.29"; v6 = "2a0a:54c0:0:17::2"; }; remote = { asn = 62240; export_community = 3000; routers = [{ v4 = "185.198.188.28"; v6 = "2a0a:54c0:0:17::1"; }]; }; }; }; }; }; services.znc = { enable = true; mutable = true; dataDir = "/persist/etc/znc"; useLegacyConfig = false; }; security.acme = { acceptTerms = true; email = "letsencrypt@lukegb.com"; certs."znc.lukegb.com" = { webroot = "/var/lib/acme/.challenges"; group = "znc-acme"; extraDomainNames = ["akiichiro.lukegb.com"]; }; }; services.nginx = { enable = true; virtualHosts = { "clouvider-lon01.as205479.net" = { listen = [ {addr = "185.198.188.29"; port = 80; ssl = false;} {addr = "[2a0a:54c0:0:17::2]"; port = 80; ssl = false;} ]; locations."/.well-known/acme-challenge" = { root = "/var/lib/acme/.challenges"; }; locations."/" = { return = "301 https://$host$request_uri"; }; }; }; }; systemd.services.minotarproxy = { description = "Minotar proxy"; wants = ["network-online.target"]; wantedBy = ["multi-user.target"]; serviceConfig = { ExecStart = ''${depot.go.minotarproxy}/bin/minotarproxy --logtostderr --server_bind=92.118.29.225:443 --autocert_insecure_bind=92.118.29.225:80 --autocert_domain=minotarproxy.lukegb.xyz --outbound_bind="92.118.29.225,92.118.29.226,92.118.29.227,92.118.29.228,92.118.29.229,92.118.29.230,92.118.29.231,92.118.29.232,92.118.29.233,92.118.29.234,92.118.29.235,92.118.29.236,92.118.29.237,92.118.29.238,92.118.29.239,92.118.29.240,92.118.29.241,92.118.29.242,92.118.29.243,92.118.29.244,92.118.29.245,92.118.29.246,92.118.29.247,92.118.29.248,92.118.29.249,92.118.29.250,92.118.29.251,92.118.29.252,92.118.29.253" --autocert_cache_dir=/run/minotarproxy''; User = "minotarproxy"; Restart = "always"; AmbientCapabilities = "CAP_NET_BIND_SERVICE"; }; }; systemd.tmpfiles.rules = [ "d /run/minotarproxy 0700 minotarproxy - -" ]; systemd.mounts = let bindMount' = dir: { unitConfig.RequiresMountsFor = dir; options = "bind"; what = "/persist${dir}"; where = dir; }; bindMountSvc = dir: svc: (bindMount' dir) // { bindsTo = [svc]; partOf = [svc]; }; bindMountSvcDynamic = dir: svc: (bindMount' "/var/lib/private/${dir}") // { requiredBy = [svc]; before = [svc]; wantedBy = ["multi-user.target"]; }; bindMount = dir: (bindMount' dir) // { wantedBy = ["multi-user.target"]; }; in [ (bindMountSvcDynamic "factorio" "factorio.service") ]; environment.etc."secrets/gitlab-runner-registration" = { text = '' CI_SERVER_URL=https://hg.lukegb.com REGISTRATION_TOKEN=${depot.ops.secrets.deployer.registrationToken} ''; mode = "0600"; }; services.gitlab-runner = { enable = true; concurrent = 1; services = { deployer = { registrationConfigFile = "/etc/secrets/gitlab-runner-registration"; executor = "shell"; tagList = [ "cacher" ]; }; }; gracefulTermination = true; gracefulTimeout = "4min"; package = depot.nix.pkgs.heptapod-runner; }; users.users.gitlab-runner = { createHome = true; home = "/srv/gitlab-runner"; }; nix.gc.automatic = false; services.factorio = { inherit (secrets.factorio) username token; enable = true; package = pkgs.factorio-headless-experimental; saveName = "lukegb20201124"; game-name = "Briefcase Full of Bees"; extraSettings = { admins = ["lukegb"]; auto_pause = true; only_admins_can_pause_the_game = false; game_password = secrets.factorioServerPassword; non_blocking_saving = true; autosave_only_on_server = true; autosave_interval = 5; autosave_slots = 60; }; }; system.stateVersion = "20.09"; }