refactor(ops): Split //ops/nixos into different locations

Splits //ops/nixos into:

* //ops/nixos.nix - utility functions for building systems
* //ops/machines - shared machine definitions (read by readTree)
* //ops/modules - shared NixOS modules (skipped by readTree)

This simplifies working with the configuration fixpoint in whitby, and
is overall a bit more in line with how NixOS systems in user folders
currently work.

Change-Id: I1322ec5cc76c0207c099c05d44828a3df0b3ffc1
Reviewed-on: https://cl.tvl.fyi/c/depot/+/2931
Tested-by: BuildkiteCI
Reviewed-by: sterni <sternenseemann@systemli.org>
Reviewed-by: glittershark <grfn@gws.fyi>
This commit is contained in:
Vincent Ambo 2021-04-11 22:50:30 +02:00 committed by tazjin
parent 7deabb8c8d
commit 90281c4eac
38 changed files with 41 additions and 60 deletions

View file

@ -0,0 +1 @@
NixOS modules are not readTree compatible.

7
ops/modules/README.md Normal file
View file

@ -0,0 +1,7 @@
NixOS modules
=============
This folder contains various NixOS modules shared by our NixOS
configurations.
It is not read by `readTree`.

75
ops/modules/clbot.nix Normal file
View file

@ -0,0 +1,75 @@
# Module that configures CLBot, our Gerrit->IRC info bridge.
{ depot, config, lib, pkgs, ... }:
let
inherit (builtins) attrValues concatStringsSep mapAttrs readFile;
inherit (pkgs) runCommandNoCC;
inherit (lib)
listToAttrs
mkEnableOption
mkIf
mkOption
removeSuffix
types;
description = "Bot to forward CL notifications";
cfg = config.services.depot.clbot;
mkFlags = flags:
concatStringsSep " "
(attrValues (mapAttrs (key: value: "-${key} \"${toString value}\"") flags));
# Escapes a unit name for use in systemd
systemdEscape = name: removeSuffix "\n" (readFile (runCommandNoCC "unit-name" {} ''
${pkgs.systemd}/bin/systemd-escape '${name}' >> $out
''));
mkUnit = flags: channel: {
name = "clbot-${systemdEscape channel}";
value = {
description = "${description} to ${channel}";
wantedBy = [ "multi-user.target" ];
script = "${depot.fun.clbot}/bin/clbot ${mkFlags (cfg.flags // {
irc_channel = channel;
})} -alsologtostderr";
serviceConfig = {
User = "clbot";
EnvironmentFile = "/etc/secrets/clbot";
Restart = "always";
};
};
};
in {
options.services.depot.clbot = {
enable = mkEnableOption description;
flags = mkOption {
type = types.attrsOf types.str;
description = "Key value pairs for command line flags";
};
channels = mkOption {
type = with types; listOf str;
description = "Channels in which to post (generates one unit per channel)";
};
};
config = mkIf cfg.enable {
# This does not use DynamicUser because we need to make some files
# (notably the SSH private key) readable by this user outside of
# the module.
users = {
groups.clbot = {};
users.clbot = {
group = "clbot";
isNormalUser = false;
};
};
systemd.services = listToAttrs (map (mkUnit cfg.flags) cfg.channels);
};
}

2
ops/modules/default.nix Normal file
View file

@ -0,0 +1,2 @@
# Make readTree happy at this level.
_: {}

49
ops/modules/irccat.nix Normal file
View file

@ -0,0 +1,49 @@
{ depot, config, lib, pkgs, ... }:
let
cfg = config.services.depot.irccat;
description = "irccat - forward messages to IRC";
# irccat expects to read its configuration from the *current
# directory*, and its configuration contains secrets.
#
# To make this work we construct the JSON configuration file and
# then recursively merge it with an on-disk secret using jq on
# service launch.
configJson = pkgs.writeText "irccat.json" (builtins.toJSON cfg.config);
configMerge = pkgs.writeShellScript "merge-irccat-config" ''
if [ ! -f "/etc/secrets/irccat.json" ]; then
echo "irccat secrets file is missing"
exit 1
fi
# jq's * is the recursive merge operator
${pkgs.jq}/bin/jq -s '.[0] * .[1]' ${configJson} /etc/secrets/irccat.json \
> /var/lib/irccat/irccat.json
'';
in {
options.services.depot.irccat = {
enable = lib.mkEnableOption description;
config = lib.mkOption {
type = lib.types.attrs; # varying value types
description = "Configuration structure (unchecked!)";
};
};
config = lib.mkIf cfg.enable {
systemd.services.irccat = {
inherit description;
preStart = "${configMerge}";
script = "${depot.third_party.irccat}/bin/irccat";
wantedBy = [ "multi-user.target" ];
serviceConfig = {
DynamicUser = true;
StateDirectory = "irccat";
WorkingDirectory = "/var/lib/irccat";
Restart = "always";
};
};
};
}

