maxwell/configuration.nix

490 lines
12 KiB
Nix

{ config, lib, pkgs, ... }:
{
imports = [
./hardware.nix
./variables.nix
./packages.nix
./jobs.nix
./matrix.nix
./email.nix
./magnetico.nix
./nameserver.nix
./custom
./secrets
];
### State
# Stateful things to do before updating:
# 1. Postgres migration
# 2. Matrix Synapse migration
system.stateVersion = "21.05";
boot.kernelPackages = pkgs.linuxPackages_latest;
boot.tmpOnTmpfs = true;
boot.kernel.sysctl = {
# avoid OOM hangs
"vm.admin_reserve_kbytes" = 262144;
};
time.timeZone = "Europe/Rome";
i18n.defaultLocale = "en_US.UTF-8";
systemd.enableEmergencyMode = false;
networking = {
hostName = "maxwell";
firewall.allowedTCPPorts = [
443 80 # reverse proxy
993 # imaps server
25 465 # smtp(s) server
8080 # hubot
3478 # turn server
5349 # turn server
3551 # apcups
18080 # monero p2p
22000 # syncthing transfer
64738 # mumble server
];
firewall.allowedUDPPorts = [
53 # powerdns
1194 # dnscrypt
3478 # turn server
21027 # syncthing discovery
64738 # mumble server
];
firewall.allowedUDPPortRanges = [
{ from=49152; to=49999; } # turn relay
];
usePredictableInterfaceNames = false;
nameservers = [ "127.0.0.1" ];
hosts."127.0.0.1" = [ config.var.hostname ];
};
# Only declarative users and no password logins
users.mutableUsers = false;
users.users ={
# Only needed for local (read emergency) shell access
root.passwordFile = config.secrets.passwords.root;
# Admin
rnhmjoj = {
uid = 1000;
extraGroups = [ "wheel" ];
isNormalUser = true;
shell = pkgs.fish;
openssh.authorizedKeys.keyFiles = [ config.secrets.publicKeys.rnhmjoj ];
};
# Admin
fazo = {
extraGroups = [ "wheel" ];
isNormalUser = true;
openssh.authorizedKeys.keyFiles = [ config.secrets.publicKeys.fazo];
};
# User
meme = {
isNormalUser = true;
shell = pkgs.fish;
openssh.authorizedKeys.keyFiles = [ config.secrets.publicKeys.meme ];
};
# Hosts the cactalogo
giu = {
isNormalUser = true;
shell = pkgs.fish;
openssh.authorizedKeys.keyFiles = with config.secrets.publicKeys;
[ rnhmjoj giu ];
};
# Needed to perform remote builds on Maxwell
builder = {
description = "Remote Nix builds user";
isNormalUser = true;
openssh.authorizedKeys.keyFiles = [ config.secrets.publicKeys.rnhmjoj-builder ];
};
# Use "git" instead of the default name to make
# SSH operation handier, example:
# git clone git@maxwell:user/repo
git = {
group = "git";
description = "Git server user";
home = "/var/lib/gitea";
isSystemUser = true;
useDefaultShell = true;
};
};
users.groups.git = { };
# Generate Diffie-Hellman parameters
# for TLS applications, like nginx.
security.dhparams = {
enable = true;
params.nginx = 2048; # prime modulus bits
};
security.sudo = {
enable = true;
# Users don't have a password
wheelNeedsPassword = false;
};
security.pam.loginLimits = [
# Limit user process to stop fork bombs
{ domain = "@users";
type = "hard";
item = "nproc";
value = "400";
}
# Disable core dumping
{ domain = "*";
type = "soft";
item = "core";
value = "0";
}
];
### ACME certificates
security.acme = with config.var; {
email = "rnhmjoj@inventati.org";
acceptTerms = true;
certs."${hostname}" = {
group = "maxwell-ydns-eu";
};
certs."riot.${hostname}" = {
group = "riot-maxwell-ydns-eu";
};
};
# Allow read access to ACME certificate
# to specific (service) users.
users.groups."maxwell-ydns-eu".members = [ "murmur" "turnserver" "nginx" ];
users.groups."riot-maxwell-ydns-eu".members = [ "nginx" ];
services.openssh = {
enable = true;
permitRootLogin = "no";
passwordAuthentication = false;
challengeResponseAuthentication = false;
};
# Traceroute easter egg
services.fakeroute = {
enable = true;
route = [
"89.111.117.32" "99.97.110.110" "111.116.32.104" "105.100.101.46"
"32.73.32.115" "101.101.32.121" "111.117.46.32" "84.104.101.114"
"101.32.105.115" "32.110.111.32" "108.105.102.101" "32.105.110.32"
"116.104.101.32" "118.111.105.100" "46.32.79.110" "108.121.32.100"
"101.97.116.104" ];
};
### Mumble server
services.murmur = {
enable = true;
registerHostname = config.var.hostname;
registerName = "Maxwell Mumble";
registerPassword = "$REG_PASSWORD";
password = "$JOIN_PASSWORD";
users = 10;
environmentFile = config.secrets.environments.murmur;
sslCert = "/var/lib/acme/${config.var.hostname}/fullchain.pem";
sslKey = "/var/lib/acme/${config.var.hostname}/key.pem";
};
### Syncthing node
services.syncthing = {
enable = true;
};
### Monero node with local RPC
services.monero = {
enable = true;
mining = {
enable = false;
threads = 4;
address = config.secrets.monero.address;
};
limits = {
upload = 250;
download = 625;
threads = 4;
};
rpc.user = config.secrets.monero.user;
rpc.password = config.secrets.monero.password;
};
### URL shortner
services.breve = with config.secrets; {
enable = true;
hostname = "localhost";
baseUrl = "https://brve.bit/";
port = 2000;
certificate = certs.breve.crt;
key = certs.breve.key;
};
### Git server
services.gitea = with config.var; {
enable = true;
domain = hostname;
appName = "Maxwell git server";
rootUrl = "https://${hostname}/git/";
user = "git";
database.user = "git";
log.level = "Error";
cookieSecure = true;
disableRegistration = false;
settings = {
security.LOGIN_REMEMBER_DAYS = 365;
attachment.MAX_SIZE = 10; # file upload size (MB)
service.DEFAULT_ALLOW_CREATE_ORGANIZATION = false;
service.EMAIL_DOMAIN_BLOCKLIST = "gmail.com";
};
};
### Searx instance
services.searx = {
enable = true;
environmentFile = config.secrets.environments.searx;
# Use nginx+uWSGI
runInUwsgi = true;
uwsgiConfig = {
disable-logging = true;
# serve using the uwsgi protocol
socket = "/run/searx/uwsgi.sock";
chmod-socket = "660";
# use /searx as url "mountpoint"
mount = "/srx=searx.webapp:application";
module = "";
manage-script-name = true;
# caching
cache2 = lib.concatStringsSep ","
[ "name=searxcache"
"items=2000"
"blocks=2000"
"blocksize=4096"
"bitmap=1"
];
};
settings =
{ general.instance_name = "searxwell";
server.base_url = "https://${config.var.hostname}/";
server.secret_key = "@SEARX_SECRET@";
# Replace DOI links with Sci-Hub
default_doi_resolver = "sci-hub.st";
## Use authenticated APIs for some services
engines = [
{ name = "wolframalpha";
api_key = "@WOLFRAM_API_KEY@";
}
{ name = "youtube";
api_key = "@YOUTUBE_API_KEY@";
}
];
};
};
# Allow nginx access to the uwsgi socket
users.groups."searx".members = [ "nginx" ];
### Reverse Proxy
services.nginx =
with config.var;
let
disableLog = ''
error_log syslog:server=unix:/dev/log crit;
access_log off;
'';
enableSTS = ''
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
'';
in
rec {
enable = true;
enableReload = true;
recommendedTlsSettings = true;
recommendedGzipSettings = true;
recommendedProxySettings = true;
# Large enough to allow file uploads.
clientMaxBodySize = "1000M";
sslDhparam = "${config.security.dhparams.path}/nginx.pem";
# Maxwell
virtualHosts."${hostname}" = {
enableACME = true;
forceSSL = true;
default = true;
extraConfig = disableLog + enableSTS;
# Returns IP address
locations."/ip".extraConfig = ''
default_type text/plain;
return 200 $remote_addr;
'';
# Asjon code coverage reports
locations."/asjon/report/" = {
index = "index.html";
alias = "/run/nginx/static/asjon/";
};
# Searx instance
locations."/srx/".extraConfig =
''
include ${pkgs.nginx}/conf/uwsgi_params;
uwsgi_pass unix:/run/searx/uwsgi.sock;
'';
locations."/srx/static/".alias = "${pkgs.searx}/share/static/";
# Git server
locations."/git/".proxyPass = "http://localhost:3000/";
# Syncthing
locations."/sync/".proxyPass = "http://localhost:8384/";
# User static files
locations."/~rnhmjoj/" = {
alias = "/run/nginx/static/rnhmjoj/";
extraConfig = "charset UTF-8;";
};
locations."/~giu/" = {
alias = "/run/nginx/static/giu/";
extraConfig = "charset UTF-8;";
};
};
# Breve URL shortner
virtualHosts."brve.bit" = with config.secrets; {
forceSSL = true;
sslCertificate = certs.breve.crt;
sslCertificateKey = certs.breve.key;
locations."/" = {
proxyPass = "https://localhost:2000";
extraConfig = "proxy_ssl_verify off;";
};
extraConfig = disableLog;
};
# The Cactalogue
virtualHosts."cacta.bit" = {
root = "/run/nginx/static/cactalogue";
extraConfig = disableLog;
};
virtualHosts."cacta.eurofusion.eu" = virtualHosts."cacta.bit";
};
# Bind mount directories for Nginx
# This avoids giving nginx traversal permission
systemd.mounts =
let bindNginx = from: to:
{ what = from;
where = "/run/nginx/static/" + to;
type = "none";
options = "bind";
wantedBy = [ "nginx.service" ];
};
in [ (bindNginx "/home/rnhmjoj/www" "rnhmjoj")
(bindNginx "/home/giu/www" "giu")
(bindNginx "/home/giu/cactalogue" "cactalogue")
(bindNginx "/var/lib/asjon/tree/report" "asjon")
];
### Misc. services
services.asjon.enable = true;
# Needed for the Asjon memory module
services.redis.enable = true;
### Program configuration
programs = {
fish.enable = true;
mosh.enable = true;
tmux = {
enable = true;
newSession = true;
baseIndex = 1;
escapeTime = 0;
historyLimit = 4096;
keyMode = "vi";
terminal = "screen-256color";
customPaneNavigationAndResize = true;
extraConfig = ''
set -g mouse on
# bindings
bind | split-window -h
bind - split-window -v
bind : command-prompt
bind -n C-k clear-history
# colors
set -g pane-border-style fg=brightblack
set -g pane-active-border fg=green
set -g message-style fg=white,bg=black
set -g status-style fg=brightblue,bg=black
setw -g mode-style fg=black,bg=cyan
# status line
set -g status on
set -g status-justify left
set -g status-left ""
set -g status-right-length 60
set -g status-right '#[fg=yellow]#(cut -d\ -f 1-3 /proc/loadavg) | #[fg=brightgreen]%a %H:%M'
setw -g window-status-format "#[fg=black#,bg=brightblack] #I #[fg=blue#,bg=black] #W "
setw -g window-status-current-format "#[fg=white#,bg=cyan] #I #[fg=black#,bg=brightblack] #W "
'';
};
};
nix = {
useSandbox = true;
# Can connect to the Nix daemon
# and upload/run code as root!
trustedUsers = [ "builder" "rnhmjoj" ];
# Use at most half the cores
buildCores = 8;
extraOptions = ''
# Always keep at least 256MiB free
min-free = 268435456
'';
};
environment.variables = {
PATH = "$HOME/.local/bin/:$PATH";
XDG_CONFIG_HOME = "$HOME/.config";
XDG_DATA_HOME = "$HOME/.local/share";
XDG_CACHE_HOME = "$HOME/.cache";
NIX_PROFILE = "$XDG_CONFIG_HOME/nix/profile";
};
# Needed to make the mosh server survive a
# user logout: systemd kills everything by default
environment.shellAliases = {
mosh-server = "systemd-run --user --scope mosh-server";
};
}