maxwell/configuration.nix

514 lines
13 KiB
Nix

{ config, lib, pkgs, ... }:
{
imports = [
./hardware.nix
./variables.nix
./packages.nix
./jobs.nix
./matrix.nix
./email.nix
./magnetico.nix
./nameserver.nix
./custom
./secrets
./fish.nix
./neovim.nix
];
### State
# Stateful things to do before updating:
# 1. Postgres migration (https://www.postgresql.org/docs/current/upgrading.html)
# 2. Matrix Synapse migration (https://matrix-org.github.io/synapse/latest/upgrade.html)
system.stateVersion = "23.05";
boot.kernelPackages = pkgs.linuxPackages_latest;
boot.tmp.useTmpfs = 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;
systemd.oomd.enable = false;
networking = {
hostName = "maxwell";
firewall.allowedTCPPorts = [
443 80 # reverse proxy
993 # imaps server
25 465 # smtp(s) server
3551 # apcups
18080 # monero p2p
22000 # syncthing transfer
64738 # mumble server
];
firewall.allowedUDPPorts = [
443 # dnscrypt
53 # powerdns
21027 # syncthing discovery
64738 # mumble server
];
usePredictableInterfaceNames = false;
nameservers = [ "127.0.0.1" ];
# ensure hostname work without DNS
hosts = with config.var;
{ ${ipv4LanAddress} = [ hostname ];
${ipv6Address} = [ hostname ];
};
};
# Only declarative users and no password logins
users.mutableUsers = false;
users.users ={
# Only needed for local (read emergency) shell access
root.hashedPasswordFile = 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 = with config.secrets.publicKeys; [
rnhmjoj-builder
giu-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; {
defaults.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" "nginx" ];
users.groups."riot-maxwell-ydns-eu".members = [ "nginx" ];
services.openssh = {
enable = true;
settings.PermitRootLogin = "no";
settings.PasswordAuthentication = false;
settings.KbdInteractiveAuthentication = 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;
appName = "Maxwell git server";
user = "git";
database.user = "git";
settings = {
server.ROOT_URL = "https://${hostname}/git/";
server.domain = hostname;
session.COOKIE_SECURE = true;
log.LEVEL = "Error";
service.DISABLE_REGISTRATION = false;
# increase cookie expiration time
security.LOGIN_REMEMBER_DAYS = 365;
# file upload size (MB)
attachment.MAX_SIZE = 10;
# new users can only create PR/issues
service.DEFAULT_ALLOW_CREATE_ORGANIZATION = false;
repository.MAX_CREATION_LIMIT = 0;
# somewhat limit spam
service.EMAIL_DOMAIN_BLOCKLIST = "gmail.com";
# allow the notify webhook to use matrix
webhook.ALLOWED_HOST_LIST = "maxwell.ydns.eu";
};
};
### Searx instance
services.searx = {
enable = true;
environmentFile = config.secrets.environments.searx;
package = pkgs.searxng;
# 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;
'';
listenTLS = [ { addr = "localhost"; port = 443; ssl = true; } ];
listenPlain = [ { addr = "[::]"; port = 80; } { addr = "0.0.0.0"; port = 80; } ];
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;
listen = listenTLS ++ listenPlain;
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 = "${config.services.searx.package}/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;
listen = listenTLS ++ listenPlain;
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";
listen = listenPlain;
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.servers."asjon" =
{ enable = true;
user = "asjon";
};
# Emergency SSH access via tor
services.tor =
{ enable = true;
client.enable = false;
relay.onionServices.emergency-access.map = [ 22 ];
};
### Program configuration
programs = {
fuse.userAllowOther = true;
fish.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.settings = {
# Can connect to the Nix daemon
# and upload/run code as root!
trusted-users = [ "builder" "rnhmjoj" ];
# Use at most half the cores
cores = 8;
max-jobs = 16;
# Always keep at least 256MiB free
min-free = 268435456;
};
environment.sessionVariables = {
PATH = [ "$HOME/bin" ];
XDG_CONFIG_HOME = "$HOME/etc";
XDG_DATA_HOME = "$HOME/var/lib";
XDG_CACHE_HOME = "$HOME/var/cache";
SYSTEMD_COLORS = "16";
};
}