View file

@ -0,0 +1,128 @@
# Gerrit configuration for the TVL monorepo
{ depot, pkgs, config, lib, ... }:
let
cfg = config.services.gerrit;
gerritHooks = pkgs.runCommandNoCC "gerrit-hooks" {} ''
mkdir -p $out
ln -s ${depot.ops.besadii}/bin/besadii $out/ref-updated
'';
in {
services.gerrit = {
enable = true;
listenAddress = "[::]:4778"; # 4778 - grrt
serverId = "4fdfa107-4df9-4596-8e0a-1d2bbdd96e36";
builtinPlugins = [
"download-commands"
"hooks"
];
plugins = with depot.third_party.gerrit_plugins; [
owners
oauth
depot.ops.gerrit-tvl
];
package = depot.third_party.gerrit;
jvmHeapLimit = "4g";
settings = {
core.packedGitLimit = "100m";
log.jsonLogging = true;
log.textLogging = false;
sshd.advertisedAddress = "code.tvl.fyi:29418";
hooks.path = "${gerritHooks}";
cache.web_sessions.maxAge = "3 months";
plugins.allowRemoteAdmin = false;
change.enableAttentionSet = true;
change.enableAssignee = false;
# Configures gerrit for being reverse-proxied by nginx as per
# https://gerrit-review.googlesource.com/Documentation/config-reverseproxy.html
gerrit = {
canonicalWebUrl = "https://cl.tvl.fyi";
docUrl = "/Documentation";
};
httpd.listenUrl = "proxy-https://${cfg.listenAddress}";
download.command = [
"checkout"
"cherry_pick"
"format_patch"
"pull"
];
# Configure for cgit.
gitweb = {
type = "custom";
url = "https://code.tvl.fyi";
project = "/";
revision = "/commit/?id=\${commit}";
branch = "/log/?h=\${branch}";
tag = "/tag/?h=\${tag}";
roottree = "/tree/?h=\${commit}";
file = "/tree/\${file}?h=\${commit}";
filehistory = "/log/\${file}?h=\${branch}";
linkname = "cgit";
};
# Auto-link panettone bug links
commentlink.panettone = {
match = "b/(\\\\d+)";
html = "<a href=\"https://b.tvl.fyi/issues/$1\">b/$1</a>";
};
# Auto-link other CLs
commentlink.gerrit = {
match = "cl/(\\\\d+)";
html = "<a href=\"https://cl.tvl.fyi/$1\">cl/$1</a>";
};
# Configures integration with CAS, which then integrates with a variety
# of backends.
auth.type = "OAUTH";
plugin.gerrit-oauth-provider-cas-oauth = {
root-url = "https://login.tvl.fyi";
client-id = "OAUTH-TVL-gerrit-Fv0d8Aizz5";
# client-secret is set in /var/lib/gerrit/etc/secure.config.
};
# Use Gerrit's built-in HTTP passwords, rather than trying to use the
# password against the backing OAuth provider.
auth.gitBasicAuthPolicy = "HTTP";
# Email sending (emails are relayed via the tazj.in domain's
# GSuite currently).
#
# Note that sendemail.smtpPass is stored in
# $site_path/etc/secure.config and is *not* controlled by Nix.
#
# Receiving email is not currently supported.
sendemail = {
enable = true;
html = false;
connectTimeout = "10sec";
from = "TVL Code Review <tvlbot@tazj.in>";
includeDiff = true;
smtpEncryption = "none";
smtpServer = "localhost";
smtpServerPort = 2525;
};
};
};
systemd.services.gerrit = {
serviceConfig = {
# There seems to be no easy way to get `DynamicUser` to play
# well with other services (e.g. by using SupplementaryGroups,
# which seem to have no effect) so we force the DynamicUser
# setting for the Gerrit service to be disabled and reuse the
# existing 'git' user.
DynamicUser = lib.mkForce false;
User = "git";
Group = "git";
};
};
}

