2020-02-11 16:41:00 +01:00
|
|
|
# This file configures camden.tazj.in, my homeserver.
|
2020-04-26 01:24:49 +02:00
|
|
|
{ depot, pkgs, lib, ... }:
|
2020-02-11 16:41:00 +01:00
|
|
|
|
|
|
|
config: let
|
2020-06-07 20:30:33 +02:00
|
|
|
nixpkgs = import depot.third_party.nixpkgsSrc {
|
2020-02-11 16:41:00 +01:00
|
|
|
config.allowUnfree = true;
|
|
|
|
};
|
2020-06-12 04:02:18 +02:00
|
|
|
|
|
|
|
nginxRedirect = { from, to, acmeHost }: {
|
|
|
|
serverName = from;
|
|
|
|
useACMEHost = acmeHost;
|
|
|
|
forceSSL = true;
|
|
|
|
|
|
|
|
extraConfig = "return 301 https://${to}$request_uri;";
|
|
|
|
};
|
2020-02-21 13:47:29 +01:00
|
|
|
in lib.fix(self: {
|
2020-05-26 02:17:55 +02:00
|
|
|
imports = [
|
2020-06-13 22:52:20 +02:00
|
|
|
"${depot.depotPath}/ops/nixos/depot.nix"
|
2020-07-09 00:03:07 +02:00
|
|
|
"${depot.depotPath}/ops/nixos/quassel.nix"
|
2020-06-13 22:52:20 +02:00
|
|
|
"${depot.depotPath}/ops/nixos/smtprelay.nix"
|
2020-07-01 01:15:47 +02:00
|
|
|
"${depot.depotPath}/ops/nixos/sourcegraph.nix"
|
2020-06-13 22:52:20 +02:00
|
|
|
"${depot.depotPath}/ops/nixos/tvl-slapd/default.nix"
|
2020-05-26 02:17:55 +02:00
|
|
|
];
|
|
|
|
depot = depot;
|
|
|
|
|
2020-02-11 16:41:00 +01:00
|
|
|
# camden is intended to boot unattended, despite having an encrypted
|
|
|
|
# root partition.
|
|
|
|
#
|
|
|
|
# The below configuration uses an externally connected USB drive
|
|
|
|
# that contains a LUKS key file to unlock the disk automatically at
|
|
|
|
# boot.
|
|
|
|
#
|
|
|
|
# TODO(tazjin): Configure LUKS unlocking via SSH instead.
|
|
|
|
boot = {
|
|
|
|
initrd = {
|
|
|
|
availableKernelModules = [
|
|
|
|
"ahci" "xhci_pci" "usbhid" "usb_storage" "sd_mod" "sdhci_pci"
|
|
|
|
"rtsx_usb_sdmmc" "r8169"
|
|
|
|
];
|
|
|
|
|
|
|
|
kernelModules = [ "dm-snapshot" ];
|
|
|
|
|
|
|
|
luks.devices.camden-crypt = {
|
|
|
|
fallbackToPassword = true;
|
|
|
|
device = "/dev/disk/by-label/camden-crypt";
|
|
|
|
keyFile = "/dev/sdb";
|
|
|
|
keyFileSize = 4096;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
loader = {
|
|
|
|
systemd-boot.enable = true;
|
|
|
|
efi.canTouchEfiVariables = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
cleanTmpDir = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
fileSystems = {
|
|
|
|
"/" = {
|
|
|
|
device = "/dev/disk/by-label/camden-root";
|
|
|
|
fsType = "ext4";
|
|
|
|
};
|
|
|
|
|
|
|
|
"/home" = {
|
|
|
|
device = "/dev/disk/by-label/camden-home";
|
|
|
|
fsType = "ext4";
|
|
|
|
};
|
|
|
|
|
|
|
|
"/boot" = {
|
|
|
|
device = "/dev/disk/by-label/BOOT";
|
|
|
|
fsType = "vfat";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2020-02-11 17:46:15 +01:00
|
|
|
nix = {
|
|
|
|
maxJobs = lib.mkDefault 4;
|
|
|
|
|
|
|
|
nixPath = [
|
|
|
|
"depot=/home/tazjin/depot"
|
2020-02-21 13:47:29 +01:00
|
|
|
"nixpkgs=${depot.third_party.nixpkgsSrc}"
|
2020-02-11 17:46:15 +01:00
|
|
|
];
|
2020-02-17 02:00:12 +01:00
|
|
|
|
|
|
|
trustedUsers = [ "root" "tazjin" ];
|
2020-04-21 23:55:32 +02:00
|
|
|
|
|
|
|
binaryCaches = [
|
|
|
|
"https://tazjin.cachix.org"
|
|
|
|
];
|
|
|
|
|
|
|
|
binaryCachePublicKeys = [
|
|
|
|
"tazjin.cachix.org-1:IZkgLeqfOr1kAZjypItHMg1NoBjm4zX9Zzep8oRSh7U="
|
|
|
|
];
|
2020-02-11 17:46:15 +01:00
|
|
|
};
|
|
|
|
nixpkgs.pkgs = nixpkgs;
|
2020-02-11 16:41:00 +01:00
|
|
|
|
|
|
|
powerManagement.cpuFreqGovernor = lib.mkDefault "powersave";
|
|
|
|
|
|
|
|
networking = {
|
|
|
|
hostName = "camden";
|
|
|
|
interfaces.enp1s0.useDHCP = true;
|
2020-04-20 18:05:37 +02:00
|
|
|
interfaces.enp1s0.ipv6.addresses = [
|
|
|
|
{
|
|
|
|
address = "2a01:4b00:821a:ce02::5";
|
|
|
|
prefixLength = 64;
|
|
|
|
}
|
|
|
|
];
|
|
|
|
|
2020-04-26 15:58:42 +02:00
|
|
|
firewall.enable = false;
|
2020-02-11 16:41:00 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
time.timeZone = "UTC";
|
|
|
|
|
|
|
|
# System-wide application setup
|
|
|
|
programs.fish.enable = true;
|
2020-02-17 01:06:55 +01:00
|
|
|
programs.mosh.enable = true;
|
|
|
|
|
2020-02-11 17:27:34 +01:00
|
|
|
environment.systemPackages =
|
|
|
|
# programs from the depot
|
2020-02-21 13:47:29 +01:00
|
|
|
(with depot; [
|
2020-04-26 16:51:38 +02:00
|
|
|
fun.idual.script
|
2020-04-26 01:24:49 +02:00
|
|
|
fun.idual.setAlarm
|
2020-02-17 01:52:07 +01:00
|
|
|
third_party.pounce
|
2020-02-11 17:27:34 +01:00
|
|
|
]) ++
|
|
|
|
|
|
|
|
# programs from nixpkgs
|
|
|
|
(with nixpkgs; [
|
2020-04-21 23:56:04 +02:00
|
|
|
bat
|
2020-02-17 01:22:19 +01:00
|
|
|
curl
|
|
|
|
direnv
|
|
|
|
emacs26-nox
|
2020-05-26 02:19:27 +02:00
|
|
|
git
|
2020-06-16 03:09:22 +02:00
|
|
|
gnupg
|
|
|
|
google-cloud-sdk
|
2020-02-17 01:22:19 +01:00
|
|
|
htop
|
2020-02-21 16:43:07 +01:00
|
|
|
jq
|
2020-02-17 01:22:19 +01:00
|
|
|
pass
|
|
|
|
pciutils
|
2020-06-16 03:09:22 +02:00
|
|
|
restic
|
2020-04-21 23:56:04 +02:00
|
|
|
ripgrep
|
2020-02-11 17:27:34 +01:00
|
|
|
]);
|
2020-02-11 16:41:00 +01:00
|
|
|
|
2020-02-12 02:04:12 +01:00
|
|
|
users = {
|
|
|
|
# Set up my own user for logging in and doing things ...
|
|
|
|
users.tazjin = {
|
|
|
|
isNormalUser = true;
|
|
|
|
uid = 1000;
|
|
|
|
extraGroups = [ "git" "wheel" ];
|
|
|
|
shell = nixpkgs.fish;
|
|
|
|
};
|
|
|
|
|
|
|
|
# Set up a user & group for general git shenanigans
|
|
|
|
groups.git = {};
|
|
|
|
users.git = {
|
|
|
|
group = "git";
|
|
|
|
isNormalUser = false;
|
|
|
|
};
|
2020-02-11 16:41:00 +01:00
|
|
|
};
|
|
|
|
|
2020-02-11 21:54:31 +01:00
|
|
|
# Services setup
|
|
|
|
services.openssh.enable = true;
|
|
|
|
services.haveged.enable = true;
|
|
|
|
|
2020-02-11 17:27:34 +01:00
|
|
|
# Join Tailscale into home network
|
2020-04-04 14:17:18 +02:00
|
|
|
services.tailscale.enable = true;
|
2020-02-11 17:27:34 +01:00
|
|
|
|
2020-04-26 19:34:10 +02:00
|
|
|
# Allow sudo-ing via the forwarded SSH agent.
|
|
|
|
security.pam.enableSSHAgentAuth = true;
|
|
|
|
|
2020-04-22 13:03:04 +02:00
|
|
|
# NixOS 20.03 broke nginx and I can't be bothered to debug it
|
|
|
|
# anymore, all solution attempts have failed, so here's a
|
|
|
|
# brute-force fix.
|
|
|
|
systemd.services.fix-nginx = {
|
2020-06-10 23:50:40 +02:00
|
|
|
script = "${nixpkgs.coreutils}/bin/chown -R nginx: /var/spool/nginx /var/cache/nginx";
|
2020-04-22 13:03:04 +02:00
|
|
|
|
|
|
|
serviceConfig = {
|
|
|
|
User = "root";
|
|
|
|
Type = "oneshot";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
systemd.timers.fix-nginx = {
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
timerConfig = {
|
|
|
|
OnCalendar = "minutely";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2020-02-12 02:08:27 +01:00
|
|
|
# Provision a TLS certificate outside of nginx to avoid
|
|
|
|
# nixpkgs#38144
|
2020-03-01 02:11:28 +01:00
|
|
|
security.acme = {
|
|
|
|
acceptTerms = true;
|
|
|
|
email = "mail@tazj.in";
|
|
|
|
|
|
|
|
certs."tazj.in" = {
|
|
|
|
user = "nginx";
|
|
|
|
group = "nginx";
|
|
|
|
webroot = "/var/lib/acme/acme-challenge";
|
|
|
|
extraDomains = {
|
2020-05-26 02:19:27 +02:00
|
|
|
"cs.tazj.in" = null;
|
2020-03-01 02:11:28 +01:00
|
|
|
"git.tazj.in" = null;
|
|
|
|
"www.tazj.in" = null;
|
|
|
|
|
|
|
|
# Local domains (for this machine only)
|
|
|
|
"camden.tazj.in" = null;
|
|
|
|
};
|
|
|
|
postRun = "systemctl reload nginx";
|
2020-02-14 12:49:04 +01:00
|
|
|
};
|
2020-04-21 04:05:03 +02:00
|
|
|
|
2020-07-09 00:03:07 +02:00
|
|
|
certs."quassel.tazj.in" = {
|
|
|
|
webroot = "/var/lib/acme/challenge-quassel";
|
|
|
|
user = "nginx"; # required because of a bug in the ACME module
|
|
|
|
group = "quassel";
|
|
|
|
allowKeysForGroup = true;
|
|
|
|
};
|
|
|
|
|
2020-04-21 04:05:03 +02:00
|
|
|
certs."tvl.fyi" = {
|
|
|
|
user = "nginx";
|
|
|
|
group = "nginx";
|
|
|
|
webroot = "/var/lib/acme/acme-challenge";
|
|
|
|
postRun = "systemctl reload nginx";
|
2020-06-07 20:30:52 +02:00
|
|
|
extraDomains = {
|
2020-06-18 04:34:01 +02:00
|
|
|
"b.tvl.fyi" = null;
|
2020-06-07 20:30:52 +02:00
|
|
|
"cl.tvl.fyi" = null;
|
|
|
|
"code.tvl.fyi" = null;
|
|
|
|
"cs.tvl.fyi" = null;
|
|
|
|
};
|
2020-04-21 04:05:03 +02:00
|
|
|
};
|
2020-02-14 12:49:04 +01:00
|
|
|
};
|
|
|
|
|
2020-02-21 16:35:51 +01:00
|
|
|
# Forward logs to Google Cloud Platform
|
|
|
|
services.journaldriver = {
|
|
|
|
enable = true;
|
|
|
|
logStream = "home";
|
|
|
|
googleCloudProject = "tazjins-infrastructure";
|
|
|
|
applicationCredentials = "/etc/gcp/key.json";
|
|
|
|
};
|
|
|
|
|
2020-07-09 00:03:07 +02:00
|
|
|
services.depot.quassel = {
|
|
|
|
enable = true;
|
|
|
|
acmeHost = "quassel.tazj.in";
|
|
|
|
bindAddresses = [
|
|
|
|
"0.0.0.0"
|
|
|
|
];
|
|
|
|
};
|
|
|
|
|
2020-05-26 02:19:27 +02:00
|
|
|
# serve my website(s)
|
2020-02-11 20:32:21 +01:00
|
|
|
services.nginx = {
|
|
|
|
enable = true;
|
|
|
|
enableReload = true;
|
2020-04-04 03:38:51 +02:00
|
|
|
package = with nixpkgs; nginx.override {
|
|
|
|
modules = [ nginxModules.rtmp ];
|
|
|
|
};
|
2020-02-11 20:32:21 +01:00
|
|
|
|
2020-02-12 02:08:27 +01:00
|
|
|
recommendedTlsSettings = true;
|
|
|
|
recommendedGzipSettings = true;
|
|
|
|
recommendedProxySettings = true;
|
2020-02-11 20:32:21 +01:00
|
|
|
|
2020-04-04 03:38:51 +02:00
|
|
|
|
|
|
|
appendConfig = ''
|
|
|
|
rtmp_auto_push on;
|
|
|
|
rtmp {
|
|
|
|
server {
|
|
|
|
listen 1935;
|
|
|
|
chunk_size 4000;
|
|
|
|
|
|
|
|
application tvl {
|
|
|
|
live on;
|
|
|
|
|
|
|
|
allow publish 88.98.195.213;
|
|
|
|
allow publish 10.0.1.0/24;
|
|
|
|
deny publish all;
|
|
|
|
|
|
|
|
allow play all;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
'';
|
|
|
|
|
2020-02-11 20:32:21 +01:00
|
|
|
commonHttpConfig = ''
|
|
|
|
log_format json_combined escape=json
|
|
|
|
'{'
|
|
|
|
'"remote_addr":"$remote_addr",'
|
2020-02-21 17:10:08 +01:00
|
|
|
'"method":"$request_method",'
|
|
|
|
'"uri":"$request_uri",'
|
|
|
|
'"status":$status,'
|
2020-02-21 17:12:48 +01:00
|
|
|
'"request_size":$request_length,'
|
2020-02-21 17:10:08 +01:00
|
|
|
'"response_size":$body_bytes_sent,'
|
|
|
|
'"response_time":$request_time,'
|
|
|
|
'"referrer":"$http_referer",'
|
|
|
|
'"user_agent":"$http_user_agent"'
|
2020-02-11 20:32:21 +01:00
|
|
|
'}';
|
|
|
|
|
2020-02-21 17:01:54 +01:00
|
|
|
access_log syslog:server=unix:/dev/log,nohostname json_combined;
|
2020-02-11 20:32:21 +01:00
|
|
|
'';
|
|
|
|
|
|
|
|
virtualHosts.homepage = {
|
2020-02-14 13:00:12 +01:00
|
|
|
serverName = "tazj.in";
|
|
|
|
serverAliases = [ "camden.tazj.in" ];
|
2020-02-11 20:32:21 +01:00
|
|
|
default = true;
|
2020-02-14 12:49:04 +01:00
|
|
|
useACMEHost = "tazj.in";
|
2020-06-26 21:28:06 +02:00
|
|
|
root = depot.users.tazjin.homepage;
|
2020-06-12 03:28:38 +02:00
|
|
|
forceSSL = true;
|
2020-02-11 20:32:21 +01:00
|
|
|
|
|
|
|
extraConfig = ''
|
2020-06-26 21:28:06 +02:00
|
|
|
${depot.users.tazjin.blog.oldRedirects}
|
2020-02-11 20:32:21 +01:00
|
|
|
|
2020-04-04 22:46:16 +02:00
|
|
|
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
|
|
|
|
|
2020-02-11 20:32:21 +01:00
|
|
|
location ~* \.(webp|woff2)$ {
|
|
|
|
add_header Cache-Control "public, max-age=31536000";
|
|
|
|
}
|
|
|
|
|
|
|
|
location /blog/ {
|
2020-06-26 21:28:06 +02:00
|
|
|
alias ${depot.users.tazjin.blog.rendered}/;
|
2020-02-11 20:32:21 +01:00
|
|
|
|
|
|
|
if ($request_uri ~ ^/(.*)\.html$) {
|
|
|
|
return 302 /$1;
|
|
|
|
}
|
|
|
|
|
|
|
|
try_files $uri $uri.html $uri/ =404;
|
|
|
|
}
|
2020-02-11 21:54:50 +01:00
|
|
|
|
2020-07-11 01:16:45 +02:00
|
|
|
location = /tazjin {
|
|
|
|
return 200 "tazjin";
|
|
|
|
}
|
|
|
|
|
2020-02-11 21:54:50 +01:00
|
|
|
location /blobs/ {
|
|
|
|
alias /var/www/blobs/;
|
|
|
|
}
|
2020-02-11 20:32:21 +01:00
|
|
|
'';
|
|
|
|
};
|
2020-02-12 02:09:03 +01:00
|
|
|
|
2020-06-12 04:02:18 +02:00
|
|
|
virtualHosts.cgit-old = nginxRedirect {
|
|
|
|
from = "git.tazj.in";
|
|
|
|
to = "code.tvl.fyi";
|
|
|
|
acmeHost = "tazj.in";
|
|
|
|
};
|
|
|
|
|
|
|
|
virtualHosts.cs-old = nginxRedirect {
|
|
|
|
from = "cs.tazj.in";
|
|
|
|
to = "cs.tvl.fyi";
|
|
|
|
acmeHost = "tazj.in";
|
|
|
|
};
|
2020-02-11 20:32:21 +01:00
|
|
|
};
|
|
|
|
|
2020-04-26 01:24:49 +02:00
|
|
|
# Timer units that can be started with systemd-run to set my alarm.
|
|
|
|
systemd.user.services.light-alarm = {
|
2020-04-26 16:51:38 +02:00
|
|
|
script = "${depot.fun.idual.script}/bin/idualctl wakey";
|
2020-04-26 01:24:49 +02:00
|
|
|
postStart = "${pkgs.systemd}/bin/systemctl --user stop light-alarm.timer";
|
|
|
|
serviceConfig = {
|
|
|
|
Type = "oneshot";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2020-06-16 03:09:22 +02:00
|
|
|
# Regularly back up Gerrit to Google Cloud Storage.
|
|
|
|
systemd.user.services.restic-gerrit = {
|
|
|
|
description = "Gerrit backups to Google Cloud Storage";
|
|
|
|
script = "${nixpkgs.restic}/bin/restic backup /var/lib/gerrit";
|
|
|
|
environment = {
|
|
|
|
RESTIC_REPOSITORY = "gs:tvl-fyi-backups:/camden";
|
|
|
|
RESTIC_PASSWORD_FILE = "%h/.config/restic/secret";
|
|
|
|
RESTIC_EXCLUDE_FILE = builtins.toFile "exclude-files" ''
|
|
|
|
/var/lib/gerrit/etc/secure.config
|
|
|
|
/var/lib/gerrit/etc/ssh_host_*_key
|
|
|
|
/var/lib/gerrit/etc/ssh_host_*_key
|
|
|
|
/var/lib/gerrit/etc/ssh_host_*_key
|
|
|
|
/var/lib/gerrit/etc/ssh_host_*_key
|
|
|
|
/var/lib/gerrit/etc/ssh_host_*_key
|
|
|
|
/var/lib/gerrit/tmp
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
systemd.user.timers.restic-gerrit = {
|
|
|
|
wantedBy = [ "timers.target" ];
|
|
|
|
timerConfig.OnCalendar = "hourly";
|
|
|
|
};
|
|
|
|
|
2020-02-11 16:41:00 +01:00
|
|
|
system.stateVersion = "19.09";
|
|
|
|
})
|