add server config
This commit is contained in:
parent
8655459e46
commit
33b4fe95c2
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1 +1,2 @@
|
|||
private.nix
|
||||
private/
|
||||
|
|
|
@ -1,5 +1,37 @@
|
|||
{
|
||||
"nodes": {
|
||||
"blobs": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1604995301,
|
||||
"narHash": "sha256-wcLzgLec6SGJA8fx1OEN1yV/Py5b+U5iyYpksUY/yLw=",
|
||||
"owner": "simple-nixos-mailserver",
|
||||
"repo": "blobs",
|
||||
"rev": "2cccdf1ca48316f2cfd1c9a0017e8de5a7156265",
|
||||
"type": "gitlab"
|
||||
},
|
||||
"original": {
|
||||
"owner": "simple-nixos-mailserver",
|
||||
"repo": "blobs",
|
||||
"type": "gitlab"
|
||||
}
|
||||
},
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1668681692,
|
||||
"narHash": "sha256-Ht91NGdewz8IQLtWZ9LCeNXMSXHUss+9COoqu6JLmXU=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "009399224d5e398d03b22badca40a37ac85412a1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
|
@ -83,6 +115,32 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixos-mailserver": {
|
||||
"inputs": {
|
||||
"blobs": "blobs",
|
||||
"flake-compat": "flake-compat",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-22_11": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"utils": "utils"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1671738303,
|
||||
"narHash": "sha256-PRgqtaWf2kMSYqVmcnmhTh+UsC0RmvXRTr+EOw5VZUA=",
|
||||
"owner": "simple-nixos-mailserver",
|
||||
"repo": "nixos-mailserver",
|
||||
"rev": "6d0d9fb966cc565a3df74d3b686f924c7615118c",
|
||||
"type": "gitlab"
|
||||
},
|
||||
"original": {
|
||||
"owner": "simple-nixos-mailserver",
|
||||
"repo": "nixos-mailserver",
|
||||
"type": "gitlab"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1683408522,
|
||||
|
@ -104,9 +162,10 @@
|
|||
"impermanence": "impermanence",
|
||||
"nix-gaming": "nix-gaming",
|
||||
"nixos-hardware": "nixos-hardware",
|
||||
"nixos-mailserver": "nixos-mailserver",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rust-overlay": "rust-overlay",
|
||||
"utils": "utils"
|
||||
"utils": "utils_2"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
|
@ -117,11 +176,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1683685144,
|
||||
"narHash": "sha256-HZBieMZj9Rp+WtbGiK5JaUciZwJ/2YX6LRe5z8jkfow=",
|
||||
"lastModified": 1683708507,
|
||||
"narHash": "sha256-i5zgWcuyZcNBnlrzVjhpAFQdJWr4OyhvQ1owAEHFFKw=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "74e44edb87aeed50798f5b81795ebad250d4a0c0",
|
||||
"rev": "ed55dc022aa23ed3c42f383cf1782290b3b939d5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -146,6 +205,21 @@
|
|||
}
|
||||
},
|
||||
"utils": {
|
||||
"locked": {
|
||||
"lastModified": 1605370193,
|
||||
"narHash": "sha256-YyMTf3URDL/otKdKgtoMChu4vfVL3vCMkRqpGifhUn0=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "5021eac20303a61fafe17224c087f5519baed54d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"utils_2": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_2"
|
||||
},
|
||||
|
|
|
@ -15,14 +15,25 @@
|
|||
url = "github:fufexan/nix-gaming";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
nixos-mailserver = {
|
||||
url = "gitlab:simple-nixos-mailserver/nixos-mailserver";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.nixpkgs-22_11.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
|
||||
outputs = inputs@{ self, nixpkgs, utils, nixos-hardware, impermanence, nix-gaming, ... }:
|
||||
outputs = inputs@{ self, nixpkgs, utils, nixos-hardware, impermanence, nix-gaming, nixos-mailserver, ... }:
|
||||
let
|
||||
hw = nixos-hardware.nixosModules;
|
||||
# IRL-related stuff I'd rather not put into git
|
||||
priv = if builtins.pathExists ./private.nix then (import ./private.nix) else { };
|
||||
getPriv = (hostname: with builtins; if hasAttr hostname priv then getAttr hostname priv else { });
|
||||
priv = if builtins.pathExists ./private/default.nix then (import ./private)
|
||||
else if builtins.pathExists ./private.nix then (import ./private.nix)
|
||||
else { };
|
||||
getPriv = hostname: with builtins; if hasAttr hostname priv then getAttr hostname priv else { };
|
||||
common = hostname: [ (getPriv hostname) impermanence.nixosModule ];
|
||||
extraArgs = {
|
||||
inherit nixpkgs;
|
||||
};
|
||||
in utils.lib.mkFlake {
|
||||
inherit self inputs;
|
||||
hostDefaults.modules = [
|
||||
|
@ -44,18 +55,24 @@
|
|||
system = "x86_64-linux";
|
||||
modules = [
|
||||
./hosts/nixmsi.nix
|
||||
impermanence.nixosModule
|
||||
nix-gaming.nixosModules.pipewireLowLatency
|
||||
hw.common-pc-ssd # enables fstrim
|
||||
hw.common-cpu-amd # microcode
|
||||
hw.common-cpu-amd-pstate # amd-pstate
|
||||
hw.common-gpu-amd # configures drivers
|
||||
hw.common-pc-laptop # enables tlp
|
||||
(getPriv "nixmsi")
|
||||
];
|
||||
extraArgs = {
|
||||
inherit nixpkgs;
|
||||
] ++ common "nixmsi";
|
||||
inherit extraArgs;
|
||||
};
|
||||
nixserver = {
|
||||
system = "x86_64-linux";
|
||||
modules = [
|
||||
./hosts/nixserver
|
||||
nixos-mailserver.nixosModules.default
|
||||
hw.common-pc-hdd
|
||||
hw.common-cpu-intel
|
||||
] ++ common "nixserver";
|
||||
inherit extraArgs;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -108,6 +108,11 @@ in {
|
|||
opengl.extraPackages = with pkgs; [ vulkan-validation-layers ];
|
||||
};
|
||||
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
settings.PasswordAuthentication = false;
|
||||
};
|
||||
|
||||
services.tlp.enable = true;
|
||||
services.tlp.settings = {
|
||||
USB_EXCLUDE_PHONE = 1;
|
||||
|
@ -207,7 +212,6 @@ in {
|
|||
++ (lib.range 1714 1764);
|
||||
networking.firewall.allowedUDPPorts = lib.range 1714 1764;
|
||||
|
||||
# networking.hostName = "nixmsi";
|
||||
networking.wireless.iwd.enable = true;
|
||||
#networking.networkmanager.enable = true;
|
||||
|
||||
|
@ -327,17 +331,6 @@ in {
|
|||
|
||||
documentation.dev.enable = true;
|
||||
|
||||
### RANDOM PATCHES ###
|
||||
|
||||
# I've had some weird issues with the entire system breaking after
|
||||
# suspend because of /dev/shm getting nuked, maybe this'll help
|
||||
services.logind.extraConfig = ''
|
||||
RemoveIPC=no
|
||||
'';
|
||||
|
||||
# why is this not part of base NixOS?
|
||||
systemd.tmpfiles.rules = [ "d /var/lib/systemd/pstore 0755 root root 14d" ];
|
||||
|
||||
# autologin once after boot
|
||||
# --skip-login means directly call login instead of first asking for username
|
||||
# (normally login asks for username too, but getty prefers to do it by itself for whatever reason)
|
||||
|
|
464
system/hosts/nixserver/default.nix
Normal file
464
system/hosts/nixserver/default.nix
Normal file
|
@ -0,0 +1,464 @@
|
|||
{ lib
|
||||
, pkgs
|
||||
, config
|
||||
, ... }:
|
||||
|
||||
let
|
||||
cfg = config.server;
|
||||
# TODO: move to lib
|
||||
quotePotentialIpV6 = addr:
|
||||
if lib.hasInfix ":" addr then "[${addr}]" else addr;
|
||||
|
||||
efiPart = "/dev/disk/by-uuid/3E2A-A5CB";
|
||||
rootUuid = "6aace237-9b48-4294-8e96-196759a5305b";
|
||||
rootPart = "/dev/disk/by-uuid/${rootUuid}";
|
||||
|
||||
hosted-domains =
|
||||
map
|
||||
(prefix: if prefix == null then cfg.domainName else "${prefix}.${cfg.domainName}")
|
||||
[
|
||||
null
|
||||
"dns"
|
||||
"mumble"
|
||||
"mail"
|
||||
"music"
|
||||
"www"
|
||||
"matrix"
|
||||
"search"
|
||||
"git"
|
||||
"cloud"
|
||||
"ns1"
|
||||
"ns2"
|
||||
];
|
||||
|
||||
in {
|
||||
imports = [
|
||||
./options.nix
|
||||
./matrix.nix
|
||||
./fdroid.nix
|
||||
./mumble.nix
|
||||
];
|
||||
|
||||
system.stateVersion = "22.11";
|
||||
|
||||
boot = {
|
||||
initrd = {
|
||||
availableKernelModules = [ "xhci_pci" "ehci_pci" "ahci" "usb_storage" "sd_mod" "sr_mod" "rtsx_pci_sdmmc" ];
|
||||
};
|
||||
kernelModules = [ "kvm-intel" ];
|
||||
kernelParams = [
|
||||
"consoleblank=60"
|
||||
];
|
||||
loader = {
|
||||
grub = {
|
||||
enable = true;
|
||||
device = "nodev";
|
||||
version = 2;
|
||||
efiSupport = true;
|
||||
efiInstallAsRemovable = true;
|
||||
gfxmodeEfi = "1920x1080";
|
||||
gfxmodeBios = "1920x1080";
|
||||
};
|
||||
efi.efiSysMountPoint = "/boot/efi";
|
||||
};
|
||||
};
|
||||
hardware.enableRedistributableFirmware = true;
|
||||
fileSystems = {
|
||||
"/" = { device = "none"; fsType = "tmpfs"; neededForBoot = true;
|
||||
options = [ "defaults" "size=2G" "mode=755" ]; };
|
||||
"/persist" =
|
||||
{ device = rootPart; fsType = "btrfs"; neededForBoot = true;
|
||||
options = [ "compress=zstd:15" ]; };
|
||||
"/boot" =
|
||||
{ device = rootPart; fsType = "btrfs"; neededForBoot = true;
|
||||
options = [ "compress=zstd:15" "subvol=boot" ]; };
|
||||
"/boot/efi" =
|
||||
{ device = efiPart; fsType = "vfat"; };
|
||||
};
|
||||
zramSwap.enable = true;
|
||||
swapDevices = [ ];
|
||||
impermanence = {
|
||||
enable = true;
|
||||
path = /persist;
|
||||
directories = [
|
||||
{ directory = /var/www/${cfg.domainName}; }
|
||||
{ directory = /var/lib/maubot; }
|
||||
{ directory = /var/lib/fdroid; }
|
||||
{ directory = config.mailserver.dkimKeyDirectory; }
|
||||
{ directory = config.mailserver.mailDirectory; }
|
||||
{ directory = /home/user; }
|
||||
{ directory = /root; }
|
||||
{ directory = /nix; }
|
||||
];
|
||||
};
|
||||
services.beesd = {
|
||||
filesystems.root = {
|
||||
spec = "UUID=${rootUuid}";
|
||||
hashTableSizeMB = 128;
|
||||
extraOptions = [ "--loadavg-target" "8.0" ];
|
||||
};
|
||||
};
|
||||
i18n.defaultLocale = lib.mkDefault "en_US.UTF-8";
|
||||
i18n.supportedLocales = lib.mkDefault [
|
||||
"C.UTF-8/UTF-8"
|
||||
"en_US.UTF-8/UTF-8"
|
||||
"en_DK.UTF-8/UTF-8"
|
||||
];
|
||||
# ISO-8601
|
||||
i18n.extraLocaleSettings.LC_TIME = "en_DK.UTF-8";
|
||||
console.font = "${pkgs.terminus_font}/share/consolefonts/ter-v24n.psf.gz";
|
||||
networking.useDHCP = true;
|
||||
networking.resolvconf.extraConfig = ''
|
||||
name_servers="127.0.0.1 ::1"
|
||||
'';
|
||||
networking.firewall = {
|
||||
enable = true;
|
||||
allowedTCPPorts = [
|
||||
# ssh
|
||||
22
|
||||
# dns
|
||||
53 853
|
||||
# http/s
|
||||
80 443
|
||||
];
|
||||
allowedUDPPorts = [
|
||||
# dns
|
||||
53 853
|
||||
# wireguard
|
||||
# 5553
|
||||
];
|
||||
};
|
||||
|
||||
# UNBOUND
|
||||
services.unbound = {
|
||||
enable = true;
|
||||
package = pkgs.unbound-with-systemd.override {
|
||||
withPythonModule = true;
|
||||
python = pkgs.python3.withPackages (pkgs: with pkgs; [ pydbus dnspython ]);
|
||||
};
|
||||
localControlSocketPath = "/run/unbound/unbound.ctl";
|
||||
resolveLocalQueries = false;
|
||||
settings = {
|
||||
server = {
|
||||
interface = [ "0.0.0.0" "::" ];
|
||||
access-control = [ "${cfg.lanCidrV4} allow" "${cfg.lanCidrV6} allow" ];
|
||||
aggressive-nsec = true;
|
||||
do-ip6 = true;
|
||||
module-config = ''"validator iterator"'';
|
||||
local-zone = [
|
||||
''"local." static''
|
||||
] ++ (lib.optionals (cfg.localIpV4 != null || cfg.localIpV6 != null) [
|
||||
''"${cfg.domainName}." typetransparent''
|
||||
]);
|
||||
local-data = builtins.concatLists (map (domain:
|
||||
lib.optionals (cfg.localIpV4 != null) [
|
||||
''"${domain}. A ${cfg.localIpV4}"''
|
||||
] ++ (lib.optionals (cfg.localIpV6 != null) [
|
||||
''"${domain}. A ${cfg.localIpV6}"''
|
||||
])) hosted-domains);
|
||||
};
|
||||
python.python-script = toString (pkgs.fetchurl {
|
||||
url = "https://raw.githubusercontent.com/NLnetLabs/unbound/a912786ca9e72dc1ccde98d5af7d23595640043b/pythonmod/examples/avahi-resolver.py";
|
||||
sha256 = "0r1iqjf08wrkpzvj6pql1jqa884hbbfy9ix5gxdrkrva09msiqgi";
|
||||
});
|
||||
remote-control.control-enable = true;
|
||||
};
|
||||
};
|
||||
systemd.services.unbound.environment.MDNS_ACCEPT_NAMES = "^.*\\.local\\.$";
|
||||
# just in case
|
||||
networking.hosts."127.0.0.1" = [ "localhost" ] ++ hosted-domains;
|
||||
|
||||
# CUPS
|
||||
services.printing = {
|
||||
enable = true;
|
||||
allowFrom = [ cfg.lanCidrV4 cfg.lanCidrV6 ];
|
||||
browsing = true;
|
||||
clientConf = ''
|
||||
ServerName ${cfg.domainName}
|
||||
'';
|
||||
defaultShared = true;
|
||||
drivers = [ pkgs.hplip ];
|
||||
startWhenNeeded = false;
|
||||
};
|
||||
|
||||
programs.fish.enable = true;
|
||||
users.defaultUserShell = pkgs.fish;
|
||||
users.users.user = {
|
||||
isNormalUser = true;
|
||||
extraGroups = [ "wheel" config.services.unbound.group ];
|
||||
};
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
comma
|
||||
git
|
||||
vim
|
||||
wget
|
||||
# rxvt-unicode-unwrapped.terminfo
|
||||
kitty.terminfo
|
||||
tmux
|
||||
];
|
||||
|
||||
services.postgresql.enable = true;
|
||||
services.postgresql.package = pkgs.postgresql_13;
|
||||
|
||||
nix = {
|
||||
settings = {
|
||||
allowed-users = [ "user" ];
|
||||
auto-optimise-store = true;
|
||||
};
|
||||
gc = {
|
||||
automatic = true;
|
||||
dates = "weekly";
|
||||
options = "--delete-older-than 30d";
|
||||
};
|
||||
package = pkgs.nixFlakes;
|
||||
extraOptions = ''
|
||||
experimental-features = nix-command flakes
|
||||
'';
|
||||
};
|
||||
systemd.services.nix-daemon.serviceConfig.LimitSTACKSoft = "infinity";
|
||||
|
||||
# SSH
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
settings.PermitRootLogin = "no";
|
||||
settings.PasswordAuthentication = false;
|
||||
listenAddresses = [{
|
||||
addr = "0.0.0.0";
|
||||
} {
|
||||
addr = "::";
|
||||
}];
|
||||
};
|
||||
services.fail2ban.enable = true;
|
||||
|
||||
# SEARXNG
|
||||
services.searx.enable = true;
|
||||
services.searx.package = pkgs.searxng.overrideAttrs (_: {
|
||||
src = pkgs.fetchFromGitHub {
|
||||
owner = "searxng";
|
||||
repo = "searxng";
|
||||
rev = "cb1c3741d7de1354b524589114617f183009f6a8";
|
||||
sha256 = "sha256-7erY5Bd1ZoTpAIDbhIupu64Xd1PQspaW6vBqu7knzNI=";
|
||||
};
|
||||
});
|
||||
services.searx.runInUwsgi = true;
|
||||
services.searx.uwsgiConfig = let inherit (config.services.searx) settings; in {
|
||||
socket = "${quotePotentialIpV6 settings.server.bind_address}:${toString settings.server.port}";
|
||||
};
|
||||
users.groups.searx.members = [ "nginx" ];
|
||||
services.searx.environmentFile = "/etc/nixos/private/searx.env";
|
||||
services.searx.settings = {
|
||||
use_default_settings = true;
|
||||
search = {
|
||||
safe_search = 0; # Filter results. 0: None, 1: Moderate, 2: Strict
|
||||
autocomplete = "duckduckgo"; # Existing autocomplete backends: "dbpedia", "duckduckgo", "google", "startpage", "swisscows", "qwant", "wikipedia" - leave blank to turn it off by default
|
||||
default_lang = ""; # Default search language - leave blank to detect from browser information or use codes from 'languages.py'
|
||||
};
|
||||
|
||||
server = {
|
||||
port = 8888;
|
||||
bind_address = "::1";
|
||||
secret_key = "@SEARX_SECRET_KEY@";
|
||||
base_url = "https://search.${cfg.domainName}/";
|
||||
image_proxy = true;
|
||||
default_http_headers = {
|
||||
X-Content-Type-Options = "nosniff";
|
||||
X-XSS-Protection = "1; mode=block";
|
||||
X-Download-Options = "noopen";
|
||||
X-Robots-Tag = "noindex, nofollow";
|
||||
Referrer-Policy = "no-referrer";
|
||||
};
|
||||
};
|
||||
outgoing = {
|
||||
request_timeout = 5.0; # default timeout in seconds, can be override by engine
|
||||
max_request_timeout = 15.0; # the maximum timeout in seconds
|
||||
pool_connections = 100; # Maximum number of allowable connections, or null
|
||||
pool_maxsize = 10; # Number of allowable keep-alive connections, or null
|
||||
enable_http2 = true; # See https://www.python-httpx.org/http2/
|
||||
};
|
||||
/* = {
|
||||
name = "soundcloud";
|
||||
disabled = true;
|
||||
};*/
|
||||
};
|
||||
services.nginx.virtualHosts."search.${cfg.domainName}" = let inherit (config.services.searx) settings; in {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
# locations."/".proxyPass = "http://${quotePotentialIpV6 settings.server.bind_address}:${toString settings.server.port}";
|
||||
locations."/".extraConfig = ''
|
||||
uwsgi_pass "${quotePotentialIpV6 settings.server.bind_address}:${toString settings.server.port}";
|
||||
include ${config.services.nginx.package}/conf/uwsgi_params;
|
||||
'';
|
||||
};
|
||||
|
||||
# NGINX
|
||||
services.nginx.enable = true;
|
||||
services.nginx.streamConfig =
|
||||
let
|
||||
cert = config.security.acme.certs."${cfg.domainName}".directory + "/fullchain.pem";
|
||||
certKey = config.security.acme.certs."${cfg.domainName}".directory + "/key.pem";
|
||||
trustedCert = config.security.acme.certs."${cfg.domainName}".directory + "/chain.pem";
|
||||
in ''
|
||||
upstream dns {
|
||||
zone dns 64k;
|
||||
server 127.0.0.1:53;
|
||||
}
|
||||
server {
|
||||
listen 853 ssl;
|
||||
ssl_certificate ${cert};
|
||||
ssl_certificate_key ${certKey};
|
||||
ssl_trusted_certificate ${trustedCert};
|
||||
proxy_pass dns;
|
||||
}
|
||||
'';
|
||||
services.nginx.commonHttpConfig = "log_format postdata '{\"ip\":\"$remote_addr\",\"time\":\"$time_iso8601\",\"referer\":\"$http_referer\",\"body\":\"$request_body\",\"ua\":\"$http_user_agent\"}';";
|
||||
services.nginx.recommendedTlsSettings = true;
|
||||
services.nginx.recommendedOptimisation = true;
|
||||
services.nginx.recommendedGzipSettings = true;
|
||||
services.nginx.recommendedProxySettings = true;
|
||||
|
||||
# BLOG
|
||||
services.nginx.virtualHosts."${cfg.domainName}" = {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
extraConfig = "autoindex on;";
|
||||
locations."/".root = "/var/www/${cfg.domainName}/";
|
||||
locations."/src".root = "/var/www/${cfg.domainName}/";
|
||||
locations."/src".extraConfig = "index force_dirlisting;";
|
||||
locations."/submit_comment".extraConfig = ''
|
||||
access_log /var/log/nginx/comments.log postdata;
|
||||
proxy_pass https://${cfg.domainName}/submit.htm;
|
||||
break;
|
||||
'';
|
||||
locations."/submit.htm" = {
|
||||
extraConfig = ''
|
||||
return 200 '<!doctype html><html><head><base href="/"/><link rel="preload" href="style.css" as="style"><title>Success!</title><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><link rel="icon" type="image/jpeg" href="pfp.jpg"><link rel="alternate" type="application/rss+xml" title="RSS" href="https://${cfg.domainName}/blog/index.xml"><link href="style.css" rel="stylesheet" /><script src="main.js"></script><meta http-equiv="refresh" content="10; url=$http_referer" /></head><body onload="documentLoaded()"><hr/><div class="main-body"><p>Success! It may take a while for your comment to get moderated.</p><p>Please wait for 10 seconds until you get redirected back...</p><p>Or just go there <a href="$http_referer">manually</a>.</p></div><hr/></body></html>';
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts."www.${cfg.domainName}" = {
|
||||
enableACME = true;
|
||||
globalRedirect = cfg.domainName;
|
||||
};
|
||||
|
||||
# MAILSERVER
|
||||
# roundcube
|
||||
services.nginx.virtualHosts."mail.${cfg.domainName}" = {
|
||||
enableACME = true;
|
||||
};
|
||||
services.roundcube = {
|
||||
enable = true;
|
||||
package = pkgs.roundcube.withPlugins (plugins: [ plugins.persistent_login ]);
|
||||
dicts = with pkgs.aspellDicts; [ en ru ];
|
||||
hostName = "mail.${cfg.domainName}";
|
||||
maxAttachmentSize = 100;
|
||||
plugins = [ "persistent_login" ];
|
||||
};
|
||||
mailserver = {
|
||||
enable = true;
|
||||
fqdn = "mail.${cfg.domainName}";
|
||||
domains = [ cfg.domainName ];
|
||||
certificateScheme = 1;
|
||||
certificateFile = config.security.acme.certs."mail.${cfg.domainName}".directory + "/fullchain.pem";
|
||||
keyFile = config.security.acme.certs."mail.${cfg.domainName}".directory + "/key.pem";
|
||||
localDnsResolver = false;
|
||||
recipientDelimiter = "-";
|
||||
lmtpSaveToDetailMailbox = "no";
|
||||
hierarchySeparator = "/";
|
||||
};
|
||||
|
||||
# Only allow local connections to noreply account
|
||||
mailserver.loginAccounts."noreply@${cfg.domainName}" = {
|
||||
# password is set in private.nix
|
||||
hashedPassword = cfg.hashedNoreplyPassword;
|
||||
sendOnly = true;
|
||||
};
|
||||
services.dovecot2.extraConfig =
|
||||
let passwd = builtins.toFile "dovecot2-local-passwd" ''
|
||||
noreply@${cfg.domainName}:{plain}${cfg.unhashedNoreplyPassword}::::::allow_nets=local,127.0.0.0/8,::1
|
||||
'';
|
||||
in ''
|
||||
passdb {
|
||||
driver = passwd-file
|
||||
args = ${passwd}
|
||||
}
|
||||
'';
|
||||
|
||||
# GITEA
|
||||
services.nginx.virtualHosts."git.${cfg.domainName}" = let inherit (config.services.gitea) settings; in {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
locations."/".proxyPass = "http://${quotePotentialIpV6 settings.server.HTTP_ADDR}:${toString settings.server.HTTP_PORT}";
|
||||
};
|
||||
services.gitea = {
|
||||
enable = true;
|
||||
database = {
|
||||
createDatabase = false;
|
||||
passwordFile = "/var/lib/gitea/db_password";
|
||||
type = "postgres";
|
||||
};
|
||||
settings = {
|
||||
mailer = {
|
||||
ENABLED = true;
|
||||
FROM = "Gitea <noreply@${cfg.domainName}>";
|
||||
MAILER_TYPE = "smtp";
|
||||
HOST = "mail.${cfg.domainName}:587";
|
||||
USER = "noreply@${cfg.domainName}";
|
||||
PASSWD = cfg.unhashedNoreplyPassword;
|
||||
SKIP_VERIFY = true;
|
||||
};
|
||||
session = {
|
||||
COOKIE_SECURE = true;
|
||||
};
|
||||
server = {
|
||||
ROOT_URL = "https://git.${cfg.domainName}";
|
||||
HTTP_ADDR = "::1";
|
||||
HTTP_PORT = 3310;
|
||||
DOMAIN = "git.${cfg.domainName}";
|
||||
# START_SSH_SERVER = true;
|
||||
# SSH_PORT = 2222;
|
||||
};
|
||||
service = {
|
||||
DISABLE_REGISTRATION = true;
|
||||
REGISTER_EMAIL_CONFIRM = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# NEXTCLOUD
|
||||
services.nginx.virtualHosts."cloud.${cfg.domainName}" = {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
};
|
||||
services.nextcloud = {
|
||||
enable = true;
|
||||
enableBrokenCiphersForSSE = false;
|
||||
package = pkgs.nextcloud26;
|
||||
autoUpdateApps.enable = true;
|
||||
# TODO: use socket auth and remove the next line
|
||||
database.createLocally = false;
|
||||
config = {
|
||||
adminpassFile = "/var/lib/nextcloud/admin_password";
|
||||
dbpassFile = "/var/lib/nextcloud/db_password";
|
||||
dbtype = "pgsql";
|
||||
dbhost = "/run/postgresql";
|
||||
overwriteProtocol = "https";
|
||||
};
|
||||
hostName = "cloud.${cfg.domainName}";
|
||||
https = true;
|
||||
};
|
||||
|
||||
systemd.services.pleroma.path = [ pkgs.exiftool pkgs.gawk ];
|
||||
services.nginx.virtualHosts."pleroma.${cfg.domainName}" = {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
locations."/".proxyPass = "http://127.0.0.1:9970";
|
||||
};
|
||||
|
||||
/*locations."/dns-query".extraConfig = ''
|
||||
grpc_pass grpc://127.0.0.1:53453;
|
||||
'';*/
|
||||
|
||||
# TODO: firefox sync?
|
||||
}
|
51
system/hosts/nixserver/fdroid.nix
Normal file
51
system/hosts/nixserver/fdroid.nix
Normal file
|
@ -0,0 +1,51 @@
|
|||
{ config
|
||||
, pkgs
|
||||
, lib
|
||||
, ... }:
|
||||
|
||||
let
|
||||
cfg = config.server;
|
||||
quotePotentialIpV6 = addr:
|
||||
if lib.hasInfix ":" addr then "[${addr}]" else addr;
|
||||
in {
|
||||
services.nginx.virtualHosts."${cfg.domainName}" = {
|
||||
locations."/fdroid/".alias = "/var/lib/fdroid/repo/";
|
||||
};
|
||||
users.users.fdroid = {
|
||||
home = "/var/lib/fdroid";
|
||||
group = "fdroid";
|
||||
isSystemUser = true;
|
||||
};
|
||||
users.groups.fdroid = { };
|
||||
systemd.timers.update-fdroid = {
|
||||
wantedBy = [ "timers.target" ];
|
||||
partOf = [ "update-fdroid.service" ];
|
||||
# slightly unusual time to reduce server load
|
||||
timerConfig.OnCalendar = [ "*-*-* 00:40:00" ]; # every day
|
||||
};
|
||||
systemd.services.update-fdroid = {
|
||||
serviceConfig = let
|
||||
inherit (pkgs) fdroidserver;
|
||||
fdroidScript = pkgs.writeText "update-froid.py" ''
|
||||
import requests, subprocess, os, sys
|
||||
|
||||
x = requests.get('https://api.github.com/repos/ppy/osu/releases').json()
|
||||
|
||||
for q in x:
|
||||
for w in q.get('assets', []):
|
||||
if w.get('name', "").endswith('.apk'):
|
||||
os.chdir('/var/lib/fdroid')
|
||||
subprocess.run(['${pkgs.wget}/bin/wget', w['browser_download_url'], '-O', '/var/tmp/lazer.apk'], check=True)
|
||||
os.rename('/var/tmp/lazer.apk', '/var/lib/fdroid/repo/sh.ppy.osulazer.apk')
|
||||
subprocess.run(['${fdroidserver}/bin/fdroid', 'update', '--allow-disabled-algorithms'])
|
||||
sys.exit()
|
||||
'';
|
||||
fdroidPython = pkgs.python3.withPackages (p: with p; [ requests ]);
|
||||
in {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${fdroidPython} ${fdroidScript}";
|
||||
};
|
||||
environment.JAVA_HOME = "${pkgs.jdk11_headless}";
|
||||
path = [ pkgs.jdk11_headless ];
|
||||
};
|
||||
}
|
122
system/hosts/nixserver/matrix.nix
Normal file
122
system/hosts/nixserver/matrix.nix
Normal file
|
@ -0,0 +1,122 @@
|
|||
{ config
|
||||
, pkgs
|
||||
, lib
|
||||
, ... }:
|
||||
|
||||
let
|
||||
cfg = config.server;
|
||||
quotePotentialIpV6 = addr:
|
||||
if lib.hasInfix ":" addr then "[${addr}]" else addr;
|
||||
matrixServerJson = {
|
||||
"m.server" = "matrix.${cfg.domainName}:443";
|
||||
};
|
||||
matrixClientJson = {
|
||||
"m.homeserver" = { base_url = "https://matrix.${cfg.domainName}"; };
|
||||
"m.identity_server" = { base_url = "https://vector.im"; };
|
||||
};
|
||||
matrixServerConfigResponse = ''
|
||||
add_header Content-Type application/json;
|
||||
return 200 '${builtins.toJSON matrixServerJson}';
|
||||
'';
|
||||
matrixClientConfigResponse = ''
|
||||
add_header Content-Type application/json;
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
return 200 '${builtins.toJSON matrixClientJson}';
|
||||
'';
|
||||
matrixAddr = "::1";
|
||||
matrixPort = 8008;
|
||||
in {
|
||||
imports = [ ./maubot.nix ];
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ 8008 8448 ];
|
||||
systemd.services.matrix-synapse.serviceConfig.TimeoutStartSec = 180;
|
||||
|
||||
services.nginx.virtualHosts."${cfg.domainName}" = {
|
||||
locations."= /.well-known/matrix/server".extraConfig = matrixServerConfigResponse;
|
||||
locations."= /.well-known/matrix/client".extraConfig = matrixClientConfigResponse;
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts."matrix.${cfg.domainName}" = {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
locations = {
|
||||
"= /.well-known/matrix/server".extraConfig = matrixServerConfigResponse;
|
||||
"= /.well-known/matrix/client".extraConfig = matrixClientConfigResponse;
|
||||
"/".proxyPass = "http://${quotePotentialIpV6 matrixAddr}:${toString matrixPort}";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.heisenbridge.wants = [ "matrix-synapse.service" ];
|
||||
systemd.services.heisenbridge.after = [ "matrix-synapse.service" ];
|
||||
services.heisenbridge = {
|
||||
enable = true;
|
||||
homeserver = "http://${quotePotentialIpV6 matrixAddr}:${toString matrixPort}/";
|
||||
};
|
||||
# so synapse can read the registration
|
||||
users.groups.heisenbridge.members = [ "matrix-synapse" ];
|
||||
|
||||
services.matrix-synapse = {
|
||||
enable = true;
|
||||
extraConfigFiles = [ "/var/lib/matrix-synapse/config.yaml" ];
|
||||
settings = {
|
||||
app_service_config_files = [
|
||||
"/var/lib/heisenbridge/registration.yml"
|
||||
];
|
||||
allow_guest_access = true;
|
||||
url_preview_enabled = true;
|
||||
tls_certificate_path = config.security.acme.certs."matrix.${cfg.domainName}".directory + "/fullchain.pem";
|
||||
tls_private_key_path = config.security.acme.certs."matrix.${cfg.domainName}".directory + "/key.pem";
|
||||
public_baseurl = "https://matrix.${cfg.domainName}/";
|
||||
server_name = "matrix.${cfg.domainName}";
|
||||
max_upload_size = "100M";
|
||||
email = {
|
||||
smtp_host = "mail.pavluk.org";
|
||||
smtp_port = 587;
|
||||
smtp_user = "noreply";
|
||||
smtp_password = cfg.unhashedNoreplyPassword;
|
||||
notif_from = "${cfg.domainName} matrix homeserver <noreply@${cfg.domainName}>";
|
||||
app_name = cfg.domainName;
|
||||
notif_for_new_users = false;
|
||||
enable_notifs = true;
|
||||
};
|
||||
listeners = [{
|
||||
port = matrixPort;
|
||||
bind_addresses = [ matrixAddr ];
|
||||
type = "http";
|
||||
tls = false;
|
||||
x_forwarded = true;
|
||||
resources = [{
|
||||
names = [ "client" "federation" ];
|
||||
compress = false;
|
||||
}];
|
||||
}];
|
||||
};
|
||||
};
|
||||
|
||||
# maubot
|
||||
users.users.maubot = {
|
||||
home = "/var/lib/maubot";
|
||||
group = "maubot";
|
||||
isSystemUser = true;
|
||||
};
|
||||
users.groups.maubot = { };
|
||||
systemd.services.maubot = {
|
||||
description = "Maubot";
|
||||
wants = [ "matrix-synapse.service" "nginx.service" ];
|
||||
after = [ "matrix-synapse.service" "nginx.service" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
environment = {
|
||||
LD_LIBRARY_PATH = "${pkgs.stdenv.cc.cc.lib}/lib";
|
||||
};
|
||||
serviceConfig = {
|
||||
User = "maubot";
|
||||
Group = "maubot";
|
||||
WorkingDirectory = "/var/lib/maubot/data";
|
||||
};
|
||||
script = "${pkgs.python3.withPackages (pks: with pks; [
|
||||
pkgs.maubot (pkgs.pineapplebot.override {
|
||||
magic = cfg.pizzabotMagic;
|
||||
}) feedparser levenshtein python-dateutil pytz
|
||||
])}/bin/python3 -m maubot";
|
||||
};
|
||||
}
|
45
system/hosts/nixserver/maubot.nix
Normal file
45
system/hosts/nixserver/maubot.nix
Normal file
|
@ -0,0 +1,45 @@
|
|||
{ config
|
||||
, pkgs
|
||||
, lib
|
||||
, ... }:
|
||||
|
||||
let
|
||||
cfg = config.server;
|
||||
quotePotentialIpV6 = addr:
|
||||
if lib.hasInfix ":" addr then "[${addr}]" else addr;
|
||||
# i've yet to create a maubot module so this is hardcoded
|
||||
maubotAddr = "127.0.0.1";
|
||||
maubotPort = 29316;
|
||||
in {
|
||||
services.nginx.virtualHosts."matrix.${cfg.domainName}".locations = {
|
||||
"/_matrix/maubot/" = {
|
||||
proxyPass = "http://${quotePotentialIpV6 maubotAddr}:${toString maubotPort}";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
};
|
||||
users.users.maubot = {
|
||||
home = "/var/lib/maubot";
|
||||
group = "maubot";
|
||||
isSystemUser = true;
|
||||
};
|
||||
users.groups.maubot = { };
|
||||
systemd.services.maubot = {
|
||||
description = "Maubot";
|
||||
wants = [ "matrix-synapse.service" "nginx.service" ];
|
||||
after = [ "matrix-synapse.service" "nginx.service" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
environment = {
|
||||
LD_LIBRARY_PATH = "${pkgs.stdenv.cc.cc.lib}/lib";
|
||||
};
|
||||
serviceConfig = {
|
||||
User = "maubot";
|
||||
Group = "maubot";
|
||||
WorkingDirectory = "/var/lib/maubot/data";
|
||||
};
|
||||
script = "${pkgs.python3.withPackages (pks: with pks; [
|
||||
pkgs.maubot (pkgs.pineapplebot.override {
|
||||
magic = cfg.pizzabotMagic;
|
||||
}) feedparser levenshtein python-dateutil pytz
|
||||
])}/bin/python3 -m maubot";
|
||||
};
|
||||
}
|
81
system/hosts/nixserver/mumble.nix
Normal file
81
system/hosts/nixserver/mumble.nix
Normal file
|
@ -0,0 +1,81 @@
|
|||
{ config
|
||||
, lib
|
||||
, ... }:
|
||||
|
||||
let
|
||||
cfg = config.server;
|
||||
quotePotentialIpV6 = addr:
|
||||
if lib.hasInfix ":" addr then "[${addr}]" else addr;
|
||||
in {
|
||||
services.murmur = {
|
||||
enable = true;
|
||||
imgMsgLength = 0;
|
||||
textMsgLength = 0;
|
||||
registerName = "mumble.${cfg.domainName}";
|
||||
registerHostname = "mumble.${cfg.domainName}";
|
||||
sslCa = config.security.acme.certs."mumble.${cfg.domainName}".directory + "/chain.pem";
|
||||
sslCert = config.security.acme.certs."mumble.${cfg.domainName}".directory + "/fullchain.pem";
|
||||
sslKey = config.security.acme.certs."mumble.${cfg.domainName}".directory + "/key.pem";
|
||||
# clientCertRequired = true;
|
||||
extraConfig = ''
|
||||
bandwidth=320000
|
||||
opusthreshold=0
|
||||
'';
|
||||
};
|
||||
# Allow murmur to read the certificate
|
||||
security.acme.certs."mumble.${cfg.domainName}" = {
|
||||
group = "nginxandmurmur";
|
||||
postRun = "systemctl try-reload-or-restart murmur";
|
||||
};
|
||||
users.groups.nginxandmurmur.members = [ "murmur" "nginx" ];
|
||||
|
||||
# Mumble music bot
|
||||
services.nginx.virtualHosts."mumble.${cfg.domainName}" = let inherit (config.services.botamusique) settings; in {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
globalRedirect = cfg.domainName;
|
||||
locations."/music".extraConfig = "return 301 https://mumble.${cfg.domainName}/music/;";
|
||||
locations."/music/".proxyPass = "http://${quotePotentialIpV6 settings.webinterface.listening_addr}:${toString settings.webinterface.listening_port}/";
|
||||
};
|
||||
|
||||
services.botamusique = {
|
||||
enable = true;
|
||||
settings = {
|
||||
youtube_dl = {
|
||||
cookiefile = "/var/lib/botamusique/cookie_ydl";
|
||||
};
|
||||
webinterface = {
|
||||
enabled = true;
|
||||
listening_addr = "::1";
|
||||
listening_port = 8181;
|
||||
is_web_proxified = true;
|
||||
access_address = "https://mumble.${cfg.domainName}/music";
|
||||
auth_method = "token";
|
||||
upload_enabled = true;
|
||||
max_upload_file_size = "100MB";
|
||||
delete_allowed = true;
|
||||
};
|
||||
bot = {
|
||||
bandwidth = 200000;
|
||||
volume = 1.0;
|
||||
ducking = true;
|
||||
ducking_volume = 0.75;
|
||||
};
|
||||
server.certificate = "/var/lib/botamusique/cert.pem";
|
||||
};
|
||||
};
|
||||
systemd.services.botamusique.wants = [ "murmur.service" ];
|
||||
systemd.services.botamusique.after = [ "murmur.service" ];
|
||||
|
||||
networking.firewall = {
|
||||
allowedTCPPorts = [
|
||||
64738
|
||||
# Used for mumble-web signaling (not sure if it needs TCP or UDP)
|
||||
# 20000 20001 20002 20003 20004 20005 20006 20007 20008 20009 20010
|
||||
];
|
||||
allowedUDPPorts = [
|
||||
64738
|
||||
# 20000 20001 20002 20003 20004 20005 20006 20007 20008 20009 20010
|
||||
];
|
||||
};
|
||||
}
|
58
system/hosts/nixserver/options.nix
Normal file
58
system/hosts/nixserver/options.nix
Normal file
|
@ -0,0 +1,58 @@
|
|||
{ lib
|
||||
, ... }:
|
||||
{
|
||||
options.server = with lib; mkOption {
|
||||
type = types.submodule {
|
||||
options = {
|
||||
domainName = mkOption {
|
||||
type = types.str;
|
||||
default = "pavluk.org";
|
||||
description = "domain name";
|
||||
};
|
||||
lanCidrV4 = mkOption {
|
||||
type = types.str;
|
||||
description = "LAN mask (IPv4)";
|
||||
example = "192.168.1.0/96";
|
||||
default = "0.0.0.0/0";
|
||||
};
|
||||
lanCidrV6 = mkOption {
|
||||
type = types.str;
|
||||
description = "LAN mask (IPv6)";
|
||||
example = "fd01:abcd::/64";
|
||||
default = "::/0";
|
||||
};
|
||||
localIpV4 = mkOption {
|
||||
type = with types; nullOr str;
|
||||
description = "server's local IPv4 address";
|
||||
example = "192.168.1.2";
|
||||
default = null;
|
||||
};
|
||||
localIpV6 = mkOption {
|
||||
type = with types; nullOr str;
|
||||
description = "server's local IPv6 address";
|
||||
example = "fd01:abcd::2";
|
||||
default = null;
|
||||
};
|
||||
noreplyPassword = mkOption {
|
||||
type = types.str;
|
||||
description = "noreply (only available via localhost) account password";
|
||||
default = "totallysafe";
|
||||
};
|
||||
hashedNoreplyPassword = mkOption {
|
||||
type = types.str;
|
||||
description = "hashed noreply password via mkpasswd -sm bcrypt";
|
||||
};
|
||||
unhashedNoreplyPassword = mkOption {
|
||||
type = types.str;
|
||||
description = "unhashed noreply password. \
|
||||
This should preferably be different from the password that is hashed for better security (yes, really)";
|
||||
};
|
||||
pizzabotMagic = mkOption {
|
||||
type = types.str;
|
||||
default = "<PIZZABOT_MAGIC_SEP>";
|
||||
};
|
||||
};
|
||||
};
|
||||
description = "server settings";
|
||||
};
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
config.programs.ccache.cacheDir
|
||||
"/var/cache/sccache"
|
||||
];
|
||||
environment.persistence."/persist".directories = lib.mkIf config.programs.ccache.enable [
|
||||
impermanence.directories = lib.mkIf config.programs.ccache.enable [
|
||||
config.programs.ccache.cacheDir
|
||||
"/var/cache/sccache"
|
||||
];
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
{ config, lib, ... }:
|
||||
|
||||
let
|
||||
cfg = config.impermanence;
|
||||
|
@ -16,7 +16,7 @@ in {
|
|||
description = "Default path for persistence";
|
||||
};
|
||||
directories = mkOption {
|
||||
type = with types; listOf path;
|
||||
type = with types; listOf (either path attrs);
|
||||
default = [ ];
|
||||
description = "Extra directories to persist";
|
||||
};
|
||||
|
@ -36,41 +36,90 @@ in {
|
|||
default = { };
|
||||
};
|
||||
config = lib.mkIf cfg.enable {
|
||||
# why is this not part of base NixOS?
|
||||
systemd.tmpfiles.rules = [ "d /var/lib/systemd/pstore 0755 root root 14d" ];
|
||||
# as weird as it sounds, I won't use tmpfs for /tmp in case I'll have to put files over 2GB there
|
||||
boot.tmp.cleanOnBoot = lib.mkIf cfg.persistTmp true;
|
||||
environment.persistence.${toString cfg.path} = {
|
||||
hideMounts = true;
|
||||
directories = map toString ([
|
||||
directories = map (x:
|
||||
if builtins.isPath x then toString x
|
||||
else if builtins.isAttrs x && x?directory && builtins.isPath x.directory then x // { directory = toString x.directory; }
|
||||
else x)
|
||||
([
|
||||
# nixos files
|
||||
/etc/nixos
|
||||
/var/lib/nixos
|
||||
{ directory = /etc/nixos; user = "root"; group = "root"; mode = "0755"; }
|
||||
{ directory = /var/lib/nixos; user = "root"; group = "root"; mode = "0755"; }
|
||||
|
||||
/var/log
|
||||
{ directory = /var/log; user = "root"; group = "root"; mode = "0755"; }
|
||||
|
||||
# persist this since everything here is cleaned up by systemd-tmpfiles over time anyway
|
||||
# ...or so I'd like to believe
|
||||
/var/lib/systemd
|
||||
/var/tmp
|
||||
{ directory = /var/lib/systemd; user = "root"; group = "root"; mode = "0755"; }
|
||||
{ directory = /var/tmp; user = "root"; group = "root"; mode = "1777"; }
|
||||
{ directory = /var/spool; user = "root"; group = "root"; mode = "0777"; }
|
||||
] ++ (lib.optionals cfg.persistTmp [
|
||||
/tmp
|
||||
{ directory = /tmp; user = "root"; group = "root"; mode = "1777"; }
|
||||
]) ++ (lib.optionals config.services.mullvad-vpn.enable [
|
||||
/etc/mullvad-vpn
|
||||
/var/cache/mullvad-vpn
|
||||
{ directory = /etc/mullvad-vpn; user = "root"; group = "root"; mode = "0700"; }
|
||||
{ directory = /var/cache/mullvad-vpn; user = "root"; group = "root"; mode = "0755"; }
|
||||
]) ++ (lib.optionals config.virtualisation.libvirtd.enable ([
|
||||
/var/cache/libvirt
|
||||
/var/lib/libvirt
|
||||
# { directory = /var/cache/libvirt; user = "root"; group = "root"; mode = "0755"; }
|
||||
{ directory = /var/lib/libvirt; user = "root"; group = "root"; mode = "0755"; }
|
||||
] ++ (lib.optionals config.virtualisation.libvirtd.qemu.swtpm.enable [
|
||||
/var/lib/swtpm-localca
|
||||
{ directory = /var/lib/swtpm-localca; user = "root"; group = "root"; mode = "0750"; }
|
||||
]))) ++ (lib.optionals config.networking.wireless.iwd.enable [
|
||||
/var/lib/iwd
|
||||
{ directory = /var/lib/iwd; user = "root"; group = "root"; mode = "0700"; }
|
||||
]) ++ (lib.optionals (builtins.any (x: x.useDHCP) (builtins.attrValues config.networking.interfaces) || config.networking.useDHCP) [
|
||||
/var/db/dhcpcd
|
||||
{ directory = /var/db/dhcpcd; user = "root"; group = "root"; mode = "0755"; }
|
||||
]) ++ (lib.optionals config.services.gitea.enable [
|
||||
{ directory = /var/lib/gitea; user = "gitea"; group = "gitea"; mode = "0755"; }
|
||||
]) ++ (lib.optionals config.services.matrix-synapse.enable [
|
||||
{ directory = /var/lib/matrix-synapse; user = "matrix-synapse"; group = "matrix-synapse"; mode = "0700"; }
|
||||
]) ++ (lib.optionals config.services.heisenbridge.enable [
|
||||
{ directory = /var/lib/heisenbridge; user = "heisenbridge"; group = "heisenbridge"; mode = "0755"; }
|
||||
]) ++ (lib.optionals config.services.murmur.enable [
|
||||
{ directory = /var/lib/murmur; user = "murmur"; group = "murmur"; mode = "0700"; }
|
||||
]) ++ (lib.optionals config.services.nextcloud.enable [
|
||||
{ directory = /var/lib/nextcloud; user = "nextcloud"; group = "nextcloud"; mode = "0750"; }
|
||||
]) ++ (lib.optionals config.services.botamusique.enable [
|
||||
{ directory = /var/lib/private/botamusique; user = "root"; group = "root"; mode = "0750"; }
|
||||
]) ++ (lib.optionals config.security.acme.acceptTerms [
|
||||
{ directory = /var/lib/acme; user = "acme"; group = "acme"; mode = "0755"; }
|
||||
]) ++ (lib.optionals config.services.printing.enable [
|
||||
{ directory = /var/lib/cups; user = "root"; group = "root"; mode = "0755"; }
|
||||
]) ++ (lib.optionals config.services.fail2ban.enable [
|
||||
{ directory = /var/lib/fail2ban; user = "fail2ban"; group = "fail2ban"; mode = "0750"; }
|
||||
]) ++ (lib.optionals config.services.opendkim.enable [
|
||||
{ directory = /var/lib/opendkim; user = "opendkim"; group = "opendkim"; mode = "0700"; }
|
||||
]) ++ (lib.optionals config.services.pleroma.enable [
|
||||
{ directory = /var/lib/pleroma; user = "pleroma"; group = "pleroma"; mode = "0700"; }
|
||||
]) ++ (lib.optionals config.services.postfix.enable [
|
||||
{ directory = /var/lib/postfix; user = "root"; group = "root"; mode = "0755"; }
|
||||
]) ++ (lib.optionals config.services.postgresql.enable [
|
||||
{ directory = /var/lib/postgresql; user = "postgres"; group = "postgres"; mode = "0755"; }
|
||||
]) ++ (lib.optionals config.services.unbound.enable [
|
||||
{ directory = /var/lib/unbound; user = "unbound"; group = "unbound"; mode = "0755"; }
|
||||
]) ++ (lib.optionals config.services.roundcube.enable [
|
||||
{ directory = /var/lib/roundcube; user = "roundcube"; group = "roundcube"; mode = "0700"; }
|
||||
]) ++ (lib.optionals config.services.rspamd.enable [
|
||||
{ directory = /var/lib/rspamd; user = "rspamd"; group = "rspamd"; mode = "0700"; }
|
||||
]) ++ (lib.optionals (
|
||||
(builtins.hasAttr "rspamd" config.services.redis.servers)
|
||||
&& (builtins.hasAttr "enable" config.services.redis.servers.rspamd)
|
||||
&& config.services.redis.servers.rspamd.enable
|
||||
) [
|
||||
{ directory = /var/lib/redis-rspamd; user = "redis-rspamd"; group = "redis-rspamd"; mode = "0700"; }
|
||||
]) ++ (lib.optionals config.services.dovecot2.enable [
|
||||
{ directory = /var/lib/dhparams; user = "root"; group = "root"; mode = "0755"; }
|
||||
{ directory = /var/lib/dovecot; user = "root"; group = "root"; mode = "0755"; }
|
||||
]) ++ (lib.optionals config.security.sudo.enable [
|
||||
/var/db/sudo/lectured
|
||||
{ directory = /var/db/sudo/lectured; user = "root"; group = "root"; mode = "0700"; }
|
||||
]) ++ cfg.directories);
|
||||
files = map toString ([
|
||||
# hardware-related
|
||||
/etc/adjtime
|
||||
# needed at least for /var/log
|
||||
/etc/machine-id
|
||||
] ++ cfg.files);
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
{ options, config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.vfio;
|
||||
in {
|
||||
|
@ -73,9 +73,10 @@ in {
|
|||
description = "VFIO settings";
|
||||
default = { };
|
||||
};
|
||||
# compatibility so this module loads on non-amd hardware
|
||||
config = let
|
||||
enableIvshmem = config.vfio.lookingGlass.enable && (builtins.length config.vfio.lookingGlass.ivshmem) > 0;
|
||||
in lib.mkIf config.vfio.enable {
|
||||
enableIvshmem = cfg.lookingGlass.enable && (builtins.length cfg.lookingGlass.ivshmem) > 0;
|
||||
in lib.mkIf cfg.enable {
|
||||
# add a custom kernel param for early loading vfio drivers
|
||||
# because if we change boot.initrd options in a specialization, two initrds will be built
|
||||
# and we don't want to build two initrds
|
||||
|
@ -151,9 +152,13 @@ in {
|
|||
SUBSYSTEM=="kvmfr", KERNEL=="kvmfr${toString i}", OWNER="${ivshmem.owner}", GROUP="kvm", MODE="0660"
|
||||
'')
|
||||
cfg.lookingGlass.ivshmem));
|
||||
hardware = {
|
||||
opengl.enable = true;
|
||||
} // (lib.optionalAttrs (cfg.enable && !(cfg.nvidiaGpu)) {
|
||||
# disable early KMS so GPU can be properly unbound
|
||||
hardware.amdgpu.loadInInitrd = lib.mkIf (!cfg.nvidiaGpu) false;
|
||||
hardware.opengl.enable = true;
|
||||
# can't use mkif because the option may not even exist
|
||||
amdgpu.loadInInitrd = false;
|
||||
});
|
||||
# needed for virt-manager
|
||||
programs.dconf.enable = true;
|
||||
virtualisation.libvirtd = {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
{ pkgs, ... }: let inherit (pkgs) callPackage; in {
|
||||
system76-scheduler = callPackage ../pkgs/system76-scheduler.nix { };
|
||||
system76-scheduler = callPackage ./system76-scheduler.nix { };
|
||||
maubot = callPackage ./maubot.nix { };
|
||||
pineapplebot = callPackage ./pineapplebot.nix { };
|
||||
}
|
||||
|
|
95
system/pkgs/maubot.nix
Normal file
95
system/pkgs/maubot.nix
Normal file
|
@ -0,0 +1,95 @@
|
|||
{ lib
|
||||
, fetchpatch
|
||||
, python3
|
||||
, runCommand
|
||||
, encryptionSupport ? true
|
||||
}:
|
||||
|
||||
let
|
||||
python = python3.override {
|
||||
packageOverrides = self: super: {
|
||||
sqlalchemy = super.buildPythonPackage rec {
|
||||
pname = "SQLAlchemy";
|
||||
version = "1.3.24";
|
||||
|
||||
src = super.fetchPypi {
|
||||
inherit pname version;
|
||||
sha256 = "sha256-67t3fL+TEjWbiXv4G6ANrg9ctp+6KhgmXcwYpvXvdRk=";
|
||||
};
|
||||
|
||||
postInstall = ''
|
||||
sed -e 's:--max-worker-restart=5::g' -i setup.cfg
|
||||
'';
|
||||
|
||||
doCheck = false;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
self = with python.pkgs; buildPythonPackage rec {
|
||||
pname = "maubot";
|
||||
version = "0.4.1";
|
||||
disabled = pythonOlder "3.8";
|
||||
|
||||
src = fetchPypi {
|
||||
inherit pname version;
|
||||
sha256 = "sha256-Ro2PPgF8818F8JewPZ3AlbfWFNNHKTZkQq+1zpm3kk4=";
|
||||
};
|
||||
|
||||
patches = [
|
||||
# add entry point
|
||||
(fetchpatch {
|
||||
url = "https://patch-diff.githubusercontent.com/raw/maubot/maubot/pull/146.patch";
|
||||
sha256 = "0yn5357z346qzy5v5g124mgiah1xsi9yyfq42zg028c8paiw8s8x";
|
||||
})
|
||||
];
|
||||
|
||||
propagatedBuildInputs = [
|
||||
# requirements.txt
|
||||
mautrix
|
||||
aiohttp
|
||||
yarl
|
||||
sqlalchemy
|
||||
asyncpg
|
||||
aiosqlite
|
||||
CommonMark
|
||||
ruamel-yaml
|
||||
attrs
|
||||
bcrypt
|
||||
packaging
|
||||
click
|
||||
colorama
|
||||
questionary
|
||||
jinja2
|
||||
]
|
||||
# optional-requirements.txt
|
||||
++ lib.optionals encryptionSupport [
|
||||
python-olm
|
||||
pycryptodome
|
||||
unpaddedbase64
|
||||
];
|
||||
|
||||
passthru.tests = {
|
||||
simple = runCommand "${pname}-tests" { } ''
|
||||
${self}/bin/mbc --help > $out
|
||||
'';
|
||||
};
|
||||
|
||||
# Setuptools is trying to do python -m maubot test
|
||||
dontUseSetuptoolsCheck = true;
|
||||
|
||||
pythonImportsCheck = [
|
||||
"maubot"
|
||||
];
|
||||
|
||||
meta = with lib; {
|
||||
description = "A plugin-based Matrix bot system written in Python";
|
||||
homepage = "https://github.com/maubot/maubot";
|
||||
changelog = "https://github.com/maubot/maubot/blob/v${version}/CHANGELOG.md";
|
||||
license = licenses.agpl3Plus;
|
||||
maintainers = with maintainers; [ chayleaf ];
|
||||
};
|
||||
};
|
||||
|
||||
in
|
||||
self
|
34
system/pkgs/pineapplebot.nix
Normal file
34
system/pkgs/pineapplebot.nix
Normal file
|
@ -0,0 +1,34 @@
|
|||
{ python3
|
||||
, fetchFromGitHub
|
||||
, rustPlatform
|
||||
, magic ? "<PIZZABOT_MAGIC_SEP>"
|
||||
, ... }:
|
||||
|
||||
python3.pkgs.buildPythonPackage rec {
|
||||
pname = "pineapplebot";
|
||||
version = "0.1.0";
|
||||
src = fetchFromGitHub {
|
||||
owner = "chayleaf";
|
||||
repo = "pizzabot_v3";
|
||||
rev = "master";
|
||||
sha256 = "sha256-ZLskMlllZfmqIlbSr0pNHHJehDycohiwqgYbuEYP7Qc=";
|
||||
};
|
||||
preBuild = ''
|
||||
head -n13 Cargo.toml > Cargo.toml.new
|
||||
mv Cargo.toml.new Cargo.toml
|
||||
'';
|
||||
sourceRoot = "source/pineapplebot";
|
||||
cargoDeps = rustPlatform.fetchCargoTarball {
|
||||
inherit src sourceRoot;
|
||||
name = "${pname}-${version}";
|
||||
sha256 = "14jxgykwg1apy97gy1j8mz7ny2cqg4q9s03a2bk9kx2y6ibm4668";
|
||||
};
|
||||
nativeBuildInputs = with rustPlatform; [
|
||||
cargoSetupHook
|
||||
maturinBuildHook
|
||||
];
|
||||
doCheck = false;
|
||||
doInstallCheck = true;
|
||||
pythonImportsCheck = [ "pineapplebot" ];
|
||||
PIZZABOT_MAGIC = magic;
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
nixmsi = { ... }: {
|
||||
# insert private config here
|
||||
};
|
||||
}
|
9
system/private.sample.nix
Normal file
9
system/private.sample.nix
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
nixmsi = { pkgs, lib, ... }: {
|
||||
# insert private config here
|
||||
# time.timeZone = ...;
|
||||
# users.users.root.initialHashedPassword = ...;
|
||||
# users.users.user.initialHashedPassword = ...;
|
||||
};
|
||||
nixserver = { ... }: { };
|
||||
}
|
Loading…
Reference in a new issue