103
ops/modules/panettone.nix Normal file
View file

@ -0,0 +1,103 @@
{ depot, config, lib, pkgs, ... }:
let
cfg = config.services.depot.panettone;
in {
options.services.depot.panettone = with lib; {
enable = mkEnableOption "Panettone issue tracker";
port = mkOption {
description = "Port on which Panettone should listen";
type = types.int;
default = 7268;
};
dbHost = mkOption {
description = "Postgresql host to connect to for Panettone";
type = types.str;
default = "localhost";
};
dbName = mkOption {
description = "Name of the database for Panettone";
type = types.str;
default = "panettone";
};
dbUser = mkOption {
description = "Name of the database user for Panettone";
type = types.str;
default = "panettone";
};
secretsFile = mkOption {
description = ''
Path to a file containing secrets, in the format accepted
by systemd's EnvironmentFile
'';
type = types.str;
};
irccatHost = mkOption {
description = "Hostname for the irccat instance";
type = types.str;
default = "localhost";
};
irccatPort = mkOption {
description = "Port for the irccat instance";
type = types.int;
default = 4722;
};
irccatChannel = mkOption {
description = "IRC channels to post to via irccat";
type = types.str;
};
};
config = lib.mkIf cfg.enable {
assertions = [{
assertion =
cfg.dbHost != "localhost" || config.services.postgresql.enable;
message = "Panettone requires a postgresql database";
} {
assertion =
cfg.dbHost != "localhost" || config.services.postgresql.enableTCPIP;
message = "Panettone can only connect to the postgresql database over TCP";
} {
assertion =
cfg.dbHost != "localhost" || (lib.any
(user: user.name == cfg.dbUser)
config.services.postgresql.ensureUsers);
message = "Panettone requires a database user";
} {
assertion =
cfg.dbHost != "localhost" || (lib.any
(db: db == cfg.dbName)
config.services.postgresql.ensureDatabases);
message = "Panettone requires a database";
}];
systemd.services.panettone = {
wantedBy = [ "multi-user.target" ];
script = "${depot.web.panettone}/bin/panettone";
serviceConfig = {
DynamicUser = true;
Restart = "always";
EnvironmentFile = cfg.secretsFile;
};
environment = {
PANETTONE_PORT = toString cfg.port;
PGHOST = "localhost";
PGUSER = cfg.dbUser;
PGDATABASE = cfg.dbName;
IRCCATHOST = cfg.irccatHost;
IRCCATPORT = toString cfg.irccatPort;
ISSUECHANNEL = cfg.irccatChannel;
};
};
};
}

27
ops/modules/paroxysm.nix Normal file
View file

@ -0,0 +1,27 @@
{ depot, config, lib, pkgs, ... }:
let
cfg = config.services.depot.paroxysm;
description = "TVL's majestic IRC bot";
in {
options.services.depot.paroxysm.enable = lib.mkEnableOption description;
config = lib.mkIf cfg.enable {
systemd.services.paroxysm = {
inherit description;
script = "${depot.fun.paroxysm}/bin/paroxysm";
wantedBy = [ "multi-user.target" ];
environment = {
PARX_DATABASE_URL = "postgresql://tvldb:tvldb@localhost/tvldb";
PARX_IRC_CONFIG_PATH = "/var/lib/paroxysm/irc.toml";
};
serviceConfig = {
DynamicUser = true;
StateDirectory = "paroxysm";
Restart = "always";
};
};
};
}

76
ops/modules/quassel.nix Normal file
View file

@ -0,0 +1,76 @@
# A more modern module for running Quassel.
{ config, lib, pkgs, ... }:
let
cfg = config.services.depot.quassel;
quasselDaemon = pkgs.quassel.override {
monolithic = false;
enableDaemon = true;
withKDE = false;
};
in {
options.services.depot.quassel = with lib; {
enable = mkEnableOption "Quassel IRC daemon";
acmeHost = mkOption {
description = "ACME host to use for the Quassel TLS certificate";
type = lib.types.str;
};
bindAddresses = mkOption {
description = "Addresses Quassel will bind to/listen on";
default = [ "127.0.0.1" ];
};
logLevel = mkOption {
description = "Log level for Quassel Core";
default = "Info";
type = lib.types.enum [
"Debug"
"Info"
"Warning"
"Error"
];
};
port = mkOption {
default = 6698;
description = ''
The port number the Quassel daemon will be listening to.
'';
};
};
config = with lib; mkIf cfg.enable {
systemd.services.quassel = {
description = "Quassel IRC daemon";
wantedBy = [ "multi-user.target" ];
script = concatStringsSep " " [
"${quasselDaemon}/bin/quasselcore"
"--listen=${concatStringsSep "," cfg.bindAddresses}"
"--port=${toString cfg.port}"
"--configdir=/var/lib/quassel"
"--require-ssl"
"--ssl-cert=/var/lib/acme/${cfg.acmeHost}/full.pem"
"--loglevel=${cfg.logLevel}"
];
serviceConfig = {
Restart = "always";
User = "quassel";
Group = "quassel";
StateDirectory = "quassel";
};
};
users = {
users.quassel = {
isNormalUser = false;
group = "quassel";
};
groups.quassel = {};
};
};
}

53
ops/modules/smtprelay.nix Normal file
View file

@ -0,0 +1,53 @@
# NixOS module for configuring the simple SMTP relay.
{ depot, pkgs, config, lib, ... }:
let
inherit (builtins) attrValues mapAttrs;
inherit (lib)
concatStringsSep
mkEnableOption
mkIf
mkOption
types
;
cfg = config.services.depot.smtprelay;
description = "Simple SMTP relay";
# Configuration values that are always overridden. In particular,
# `config` is specified to always load $StateDirectory/secure.config
# (so that passwords can be loaded from there) and logging is pinned
# to stdout for journald compatibility.
overrideArgs = {
logfile = "";
config = "/var/lib/smtprelay/secure.config";
};
# Creates the command line argument string for the service.
prepareArgs = args:
concatStringsSep " "
(attrValues (mapAttrs (key: value: "-${key} '${toString value}'")
(args // overrideArgs)));
in {
options.services.depot.smtprelay = {
enable = mkEnableOption description;
args = mkOption {
type = types.attrsOf types.str;
description = "Key value pairs for command line arguments";
};
};
config = mkIf cfg.enable {
systemd.services.smtprelay = {
inherit description;
script = "${depot.third_party.smtprelay}/bin/smtprelay ${prepareArgs cfg.args}";
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Restart = "always";
StateDirectory = "smtprelay";
DynamicUser = true;
};
};
};
}

View file

@ -0,0 +1,51 @@
# Run sourcegraph, including its entire machinery, in a container.
# Running it outside of a container is a futile endeavour for now.
{ depot, config, pkgs, lib, ... }:
let
cfg = config.services.depot.sourcegraph;
in {
options.services.depot.sourcegraph = with lib; {
enable = mkEnableOption "SourceGraph code search engine";
port = mkOption {
description = "Port on which SourceGraph should listen";
type = types.int;
default = 3463;
};
cheddarPort = mkOption {
description = "Port on which cheddar should listen";
type = types.int;
default = 4238;
};
};
config = lib.mkIf cfg.enable {
# Run a cheddar syntax highlighting server
systemd.services.cheddar-server = {
wantedBy = [ "multi-user.target" ];
script = "${depot.tools.cheddar}/bin/cheddar --listen 0.0.0.0:${toString cfg.cheddarPort} --sourcegraph-server";
serviceConfig = {
DynamicUser = true;
Restart = "always";
};
};
virtualisation.oci-containers.containers.sourcegraph = {
image = "sourcegraph/server:3.26.0";
ports = [
"127.0.0.1:${toString cfg.port}:7080"
];
volumes = [
"/var/lib/sourcegraph/etc:/etc/sourcegraph"
"/var/lib/sourcegraph/data:/var/opt/sourcegraph"
];
environment.SRC_SYNTECT_SERVER = "http://172.17.0.1:${toString cfg.cheddarPort}";
};
};
}

View file

@ -0,0 +1,48 @@
# Configuration for the TVL buildkite agents.
{ config, depot, pkgs, lib, ... }:
let
cfg = config.services.depot.buildkite;
agents = lib.range 1 cfg.agentCount;
description = "Buildkite agents for TVL";
# All Buildkite hooks are actually besadii, but it's being invoked
# with different names.
buildkiteHooks = pkgs.runCommandNoCC "buildkite-hooks" {} ''
mkdir -p $out/bin
ln -s ${depot.ops.besadii}/bin/besadii $out/bin/post-command
'';
in {
options.services.depot.buildkite = {
enable = lib.mkEnableOption description;
agentCount = lib.mkOption {
type = lib.types.int;
description = "Number of Buildkite agents to launch";
};
};
config = lib.mkIf cfg.enable {
# Run the Buildkite agents using the default upstream module.
services.buildkite-agents = builtins.listToAttrs (map (n: rec {
name = "whitby-${toString n}";
value = {
inherit name;
enable = true;
tokenPath = "/etc/secrets/buildkite-agent-token";
hooks.post-command = "${buildkiteHooks}/bin/post-command";
};
}) agents);
# Set up a group for all Buildkite agent users
users = {
groups.buildkite-agents = {};
users = builtins.listToAttrs (map (n: rec {
name = "buildkite-agent-whitby-${toString n}";
value = {
group = lib.mkForce "buildkite-agents";
extraGroups = [ name ];
};
}) agents);
};
};
}

View file

@ -0,0 +1,89 @@
# Configures an OpenLDAP instance for TVL
#
# TODO(tazjin): Configure ldaps://
{ depot, lib, pkgs, ... }:
with depot.nix.yants;
let
user = struct {
username = string;
email = string;
password = string;
displayName = option string;
};
toLdif = defun [ user string ] (u: ''
dn: cn=${u.username},ou=users,dc=tvl,dc=fyi
objectClass: organizationalPerson
objectClass: inetOrgPerson
sn: ${u.username}
cn: ${u.username}
displayName: ${u.displayName or u.username}
mail: ${u.email}
userPassword: ${u.password}
'');
inherit (depot.ops) users;
in {
# Use our patched OpenLDAP derivation which enables stronger password hashing.
#
# Unfortunately the module for OpenLDAP has no package option, so we
# need to override it system-wide. Be aware that this triggers a
# *large* number of rebuilds of packages such as GPG and Python.
nixpkgs.overlays = [
(_: _: {
inherit (depot.third_party) openldap;
})
];
services.openldap = {
enable = true;
dataDir = "/var/lib/openldap";
database = "mdb";
suffix = "dc=tvl,dc=fyi";
rootdn = "cn=admin,dc=tvl,dc=fyi";
rootpw = "{ARGON2}$argon2id$v=19$m=65536,t=2,p=1$OfcgkOQ96VQ3aJj7NfA9vQ$oS6HQOkYl/bUYg4SejpltQYy7kvqx/RUxvoR4zo1vXU";
settings.children = {
"olcDatabase={1}mdb".attrs = {
objectClass = [ "olcDatabaseConfig" "olcMdbConfig" ];
olcDatabase = "{1}mdb";
olcSuffix = "dc=tvl,dc=fyi";
olcAccess = "to * by * read";
};
"cn=module{0}".attrs = {
objectClass = "olcModuleList";
olcModuleLoad = "pw-argon2";
};
};
# Contents are immutable at runtime, and adding user accounts etc.
# is done statically in the LDIF-formatted contents in this folder.
declarativeContents."dc=tvl,dc=fyi" = ''
dn: dc=tvl,dc=fyi
dc: tvl
o: TVL LDAP server
description: Root entry for tvl.fyi
objectClass: top
objectClass: dcObject
objectClass: organization
dn: ou=users,dc=tvl,dc=fyi
ou: users
description: All users in TVL
objectClass: top
objectClass: organizationalUnit
dn: ou=groups,dc=tvl,dc=fyi
ou: groups
description: All groups in TVL
objectClass: top
objectClass: organizationalUnit
${lib.concatStringsSep "\n" (map toLdif users)}
'';
};
}

View file

@ -0,0 +1,24 @@
# Configures an Apereo CAS instance for TVL SSO
{ depot, ... }:
let
inherit (depot.third_party) apereo-cas;
in {
config = {
environment.systemPackages = [ apereo-cas ];
systemd.services.apereo-cas = {
description = "Apereo CAS Single Sign On server";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
serviceConfig = {
User = "apereo-cas";
Group = "apereo-cas";
ExecStart = "${apereo-cas}/bin/cas";
EnvironmentFile = "/etc/cas/secrets";
Restart = "always";
};
};
users.users.apereo-cas = {};
users.groups.apereo-cas = {};
};
}

View file

@ -0,0 +1,12 @@
{ config, lib, pkgs, ... }:
{
boot = {
extraModulePackages = [ config.boot.kernelPackages.v4l2loopback ];
kernelModules = [ "v4l2loopback" ];
extraModprobeConfig = ''
options v4l2loopback exclusive_caps=1
'';
};
}

View file

@ -0,0 +1,32 @@
{ config, ... }:
{
imports = [
./base.nix
];
config = {
services.nginx.virtualHosts."b-shortlink" = {
serverName = "b";
extraConfig = "return 302 https://b.tvl.fyi$request_uri;";
};
services.nginx.virtualHosts."b.tvl.fyi" = {
serverName = "b.tvl.fyi";
serverAliases = [ "b.tvl.su" ];
enableACME = true;
forceSSL = true;
extraConfig = ''
# Forward short links to issues to the issue itself (b/32)
location ~ ^/(\d+)$ {
return 302 https://b.tvl.fyi/issues$request_uri;
}
location / {
proxy_pass http://localhost:${toString config.services.depot.panettone.port};
}
'';
};
};
}

36
ops/modules/www/base.nix Normal file
View file

@ -0,0 +1,36 @@
{ config, pkgs, ... }:
{
config = {
services.nginx = {
enable = true;
enableReload = true;
recommendedTlsSettings = true;
recommendedGzipSettings = true;
recommendedProxySettings = true;
};
# 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.
#
# TODO(tazjin): Find a link to the upstream issue and see if
# they've sorted it after ~20.09
systemd.services.fix-nginx = {
script = "${pkgs.coreutils}/bin/chown -f -R nginx: /var/spool/nginx /var/cache/nginx";
serviceConfig = {
User = "root";
Type = "oneshot";
};
};
systemd.timers.fix-nginx = {
wantedBy = [ "multi-user.target" ];
timerConfig = {
OnCalendar = "minutely";
};
};
};
}

View file

@ -0,0 +1,26 @@
{ config, ... }:
{
imports = [
./base.nix
];
config = {
services.nginx.virtualHosts."cache.tvl.su" = {
serverName = "cache.tvl.su";
serverAliases = [ "cache.tvl.fyi" ];
enableACME = true;
forceSSL = true;
extraConfig = ''
location = /cache-key.pub {
alias /etc/secrets/nix-cache-key.pub;
}
location / {
proxy_pass http://localhost:${toString config.services.nix-serve.port};
}
'';
};
};
}

View file

@ -0,0 +1,30 @@
{ config, ... }:
{
imports = [
./base.nix
];
config = {
services.nginx.virtualHosts."cl-shortlink" = {
serverName = "cl";
extraConfig = "return 302 https://cl.tvl.fyi$request_uri;";
};
services.nginx.virtualHosts.gerrit = {
serverName = "cl.tvl.fyi";
serverAliases = [ "cl.tvl.su" ];
enableACME = true;
forceSSL = true;
extraConfig = ''
location / {
proxy_pass http://localhost:4778;
proxy_set_header X-Forwarded-For $remote_addr;
# The :443 suffix is a workaround for https://b.tvl.fyi/issues/88.
proxy_set_header Host $host:443;
}
'';
};
};
}

View file

@ -0,0 +1,35 @@
{ depot, ... }:
{
imports = [
./base.nix
];
config = {
services.nginx.virtualHosts.cgit = {
serverName = "code.tvl.fyi";
serverAliases = [ "code.tvl.su" ];
enableACME = true;
forceSSL = true;
extraConfig = ''
# Serve the rendered Tvix component SVG.
#
# TODO(tazjin): Implement a way of serving this dynamically
location = /about/tvix/docs/component-flow.svg {
alias ${depot.tvix.docs.svg}/component-flow.svg;
}
# Static assets must always hit the root.
location ~ ^/(favicon\.ico|cgit\.(css|png))$ {
proxy_pass http://localhost:2448;
}
# Everything else hits the depot directly.
location / {
proxy_pass http://localhost:2448/cgit.cgi/depot/;
}
'';
};
};
}

View file

@ -0,0 +1,31 @@
{ config, ... }:
{
imports = [
./base.nix
];
config = {
services.nginx.virtualHosts."cs.tvl.fyi" = {
serverName = "cs.tvl.fyi";
serverAliases = [ "cs.tvl.su" ];
enableACME = true;
forceSSL = true;
extraConfig = ''
location = / {
return 301 https://cs.tvl.fyi/depot;
}
location / {
proxy_set_header X-Sg-Auth "Anonymous";
proxy_pass http://localhost:${toString config.services.depot.sourcegraph.port};
}
location /users/Anonymous/settings {
return 301 https://cs.tvl.fyi;
}
'';
};
};
}

View file

@ -0,0 +1,24 @@
{ ... }:
{
imports = [
./base.nix
];
config = {
services.nginx.virtualHosts."login.tvl.fyi" = {
serverName = "login.tvl.fyi";
enableACME = true;
forceSSL = true;
extraConfig = ''
location / {
proxy_pass http://localhost:8443;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Host $host;
}
'';
};
};
}

View file

@ -0,0 +1,40 @@
# serve tazjin's website & blog
{ depot, config, lib, pkgs, ... }:
{
imports = [
./base.nix
];
config = {
services.nginx.virtualHosts."tazj.in" = {
enableACME = true;
forceSSL = true;
root = depot.users.tazjin.homepage;
extraConfig = ''
${depot.users.tazjin.blog.oldRedirects}
location /blog/ {
alias ${depot.users.tazjin.blog.rendered}/;
if ($request_uri ~ ^/(.*)\.html$) {
return 302 /$1;
}
try_files $uri $uri.html $uri/ =404;
}
# Temporary place for serving static files.
location /blobs/ {
alias /var/lib/tazjins-blobs/;
}
'';
};
services.nginx.virtualHosts."git.tazj.in" = {
enableACME = true;
forceSSL = true;
extraConfig = "return 301 https://code.tvl.fyi$request_uri;";
};
};
}

View file

@ -0,0 +1,25 @@
{ depot, ... }:
{
imports = [
./base.nix
];
config = {
services.nginx.virtualHosts."todo.tvl.fyi" = {
serverName = "todo.tvl.fyi";
serverAliases = [ "todo.tvl.su" ];
root = depot.web.todolist;
enableACME = true;
forceSSL = true;
extraConfig = ''
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
location ~* \.(webp|woff2)$ {
add_header Cache-Control "public, max-age=31536000";
}
'';
};
};
}

View file

@ -0,0 +1,30 @@
{ depot, ... }:
{
imports = [
./base.nix
];
config = {
services.nginx.virtualHosts."tvl.fyi" = {
serverName = "tvl.fyi";
root = depot.web.tvl;
enableACME = true;
forceSSL = true;
extraConfig = ''
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
rewrite ^/builds/?$ https://buildkite.com/tvl/depot/ last;
rewrite ^/monorepo-doc/?$ https://docs.google.com/document/d/1nnyByXcH0F6GOmEezNOUa2RFelpeRpDToBLYD_CtjWE/edit?usp=sharing last;
rewrite ^/irc/?$ ircs://chat.freenode.net:6697/##tvl last;
location ~* \.(webp|woff2)$ {
add_header Cache-Control "public, max-age=31536000";
}
'';
};
};
}

View file

@ -0,0 +1,15 @@
{ depot, lib, pkgs, ... }:
{
imports = [
./base.nix
];
config = {
services.nginx.virtualHosts."wigglydonke.rs" = {
enableACME = true;
forceSSL = true;
root = "${depot.depotPath}/users/glittershark/wigglydonke.rs";
};
};
}