Compare commits

..

2 commits

Author SHA1 Message Date
4b492a2028
nextcloud: fork module from nixpkgs and add extraOptions
- nextcloud now has its own container
 - redis caching appears to work
 - this now uses nextcloud 21
2021-03-25 18:34:35 +01:00
0882960b9a
First draft for a nextcloud deployment on nix
Things to note:
 - DO NOT DEPLOY THIS
 - use nixos-container for testing instead

I've played around with nextcloud on NixOS, essentially following the
examples given in the NixOS manual and searching through some of the
other options. Nextcloud itself works fine with this setup, as does
its database (postgres), and most of the other basic stuff.

However, the nextcloud module as it currently exists appears to be fairly
limited and incomplete in its capabilities, e.g. lack of options for redis
or multiple php pools; in general, it lacks extraOptions-hooks. For redis
the documentation even explicitely notes (in caching.redis) that redis
requires additional options set in `config.php`, but it appears these cannot
currently be set using nix.

I guess we have as options:
 - I missed something and it does in fact work
 - we can wait for later versions; looks like 21.03 will add at least *some* more
 - we can fork the module and add options ourselves
 - we can configure it nextcloud by manually editing `config.php`, as it's not
   actually inside the nix store but at /var/lib/nextcloud/config (veto)

See comments for additional notes and todos.
2021-03-25 18:34:35 +01:00
307 changed files with 3134 additions and 19222 deletions

1
.gitignore vendored
View file

@ -2,4 +2,3 @@ result
ecdsa_host
secrets/
.*.swp
.deploy-gc/*

9
.gitlab-ci.yml Normal file
View file

@ -0,0 +1,9 @@
stages:
- build
build:
tags:
- nix
stage: build
script:
- nix-build -A deploy.all

View file

@ -1 +0,0 @@
websites/*

View file

@ -1,23 +0,0 @@
keys:
- &parsons age1yql8qaf7upraqy4cq397tt4vgs046hq0v59qymla8t3x0ujqvu4sesgsvw
- &hexchen-backup age1zgdegurzlr8cw9948wgf4q5qh3efltwhhzus5tt6az5xvvsux9us2v4tyd
- &stuebinm-ilex age18wkr3kjalalzrq9l05q32gnlaqr7t6rqqzde307m83rs9fp4xcfsdtj9gt
- &stuebinm-surltesh-echer age1q88az2y5hnx8naqsvrurllqj6y5gtehrpa9emmrxy5ghwsr7pvnqf7tfpx
- &stuebinm-abbenay age18nkru4pwvvapdw76nauv2xdtlj8cvyv3ugahe9kcxtvtsptx2eyqw7p0m6
- &octycs-m age1fm3e99tdyrsvztdchxxllt9nat35xzvd68d09y8scu9jfc7kvvuquhr49c
- &zauberberg-conway age16fk0m26n0fr2vmuxm2mjsmrawclde2mlyj6wg3ee9jvzmu5ru3ustgs5jq
- &moira-2022-06 age1l694a4xht7r0eza9r2vjncupmp6cxyk3k9x2ljwynnur4m2lc5jqmy3jut
- &moira-openpgp age1m374x78q9eykua32ldrqxh8rh36kz6jyre69a263krf28hcycsqsrmshl0
creation_rules:
- path_regex: secrets.yaml
key_groups:
- age:
- *parsons
- *hexchen-backup
- *stuebinm-ilex
- *stuebinm-surltesh-echer
- *stuebinm-abbenay
- *octycs-m
- *zauberberg-conway
- *moira-2022-06
- *moira-openpgp

24
LICENSE
View file

@ -1,24 +0,0 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>

View file

@ -1,81 +1,32 @@
# hacc nixfiles
Welcome to the hacc nixfiles (haccfiles). This is how we configure (most of)
our infrastructure.
welcome to hacc nixfiles (haccfiles). this is the code describing our nix-based infrastructure.
## General layout
## structure
- `flake.nix`: Entrypoint & dependencies
- `default.nix`: Entrypoint to the config
- `common/`: configuration common to all hosts
- `desktop/`: desktop-relevant communication
- `modules/`: home-grown modules for hacc-specific services
- `pkgs/`: packages we need which aren't in nixpkgs
- `websites/`: static websites hosted by us
- `common/`: meta-level config, reusable across machines
- `parsons/`: our sole server, its config & the services it runs
- `nix/`: sources files, managed with niv
- `pkgs/`: packages we built and don't want to upstream
Right now, we only have a single host. We might add more again in the future.
## working with the haccfiles
## Working with this repo
You will need a flake-enabled nix installation, and have your ssh config set up
so that `ssh parsons` will connect to `parsons.hacc.space`.
### Deploying remotely
It's recommended to use [deploy_rs](https://github.com/serokell/deploy-rs):
~~~shell
deploy .#parsons -k [--dry-activate]
~~~
Alternatively, using just `nixos-rebuild`:
~~~shell
nixos-rebuild --flake .#parsons --target-host parsons \
--use-remote-sudo --use-substitutes [test|switch|dry-activate]
~~~
### Re-deploying on parsons itself
Simply do:
~~~shell
nixos-rebuild --flake .#parsons [test|switch|dry-activate]
~~~
## Working on websites
Websites are exposed as flake outputs: if you're working on a website & want to
check it in a browser, do e.g.
~~~shell
nix run .#\"muc.hacc.earth\"
~~~
to start a local http server (note that some of our websites need a directory
to be built in; these use `/tmp/hacc-website`).
To add a new website, add a new subdirectory to `websites`; nix will generate a
vhost config based on that directory's name. Add a `default.nix` in your directory
describing how to build the website, and give its derivation a `watch` attribute
to make the `nix run` setup work.
## I don't want to build this long dependency / want a cached version!
If it's still available on parsons from a previous deploy, do:
```shell
nix copy --from ssh://parsons /nix/store/...
deploy:
``` shell
nix build -f . deploy.$hostname && ./result switch
```
Note: don't just copy the .drv file (which Nix complains about if it can't
build something), that's just the description of how to build it! If you
don't know the actual outpath, look in the .drv file (should start with
`Derive([("out","[the path you want]"...`)
`$hostname` can be replaced with any hostname or group
## committing to haccfiles
- Things on `main` should always reflect the config that's actually deployed on
parsons, except during testing / debugging sessions
- Golden Rule: DO NOT COMMIT TO MAIN
- exceptions apply, if you are not sure where to commit, don't commit to main
- split up commits, every commit is one atomic change
- follow the commit format: "place: $change"
- place: e.g. `modules/$module`, `services/$service` ...
- change: describe your change. Please wrap your lines sensibly (or configure
your editor to do this for you)
- e.g. no big "did some changes" but instead "updated service x", "updated service y", "update service z"
- follow the commit format: "$prefix$place: $change"
- prefix: one of fixup, nothing
- place: one of "modules/$module", "$hostname/service", "common/($place)", "pkgs/$pkgs" or "sources"
- change: describe your change, don't go over the character limit where git starts hiding/wrapping
- Exception: autogenerated messages (merge commits, reverts, etc)
- don't overuse merge commits, try to rebase things if possible with reasonable
effort

View file

@ -1,12 +1,16 @@
{ config, lib, pkgs, modules, sources, ... }:
{ config, lib, pkgs, ... }:
{
let
sources = import ../nix/sources.nix;
in {
imports = [
../modules
./users.nix
(sources.home-manager + "/nixos")
(sources.pbb-nixfiles + "/modules/nftables")
];
boot.kernelPackages = lib.mkDefault pkgs.linuxPackages;
boot.kernelPackages = lib.mkDefault pkgs.linuxPackages_latest;
boot.kernelParams = [ "quiet" ];
networking.domain = lib.mkDefault "hacc.space";
@ -15,31 +19,24 @@
SystemMaxUse=512M
MaxRetentionSec=48h
'';
nix.package = pkgs.lix;
nix.gc.automatic = lib.mkDefault true;
nix.gc.options = lib.mkDefault "--delete-older-than 7d";
nix.settings.trusted-users = [ "root" "@wheel" ];
nix.extraOptions = ''
experimental-features = nix-command flakes
'';
nix.gc.options = lib.mkDefault "--delete-older-than 1w";
nix.trustedUsers = [ "root" "@wheel" ];
environment.variables.EDITOR = "vim";
services.openssh = {
enable = true;
ports = lib.mkDefault [ 62954 ];
settings = {
X11Forwarding = true;
PermitRootLogin = "prohibit-password";
PasswordAuthentication = false;
KbdInteractiveAuthentication = false;
StreamLocalBindUnlink = true;
};
passwordAuthentication = false;
challengeResponseAuthentication = false;
permitRootLogin = lib.mkDefault "prohibit-password";
extraConfig = "StreamLocalBindUnlink yes";
forwardX11 = true;
};
programs.mosh.enable = true;
programs.fish.enable = true;
security.sudo.wheelNeedsPassword = lib.mkDefault false;
i18n.defaultLocale = "en_IE.UTF-8";
time.timeZone = "UTC";
console = {
font = "Lat2-Terminus16";
keyMap = "de";
@ -48,8 +45,8 @@
environment.systemPackages = with pkgs; [
smartmontools lm_sensors htop tcpdump nload iftop
bottom
ripgrep vgrep
# bottom
ripgrep
git wget
kitty.terminfo
rsync pv progress
@ -61,11 +58,11 @@
whois
iperf
fd
eza
exa
socat
tmux
gnupg
vim neovim
vim
patchelf
binutils
dnsutils
@ -73,19 +70,14 @@
nmap
s-tui stress
ffmpeg-full
bat
niv
sqlite-interactive
hacc-scripts
];
security.acme.defaults.email = "info+acme@hacc.space";
security.acme.email = "info+acme@hacc.space";
security.acme.acceptTerms = true;
services.nginx.appendHttpConfig = ''
access_log off;
add_header Permissions-Policy "interest-cohort=()";
'';
networking.nftables.enable = true;
petabyte.nftables.enable = true;
}

9
common/hexchen.nix Normal file
View file

@ -0,0 +1,9 @@
{config, lib, pkgs, ...}:
let
sources = import ../nix/sources.nix;
in {
imports = [
(import sources.nix-hexchen).users.hexchen.base
];
}

View file

@ -1,6 +1,11 @@
{ config, pkgs, lib, ... }:
{
# imports = [
# ./hexchen.nix
# ];
home-manager.useGlobalPkgs = true;
users.users = {
root = {
@ -8,14 +13,18 @@
};
# all the actual config is imported from hexchen's nixfiles
hexchen = {
uid = lib.mkForce 1000;
# hexchen = {
# uid = lib.mkForce 1000;
# isNormalUser = true;
# extraGroups = [ "wheel" ];
# };
stuebinm = {
uid = 1005;
isNormalUser = true;
extraGroups = [ "wheel" ];
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINJ0tCxsEilAzV6LaNpUpcjzyEn4ptw8kFz3R+Z3YjEF hexchen@backup"
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDI3T1eFS77URHZ/HVWkMOqx7W1U54zJtn9C7QWsHOtyH72i/4EVj8SxYqLllElh1kuKUXSUipPeEzVsipFVvfH0wEuTDgFffiSQ3a8lfUgdEBuoySwceEoPgc5deapkOmiDIDeeWlrRe3nqspLRrSWU1DirMxoFPbwqJXRvpl6qJPxRg+2IolDcXlZ6yxB4Vv48vzRfVzZNUz7Pjmy2ebU8PbDoFWL/S3m7yOzQpv3L7KYBz7+rkjuF3AU2vy6CAfIySkVpspZZLtkTGCIJF228ev0e8NvhuN6ZnjzXxVTQOy32HCdPdbBbicu0uHfZ5O7JX9DjGd8kk1r2dnZwwy/ hexchen@yubi5"
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC4CLJ+mFfq5XiBXROKewmN9WYmj+79bj/AoaR6Iud2pirulot3tkrrLe2cMjiNWFX8CGVqrsAELKUA8EyUTJfStlcTE0/QNESTRmdDaC+lZL41pWUO9KOiD6/0axAhHXrSJ0ScvbqtD0CtpnCKKxtuOflVPoUGZsH9cLKJNRKfEka0H0GgeKb5Tp618R/WNAQOwaCcXzg/nG4Bgv3gJW4Nm9IKy/MwRZqtILi8Mtd+2diTqpMwyNRmbenmRHCQ1vRw46joYkledVqrmSlfSMFgIHI1zRSBXb/JkG2IvIyB5TGbTkC4N2fqJNpH8wnCKuOvs46xmgdiRA26P48C2em3 hexchen@yubi5c"
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDQtJQ8fUfwsC9Q39sNpZ41RRbW91QXDLKltsYK+TLidQ5IJj2KsG/lkd433Tod6PzSvB2PcfIfnvUz7GQuS1UwXHMdLEy0/kqeYrSi6QlAxFyFBSTsUZ4d+HHwBBoXhu1Iaoch/FJNI0FhfBciIii05UyYuPj5zGgvWhnfD53Ll8HA6XVXhSK09+9GRGq57Mix5N9AkzfEF83aRUF9Qfl7Jl16rOjIgtS8hbL0kXIKUeCxZA2xi/lNHEQRriCiriPmPGOhiPcNXzbekw7IbFfE3If1CHnj7KA4KnafHAd+uHvQAce5Y4v2vMOPfGVh1cm84VTzdSPEW5V1hFjOlSnnuCQtAzkQLv8zed2NLj73GgFlcUrYKERcH84wydD0gEednNKsW8T2NzgO2eNCBf0LrcFp17qmWLv51A3jofEX5tQ3PZ7zbtR4DMUmrizrsBWDYiHJOMVeMs/9TnmIc3PL17qvVvFI7OcYxl+SPPpPtaBzxXZAMIvGFppzYxRylBcBhNvE+bXXgLFXh5cbUcwgXjvrX0y8Gv/5S4E55+i2rQMqC55+O48snoSeNlQDZV+B9setXoC93K9fBurmCX8ObnNRvvghcwUl9OBSW5K9TBdl6FF3+Z3gOCIxOMGQQKJUS5/g/eLFJ+13Y5qAPS49XJzaBiTmDrRi8x22p7sU1Q== stuebinm@in.tum.de"
];
};
@ -24,7 +33,7 @@
isNormalUser = true;
extraGroups = [ "wheel" ];
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIQqFXSlqW+D4ZtVdCiN9IT461iwyqy2taBRD3qkvXqn m@octycs.eu"
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDobGLrA6YQAKdJkZMpAsqjlk744G/pCJEvAUNJDuT1Sr59BFKDchPT03exb0o39mjH4iqvw4JDI10RfylKbR1736Ji2yRLlbCzUdgv2CfZc28TAO0rscyT49RHJmzEEE5QD4Ge7MgvFBEmZKXAxntA8M8EbxxEVfzhWp3751BYkzrCbJiHMXcTb+BG9P6rmrraINmgUJxywym5PsMYt2sfHlVus3hSpWnCR/cu0nxmW9E6Tm6CzSkWOXOTdjVuc0Kgh5GXaKDROzJ9K7cJAhd5t8Yzqtpm2xfSU5FVVUH9i7PbXOo8FL82Xi6kWMgdFNLvKimxGqW+bCv3ROlyKWF4I+HQdfdL181KaOQ40jAvjmldrB/ZiEbuWYSBZ/XhxFkKrtBYPDFHq/a5lnH3OvcDm7+/LhwIKUnyZyQ2dXOLOTOEDsO/69xwNveCB8of9o/erDbOeb+d44cXUFpPMUTz4bHXEP6y+zz8TB8/aleGbLQCPUzRZfvazN95jGUDqkumi9B3Lf+W/KpjVUgu3NQsUuJn6khMYW9VefnJvHwzbWpqIzbzNePL4iZFECv4NHPQHO/katajnMbkCie9rfnLk1EjJnrSnZUInEygkW/7Eu4EQM2h7lU4HYfwP1c4ubCFdES0ELGqSuJRwd/ORDbgxbuKOQ7gZ3/lgHdr9KGqJQ== markus.amaseder@amaseder.de"
];
hashedPassword = "$6$qQEbD8Ejx/y$6/nkX8CmFBtAlUP/UbFKVMVlA.ZvVbjQZRABqXQjU11tKpY25ww.MCGGMEKFv.7I/UH/126/q0S3ROTqePUEc.";
};
@ -34,53 +43,20 @@
isNormalUser = true;
extraGroups = [ "wheel" "cdrom" ];
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOfxXSy22k2EZwz1EtvIMwQKGWsswEBeLn5ClhuiI4Ma lukas@Conway.lan"
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCt34ou3NYWoUayWrJa5ISzihAAhFiwolJPmm2fF9llPUUA8DP3BQRiKeqDlkDzhWLwztb+dNIUuregiFJdRN5Q2JZBKlM7Gqb1QtPhtK+xe2pyZPX2SWKIsKA6j3VAThhXsQdj3slXu3dG8FF7j+IFg/eTgpeQIFQQkMIc204ha8OP2ASYAJqgJVbXq8Xh3KkAc1HSrjYJLntryvK10wyU8p3ug370dMu3vRUn44FEyDzXFM9rfsgysQTzVgp+sXdRfMLeyvf+SUrE8hiPjzevF2nsUP0Xf/rIaK5VayChPLXJkulognINzvuVWAdwNPDLpgGwkjglF2681Ag88bLX allesmoeglicheundvielmehr@hotmail.de"
];
packages = with pkgs; [ ffmpeg ];
};
moira = {
schweby = {
uid = 1004;
shell = pkgs.fish;
isNormalUser = true;
extraGroups = [ "wheel" "cdrom" ];
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJrcJRF71+XM5YZj+SaSiGcdVZ0IDxGBXIWssDtHiTtr moira_2022_06"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINUa7NLrRqQ3j4KSGIw0vSvLMTO0gSZeCypQnJ/Viqm8 openpgp:0xBE0BE8A3"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL6JWi0MBDz0Zy4zjauQv28xYmHyapb8D4zeesq91LLE schweby@txsbcct"
];
hashedPassword = "$6$zkAsaVdmIduqZxez$GY9aBlYeP41F0it/VbbZzLLLRQhHAbDdFsa3e/1GS9McTuSimMHODg6HqNVEH1zSqD3afhK/0UHfqbtF5qpi90";
};
stuebinm = {
uid = 1005;
isNormalUser = true;
extraGroups = [ "wheel" ];
shell = pkgs.fish;
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG7J3peZGB4XGJKI1dV5PdpQS+TzmoJ7qL//ipCG7G5K stuebinm@surltesh-echer"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKPB74xA2GBXnDwPEEaxWLONdQyBwjDoJHYagKRQXwO2 stuebinm@abbenay"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH8e9WrHsknoFwBm/YaigOSz9VI8dXRRR5G9BX4kKt9/ stuebinm@ilex"
];
};
leah2 = {
uid = 1006;
shell = pkgs.fish;
isNormalUser = true;
extraGroups = [ "wheel" "cdrom" ];
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK4o/ncaQUorp/BeZesPnVhzvfoqLJW3WZHtz+CWQvFU"
];
};
floppy = {
uid = 1007;
shell = pkgs.fish;
isNormalUser = true;
extraGroups = [ "wheel" "cdrom" ];
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDyVQhFDcoMnoYivQu1h8NCTWa+2WriZ1m5BilkuUk4u"
];
};
};
}

7
default.nix Normal file
View file

@ -0,0 +1,7 @@
rec {
sources = import ./nix/sources.nix;
pkgs = import ./pkgs {};
inherit (pkgs) lib;
inherit (import (sources.nix-hexchen + "/lib/hosts.nix") { inherit pkgs; hostsDir = ./hosts; commonImports = [./common]; pkgsPath = ./pkgs; }) hosts groups;
deploy = import (sources.nix-hexchen + "/lib/deploy.nix") { inherit pkgs hosts groups; };
}

33
desktop/default.nix Normal file
View file

@ -0,0 +1,33 @@
{ config, lib, pkgs, ... }:
{
boot.plymouth.enable = true;
nixpkgs.config = {
mumble.speechdSupport = true;
allowUnfree = true;
};
# boot.plymouth.splashBeforeUnlock = true;
users.users.schweby.packages = with pkgs; [
pulsemixer pavucontrol
firefox git kitty j4-dmenu-desktop bemenu
breeze-qt5 mako
mpv youtube-dl
wl-clipboard mumble
xdg_utils
slurp grim libnotify
_1password-gui
# gnome3.nautilus
] ++ (with pkgs; [ alacritty picom feh copyq polybar cinnamon.nemo rofi arandr notepadqq nomacs bat ]);
sound.enable = true;
hardware.pulseaudio = {
enable = true;
package = pkgs.pulseaudioFull;
};
networking.useDHCP = lib.mkDefault true;
hardware.opengl.enable = true;
services.xserver = {
windowManager.bspwm.enable = true;
layout = "de";
};
}

14
desktop/gnome.nix Normal file
View file

@ -0,0 +1,14 @@
{config, lib, pkgs, ...}:
{
services.xserver.displayManager.lightdm = {
enable = true;
};
services.xserver = {
enable = true;
# videoDrivers = [ "nvidia" ];
};
# hardware.nvidia.modesetting.enable = true;
services.xserver.desktopManager.plasma5.enable = true;
}

10
desktop/streaming.nix Normal file
View file

@ -0,0 +1,10 @@
{ config, pkgs, ...}:
{
boot = {
extraModulePackages = with config.boot.kernelPackages; [ v4l2loopback ];
kernelModules = [ "v4l2loopback" ];
};
environment.systemPackages = with pkgs; [ obs-studio ];
}

View file

@ -1,7 +0,0 @@
+++
title = "hacc infra documentation"
page_template = "doc-page.html"
sort_by="title"
+++

View file

@ -1,10 +0,0 @@
+++
title = "Authentication"
categories = [ "services", "uffd" ]
+++
We use [uffd](https://git.cccv.de/uffd/uffd) for our SSO, for better or worse.
Mostly for worse.

View file

@ -1,20 +0,0 @@
+++
title = "Domains"
categories = [ "domains", "meta" ]
+++
Perhaps too many of them.
## Domains
| domain | mc | status | date | reseller | owner | custody |
| :------------------- | :-: | :-----: | :------: | :---------- | :--------- | :-----: |
| 4future.dev | yes | | | | | hacc e.V. |
| infra4future.de | yes | | | | | hacc e.V. |
| hacc.space | yes | | | | | hacc e.V. |
| hacc.earth | yes | | | | | hacc e.V. |
| hacc.media | yes | | | | | hacc e.V. |
| hacc.wiki | no | | | | | |
mc = managed by cloudflare
status = (renewl | autorenewl | expires)

View file

@ -1,16 +0,0 @@
+++
title = "Hostname schema"
+++
[Badass Anarchist Women](https://listverse.com/2018/09/27/10-absolutely-badass-anarchist-women-who-challenged-the-system/)
- keller
- deCleyre
- davidNeel
- leGuin
- [parsons](../parsons)
- ohair
- berneri
- michel
- sanger
- goldman

View file

@ -1,17 +0,0 @@
+++
title = "LXC"
categories = [ "lxc" ]
+++
Some things don't easily run on NixOS. For these we have LXC containers running
debian.
Right now, only onlyoffice is left.
## Useful commands
- login to a container as root with a usable shell
`lxc-attach -n <name> -- /usr/bin/sudo -i`
- restarting the keycloak and ldap containers
`lxc-stop -n <name> && lxc-start -n <name>`
- restarting their network bridge:
`systemctl restart lxcbr0-netdev.services`

View file

@ -1,18 +0,0 @@
+++
title = "Rebooting Parsons"
categories = [ "nix" ]
+++
## Check integrity after unexpected shutdown
These steps are only required if the server shut down unexpectedly or you suspect tampering.
TODO
## Unlock full disk encryption
Connection to the server via the command listed in the shared password manager.
Only the Vorstand has access to it!
Enter the passwords for dpool and zroot.
If both are correct, you will be disconnected and the server continues the boot sequence.
The server should be up after about minute. Please check all services for availability.

View file

@ -1,21 +0,0 @@
+++
title = "Secrets"
categories = [ "services", "sops" ]
+++
## Secret management
We use [sops-nix](https://github.com/Mic92/sops-nix) to manage secrets which we'd
like to have in Git but don't want to be public. Entries in `secrets.yaml` are
encrypted for each of the age keys listed in `.sops.yaml`, which are themselves
derived from ssh keys.
For the initial set up, please take a look at the sops-nix Readme file.
To edit the secrets file, run `sops secrets.yaml`, which will decrypt the
file & open it in your $EDITOR, then re-encrypt it when you're done.
To add a new key, use `ssh-to-age` to convert your ssh key to age, and add it to
`sops.yaml`. Then do `sops updatekeys secrets.yaml` to re-encrypt the file for
the new set of keys.

View file

@ -1,5 +0,0 @@
+++
title = "Services"
sort_by = "title"
page_template = "doc-page.html"
+++

View file

@ -1,19 +0,0 @@
+++
title = "ACME / letsencrypt"
categories = [ "domain", "https", "ssl", "tls", "Certificates" ]
+++
# Usage
We use the ACME module's nginx integration for basically everything. Beware of
rate limits when redeploying lots of things at once! Let's Encrypt is a little
picky about those.
## Workarounds & peculiar configuration choices
Certs live under `/var/lib/acme/`
If you need to remove a cert for whatever reason, be aware that there is a
hidden `.lego` folder, that contains state as well

View file

@ -1,68 +0,0 @@
+++
title = "hedgedoc"
taxonomies.categories = [ "services" ]
+++
hegedoc was once called codiMD, so container, config and users are still called codimd.
**Do NOT change this** unless you're sure what you're doing.
We have two instances:
- `pad-hacc`/pad.hacc.space is connected to our SSO/uffd
- `pad-i4f`/pad.infra4future.de is not connected to our SSO and meant to be more public
## Basic Troubleshooting
Usually if hedgedoc dies, it's because postgresql wasn't there yet. Just restart
hedgedoc.
## More Troubles
log into the container and take a look at the logs
~~~shell
sudo nixos-container root-login codimd
journalctl -e
~~~
### fixing failed database upgrades
see https://docs.hedgedoc.org/guides/migration-troubleshooting/ (copied below
for convenience?):
In some cases, HedgeDoc might apply migrations without correctly saving the
progress. It will then refuse to start with "already exists"-errors like
ERROR: type "enum_Notes_permission" already exists.
Get the name of the failing migration and append .js to it. For example, if
you encounter this error:
~~~
== 20180306150303-fix-enum: migrating =======
ERROR: type "enum_Notes_permission" already exists
~~~
the name of the failed migration would be 20180306150303-fix-enum.js.
The SQL-statement may look like this:
~~~
INSERT INTO "SequelizeMeta" (name) VALUES ('20180306150303-fix-enum.js');
~~~
Make sure HedgeDoc does not run and insert the name into the SequelizeMeta table.
Enter the container switch to the postgres user, open psql and commect to the
codimd database:
~~~shell
su postgres
psql
\l
\c codimd
UN adjusted SQL STAMEMENT from above ]
\q
~~~
Start HedgeDoc again and observe if it starts correctly. It may be necessary to
repeat this process and insert multiple migrations into the SequelizeMeta table.

View file

@ -1,65 +0,0 @@
+++
title = "mail"
taxonomies.categories = [ "services" ]
+++
Mail is not connected to our SSO!
## adding a mail account
- We use `@hacc.space` for our mails
- `@infra4future.de` is reserved for services, old user accounts will be
forwarded & logins disabled
- choose a name (no aliases or other names can be the same)
- generate a sha-512 password hash ```mkpasswd -m sha-512``` - **never add an
unhashed password!**
- add your account to `loginAccounts =` in `//parsons/mail.nix`
- build and redeploy parsons
**example:**
```
zwoelfontheshelf@hacc.space" = {
hashedPassword = "$6$ISAaU8X6D$oGKe9WXDWrRpGzHUEdxrxdtgvzuGOkBMuDc82IZhegpsv1bqd550FhZZrI40IjZTA5Hy2MZ8j/0efpnQ4fOQH0";
};
```
## adding to a forward address
- add the mail address to the corresponding `extraVirtualAliases =`
- build and redeploy parsons
## adding a forward address
- add the address to `extraVirtualAliases =`
- add the addresses it should forward to
- build and redeploy parsons
**example:**
```
"himmel@hacc.space" = [
"hexchen@hacc.space"
"zauberberg@hacc.space"
];
```
## sending & receiving mail
### as a user
- Your mail client should auto configure correctly
~~~
mailserver: mail.hacc.space (everywhere)
username: $your_mail_address
sending via smtp: port 587 or 465
recieving
imap: port 993
TLS and STARTTLS are supported
~~~
- You can send mail as you and any alias you receive mail from. Set a second Identity in your e-mail client
### as an application
- mailserver: `mail.hacc.space`
- Do **not** use port 25. It's for server to server communication only.
- Use smtp ports `587` or `465`
- enable TLS if possible
- only send mail from `noreply@infra4future.de`
- Password is somewhere (TODO!)

View file

@ -1,40 +0,0 @@
+++
title = "mumble"
taxonomies.categories = [ "mumble" ]
+++
[offical Docmuentation](https://wiki.mumble.info/wiki/Main_Page)
Mumble's server is called murmur, but the naming is inconsistent. Sometimes
it's also just called mumble server.
# Usage
## registration
Users need to be registered to join any other channel than public.
An already registered user has to register them with the server.
1. right click on the username
2. choose register in the menu. Done.
## restricted channels
Every channel in the hacc category except for plenum can only be accessed by
members of the hacc group.
## adding users to a group
Only admins can edit groups, and only registered users can be added to groups.
1. right click on the Root channel
2. select Edit...
2. In Groups select $groupname
3. make the change you want to make
4. click "OK"
# Config details
- the server is not registered with mumble & not on the public server list
- the bitrate is set to 128kb/s; otherwise the client would complain that the
server bitrate is less then the configured (default) in its local settings
# Hacks
- murmur needs a TLS cert, which we get via the ACME module
- there's a funny group setup so that hopefully murmurd can read the cert
- this seems to work fine now, but was some source of trouble in the past

View file

@ -1,18 +0,0 @@
+++
title = "$Service Name"
draft = true ## Remove this line to make file appear on website
+++
<general information & pointers to official documentation>
# Usage
<usage from an admin's perspective>
# Config Notes
<what should one keep in mind when reading the nix file?>
## Updating
<anything to keep in mind?>
# Hacks
<ugly things which might break or cause general ???? states>

View file

@ -1,24 +0,0 @@
+++
title = "Use ZFS snapshot"
taxonomies.categories = [ "zfs", "snapshot", "filesystem", "backup", "update", "upgrade" ]
+++
## Make a ZFS snapshot
~~~shell
sudo zfs snapshot zroot/safe/persist@<name>
~~~
## Rollback
### single files
The snapshots can be accessed under `<mountpoint>/.zfs/snapshot/...`
### fully
~~~shell
sudo zfs rollback zroot/safe/persist@<name>
~~~
## Delete a ZFS snapshot
~~~shell
sudo zfs destroy zroot/safe/persist@<name>
~~~

View file

@ -1,229 +0,0 @@
{
"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"
}
},
"deploy-rs": {
"inputs": {
"flake-compat": "flake-compat",
"nixpkgs": [
"nixpkgs"
],
"utils": "utils"
},
"locked": {
"lastModified": 1727447169,
"narHash": "sha256-3KyjMPUKHkiWhwR91J1YchF6zb6gvckCAY1jOE+ne0U=",
"owner": "serokell",
"repo": "deploy-rs",
"rev": "aa07eb05537d4cd025e2310397a6adcedfe72c76",
"type": "github"
},
"original": {
"owner": "serokell",
"repo": "deploy-rs",
"type": "github"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1696426674,
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"nixos-mailserver": {
"inputs": {
"blobs": "blobs",
"flake-compat": [
"deploy-rs",
"flake-compat"
],
"nixpkgs": [
"nixpkgs-unstable"
],
"nixpkgs-24_05": "nixpkgs-24_05"
},
"locked": {
"lastModified": 1734370678,
"narHash": "sha256-a8zkti1QM5Oxkdfnzr/NjrFlyqI36/kYV/X8G1jOmB4=",
"owner": "simple-nixos-mailserver",
"repo": "nixos-mailserver",
"rev": "c43d8c4a3ce84a7bebd110b06e69365484db6208",
"type": "gitlab"
},
"original": {
"owner": "simple-nixos-mailserver",
"ref": "master",
"repo": "nixos-mailserver",
"type": "gitlab"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1734298236,
"narHash": "sha256-aWhhqY44xBjMoO9r5fyPp5u8tqUNWRZ/m/P+abMSs5c=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "eb919d9300b6a18f8583f58aef16db458fbd7bec",
"type": "github"
},
"original": {
"id": "nixpkgs",
"ref": "nixos-24.11-small",
"type": "indirect"
}
},
"nixpkgs-24_05": {
"locked": {
"lastModified": 1731797254,
"narHash": "sha256-df3dJApLPhd11AlueuoN0Q4fHo/hagP75LlM5K1sz9g=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "e8c38b73aeb218e27163376a2d617e61a2ad9b59",
"type": "github"
},
"original": {
"id": "nixpkgs",
"ref": "nixos-24.05",
"type": "indirect"
}
},
"nixpkgs-oldstable": {
"locked": {
"lastModified": 1678761643,
"narHash": "sha256-tapXZvg6Kg5Fm7Fm6i+7cRC5Exp2lX7cgMrqsfrGhuc=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "c4aec3c021620d98861639946123214207e98344",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "c4aec3c021620d98861639946123214207e98344",
"type": "github"
}
},
"nixpkgs-unstable": {
"locked": {
"lastModified": 1734318609,
"narHash": "sha256-VPbVfHSvFs58T+kbseS7wa9WP6p2z7RJmjTnV4pAPQ0=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "66cdf593c0041cf1efc9b2889d80c9a5c497b284",
"type": "github"
},
"original": {
"id": "nixpkgs",
"ref": "nixos-unstable-small",
"type": "indirect"
}
},
"root": {
"inputs": {
"deploy-rs": "deploy-rs",
"nixos-mailserver": "nixos-mailserver",
"nixpkgs": "nixpkgs",
"nixpkgs-oldstable": "nixpkgs-oldstable",
"nixpkgs-unstable": "nixpkgs-unstable",
"sops-nix": "sops-nix",
"tracktrain": "tracktrain"
}
},
"sops-nix": {
"inputs": {
"nixpkgs": [
"nixpkgs-unstable"
]
},
"locked": {
"lastModified": 1733965552,
"narHash": "sha256-GZ4YtqkfyTjJFVCub5yAFWsHknG1nS/zfk7MuHht4Fs=",
"owner": "Mic92",
"repo": "sops-nix",
"rev": "2d73fc6ac4eba4b9a83d3cb8275096fbb7ab4004",
"type": "github"
},
"original": {
"owner": "Mic92",
"repo": "sops-nix",
"type": "github"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"tracktrain": {
"flake": false,
"locked": {
"lastModified": 1720213096,
"narHash": "sha256-GrSXD6WvyiXcHx1s+48PEZVn/MTtBJAXpgds+NdEL2g=",
"ref": "main",
"rev": "2943327863bfe5c6e793e5c40e473a2755d45642",
"revCount": 126,
"type": "git",
"url": "https://stuebinm.eu/git/tracktrain"
},
"original": {
"ref": "main",
"type": "git",
"url": "https://stuebinm.eu/git/tracktrain"
}
},
"utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1701680307,
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

View file

@ -1,88 +0,0 @@
{
description = "hacc infra stuff";
inputs = {
nixpkgs.url = "nixpkgs/nixos-24.11-small";
nixpkgs-unstable.url = "nixpkgs/nixos-unstable-small";
nixpkgs-oldstable.url = "github:/NixOS/nixpkgs?rev=c4aec3c021620d98861639946123214207e98344";
nixos-mailserver.url = "gitlab:simple-nixos-mailserver/nixos-mailserver/master";
tracktrain.url = "git+https://stuebinm.eu/git/tracktrain?ref=main";
tracktrain.flake = false;
deploy-rs.url = "github:serokell/deploy-rs";
deploy-rs.inputs.nixpkgs.follows = "nixpkgs";
sops-nix.url = "github:Mic92/sops-nix";
sops-nix.inputs.nixpkgs.follows = "nixpkgs-unstable";
# these exist mostly to make the flake.lock somewhat more human-friendly
# note that in theory doing this might break things, but it seems fairly unlikely
nixos-mailserver.inputs = {
nixpkgs.follows = "nixpkgs-unstable";
flake-compat.follows = "/deploy-rs/flake-compat";
};
};
outputs = { self, nixpkgs, deploy-rs, sops-nix, ... }@inputs:
let modules = {
bindMounts = import ./modules/bindmounts.nix;
nopersist = import ./modules/nopersist.nix;
encboot = import ./modules/encboot.nix;
};
profiles = {
container = import ./modules/container-profile.nix;
};
pkgs = import ./pkgs {
sources = inputs;
system = "x86_64-linux";
config.allowUnfree = true;
};
in {
nixosConfigurations.parsons = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./parsons/configuration.nix
./modules/buildinfo.nix
./modules/containers.nix
sops-nix.nixosModules.sops
{ nixpkgs.pkgs = pkgs; }
];
specialArgs = {
sources = inputs;
inherit modules profiles;
inherit (nixpkgs.lib) nixosSystem;
};
};
deploy.nodes.parsons = {
hostname = "parsons";
profiles.system = {
user = "root";
autoRollback = false;
path = deploy-rs.lib.x86_64-linux.activate.nixos
self.nixosConfigurations.parsons;
};
};
# This is highly advised, and will prevent many possible mistakes
checks = builtins.mapAttrs
(system: deployLib: deployLib.deployChecks self.deploy)
deploy-rs.lib;
apps.x86_64-linux =
let
mkApp = pkg: {
type = "app";
program = pkgs.lib.getExe pkg;
};
websites = pkgs.lib.mapAttrs (name: mkApp)
self.nixosConfigurations.parsons.config.hacc.websites.builders;
in
{ docs = websites."docs.hacc.space"; } // websites;
packages.x86_64-linux = {
inherit (pkgs) mattermost hacc-scripts;
};
};
}

View file

@ -0,0 +1,133 @@
{ config, lib, pkgs, ... }:
{
imports = [
../../common
./encboot.nix
./hardware.nix
./services/murmur.nix
./services/mail.nix
./services/codimd.nix
../../common
# ./wireguard.nix
./services/nginx.nix
# ./k8s.nix
./services/docker.nix
./services/gitlab-runner.nix
./services/lantifa.nix
./services/hasenloch.nix
./services/syncthing.nix
./services/monitoring.nix
./services/workadventure.nix
./services/minecraft.nix
./services/mattermost.nix
];
boot.loader.grub.enable = true;
boot.loader.grub.version = 2;
boot.loader.grub.device = "/dev/sda";
boot.supportedFilesystems = [ "zfs" ];
# stop presumably docker form loading ip_tables and breaking nftables
boot.blacklistedKernelModules = [ "ip_tables" "ip6_tables" ];
# networking
networking.hostName = "hainich";
networking.hostId = "8a58cb2f";
networking.useDHCP = true;
networking.interfaces.enp6s0.ipv4.addresses = [
{
address = "46.4.63.148";
prefixLength = 27;
}
{
address = "46.4.63.158";
prefixLength = 27;
}
];
networking.interfaces.enp6s0.ipv6.addresses = [ {
address = "2a01:4f8:140:84c9::1";
prefixLength = 64;
} ];
networking.defaultGateway = "46.4.63.129";
networking.nameservers = [
"1.1.1.1" "1.0.0.1"
"2606:4700:4700::1111" "2606:4700:4700::1001"
];
networking.defaultGateway6 = {
address = "fe80::1";
interface = "enp6s0";
};
hacc.nftables.nat.enable = true;
networking.nat.internalInterfaces = ["ve-+"];
networking.nat.internalIPs = [ "192.168.100.0/24" "172.17.0.0/16" ];
networking.nat.externalInterface = "enp6s0";
networking.firewall.allowedTCPPorts = [ 22 80 443 ];
# networking.firewall.allowedUDPPorts = [ ... ];
# networking.firewall.enable = false;
# misc
time.timeZone = "UTC";
environment.systemPackages = with pkgs; [
wget vim git
];
services.openssh.enable = true;
services.openssh.ports = [ 22 62954 ];
users.users.root = {
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL6JWi0MBDz0Zy4zjauQv28xYmHyapb8D4zeesq91LLE schweby@txsbcct"
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCvmrk3i04tXfrSlZtHFbG3o6lQgh3ODMWmGDING4TJ4ctidexmMNY15IjVjzXZgQSET1uKLDLITiaPsii8vaWERZfjm3jjub845mpKkKv48nYdM0eCbv7n604CA3lwoB5ebRgULg4oGTi60rQ4trFf3iTkJfmiLsieFBZz7l+DfgeDEjDNSJcrkOggGBrjE5vBXoDimdkNh8kBNwgMDj1kPR/FHDqybSd5hohCJ5FzQg9vzl/x/H1rzJJKYPO4svSgHkYNkeoL84IZNeHom+UEHX0rw2qAIEN6AiHvNUJR38relvQYxbVdDSlaGN3g26H2ehsmolf+U0uQlRAXTHo0NbXNVYOfijFKL/jWxNfH0aRycf09Lu60oY54gkqS/J0GoQe/OGNq1Zy72DI+zAwEzyCGfSDbAgVF7Y3mU2HqcqGqNzu7Ade5oCbLmkT7yzDM3x6IsmT1tO8dYiT8Qv+zFAECkRpw3yDkJkPOxNKg10oM318whMTtM3yqntE90hk= schweby@taxusbaccata"
];
initialHashedPassword = "$6$F316njEF2$GMF4OmPSF6QgZ3P/DblQ/UFMgoo98bztbdw7X0ygvBGC1UMMIc13Vtxjd/ZGRYW/pEHACZZ7sbRZ48t6xhvO7/";
# shell = pkgs.fish;
};
# storage stuffs!
services.zfs = {
autoSnapshot = {
enable = true;
};
autoScrub = {
enable = true;
};
};
boot.kernelPackages = pkgs.linuxPackages;
# services.restic.backups.tardis = {
# passwordFile = "/etc/restic/system";
# s3CredentialsFile = "/etc/restic/system.s3creds";
# paths = [
# "/data"
# "/home"
# "/run/florinori"
# "/var/lib/containers/codimd/var/lib/codimd"
# "/var/lib/containers/codimd/var/backup/postgresql"
# "/var/lib/containers/lantifa/var/lib/mediawiki"
# "/var/lib/containers/lantifa/var/backup/mysql"
# "/var/lib/murmur"
# "/var/lib/syncthing"
# ];
# pruneOpts = [
# "--keep-daily 7"
# "--keep-weekly 5"
# "--keep-monthly 12"
# ];
# repository = "b2:tardis-hainich:system";
# };
# This value determines the NixOS release from which the default
# settings for stateful data, like file locations and database versions
# on your system were taken. Its perfectly fine and recommended to leave
# this value at the release version of the first install of this system.
# Before changing this value read the documentation for this option
# (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
system.stateVersion = "20.03"; # Did you read the comment?
}

28
hosts/hainich/encboot.nix Normal file
View file

@ -0,0 +1,28 @@
{ config, lib, pkgs, ... }:
{
boot.initrd.kernelModules = [ "r8169" ]; # add network card driver
boot.kernelParams = ["ip=:::::enp6s0:dhcp"]; # enable dhcp on primary network interface
boot.initrd.network = {
enable = true;
ssh = {
enable = true;
port = 2222;
# TODO: Modify system config so that this works
# authorizedKeys = with lib; concatLists (mapAttrsToList (name: user: if elem "wheel" user.extraGroups then user.openssh.authorizedKeys.keys else []) config.users.users);
authorizedKeys = config.users.users.root.openssh.authorizedKeys.keys;
hostKeys = [ /run/keys/ecdsa_host ];
};
# TODO: curl some webhook here to alert?
# possibly quite hard to do, we only have limited wget or netcat available
# how this all works:
# when someone logs in via ssh, they are prompted to unlock the zfs volume
# afterwards zfs is killed in order for the boot to progress
# timeout of 120s still applies afaik
postCommands = ''
zpool import zroot
zpool import dpool
echo "zfs load-key -a; killall zfs && exit" >> /root/.profile
'';
};
}

View file

@ -0,0 +1,52 @@
{ config, lib, pkgs, ... }:
{
boot.initrd.availableKernelModules = [ "uhci_hcd" "ahci" "sd_mod" ];
boot.kernelModules = [ "kvm-intel" ];
boot.extraModulePackages = [ ];
fileSystems."/" =
{ device = "zroot/root/nixos";
fsType = "zfs";
};
fileSystems."/nix" =
{ device = "zroot/root/nixos/nix";
fsType = "zfs";
};
fileSystems."/home" =
{ device = "dpool/home";
fsType = "zfs";
};
fileSystems."/var/lib/containers" =
{ device = "dpool/containers";
fsType = "zfs";
};
fileSystems."/var/lib/docker" =
{ device = "dpool/docker";
fsType = "zfs";
};
fileSystems."/var/lib/gitlab-runner" =
{ device = "dpool/gitlab-runner";
fsType = "zfs";
};
fileSystems."/data" =
{ device = "dpool/data";
fsType = "zfs";
};
fileSystems."/boot" =
{ device = "/dev/disk/by-uuid/40125f55-7fe8-4850-902e-b4d6e22f0335";
fsType = "ext2";
};
swapDevices = [ ];
nix.maxJobs = lib.mkDefault 12;
powerManagement.cpuFreqGovernor = lib.mkDefault "ondemand";
}

125
hosts/hainich/k8s.nix Normal file
View file

@ -0,0 +1,125 @@
{ config, pkgs, ... }:
{
services.etcd = {
advertiseClientUrls = [
"https://[2a0d:eb04:8:10::1]:2379"
];
listenClientUrls = [
"https://[2a0d:eb04:8:10::1]:2379"
];
listenPeerUrls = [
"https://[::1]:2380"
];
};
services.kubernetes = {
roles = [ "master" "node" ];
flannel.enable = false;
addons.dns = {
enable = true;
clusterIp = "2a0d:eb04:8:11::53";
reconcileMode = "EnsureExists";
};
pki.cfsslAPIExtraSANs = [ "hainich.hacc.space" ];
apiserver = {
advertiseAddress = "2a0d:eb04:8:10::1";
extraSANs = [
"2a0d:eb04:8:10::1" "2a0d:eb04:8:11::1" "hainich.hacc.space"
];
bindAddress = "::";
insecureBindAddress = "::1";
etcd = {
servers = [ "https://[2a0d:eb04:8:10::1]:2379" ];
};
serviceClusterIpRange = "2a0d:eb04:8:11::/120";
extraOpts = "--allow-privileged=true";
};
controllerManager = {
bindAddress = "::";
clusterCidr = "2a0d:eb04:8:12::/64";
};
kubelet = {
address = "::";
clusterDns = "2a0d:eb04:8:11::53";
};
proxy = {
bindAddress = "::";
};
scheduler = {
address = "::1" ;
};
apiserverAddress = "https://[2a0d:eb04:8:10::1]:6443";
clusterCidr = "2a0d:eb04:8:12::/64";
easyCerts = true;
masterAddress = "hainich.hacc.space";
};
networking.firewall = {
allowedTCPPorts = [ 80 443 6443 ];
trustedInterfaces = [
"cbr0" "tunnat64"
];
extraCommands = ''
iptables -t nat -A POSTROUTING -o enp6s0 -j SNAT --to 46.4.63.158
iptables -A FORWARD -i tunnat64 -j ACCEPT
iptables -t nat -A PREROUTING -p tcp -d 46.4.63.158 --dport 80 -j DNAT --to-destination 10.255.255.2:80
iptables -t nat -A PREROUTING -p tcp -d 46.4.63.158 --dport 443 -j DNAT --to-destination 10.255.255.2:443
iptables -t nat -A PREROUTING -p tcp -d 46.4.63.158 --dport 6443 -j DNAT --to-destination 10.255.255.1:443
ip6tables -A FORWARD -i tunnat64 -j ACCEPT
ip6tables -A INPUT -i tunnat64 -j ACCEPT
'';
extraStopCommands = ''
iptables -t nat -D POSTROUTING -o enp6s0 -j SNAT --to 46.4.63.158
iptables -D FORWARD -i tunnat64 -j ACCEPT
iptables -t nat -D PREROUTING -p tcp -d 46.4.63.158 --dport 80 -j DNAT --to-destination 10.255.255.2:80
iptables -t nat -D PREROUTING -p tcp -d 46.4.63.158 --dport 443 -j DNAT --to-destination 10.255.255.2:443
iptables -t nat -D PREROUTING -p tcp -d 46.4.63.158 --dport 6443 -j DNAT --to-destination 10.255.255.1:443
ip6tables -A FORWARD -i tunnat64 -j ACCEPT
ip6tables -A INPUT -i tunnat64 -j ACCEPT
'';
};
systemd.services.tayga = (let
config = pkgs.writeText "tayga.conf" ''
tun-device tunnat64
ipv4-addr 10.255.255.254
prefix 2a0d:eb04:8:10:64::/96
dynamic-pool 10.255.255.0/24
map 10.255.255.1 2a0d:eb04:8:10::1
map 10.255.255.2 2a0d:eb04:8:11::2
strict-frag-hdr 1
'';
startScript = pkgs.writeScriptBin "tayga-start" ''
#! ${pkgs.runtimeShell} -e
${pkgs.iproute}/bin/ip link set up tunnat64 || true
${pkgs.iproute}/bin/ip route add 10.255.255.0/24 dev tunnat64 || true
${pkgs.iproute}/bin/ip -6 route add 2a0d:eb04:8:10:64::/96 dev tunnat64 || true
${pkgs.tayga}/bin/tayga -d --config ${config}
'';
in {
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
serviceConfig = {
ExecStart = ''${startScript}/bin/tayga-start'';
};
});
networking.interfaces.cbr0.ipv6.routes = [{
address = "2a0d:eb04:8:10::";
prefixLength = 60;
}];
networking.interfaces.tunnat64 = {
virtual = true;
};
# openebs expects some stuff to be there.
system.activationScripts.openebs = ''
mkdir -p /usr/lib /usr/sbin
ln -sf ${pkgs.zfs.lib}/lib/* /usr/lib/
ln -sf ${pkgs.zfs}/bin/zfs /usr/sbin/
'';
}

View file

@ -0,0 +1,85 @@
{ config, lib, pkgs, ... }:
{
containers.codimd = {
privateNetwork = true;
hostAddress = "192.168.100.1";
localAddress = "192.168.100.3";
autoStart = true;
config = { config, lib, pkgs, ... }: {
networking.firewall.enable = false;
services.coredns = {
enable = true;
config = ''
.:53 {
forward . 1.1.1.1
}
'';
};
services.hedgedoc = {
enable = true;
configuration = {
allowAnonymous = true;
allowFreeURL = true;
allowGravatar = false;
allowOrigin = [ "localhost" "pad.hacc.space" "fff-muc.de" ];
dbURL = "postgres://codimd:codimd@localhost:5432/codimd";
defaultPermission = "limited";
domain = "pad.hacc.space";
host = "0.0.0.0";
protocolUseSSL = true;
hsts.preload = false;
email = false;
oauth2 = {
authorizationURL = "https://auth.infra4future.de/auth/realms/forfuture/protocol/openid-connect/auth";
tokenURL = "https://auth.infra4future.de/auth/realms/forfuture/protocol/openid-connect/token";
clientID = "codimd";
clientSecret = "1a730af1-4d6e-4c1d-8f7e-72375c9b8d62";
};
};
};
systemd.services.hedgedoc.environment = {
"CMD_OAUTH2_USER_PROFILE_URL" = "https://auth.infra4future.de/auth/realms/forfuture/protocol/openid-connect/userinfo";
"CMD_OAUTH2_USER_PROFILE_USERNAME_ATTR" = "name";
"CMD_OAUTH2_USER_PROFILE_DISPLAY_NAME_ATTR" = "display-name";
"CMD_OAUTH2_USER_PROFILE_EMAIL_ATTR" = "email";
"CMD_OAUTH2_PROVIDERNAME" = "Infra4Future";
};
services.postgresql = {
enable = true;
ensureDatabases = [ "codimd" ];
ensureUsers = [{
name = "codimd";
ensurePermissions = {
"DATABASE codimd" = "ALL PRIVILEGES";
};
}];
};
services.postgresqlBackup = {
enable = true;
databases = [ "codimd" ];
startAt = "*-*-* 23:45:00";
};
};
};
services.nginx.virtualHosts."pad.hacc.space" = {
forceSSL = true;
enableACME = true;
locations."/" = {
proxyPass = "http://192.168.100.3:3000";
extraConfig = ''
proxy_pass_request_headers on;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
add_header Access-Control-Allow-Origin "*";
proxy_buffering off;
'';
};
};
}

View file

@ -0,0 +1,32 @@
{ config, lib, pkgs, ... }:
{
virtualisation.oci-containers.containers."ghost-waszumfff" = {
autoStart = true;
environment = {
url = "https://waszumfff.4future.dev";
};
image = "ghost:alpine";
ports = [ "127.0.0.1:2368:2368" ];
volumes = [ "/run/florinori:/var/lib/ghost/content" ];
};
fileSystems."/run/florinori" =
{ device = "dpool/k8s/florinori";
fsType = "zfs";
};
services.nginx.virtualHosts."waszumfff.4future.dev" = {
enableACME = true;
forceSSL = true;
locations."/" = {
proxyPass = "http://127.0.0.1:2368";
extraConfig = "
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $http_host;
";
};
};
}

View file

@ -0,0 +1,62 @@
{config, pkgs, lib, ...}:
{
services.gitlab-runner = {
enable = true;
concurrent = 4;
services = {
infra4future = {
buildsDir = "/var/lib/gitlab-runner/builds";
dockerImage = "nixos/nix";
executor = "docker";
registrationConfigFile = "/etc/gitlab-runner/gitlab-runner.env";
};
nix = {
registrationConfigFile = "/etc/gitlab-runner/gitlab-runner.env";
dockerImage = "alpine";
dockerVolumes = [
"/nix/store:/nix/store:ro"
"/nix/var/nix/db:/nix/var/nix/db:ro"
"/nix/var/nix/daemon-socket:/nix/var/nix/daemon-socket:ro"
];
dockerDisableCache = true;
preBuildScript = pkgs.writeScript "setup-container" ''
mkdir -p -m 0755 /nix/var/log/nix/drvs
mkdir -p -m 0755 /nix/var/nix/gcroots
mkdir -p -m 0755 /nix/var/nix/profiles
mkdir -p -m 0755 /nix/var/nix/temproots
mkdir -p -m 0755 /nix/var/nix/userpool
mkdir -p -m 1777 /nix/var/nix/gcroots/per-user
mkdir -p -m 1777 /nix/var/nix/profiles/per-user
mkdir -p -m 0755 /nix/var/nix/profiles/per-user/root
mkdir -p -m 0700 "$HOME/.nix-defexpr"
. ${pkgs.nix}/etc/profile.d/nix.sh
${pkgs.nix}/bin/nix-env -i ${lib.concatStringsSep " " (with pkgs; [ nix cacert git openssh ])}
${pkgs.nix}/bin/nix-channel --add https://nixos.org/channels/nixpkgs-unstable
${pkgs.nix}/bin/nix-channel --update nixpkgs
'';
environmentVariables = {
ENV = "/etc/profile";
USER = "root";
NIX_REMOTE = "daemon";
PATH = "/nix/var/nix/profiles/default/bin:/nix/var/nix/profiles/default/sbin:/bin:/sbin:/usr/bin:/usr/sbin";
NIX_SSL_CERT_FILE = "/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt";
};
tagList = [ "nix" ];
};
};
};
systemd.services.gitlab-runner.serviceConfig = {
DynamicUser = lib.mkForce false;
User = "gitlab-runner";
};
users.users.gitlab-runner = {
home = "/var/lib/gitlab-runner";
extraGroups = [ "docker" ];
isSystemUser = true;
};
virtualisation.docker.storageDriver = "zfs";
}

View file

@ -0,0 +1,92 @@
{ pkgs, config, ...}:
{
containers.hasenloch = {
autoStart = true;
privateNetwork = true;
hostAddress = "192.168.100.5";
localAddress = "192.168.100.7";
config = { pkgs, config2, ...}: {
services.engelsystem = {
enable = true;
package = pkgs.engelsystem.overrideAttrs (oldAttrs: rec {
version = "3.1.1-r2r";
src = pkgs.fetchzip {
url = "https://schwe.by/files/engelsystem2.zip";
sha256 = "0kqididzlslzrcpx89pf57008lh040ghhhab83sz28zabsm9945q";
};
});
domain = "himmel.hacc.earth";
config = {
url = "https://himmel.hacc.earth";
trusted_proxies = [ "${config.containers.hasenloch.hostAddress}/31" ];
rewrite_urls = true;
app_name = "Hasenloch";
footer_items = {
FAQ = "TODO";
Contact = "TODO";
};
signup_requires_arrival = true;
enable_dect = true;
enable_pronoun = true;
enable_tshirt_size = false;
night_shifts.enabled = false;
autoarrive = true;
theme = 15;
database = {
database = "engelsystem";
host = "localhost";
username = "engelsystem";
};
email = {
driver = "smtp";
encryption = "tls";
from = {
address = "noreply@infra4future.de";
name = "divoc Hasenloch";
};
host = "mail.hacc.space";
password = {
_secret = "/var/keys/engelsystem/mail";
};
port = 587;
username = "noreply@infra4future.de";
};
};
};
networking.firewall.allowedTCPPorts = [ 80 ];
networking.firewall.enable = false;
services.coredns = {
enable = true;
config = ''
.:53 {
forward . 1.1.1.1
}
'';
};
};
};
services.nginx.recommendedProxySettings = true;
services.nginx.virtualHosts."himmel.hacc.earth" = {
locations."/".proxyPass = "http://" + config.containers.hasenloch.localAddress;
forceSSL = true;
enableACME = true;
};
networking.nat.enable = true;
networking.nat.internalInterfaces = ["ve-hasenloch"];
networking.nat.externalInterface = "enp6s0";
}

View file

@ -0,0 +1,97 @@
{ config, lib, pkgs, ... }:
let
unstable = import (import ../../../nix/sources.nix).nixpkgs-unstable {};
in {
containers.lantifa = {
autoStart = true;
privateNetwork = true;
hostAddress6 = "fd00::42:14";
localAddress6 = "fd00::42:15";
config = {config, pkgs, ... }: {
networking.hosts."::1" = [ "wiki.lantifa.org" ];
networking.firewall.enable = false;
users.users.mediawiki.extraGroups = [ "keys" ];
services.mediawiki = {
enable = true;
name = "LANtifa";
package = unstable.mediawiki;
database.createLocally = true;
passwordFile = "/var/lib/mediawiki/mediawiki-password";
extraConfig = let
wikidb = pkgs.fetchzip {
url = "http://www.kennel17.co.uk/uploads/testwiki/e/e9/WikiDB.zip";
sha256 = "0d4f2ygglz4w515a7lgw59500q3xmr92xxhsmh8p204yaa769x8v";
};
in ''
// Configure short URLs
$wgScriptPath = "";
$wgArticlePath = "/wiki/$1";
$wgUsePathInfo = true;
require_once('${wikidb}/WikiDB.php');
$wgExtraNamespaces = array( 100 => "Table", 101 => "Table_Talk",);
$wgWikiDBNamespaces = 100;
$wgGroupPermissions['user']['writeapi'] = true;
$wgDefaultUserOptions['visualeditor-enable'] = 1;
$wgLogo = "images/c/c5/LantifaLogoFem0.3.png";
// PageForms config
$wgGroupPermissions['*']['viewedittab'] = false;
$wgGroupPermissions['user']['viewedittab'] = true;
// Moderation setting
$wgModerationNotificationEnable = true;
$wgModerationEmail = "wiki_mod@lantifa.org";
$wgLogRestrictions["newusers"] = 'moderation';
// intersection / DynamicPageList config
$wgDLPMaxCacheTime = 5 * 60;
'';
extensions = {
TemplateData = null;
VisualEditor = null;
InputBox = null;
Moderation = pkgs.fetchzip {
url = "https://github.com/edwardspec/mediawiki-moderation/archive/v1.4.20.tar.gz";
sha256 = "1k0z44jfqsxzwy6jjz3yfibiq8wi845d5iwwh8j3yijn2854fj0i";
};
intersection = pkgs.fetchzip { # This is the DynamicPageList extension
url = "https://extdist.wmflabs.org/dist/extensions/intersection-REL1_35-f657385.tar.gz";
sha256 = "0f4bpxdfj5k4ll56s3i6cpgcpfalsff307shdhqhrbl0n3kbr3q0";
};
PageForms = pkgs.fetchzip {
url = "https://github.com/wikimedia/mediawiki-extensions-PageForms/archive/5.0.1.zip";
sha256 = "172m7p941fbkl29h5bhanx3dn42jfmzgyvgmgm2lgdbmkawwly96";
};
};
virtualHost = {
hostName = "wiki.lantifa.org";
listen = [ { port = 80; } ];
adminAddr = "admin@hacc.space";
extraConfig = ''
RewriteEngine On
RewriteRule ^/?wiki(/.*)?$ %{DOCUMENT_ROOT}/index.php [L]
RewriteRule ^/*$ %{DOCUMENT_ROOT}/index.php [L]
'';
};
};
services.mysqlBackup = {
enable = true;
databases = [ "mediawiki" ];
calendar = "*-*-* 23:45:00";
};
};
};
services.nginx.virtualHosts."wiki.lantifa.org" = {
locations."/".proxyPass = "http://[" + config.containers.lantifa.localAddress6 + "]";
forceSSL = true;
enableACME = true;
};
}

View file

@ -0,0 +1,177 @@
{ config, pkgs, lib, ... }:
let
sources = import ../../../nix/sources.nix;
in {
imports = [
sources.nixos-mailserver.outPath
];
mailserver = {
mailDirectory = "/data/mail";
enable = true;
fqdn = "mail.hacc.space";
domains = [ "hacc.space" "hacc.earth" "4future.dev" "4futu.re" "infra4future.de" "discuss.infra4future.de" ];
loginAccounts = {
# "hexchen@hacc.space" = {
# hashedPassword = "$6$x9skYtRp4dgxC$1y8gPC2BuVqG3kJVSMGgzZv0Bg1T9qxcnBWLIDbANy1d//SQ23Y7s3IMYcEPd1/l/MYWD9Y/Qse6HbT5w5Xwq/";
# aliases = [
# "postmaster@hacc.space"
# "abuse@hacc.space"
# ];
# };
"octycs@hacc.space" = {
hashedPassword = "$6$KceTivtJ$58jxhYF6ULfivNsb3Z0J7PnGea0Hs2wTWh3c9FrKRIAmuOD96u2IDgZRCn6P5NrXA0BL.n6HC2RS3r.4JnOmg.";
aliases = [
"markus@hacc.space"
];
};
"raphael@hacc.space" = {
hashedPassword = "$6$QveHpwMcp9mkFVAU$EFuahOrJIxPg.c.WGFHtrP3.onwJYwvP7fiBHHGb9jhosewZ2tEUP.2D3uyDLhd9Cfny6Yp4jDk/Hkjk7/ME1/";
};
"engelsystem@hacc.space" = {
hashedPassword = "$6$5cIAEhJ7af7M$eJBPQc3ONd.N3HKPFpxfG7liZbUXPvWuSpWVgeG7rmsG7f7.Zdxtodvt5VaXoA3AEiv3GqcY.gKHISK/Gg0ib/";
};
"schweby@hacc.space" = {
hashedPassword = "$6$BpYhwcZNrkLhVqK$6FMqA/vUkdV4GBlHLSqS5DRCb/CaLDNeIsBcZ8G30heytS/tJj2Ag7b1ovSltTA4PUfhee3pJrz1BkwkA93vN1";
aliases = [
"postmaster@hacc.space"
"abuse@hacc.space"
"hexchen@hacc.space"
];
};
"zauberberg@hacc.space" = {
hashedPassword = "$6$ISAaU8X6D$oGKe9WXDWrRpGzHUTdxrxdtg9zuGOlBMuDc82IZhegpsv1bqd550FhZZrI40IjZTA5Hy2MZ8j/0efpnQ4fOQH0";
aliases = [
"lukas@hacc.space"
];
};
"talx@hacc.space" = {
hashedPassword = "$6$0hIKRoMJS./JSE$tXizRgphhNM3ZYx216VdRv1OiyZoYXsjGqSudTDu8vB8eZb03Axi31VKV87RXiEGGixdvTsHEKpx032aOzzt31";
};
"unms@hacc.space" = {
hashedPassword = "$6$pYlNP37913$sGE3L722ceP.1Qm5lsffYUN919hPP1xRTrzco3ic3Op21iiknBkOY04eY2l3Um/Bpk/yV89aJD0eaB/5RCbWR1";
};
"noreply@hacc.space" = {
hashedPassword = "$6$YsqMoItITZUzI5wo$5Lejf8XBHRx4LW4VuZ9wJCiBbT4kOV/EZaCdWQ07eVIrkRTZwXWZ5zfsh.olXEFwvpNWN.DBnU.dQc.cC0/ra/";
};
"stuebinm@hacc.space" = {
hashedPassword = "$6$mjrMQG5smqLRlm$WzmbiZnGlEXGT7hj/n2qz0nvVzGyZfMToCyLRi0wErfVEHI7y7jtWoHqIWnpcHAM29UocsIFFsUCb3XqQCwwB.";
};
"newsletter@hacc.space" = {
hashedPassword = "$6$f0xKnQxBInd$zbVIi1lTKWauqW.c8sMNLHNwzn81oQrVOiIfJwPa98n9xWz/NkjuWLYuFpK.MSZwNwP7Yv/a/qaOb9v8qv/.N1";
};
"lenny@hacc.space" = {
hashedPassword = "$6$EZpv9XImv5F3$p2NSoo5gLxh6NnB3/C6wF8knRTuMHqDXYF3BEscaQuk7qok2Z13xKT/6mFvvSKKBnFCuYptgnfGswmoqIzm/1/";
aliases = [
"rinderhacc@hacc.space"
];
};
# service accounts
"gitlab@infra4future.de".hashedPassword = "$6$8vvkYuxv$9xV5WktsqfgM3cWSxonjtaohm7oqvDC5qsgJCJBATwesjTRxd/QTLa7t7teK8Nzyl.Py26xz.NvYowCZQ4aBE1";
"noreply@infra4future.de".hashedPassword = "$6$uaD8bRcT1$gFqhFyu5RUsyUUOG5b.kN.JAJ1rVHvaYhpeRHoMvrERAMgBu1FHu2oDnjTsy.5NKoLc5xpI5uv4Gpy4YbmDmV.";
"discuss@infra4future.de".hashedPassword = "$6$8x8/OlMFjq1$S54jdBh7WjrdC6UtbYAHHzMJak7Ai/CjwmWBBbqh7yRHuZt.mfZrsfBNiL3JKBHE7seQ7JYRU99lJKCU6Aujg/";
};
extraVirtualAliases = {
# address = forward address;
"info@hacc.space" = [
# "hexchen@hacc.space"
"octycs@hacc.space"
"raphael@hacc.space"
"schweby@hacc.space"
"zauberberg@hacc.space"
"stuebinm@hacc.space"
"lenny@hacc.space"
];
"himmel@hacc.space" = [
# "hexchen@hacc.space"
"schweby@hacc.space"
"zauberberg@hacc.space"
];
"admin@hacc.space" = [
# "hexchen@hacc.space"
"schweby@hacc.space"
"zauberberg@hacc.space"
];
"voc@hacc.space" = [
# "hexchen@hacc.space"
"schweby@hacc.space"
"octycs@hacc.space"
"stuebinm@hacc.space"
"zauberberg@hacc.space"
"lenny@hacc.space"
];
"vorstand@hacc.space" = [
"raphael@hacc.space"
"schweby@hacc.space"
"zauberberg@hacc.space"
];
"mitglieder@hacc.space" = [
"raphael@hacc.space"
"schweby@hacc.space"
"zauberberg@hacc.space"
"lenny@hacc.space"
"octycs@hacc.space"
];
};
# Use Let's Encrypt certificates. Note that this needs to set up a stripped
# down nginx and opens port 80.
certificateScheme = 3;
# Enable IMAP and POP3
enableImap = true;
enablePop3 = true;
enableImapSsl = true;
enablePop3Ssl = true;
# Enable the ManageSieve protocol
enableManageSieve = true;
# whether to scan inbound emails for viruses (note that this requires at least
# 1 Gb RAM for the server. Without virus scanning 256 MB RAM should be plenty)
virusScanning = false;
};
services.postfix.submissionOptions.smtpd_sender_restrictions = "reject_non_fqdn_sender,reject_unknown_sender_domain,permit";
services.postfix.submissionsOptions.smtpd_sender_restrictions = "reject_non_fqdn_sender,reject_unknown_sender_domain,permit";
services.postfix.virtual = ''
@4future.dev @hacc.space
@4futu.re @hacc.space
@hacc.earth @hacc.space
@discuss.infra4future.de discuss@infra4future.de
admin@infra4future.de admin@hacc.space
noreply@infra4future.de admin@hacc.space
lukas@infra4future.de zauberberg@hacc.space
info@infra4future.de admin@hacc.space
postmaster@infra4future.de admin@hacc.space
voc@infra4future.de admin@hacc.space
haccvoc@infra4future.de admin@hacc.space
contact@hacc.space info@hacc.space
'';
systemd.services.alps = {
enable = true;
script = "${pkgs.alps}/bin/alps -theme alps imaps://mail.hacc.space:993 smtps://mail.hacc.space:465";
serviceConfig.WorkingDirectory = "${pkgs.alps}/share/alps";
};
services.nginx.virtualHosts."mail.hacc.space" = {
enableACME = true;
forceSSL = true;
locations."/".proxyPass = "http://[::1]:1323";
};
}

View file

@ -1,27 +1,33 @@
{ config, pkgs, lib, ...}:
{config, pkgs, lib, ...}:
{
sops.secrets = {
"mattermost/env" = {};
};
containers.mattermost = {
autoStart = true;
privateNetwork = true;
hostAddress = "192.168.100.30";
localAddress = "192.168.100.31";
hacc.containers.mattermost = {
bindSecrets = true;
bindMounts."/secrets" = {
hostPath = "/var/lib/mattermost/";
isReadOnly = true;
};
config = { config, lib, pkgs, ... }: {
environment.systemPackages = [ pkgs.morph pkgs.pgloader ];
config = {pkgs, config, ...}: {
systemd.services.mattermost.serviceConfig.EnvironmentFile =
lib.mkForce "/secrets/env";
# have to import these here, since container's dont
# inherit imports of their environment.
imports = [ ../../../modules/mattermost.nix ];
services.mattermost = {
# couldn't figure out how to actually overwrite modules, so now
# there's two mattermost modules ...
services.mattermost-patched = {
enable = true;
siteUrl = "https://mattermost.infra4future.de";
siteName = "Mattermost for Future";
siteUrl = "https://mattermost-beta.infra4future.de";
siteName = "Mattermost - Blabla for Future";
listenAddress = "0.0.0.0:3000";
mutableConfig = false;
statePath = "/persist/mattermost";
secretConfig = "/secrets/secrets.json";
extraConfig = {
ServiceSettings = {
@ -48,13 +54,10 @@
EnableSVGs = true;
EnableLaTeX = true;
ThreadAutoFollow = true;
EnableSecurityFixAlert = false;
CollapsedThreads = "default_on";
};
TeamSettings = {
EnableTeamCreation = true;
EnableUserCreation = true;
MaxUsersPerTeam = 250;
EnableOpenServer = false;
EnableUserDeactivation = true;
ExperimentalViewArchivedChannels = true;
@ -63,8 +66,8 @@
LogSettings = {
EnableConsole = true;
ConsoleLevel = "ERROR";
EnableDiagnostics = false;
EnableWebhookDebugging = false;
EnableDiagnostics = true;
EnableWebhookDebugging = true;
};
NotificationLogSettings = {
EnableConsole = true;
@ -82,7 +85,7 @@
EnableFileAttachments = true;
MaxFileSize = 52428800;
DriverName = "local";
Directory = "/persist/mattermost/upload-storage";
Directory = "/var/lib/mattermost/uploads-storage";
EnablePublicLink = true;
PublicLinkSalt = "3k7p3yxdhz6798b3b9openfr9rn3ymwu";
};
@ -98,21 +101,12 @@
EnableSMTPAuth = true;
SMTPUsername = "noreply@infra4future.de";
SMTPServer = "mail.hacc.space";
SMTPPort = "465";
SMTPServerTimeout = 10;
ConnectionSecurity = "TLS";
};
RateLimitSettings.Enable = false;
PrivacySettings = {
ShowEmailAddress = false;
ShowFullName = true;
};
# to disable the extra landing page advertising the app
NativeAppSettings = {
AppDownloadLink = "";
AndroidAppDownloadLink = "";
IosAppDownloadLink = "";
};
SupportSettings = {
TermsOfServiceLink = "https://infra4future.de/nutzungsbedingungen.html";
PrivacyPolicyLink = "https://infra4future.de/nutzungsbedingungen.html";
@ -124,11 +118,11 @@
AnnouncementSettings.EnableBanner = false;
GitLabSettings = {
Enable = true;
Id = "mattermost";
Id = "mattermost-beta";
Scope = "";
AuthEndpoint = "https://login.infra4future.de/oauth2/authorize";
TokenEndpoint = "https://login.infra4future.de/oauth2/token";
UserApiEndpoint = "https://login.infra4future.de/oauth2/userinfo";
AuthEndpoint = "https://auth.infra4future.de/auth/realms/forfuture/protocol/openid-connect/auth";
TokenEndpoint = "https://auth.infra4future.de/auth/realms/forfuture/protocol/openid-connect/token";
UserApiEndpoint = "https://auth.infra4future.de/auth/realms/forfuture/protocol/openid-connect/userinfo";
};
# for some reason, these don't appear to be working; the startup
# process complaines and sets these back to en
@ -144,12 +138,18 @@
Enable = true;
EnableUploads = true;
Plugins = {
bigbluebutton = {
adminonly = false;
base_url = "https://bbb.infra4future.de/bigbluebutton/api";
salt = "zKCsNeaEniC115ynHOsZopgA4iTiJjzgeiPNoCEc";
};
"com.github.matterpoll.matterpoll" = {
experimentalui = true;
trigger = "poll";
};
};
PluginStates = {
bigbluebutton.Enable = true;
"com.github.matterpoll.matterpoll".Enable = true;
};
};
@ -157,9 +157,6 @@
ClusterSettings.Enable = false;
MetricsSettings.Enable = false;
GuestAccountsSettings.Enable = false;
FeatureFlags.CollapsedThreads = true;
SqlSettings.DriverName = "postgres";
SqlSettings.DataSource = "postgres:///mattermost?host=/run/postgresql";
};
# turn of the weirder parts of this module (which insist on passwords
@ -172,40 +169,45 @@
services.postgresql = {
enable = lib.mkForce true; # mattermost sets this to false. wtf.
package = pkgs.postgresql_15;
ensureDatabases = [ "mattermost" ];
ensureUsers = [ {
name = "mattermost";
ensureDBOwnership = true;
ensurePermissions = { "DATABASE mattermost" = "ALL PRIVILEGES"; };
} ];
authentication = lib.mkForce ''
# Generated file; do not edit!
local all all trust
local all all trust
host mattermost mattermost ::1/128 trust
'';
};
services.postgresqlBackup = {
networking.firewall.allowedTCPPorts = [ 3000 ];
services.coredns = {
enable = true;
databases = [ "mattermost" ];
startAt = "*-*-* 23:45:00";
location = "/persist/backups/postgres";
config = ''
.:53 {
forward . 1.1.1.1
}
'';
};
};
};
services.nginx.virtualHosts."mattermost.infra4future.de" = {
services.nginx.virtualHosts."mattermost-beta.infra4future.de" = {
locations."/" = {
proxyPass = "http://${config.containers.mattermost.localAddress}:3000";
proxyWebsockets = true;
extraConfig = ''
# Mattermost CSR Patch
proxy_hide_header Content-Security-Policy;
proxy_hide_header X-Frame-Options;
proxy_redirect off;
'';
};
forceSSL = true;
enableACME = true;
};
networking.nat = {
enable = true;
internalInterfaces = [ "ve-mattermost" ];
externalInterface = "enp6s0";
};
}

View file

@ -0,0 +1,49 @@
{pkgs, lib, config, ...}:
{
nixpkgs.config.allowUnfree = true;
networking.firewall.allowedTCPPorts = [ 25565 ];
services.minecraft-server = {
enable = true;
package = let
version = "16.5-567";
url = "https://papermc.io/api/v2/projects/paper/versions/1.16.5/builds/567/downloads/paper-1.16.5-567.jar";
sha256 = "0193fgxabyzhvidf05lswpgajkq4a0c4n0hcpigqhhsir949yaia";
in (pkgs.minecraft-server.overrideAttrs (old: rec {
name = "minecraft-server-${version}";
inherit version;
src = pkgs.fetchurl {
inherit url sha256;
};
}));
eula = true;
declarative = true;
jvmOpts = "-Xmx1536M -Xms512M";
serverProperties = {
server-port = "25565";
gamemode = "survival";
motd = "NixCraft4future";
max-players = "20";
whitelist = true;
force-gamemode = true;
difficulty = "easy";
allow-flight= false;
pvp = false;
enable-rcon = false;
};
whitelist = {
AaronPirt = "bbb8a319-a0fe-4b7a-bdcc-d7941a7fcfa8";
ACY2003 = "e6caedfb-95de-44b6-bea7-962e765f2b74";
Hexchen = "137ad280-856c-4f27-b258-b263d4e6863b";
laXDer = "98043845-8bac-4d38-a479-d116eea90356";
Naigh = "96dd9a77-2a65-415b-8d48-1f00e146dc42";
Schweby = "a5680c67-1a85-4a9b-81b6-a3a0b7b52467";
wolkenzebratopf = "34f47e5b-3f81-4639-ab6b-97be5e358054";
yan_min = "a2d1b6f2-1b58-4433-be67-f9872c4332f1";
Zauberberg = "4c59c4c3-f16b-4b7e-b707-9a176958e7cf";
};
};
}

View file

@ -0,0 +1,42 @@
{ config, lib, pkgs, ... }:
{
services.prometheus = {
enable = true;
webExternalUrl = "https://stats.hacc.space";
exporters = {
dovecot = {
enable = true;
scopes = [ "user" "global" ];
socketPath = "/var/run/dovecot2/old-stats";
};
nginx.enable = true;
node.enable = true;
postfix = {
enable = true;
systemd.enable = true;
};
rspamd.enable = true;
};
scrapeConfigs = (lib.mapAttrsToList (name: val:
{
job_name = "${name}-${config.networking.hostName}";
static_configs = [{
targets = [ "localhost:${toString val.port}" ];
labels.host = config.networking.hostName;
}];
}
) (lib.filterAttrs (_: val: val.enable) config.services.prometheus.exporters));
};
services.dovecot2.extraConfig = ''
mail_plugins = $mail_plugins old_stats
service old-stats {
unix_listener old-stats {
user = dovecot-exporter
group = dovecot-exporter
}
}
'';
services.nginx.statusPage = true;
}

View file

@ -0,0 +1,48 @@
{ config, lib, pkgs, ... }:
let
mumblesite = pkgs.stdenv.mkDerivation {
name = "mumble.hacc.space-website";
src = pkgs.fetchgit {
url = "https://gitlab.infra4future.de/hacc/infra4future/mumble.infra4future.de";
rev = "597c4a2fa7a146f2fd58924cb2b181d530a2a866";
sha256 = "15vh0xqx0xcm09ij877jxkd6gb5nm2hbmyz47y5019xywa766s3h";
};
buildPhase = ''
${pkgs.jekyll.outPath}/bin/jekyll build
'';
installPhase = ''
mkdir -p $out
cp -r _site/* $out
'';
};
in
{
services.murmur = {
enable = true;
logDays = -1;
welcometext = "Welcome to mumble4future! Brought to you by infra4future. The server is now reachable under mumble.hacc.space, please update your bookmarks.";
sslKey = "/var/lib/acme/mumble.hacc.space/key.pem";
sslCert = "/var/lib/acme/mumble.hacc.space/fullchain.pem";
bandwidth = 128000;
};
networking.firewall.allowedTCPPorts = [ config.services.murmur.port ];
networking.firewall.allowedUDPPorts = [ config.services.murmur.port ];
services.nginx.virtualHosts =
let vhost = {
forceSSL = true;
enableACME = true;
root = mumblesite.outPath;
};
in {
"mumble.infra4future.de" = vhost;
"mumble.hacc.space" = vhost;
};
# set ACLs so that the murmur user can read the certificates
security.acme.certs."mumble.hacc.space".postRun = "setfacl -Rm u:murmur:rX /var/lib/acme/mumble.hacc.space";
}

View file

@ -0,0 +1,109 @@
# TODOs before actually using this
# - change root auth to use adminpassFile
# - figure out how to use multiple pools (do we need this?)
# - how to enable ldap?
#
# Additional notes:
# - there is a services.nextcloud.phpExtraExtensions, which may be
# useful for this, but it's only in nixos-unstable for now
# - there's a services.nextcloud.autoUpdateApps do we trust nextcloud
# enough to enable it, or will everything break if we do?
{pkgs, config, ...}:
{
containers.nextcloud = {
autoStart = true;
privateNetwork = true;
hostAddress6 = "fd00::10:1";
localAddress6 = "fs00::10:2";
config = { pkgs, ... }: {
environment.systemPackages = [ pkgs.htop ];
imports = [ ./nextcloud-module.nix ];
services.nextcloud-patched = {
enable = true;
# must be set manually; may not be incremented by more than one at
# a time, otherwise nextcloud WILL break
package = pkgs.nextcloud21;
hostName = "cloud2.infra4future.de";
config = {
dbtype = "pgsql";
dbuser = "nextcloud";
dbhost = "/run/postgresql"; # nextcloud will add /.s.PGSQL.5432 by itself
dbname = "nextcloud";
# there's also a adminpassFile option, but for testing this seems
# enough (less fiddling with getting the file into a nixos
# container for ad-hoc setups)
adminpass = "root";
adminuser = "root";
};
caching.redis = true;
# multiple pools may be doable using services.phpfpm.pools,
# but i have not tried this yet. The nextcloud module defines a
# pool "nextcloud"
poolSettings = {
pm = "dynamic";
"pm.max_children" = "32";
"pm.max_requests" = "500";
"pm.max_spare_servers" = "4";
"pm.min_spare_servers" = "2";
"pm.start_servers" = "2";
};
extraOptions = ''
'redis' => array(
'host' => '/run/redis/redis.sock',
'port' => 0,
'dbindex' => 0,
'password' => 'secret',
'timeout' => 1.5,
),
'';
};
services.redis = {
enable = true;
unixSocket = "/var/run/redis/redis.sock";
};
services.postgresql = {
enable = true;
ensureDatabases = [ "nextcloud" ];
ensureUsers = [
{ # by default, postgres has unix sockets enabled, and allows a
# system user `nextcloud` to log in without other authentication
name = "nextcloud";
ensurePermissions."DATABASE nextcloud" = "ALL PRIVILEGES";
}
];
};
# ensure that postgres is running *before* running the setup
systemd.services."nextcloud-setup" = {
requires = ["postgresql.service"];
after = ["postgresql.service"];
};
networking.firewall.allowedTCPPorts = [ 80 443 ];
};
};
services.nginx.virtualHosts."cloud2.infra4future.de" = {
locations."/".proxyPass = "http:[${config.containers.nextcloud.localAddress6}]";
enableACME = true;
forceSSL = true;
};
}

View file

@ -0,0 +1,51 @@
{ config, lib, pkgs, ... }:
{
security.acme.acceptTerms = true;
security.acme.email = "info+acme@hacc.space";
services.nginx.enable = true;
services.nginx.package = pkgs.nginx.override {
modules = [ pkgs.nginxModules.rtmp ];
};
# services.nginx.recommendedProxySettings = true;
services.nginx.virtualHosts = let
in {
# let all empty subdomains pointing to hainich return 404
"hainich.hacc.space" = {
default = true;
locations."/".return = "404";
};
"hacc.space" = {
enableACME = true;
forceSSL = true;
locations."/".return = "301 https://hacc.earth";
};
};
networking.firewall.allowedTCPPorts = [ 1935 ];
services.nginx.appendConfig = ''
rtmp {
server {
listen 1935;
application cutiestream {
live on;
allow publish all;
allow play all;
}
application ingest {
live on;
record all;
record_path /data/ingest;
record_unique on;
include /var/secrets/ingest.conf;
}
}
}
'';
systemd.services.nginx.serviceConfig.ReadWriteDirectories = "/data/ingest /var/secrets";
}

View file

@ -0,0 +1,53 @@
{ config, lib, pkgs, ... }:
{
services.syncthing = {
enable = true;
relay.enable = false;
openDefaultPorts = true;
declarative = {
devices = {
# schweby
txsbcct = {
addresses = []; # empty = dynamic
id = "AQHOPTO-X3LWJXZ-2SPLSEW-MCVMX3R-VSLPPYE-NIOTDMW-QOYRSDZ-2LR7RAD";
};
octycs = {
addresses = []; # empty = dynamic
id = "KIJVGWZ-GRXPAUX-ZOTZDLS-KUKANCC-A2IBZRM-BT3RZK7-5M43O6R-OZD5IQE";
};
stuebinm-desktop = {
addresses = []; # empty = dynamic
id = "CWZTKG7-F45LE2O-TIT6IBC-RQD6MLH-K5ECUGJ-LOHJXF3-I2F4R6I-JVMRLAJ";
};
raphael-laptop = {
addresses = []; # empty = dynamic
id = "72B3T74-NOMJV3X-EVJXTJF-5GGAEZB-ZDKBHXQ-VQNRYEU-YCPA2JP-L6NGAAG";
};
# zauberberg
# conway = {
# addresses = []; # empty = dynamic
# id = "HV7IU2N-Q4W3A7F-BSASR43-OB575SM-47FY2UW-7N5GMFM-PX3LWRN-HXBXMQF";
# };
# hexchen
# storah = {
# addresses = [ "tcp://46.4.62.95:22000" "quic://46.4.62.95:22000" ];
# id = "SGHQ2JA-7FJ6CKM-N3I54R4-UOJC5KO-7W22O62-YLTF26F-S7DLZG4-ZLP7HAM";
# };
};
folders = {
"/var/lib/syncthing/hacc" = {
id = "qt2ly-xvvvs";
devices = [ "txsbcct" "octycs" "stuebinm-desktop" "raphael-laptop" ];
type = "receiveonly";
versioning = {
type = "simple";
params.keep = "10";
};
};
};
};
};
}

View file

@ -0,0 +1,116 @@
{pkgs, lib, config, ...}:
let
wa-container-ip = "fd00::42:16";
# this is a static "secret" that is also compiled into workadventure,
# so it seems ok to put it into the nix store
coturn-auth-secret = "990bc6fc68c720a9159f9c7613b2dcc3cc9ffb4f";
# domain on which workadventure is served
domain = "void.hacc.space";
# FUNFACT:
# the nixos-container module is sufficiently broken that if you move these
# fetchgits into the container config below, Nix will run into infinite recursion!
# contains the hacc assembly map
haccpkgssrc = pkgs.fetchgit {
url = "https://gitlab.infra4future.de/stuebinm/workadventure-nix-hacc";
rev = "23a085b0386595f9e769ef3c182749cecc342ead";
sha256 = "199np37dkhk52lsjw0f9x2h9vfi86xs18gk5pfijs6pc1hr11scd";
};
# contains the workadventure module
workadventurenix = pkgs.fetchgit {
url = "https://stuebinm.eu/git/workadventure-nix";
rev = "5d61d1bcb2fe11a3ff469a4f3a1be1885218472d";
sha256 = "0yd46n8vdyszb59rclq5p1m9z6hvrgpq258cic5glnqsnya8885v";
};
haccpkgs = (import "${haccpkgssrc}/default.nix") {inherit pkgs lib;};
in
{
# not the most intuitive of container names, but "workadventure" is too long
containers.wa-void = {
config = {config, pkgs, ...}: {
imports = [ workadventurenix.outPath ];
networking.firewall.allowedTCPPorts = [ 80 ];
services.workadventure."void.hacc.space" = {
packageset = (import "${workadventurenix.outPath}/wapkgs.nix" {inherit pkgs lib;}).workadventure-tabascoeye;
nginx = {
default = true;
inherit domain;
maps = {
serve = true;
path = haccpkgs.workadventure-hacc-rc3-map.outPath + "/";
};
};
frontend.startRoomUrl = "/_/global/void.hacc.space/maps/main.json";
commonConfig = {
webrtc.stun.url = "stun:turn.hacc.space:3478";
webrtc.turn = {
url = "turn:95.217.159.23";
user = "turn";
password = coturn-auth-secret;
};
jitsi.url = "meet.ffmuc.net";
};
};
};
privateNetwork = true;
hostAddress6 = "fd00::42:14";
localAddress6 = wa-container-ip;
autoStart = true;
};
services.coturn = {
enable = true;
realm = "turn.hacc.space";
static-auth-secret = coturn-auth-secret;
use-auth-secret = true;
no-cli = true;
no-tcp-relay = true;
cert = config.security.acme.certs."turn.hacc.space".directory + "full.pem";
pkey = config.security.acme.certs."turn.hacc.space".directory + "key.pem";
};
services.nginx = {
virtualHosts."void.hacc.space" = {
forceSSL = true;
enableACME = true;
locations."/" = {
proxyPass = "http://[${wa-container-ip}]";
proxyWebsockets = true;
};
};
# this isn't actually needed, but acme requires a webserver to serve
# challanges, so I guess it's easier to just define a virtualHost here
virtualHosts."turn.hacc.space" = {
enableACME = true;
forceSSL = true;
};
};
networking.firewall = with config.services.coturn;
let
ports = [ listening-port tls-listening-port ];
in {
allowedTCPPorts = [ 80 ] ++ ports;
allowedUDPPorts = ports;
allowedUDPPortRanges = [
{ from = min-port; to = max-port; }
];
};
}

View file

@ -0,0 +1,34 @@
{ config, lib, pkgs, ... }:
{
systemd.services.wireguard-upstream = {
wants = [ "wg-upstream-key.service" ];
after = [ "wg-upstream-key.service" ];
};
networking.wireguard.interfaces.upstream = {
ips = [ "2a0d:eb04:8:ffff:2::2/128" ];
generatePrivateKeyFile = true;
privateKeyFile = "/etc/wireguard/upstream.key";
listenPort = 51820;
peers = [
{
allowedIPs = [ "::/0" ];
endpoint = "103.105.50.220:51823";
publicKey = "qL5xKnQ7xLbtTvu0VmLBwHExteJBhmCe5S/0ZoXBeXY=";
}
];
postSetup = ''
${pkgs.iproute}/bin/ip addr del dev upstream 2a0d:eb04:8:ffff:2::2/128
${pkgs.iproute}/bin/ip addr add dev upstream 2a0d:eb04:8:ffff:2::2/128 peer 2a0d:eb04:8:ffff:2::1/128
'';
};
networking.interfaces.lo.ipv6 = {
addresses = [{
address = "2a0d:eb04:8:10::1";
prefixLength = 128;
}];
};
networking.defaultGateway6 = {
address = "2a0d:eb04:8:ffff:2::1";
interface = "upstream";
};
}

View file

@ -0,0 +1,51 @@
{ config, pkgs, ... }:
{
imports =
[ # Include the results of the hardware scan.
./hardware-config.nix
../../common
../../desktop
../../desktop/streaming.nix
../../desktop/gnome.nix
];
boot.loader.grub ={
enable = true;
version = 2;
efiSupport = true;
device = "nodev";
};
boot.loader.efi = {
canTouchEfiVariables = true;
efiSysMountPoint = "/boot";
};
hardware.decklink.enable = true;
networking.hostName = "nixda"; # Define your hostname.
environment.systemPackages = with pkgs; [ blackmagicDesktopVideo blender ];
networking.wg-quick.interfaces.cornbox = {
privateKeyFile = "/etc/wireguard/cornbox.key";
address = [ "195.39.247.67/28" "2a0f:4ac0:1337::12/64" ];
postUp = "ip link set dev cornbox mtu 1400";
peers = [
{
allowedIPs = [ "2a0f:4ac0:1337::/48" "195.39.247.64/27" ];
publicKey = "8IWyiQL3wKP9CD/4UdS9b8mcbL67mkUyeSPORgEPvV0=";
endpoint = "cornbox.hetzner.chaoswit.ch:51821";
}
];
};
# This value determines the NixOS release from which the default
# settings for stateful data, like file locations and database versions
# on your system were taken. Its perfectly fine and recommended to leave
# this value at the release version of the first install of this system.
# Before changing this value read the documentation for this option
# (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
system.stateVersion = "20.09"; # Did you read the comment?
}

View file

@ -0,0 +1,31 @@
{ config, lib, pkgs, modulesPath, ... }:
{
imports =
[ (modulesPath + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = [ "nvme" "ehci_pci" "xhci_pci" "ahci" "usb_storage" "usbhid" "sd_mod" "sr_mod" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ "kvm-amd" ];
boot.extraModulePackages = [ ];
fileSystems."/" =
{ device = "/dev/disk/by-uuid/dfbfee26-c2c0-4c0c-b145-6362c7650ac9";
fsType = "btrfs";
options = [ "subvol=@nix" ];
};
fileSystems."/home" =
{ device = "/dev/disk/by-uuid/dfbfee26-c2c0-4c0c-b145-6362c7650ac9";
fsType = "btrfs";
options = [ "subvol=@home" ];
};
fileSystems."/boot" =
{ device = "/dev/disk/by-uuid/A358-97BC";
fsType = "vfat";
};
swapDevices = [ ];
}

View file

@ -1,28 +0,0 @@
{ config, lib, pkgs, ... }:
with lib;
let cfg = config.hacc;
in {
options.hacc.bindMounts = mkOption {
type = types.attrsOf types.str;
default = { };
example = { "/etc/asdf" = "/persist/asdf"; };
};
options.hacc.bindToPersist = mkOption {
type = types.listOf types.str;
default = [];
example = [ "postgres" ];
};
config.fileSystems = mapAttrs (_: device: {
inherit device;
options = [ "bind" ];
}) cfg.bindMounts;
config.hacc.bindMounts = listToAttrs
(map (name: { inherit name; value = "/persist${name}"; })
cfg.bindToPersist);
}

View file

@ -1,29 +0,0 @@
{ config, lib, pkgs, sources, ... }:
let
self = sources.self;
formatDate = date: with lib.strings;
let
year = substring 0 4 date;
month = substring 4 2 date;
day = substring 6 2 date;
hour = substring 8 2 date;
minute = substring 10 2 date;
second = substring 12 2 date;
in
"${year}-${month}-${day} ${hour}:${minute}:${second} UTC";
in
{
system.nixos.label = "${config.system.nixos.release}-haccfiles-${self.shortRev or self.dirtyShortRev}";
users.motd = ''
Welcome to ${config.networking.hostName}, running NixOS ${config.system.nixos.release}!
Built from haccfiles ${self.rev or self.dirtyRev}.
Last commit was at ${formatDate self.lastModifiedDate}.
${if self ? dirtyRev then "\nPlease remember to commit your changes.\n" else ""}
'';
# used by monit
environment.etc."haccfiles-commit".text = self.rev or self.dirtyRev;
environment.etc."haccfiles-timestamp".text = builtins.toString self.lastModified;
}

View file

@ -1,18 +0,0 @@
{ lib, ...}:
{
boot.isContainer = true;
networking.useDHCP = false;
users.users.root.hashedPassword = "";
networking.firewall.enable = false;
services.coredns = {
enable = true;
config = ''
.:53 {
forward . 1.1.1.1
}
'';
};
system.stateVersion = lib.mkDefault "21.05";
}

View file

@ -1,95 +0,0 @@
{ config, lib, pkgs, modules, profiles, sources, nixosSystem, ... }:
let
mkIPv4 = index: local:
"192.168.${if local then "100" else "101"}.${toString index}";
mkIPv6 = index: local:
"fd00::${if local then "100" else "101"}:${toString index}";
evalConfig = nixosConfig: (nixosSystem {
inherit (config.nixpkgs) system;
modules = [
nixosConfig
modules.nopersist
profiles.container
{ nixpkgs.pkgs = lib.mkForce pkgs; }
];
specialArgs = {
inherit modules sources;
};
}).config.system.build.toplevel;
in {
options.hacc.containers = with lib.options;
mkOption {
description = ''
hacc-specific containers. These are a thin wrapper around "normal" nixos containers:
- they automatically get an IPv4/IPv6 address assigned
(note that these are not guaranteed to be stable across config changes,
so please use {option}`containers.<name>.hostAddress` & friends to
reference them elsewhere)
- they set a couple default options (e.g. ephemeral, autoStart, privateNetwork)
- they are evaluated with our own version of {nix}`evalConfig`, which includes a
couple more modules by default, use our version of `nixpkgs`, and includes the
{nix}`profiles.containers` profile setting sane defaults for containers.
'';
default = { };
type = with lib.types;
types.attrsOf (types.submodule {
options = {
bindToPersist = mkOption {
default = true;
type = types.bool;
description =
"Wether to mount /persist/containers/<name> at /persist into this container.";
};
bindSecrets = mkOption {
default = false;
type = types.bool;
description =
"Whether to mount /run/secrets/<name> at /secrets into this container.";
};
config = mkOption {
type = types.unspecified;
description =
"The container's config, to be evaluated with our own {nix}`evalConfig`.";
};
};
});
};
# wrapped into imap1, which enumerates the containers; IP addresses are then
# simply assigned based on the order the containers are in the list.
config.containers = lib.mkMerge (lib.imap1
(index: { name, value }: let container = value; in {
${name} = {
hostAddress = mkIPv4 index false;
localAddress = mkIPv4 index true;
hostAddress6 = mkIPv6 index false;
localAddress6 = mkIPv6 index true;
privateNetwork = true;
autoStart = true;
ephemeral = true;
bindMounts = lib.mkMerge [
(lib.mkIf container.bindToPersist {
"/persist" = {
hostPath = "/persist/containers/${name}";
isReadOnly = false;
};
})
(lib.mkIf container.bindSecrets {
"/secrets" = {
hostPath = "/run/secrets/${name}";
isReadOnly = true;
};
})
];
path = evalConfig container.config;
};
}) (lib.attrsToList config.hacc.containers));
}

21
modules/decklink.nix Normal file
View file

@ -0,0 +1,21 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.hardware.decklink;
kernelPackages = config.boot.kernelPackages;
in
{
options.hardware.decklink.enable = mkEnableOption "Enable hardware support for the Blackmagic Design Decklink audio/video interfaces.";
config = mkIf cfg.enable {
boot.kernelModules = [ "blackmagic" "blackmagic-io" "snd_blackmagic-io" ];
boot.extraModulePackages = [ kernelPackages.decklink ];
systemd.services."DecklinkVideoHelper" = {
after = [ "syslog.target" "local-fs.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig.ExecStart = "${pkgs.blackmagicDesktopVideo}/bin/DesktopVideoHelper -n";
};
};
}

View file

@ -1,7 +1,9 @@
{ ... }:
{
let
sources = import ../nix/sources.nix;
in {
imports = [
./websites.nix
./nftnat
./decklink.nix
];
}

View file

@ -1,45 +0,0 @@
{ config, pkgs, lib, ... }:
with lib;
let cfg = config.hacc.encboot;
in {
options = {
hacc.encboot = {
enable = mkOption {
type = types.bool;
default = false;
};
networkDrivers = mkOption { type = with types; listOf str; };
dataset = mkOption {
type = types.str;
default = "zroot";
};
};
};
config = mkIf cfg.enable {
boot.initrd.kernelModules = cfg.networkDrivers;
boot.initrd.network = {
enable = true;
ssh = {
enable = true;
port = 2222;
authorizedKeys = with lib;
concatLists (mapAttrsToList (name: user:
if elem "wheel" user.extraGroups then
user.openssh.authorizedKeys.keys
else
[ ]) config.users.users);
hostKeys = [ /etc/ssh/encboot_host ];
};
postCommands = ''
zpool import ${cfg.dataset}
echo "zfs load-key -a; killall zfs && exit" >> /root/.profile
'';
};
};
}

257
modules/mattermost.nix Normal file
View file

@ -0,0 +1,257 @@
{ config, pkgs, lib, ... }:
with lib;
let
cfg = config.services.mattermost-patched;
defaultConfig = builtins.fromJSON (builtins.replaceStrings [ "\\u0026" ] [ "&" ]
(readFile "${pkgs.mattermost}/config/config.json")
);
database = "postgres://${cfg.localDatabaseUser}:${cfg.localDatabasePassword}@localhost:5432/${cfg.localDatabaseName}?sslmode=disable&connect_timeout=10";
mattermostConf = foldl recursiveUpdate defaultConfig
[ { ServiceSettings.SiteURL = cfg.siteUrl;
ServiceSettings.ListenAddress = cfg.listenAddress;
TeamSettings.SiteName = cfg.siteName;
SqlSettings.DriverName = "postgres";
SqlSettings.DataSource = database;
}
cfg.extraConfig
];
mattermostConfJSON = pkgs.writeText "mattermost-config-raw.json" (builtins.toJSON mattermostConf);
in
{
options = {
services.mattermost-patched = {
enable = mkEnableOption "Mattermost chat server";
statePath = mkOption {
type = types.str;
default = "/var/lib/mattermost";
description = "Mattermost working directory";
};
siteUrl = mkOption {
type = types.str;
example = "https://chat.example.com";
description = ''
URL this Mattermost instance is reachable under, without trailing slash.
'';
};
siteName = mkOption {
type = types.str;
default = "Mattermost";
description = "Name of this Mattermost site.";
};
listenAddress = mkOption {
type = types.str;
default = ":8065";
example = "[::1]:8065";
description = ''
Address and port this Mattermost instance listens to.
'';
};
mutableConfig = mkOption {
type = types.bool;
default = false;
description = ''
Whether the Mattermost config.json is writeable by Mattermost.
Most of the settings can be edited in the system console of
Mattermost if this option is enabled. A template config using
the options specified in services.mattermost will be generated
but won't be overwritten on changes or rebuilds.
If this option is disabled, changes in the system console won't
be possible (default). If an config.json is present, it will be
overwritten!
'';
};
extraConfig = mkOption {
type = types.attrs;
default = { };
description = ''
Addtional configuration options as Nix attribute set in config.json schema.
'';
};
secretConfig = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Path to a json file containing secret config values, which should
not be written into the Nix store. If it is not null (the default)
and mutableConfig is set to false, then the mattermost service will
join the file at this path into its config.
Note that this file cannot be used to overwrite values already
specified by the other options of this module.
'';
};
localDatabaseCreate = mkOption {
type = types.bool;
default = true;
description = ''
Create a local PostgreSQL database for Mattermost automatically.
'';
};
localDatabaseName = mkOption {
type = types.str;
default = "mattermost";
description = ''
Local Mattermost database name.
'';
};
localDatabaseUser = mkOption {
type = types.str;
default = "mattermost";
description = ''
Local Mattermost database username.
'';
};
localDatabasePassword = mkOption {
type = types.str;
default = "mmpgsecret";
description = ''
Password for local Mattermost database user.
'';
};
user = mkOption {
type = types.str;
default = "mattermost";
description = ''
User which runs the Mattermost service.
'';
};
group = mkOption {
type = types.str;
default = "mattermost";
description = ''
Group which runs the Mattermost service.
'';
};
matterircd = {
enable = mkEnableOption "Mattermost IRC bridge";
parameters = mkOption {
type = types.listOf types.str;
default = [ ];
example = [ "-mmserver chat.example.com" "-bind [::]:6667" ];
description = ''
Set commandline parameters to pass to matterircd. See
https://github.com/42wim/matterircd#usage for more information.
'';
};
};
};
};
config = mkMerge [
(mkIf cfg.enable {
users.users = optionalAttrs (cfg.user == "mattermost") {
mattermost = {
group = cfg.group;
uid = config.ids.uids.mattermost;
home = cfg.statePath;
};
};
users.groups = optionalAttrs (cfg.group == "mattermost") {
mattermost.gid = config.ids.gids.mattermost;
};
services.postgresql.enable = cfg.localDatabaseCreate;
# The systemd service will fail to execute the preStart hook
# if the WorkingDirectory does not exist
system.activationScripts.mattermost = ''
mkdir -p ${cfg.statePath}
'';
systemd.services.mattermost = {
description = "Mattermost chat service";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" "postgresql.service" ];
preStart = ''
mkdir -p ${cfg.statePath}/{data,config,logs}
ln -sf ${pkgs.mattermost}/{bin,fonts,i18n,templates,client} ${cfg.statePath}
'' + lib.optionalString (!cfg.mutableConfig) ''
rm -f ${cfg.statePath}/config/config.json
'' + (if cfg.secretConfig == null
then ''
cp ${mattermostConfJSON} ${cfg.statePath}/config/config.json
''
else ''
${pkgs.jq}/bin/jq -s ".[1] * .[0]" ${cfg.secretConfig} ${mattermostConfJSON} > ${cfg.statePath}/config/config.json
'')
+ ''
${pkgs.mattermost}/bin/mattermost config migrate ${cfg.statePath}/config/config.json ${database}
'' + lib.optionalString cfg.mutableConfig ''
if ! test -e "${cfg.statePath}/config/.initial-created"; then
rm -f ${cfg.statePath}/config/config.json
cp ${mattermostConfJSON} ${cfg.statePath}/config/config.json
touch ${cfg.statePath}/config/.initial-created
fi
'' + lib.optionalString cfg.localDatabaseCreate ''
if ! test -e "${cfg.statePath}/.db-created"; then
${pkgs.sudo}/bin/sudo -u ${config.services.postgresql.superUser} \
${config.services.postgresql.package}/bin/psql postgres -c \
"CREATE ROLE ${cfg.localDatabaseUser} WITH LOGIN NOCREATEDB NOCREATEROLE ENCRYPTED PASSWORD '${cfg.localDatabasePassword}'"
${pkgs.sudo}/bin/sudo -u ${config.services.postgresql.superUser} \
${config.services.postgresql.package}/bin/createdb \
--owner ${cfg.localDatabaseUser} ${cfg.localDatabaseName}
touch ${cfg.statePath}/.db-created
fi
'' + ''
chown ${cfg.user}:${cfg.group} -R ${cfg.statePath}
chmod u+rw,g+r,o-rwx -R ${cfg.statePath}
'';
serviceConfig = {
PermissionsStartOnly = true;
User = cfg.user;
Group = cfg.group;
ExecStart = "${pkgs.mattermost}/bin/mattermost" +
(lib.optionalString (!cfg.mutableConfig) " -c ${database}");
WorkingDirectory = "${cfg.statePath}";
Restart = "always";
RestartSec = "10";
LimitNOFILE = "49152";
};
unitConfig.JoinsNamespaceOf = mkIf cfg.localDatabaseCreate "postgresql.service";
};
})
(mkIf cfg.matterircd.enable {
systemd.services.matterircd = {
description = "Mattermost IRC bridge service";
wantedBy = [ "multi-user.target" ];
serviceConfig = {
User = "nobody";
Group = "nogroup";
ExecStart = "${pkgs.matterircd}/bin/matterircd ${concatStringsSep " " cfg.matterircd.parameters}";
WorkingDirectory = "/tmp";
PrivateTmp = true;
Restart = "always";
RestartSec = "5";
};
};
})
];
}

721
modules/nextcloud.nix Normal file
View file

@ -0,0 +1,721 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.nextcloud-patched;
fpm = config.services.phpfpm.pools.nextcloud;
phpPackage =
let
base = pkgs.php74;
in
base.buildEnv {
extensions = { enabled, all }: with all;
enabled ++ [
apcu redis memcached imagick
];
extraConfig = phpOptionsStr;
};
toKeyValue = generators.toKeyValue {
mkKeyValue = generators.mkKeyValueDefault {} " = ";
};
phpOptions = {
upload_max_filesize = cfg.maxUploadSize;
post_max_size = cfg.maxUploadSize;
memory_limit = cfg.maxUploadSize;
} // cfg.phpOptions
// optionalAttrs cfg.caching.apcu {
"apc.enable_cli" = "1";
};
phpOptionsStr = toKeyValue phpOptions;
occ = pkgs.writeScriptBin "nextcloud-occ" ''
#! ${pkgs.runtimeShell}
cd ${cfg.package}
sudo=exec
if [[ "$USER" != nextcloud ]]; then
sudo='exec /run/wrappers/bin/sudo -u nextcloud --preserve-env=NEXTCLOUD_CONFIG_DIR --preserve-env=OC_PASS'
fi
export NEXTCLOUD_CONFIG_DIR="${cfg.home}/config"
$sudo \
${phpPackage}/bin/php \
occ $*
'';
inherit (config.system) stateVersion;
in {
imports = [
(mkRemovedOptionModule [ "services" "nextcloud-patched" "nginx" "enable" ] ''
The nextcloud module supports `nginx` as reverse-proxy by default and doesn't
support other reverse-proxies officially.
However it's possible to use an alternative reverse-proxy by
* disabling nginx
* setting `listen.owner` & `listen.group` in the phpfpm-pool to a different value
Further details about this can be found in the `Nextcloud`-section of the NixOS-manual
(which can be openend e.g. by running `nixos-help`).
'')
];
options.services.nextcloud-patched = {
enable = mkEnableOption "nextcloud";
hostName = mkOption {
type = types.str;
description = "FQDN for the nextcloud instance.";
};
home = mkOption {
type = types.str;
default = "/var/lib/nextcloud";
description = "Storage path of nextcloud.";
};
logLevel = mkOption {
type = types.ints.between 0 4;
default = 2;
description = "Log level value between 0 (DEBUG) and 4 (FATAL).";
};
https = mkOption {
type = types.bool;
default = false;
description = "Use https for generated links.";
};
package = mkOption {
type = types.package;
description = "Which package to use for the Nextcloud instance.";
relatedPackages = [ "nextcloud18" "nextcloud19" "nextcloud20" "nextcloud21" ];
};
maxUploadSize = mkOption {
default = "512M";
type = types.str;
description = ''
Defines the upload limit for files. This changes the relevant options
in php.ini and nginx if enabled.
'';
};
skeletonDirectory = mkOption {
default = "";
type = types.str;
description = ''
The directory where the skeleton files are located. These files will be
copied to the data directory of new users. Leave empty to not copy any
skeleton files.
'';
};
webfinger = mkOption {
type = types.bool;
default = false;
description = ''
Enable this option if you plan on using the webfinger plugin.
The appropriate nginx rewrite rules will be added to your configuration.
'';
};
phpOptions = mkOption {
type = types.attrsOf types.str;
default = {
short_open_tag = "Off";
expose_php = "Off";
error_reporting = "E_ALL & ~E_DEPRECATED & ~E_STRICT";
display_errors = "stderr";
"opcache.enable_cli" = "1";
"opcache.interned_strings_buffer" = "8";
"opcache.max_accelerated_files" = "10000";
"opcache.memory_consumption" = "128";
"opcache.revalidate_freq" = "1";
"opcache.fast_shutdown" = "1";
"openssl.cafile" = "/etc/ssl/certs/ca-certificates.crt";
catch_workers_output = "yes";
};
description = ''
Options for PHP's php.ini file for nextcloud.
'';
};
poolSettings = mkOption {
type = with types; attrsOf (oneOf [ str int bool ]);
default = {
"pm" = "dynamic";
"pm.max_children" = "32";
"pm.start_servers" = "2";
"pm.min_spare_servers" = "2";
"pm.max_spare_servers" = "4";
"pm.max_requests" = "500";
};
description = ''
Options for nextcloud's PHP pool. See the documentation on <literal>php-fpm.conf</literal> for details on configuration directives.
'';
};
poolConfig = mkOption {
type = types.nullOr types.lines;
default = null;
description = ''
Options for nextcloud's PHP pool. See the documentation on <literal>php-fpm.conf</literal> for details on configuration directives.
'';
};
config = {
dbtype = mkOption {
type = types.enum [ "sqlite" "pgsql" "mysql" ];
default = "sqlite";
description = "Database type.";
};
dbname = mkOption {
type = types.nullOr types.str;
default = "nextcloud";
description = "Database name.";
};
dbuser = mkOption {
type = types.nullOr types.str;
default = "nextcloud";
description = "Database user.";
};
dbpass = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Database password. Use <literal>dbpassFile</literal> to avoid this
being world-readable in the <literal>/nix/store</literal>.
'';
};
dbpassFile = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
The full path to a file that contains the database password.
'';
};
dbhost = mkOption {
type = types.nullOr types.str;
default = "localhost";
description = ''
Database host.
Note: for using Unix authentication with PostgreSQL, this should be
set to <literal>/run/postgresql</literal>.
'';
};
dbport = mkOption {
type = with types; nullOr (either int str);
default = null;
description = "Database port.";
};
dbtableprefix = mkOption {
type = types.nullOr types.str;
default = null;
description = "Table prefix in Nextcloud database.";
};
adminuser = mkOption {
type = types.str;
default = "root";
description = "Admin username.";
};
adminpass = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Admin password. Use <literal>adminpassFile</literal> to avoid this
being world-readable in the <literal>/nix/store</literal>.
'';
};
adminpassFile = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
The full path to a file that contains the admin's password. Must be
readable by user <literal>nextcloud</literal>.
'';
};
extraTrustedDomains = mkOption {
type = types.listOf types.str;
default = [];
description = ''
Trusted domains, from which the nextcloud installation will be
acessible. You don't need to add
<literal>services.nextcloud.hostname</literal> here.
'';
};
trustedProxies = mkOption {
type = types.listOf types.str;
default = [];
description = ''
Trusted proxies, to provide if the nextcloud installation is being
proxied to secure against e.g. spoofing.
'';
};
overwriteProtocol = mkOption {
type = types.nullOr (types.enum [ "http" "https" ]);
default = null;
example = "https";
description = ''
Force Nextcloud to always use HTTPS i.e. for link generation. Nextcloud
uses the currently used protocol by default, but when behind a reverse-proxy,
it may use <literal>http</literal> for everything although Nextcloud
may be served via HTTPS.
'';
};
defaultPhoneRegion = mkOption {
default = null;
type = types.nullOr types.str;
example = "DE";
description = ''
<warning>
<para>This option exists since Nextcloud 21! If older versions are used,
this will throw an eval-error!</para>
</warning>
<link xlink:href="https://www.iso.org/iso-3166-country-codes.html">ISO 3611-1</link>
country codes for automatic phone-number detection without a country code.
With e.g. <literal>DE</literal> set, the <literal>+49</literal> can be omitted for
phone-numbers.
'';
};
};
caching = {
apcu = mkOption {
type = types.bool;
default = true;
description = ''
Whether to load the APCu module into PHP.
'';
};
redis = mkOption {
type = types.bool;
default = false;
description = ''
Whether to load the Redis module into PHP.
You still need to enable Redis in your config.php.
See https://docs.nextcloud.com/server/14/admin_manual/configuration_server/caching_configuration.html
'';
};
memcached = mkOption {
type = types.bool;
default = false;
description = ''
Whether to load the Memcached module into PHP.
You still need to enable Memcached in your config.php.
See https://docs.nextcloud.com/server/14/admin_manual/configuration_server/caching_configuration.html
'';
};
};
autoUpdateApps = {
enable = mkOption {
type = types.bool;
default = false;
description = ''
Run regular auto update of all apps installed from the nextcloud app store.
'';
};
startAt = mkOption {
type = with types; either str (listOf str);
default = "05:00:00";
example = "Sun 14:00:00";
description = ''
When to run the update. See `systemd.services.&lt;name&gt;.startAt`.
'';
};
};
occ = mkOption {
type = types.package;
default = occ;
internal = true;
description = ''
The nextcloud-occ program preconfigured to target this Nextcloud instance.
'';
};
extraOptions = mkOption {
type = types.str;
default = "";
description = ''
Extra options which should be appended to nextcloud's config.php file
'';
};
};
config = mkIf cfg.enable (mkMerge [
{ assertions = let acfg = cfg.config; in [
{ assertion = !(acfg.dbpass != null && acfg.dbpassFile != null);
message = "Please specify no more than one of dbpass or dbpassFile";
}
{ assertion = ((acfg.adminpass != null || acfg.adminpassFile != null)
&& !(acfg.adminpass != null && acfg.adminpassFile != null));
message = "Please specify exactly one of adminpass or adminpassFile";
}
{ assertion = versionOlder cfg.package.version "21" -> cfg.config.defaultPhoneRegion == null;
message = "The `defaultPhoneRegion'-setting is only supported for Nextcloud >=21!";
}
];
warnings = []
++ (optional (cfg.poolConfig != null) ''
Using config.services.nextcloud.poolConfig is deprecated and will become unsupported in a future release.
Please migrate your configuration to config.services.nextcloud.poolSettings.
'')
++ (optional (versionOlder cfg.package.version "18") ''
A legacy Nextcloud install (from before NixOS 20.03) may be installed.
You're currently deploying an older version of Nextcloud. This may be needed
since Nextcloud doesn't allow major version upgrades that skip multiple
versions (i.e. an upgrade from 16 is possible to 17, but not 16 to 18).
It is assumed that Nextcloud will be upgraded from version 16 to 17.
* If this is a fresh install, there will be no upgrade to do now.
* If this server already had Nextcloud installed, first deploy this to your
server, and wait until the upgrade to 17 is finished.
Then, set `services.nextcloud.package` to `pkgs.nextcloud18` to upgrade to
Nextcloud version 18. Please note that Nextcloud 19 is already out and it's
recommended to upgrade to nextcloud19 after that.
'')
++ (optional (versionOlder cfg.package.version "19") ''
A legacy Nextcloud install (from before NixOS 20.09) may be installed.
If/After nextcloud18 is installed successfully, you can safely upgrade to
nextcloud19. If not, please upgrade to nextcloud18 first since Nextcloud doesn't
support upgrades that skip multiple versions (i.e. an upgrade from 17 to 19 isn't
possible, but an upgrade from 18 to 19).
'')
++ (optional (versionOlder cfg.package.version "21") ''
The latest Nextcloud release is v21 which can be installed by setting
`services.nextcloud.package` to `pkgs.nextcloud21`. Please note that if you're
on `pkgs.nextcloud19`, you'll have to install `pkgs.nextcloud20` first.
'');
services.nextcloud-patched.package = with pkgs;
mkDefault (
if pkgs ? nextcloud
then throw ''
The `pkgs.nextcloud`-attribute has been removed. If it's supposed to be the default
nextcloud defined in an overlay, please set `services.nextcloud.package` to
`pkgs.nextcloud`.
''
else if versionOlder stateVersion "20.03" then nextcloud17
else if versionOlder stateVersion "20.09" then nextcloud18
else nextcloud19
);
}
{ systemd.timers.nextcloud-cron = {
wantedBy = [ "timers.target" ];
timerConfig.OnBootSec = "5m";
timerConfig.OnUnitActiveSec = "15m";
timerConfig.Unit = "nextcloud-cron.service";
};
systemd.services = {
# When upgrading the Nextcloud package, Nextcloud can report errors such as
# "The files of the app [all apps in /var/lib/nextcloud/apps] were not replaced correctly"
# Restarting phpfpm on Nextcloud package update fixes these issues (but this is a workaround).
phpfpm-nextcloud.restartTriggers = [ cfg.package ];
nextcloud-setup = let
c = cfg.config;
writePhpArrary = a: "[${concatMapStringsSep "," (val: ''"${toString val}"'') a}]";
overrideConfig = pkgs.writeText "nextcloud-config.php" ''
<?php
${optionalString (c.dbpassFile != null) ''
function nix_read_pwd() {
$file = "${c.dbpassFile}";
if (!file_exists($file)) {
throw new \RuntimeException(sprintf(
"Cannot start Nextcloud, dbpass file %s set by NixOS doesn't exist!",
$file
));
}
return trim(file_get_contents($file));
}
''}
$CONFIG = [
'apps_paths' => [
[ 'path' => '${cfg.home}/apps', 'url' => '/apps', 'writable' => false ],
[ 'path' => '${cfg.home}/store-apps', 'url' => '/store-apps', 'writable' => true ],
],
'datadirectory' => '${cfg.home}/data',
'skeletondirectory' => '${cfg.skeletonDirectory}',
${optionalString cfg.caching.apcu "'memcache.local' => '\\OC\\Memcache\\APCu',"}
'log_type' => 'syslog',
'log_level' => '${builtins.toString cfg.logLevel}',
${optionalString (c.overwriteProtocol != null) "'overwriteprotocol' => '${c.overwriteProtocol}',"}
${optionalString (c.dbname != null) "'dbname' => '${c.dbname}',"}
${optionalString (c.dbhost != null) "'dbhost' => '${c.dbhost}',"}
${optionalString (c.dbport != null) "'dbport' => '${toString c.dbport}',"}
${optionalString (c.dbuser != null) "'dbuser' => '${c.dbuser}',"}
${optionalString (c.dbtableprefix != null) "'dbtableprefix' => '${toString c.dbtableprefix}',"}
${optionalString (c.dbpass != null) "'dbpassword' => '${c.dbpass}',"}
${optionalString (c.dbpassFile != null) "'dbpassword' => nix_read_pwd(),"}
'dbtype' => '${c.dbtype}',
'trusted_domains' => ${writePhpArrary ([ cfg.hostName ] ++ c.extraTrustedDomains)},
'trusted_proxies' => ${writePhpArrary (c.trustedProxies)},
${optionalString (c.defaultPhoneRegion != null) "'default_phone_region' => '${c.defaultPhoneRegion}',"}
${optionalString (cfg.extraOptions != "") cfg.extraOptions}
];
'';
occInstallCmd = let
dbpass = if c.dbpassFile != null
then ''"$(<"${toString c.dbpassFile}")"''
else if c.dbpass != null
then ''"${toString c.dbpass}"''
else ''""'';
adminpass = if c.adminpassFile != null
then ''"$(<"${toString c.adminpassFile}")"''
else ''"${toString c.adminpass}"'';
installFlags = concatStringsSep " \\\n "
(mapAttrsToList (k: v: "${k} ${toString v}") {
"--database" = ''"${c.dbtype}"'';
# The following attributes are optional depending on the type of
# database. Those that evaluate to null on the left hand side
# will be omitted.
${if c.dbname != null then "--database-name" else null} = ''"${c.dbname}"'';
${if c.dbhost != null then "--database-host" else null} = ''"${c.dbhost}"'';
${if c.dbport != null then "--database-port" else null} = ''"${toString c.dbport}"'';
${if c.dbuser != null then "--database-user" else null} = ''"${c.dbuser}"'';
"--database-pass" = dbpass;
${if c.dbtableprefix != null
then "--database-table-prefix" else null} = ''"${toString c.dbtableprefix}"'';
"--admin-user" = ''"${c.adminuser}"'';
"--admin-pass" = adminpass;
"--data-dir" = ''"${cfg.home}/data"'';
});
in ''
${occ}/bin/nextcloud-occ maintenance:install \
${installFlags}
'';
occSetTrustedDomainsCmd = concatStringsSep "\n" (imap0
(i: v: ''
${occ}/bin/nextcloud-occ config:system:set trusted_domains \
${toString i} --value="${toString v}"
'') ([ cfg.hostName ] ++ cfg.config.extraTrustedDomains));
in {
wantedBy = [ "multi-user.target" ];
before = [ "phpfpm-nextcloud.service" ];
path = [ occ ];
script = ''
chmod og+x ${cfg.home}
${optionalString (c.dbpassFile != null) ''
if [ ! -r "${c.dbpassFile}" ]; then
echo "dbpassFile ${c.dbpassFile} is not readable by nextcloud:nextcloud! Aborting..."
exit 1
fi
if [ -z "$(<${c.dbpassFile})" ]; then
echo "dbpassFile ${c.dbpassFile} is empty!"
exit 1
fi
''}
${optionalString (c.adminpassFile != null) ''
if [ ! -r "${c.adminpassFile}" ]; then
echo "adminpassFile ${c.adminpassFile} is not readable by nextcloud:nextcloud! Aborting..."
exit 1
fi
if [ -z "$(<${c.adminpassFile})" ]; then
echo "adminpassFile ${c.adminpassFile} is empty!"
exit 1
fi
''}
ln -sf ${cfg.package}/apps ${cfg.home}/
# create nextcloud directories.
# if the directories exist already with wrong permissions, we fix that
for dir in ${cfg.home}/config ${cfg.home}/data ${cfg.home}/store-apps; do
if [ ! -e $dir ]; then
install -o nextcloud -g nextcloud -d $dir
elif [ $(stat -c "%G" $dir) != "nextcloud" ]; then
chgrp -R nextcloud $dir
fi
done
ln -sf ${overrideConfig} ${cfg.home}/config/override.config.php
# Do not install if already installed
if [[ ! -e ${cfg.home}/config/config.php ]]; then
${occInstallCmd}
fi
${occ}/bin/nextcloud-occ upgrade
${occ}/bin/nextcloud-occ config:system:delete trusted_domains
${occSetTrustedDomainsCmd}
'';
serviceConfig.Type = "oneshot";
serviceConfig.User = "nextcloud";
};
nextcloud-cron = {
environment.NEXTCLOUD_CONFIG_DIR = "${cfg.home}/config";
serviceConfig.Type = "oneshot";
serviceConfig.User = "nextcloud";
serviceConfig.ExecStart = "${phpPackage}/bin/php -f ${cfg.package}/cron.php";
};
nextcloud-update-plugins = mkIf cfg.autoUpdateApps.enable {
serviceConfig.Type = "oneshot";
serviceConfig.ExecStart = "${occ}/bin/nextcloud-occ app:update --all";
serviceConfig.User = "nextcloud";
startAt = cfg.autoUpdateApps.startAt;
};
};
services.phpfpm = {
pools.nextcloud = {
user = "nextcloud";
group = "nextcloud";
phpOptions = phpOptionsStr;
phpPackage = phpPackage;
phpEnv = {
NEXTCLOUD_CONFIG_DIR = "${cfg.home}/config";
PATH = "/run/wrappers/bin:/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin:/usr/bin:/bin";
};
settings = mapAttrs (name: mkDefault) {
"listen.owner" = config.services.nginx.user;
"listen.group" = config.services.nginx.group;
} // cfg.poolSettings;
extraConfig = cfg.poolConfig;
};
};
users.users.nextcloud = {
home = "${cfg.home}";
group = "nextcloud";
createHome = true;
};
users.groups.nextcloud.members = [ "nextcloud" config.services.nginx.user ];
environment.systemPackages = [ occ ];
services.nginx.enable = mkDefault true;
services.nginx.virtualHosts.${cfg.hostName} = let
major = toInt (versions.major cfg.package.version);
in {
root = cfg.package;
locations = {
"= /robots.txt" = {
priority = 100;
extraConfig = ''
allow all;
log_not_found off;
access_log off;
'';
};
"= /" = {
priority = 100;
extraConfig = ''
if ( $http_user_agent ~ ^DavClnt ) {
return 302 /remote.php/webdav/$is_args$args;
}
'';
};
"/" = {
priority = 900;
extraConfig = "rewrite ^ /index.php;";
};
"~ ^/store-apps" = {
priority = 201;
extraConfig = "root ${cfg.home};";
};
"^~ /.well-known" = {
priority = 210;
extraConfig = ''
absolute_redirect off;
location = /.well-known/carddav {
return 301 /remote.php/dav;
}
location = /.well-known/caldav {
return 301 /remote.php/dav;
}
location ~ ^/\.well-known/(?!acme-challenge|pki-validation) {
return 301 /index.php$request_uri;
}
try_files $uri $uri/ =404;
'';
};
"~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/)".extraConfig = ''
return 404;
'';
"~ ^/(?:\\.(?!well-known)|autotest|occ|issue|indie|db_|console)".extraConfig = ''
return 404;
'';
"~ ^\\/(?:index|remote|public|cron|core\\/ajax\\/update|status|ocs\\/v[12]|updater\\/.+|oc[ms]-provider\\/.+|.+\\/richdocumentscode\\/proxy)\\.php(?:$|\\/)" = {
priority = 500;
extraConfig = ''
include ${config.services.nginx.package}/conf/fastcgi.conf;
fastcgi_split_path_info ^(.+?\.php)(\\/.*)$;
set $path_info $fastcgi_path_info;
try_files $fastcgi_script_name =404;
fastcgi_param PATH_INFO $path_info;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS ${if cfg.https then "on" else "off"};
fastcgi_param modHeadersAvailable true;
fastcgi_param front_controller_active true;
fastcgi_pass unix:${fpm.socket};
fastcgi_intercept_errors on;
fastcgi_request_buffering off;
fastcgi_read_timeout 120s;
'';
};
"~ \\.(?:css|js|woff2?|svg|gif|map)$".extraConfig = ''
try_files $uri /index.php$request_uri;
expires 6M;
access_log off;
'';
"~ ^\\/(?:updater|ocs-provider|ocm-provider)(?:$|\\/)".extraConfig = ''
try_files $uri/ =404;
index index.php;
'';
"~ \\.(?:png|html|ttf|ico|jpg|jpeg|bcmap|mp4|webm)$".extraConfig = ''
try_files $uri /index.php$request_uri;
access_log off;
'';
};
extraConfig = ''
index index.php index.html /index.php$request_uri;
expires 1m;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
add_header X-Frame-Options sameorigin;
add_header Referrer-Policy no-referrer;
add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
client_max_body_size ${cfg.maxUploadSize};
fastcgi_buffers 64 4K;
fastcgi_hide_header X-Powered-By;
gzip on;
gzip_vary on;
gzip_comp_level 4;
gzip_min_length 256;
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
${optionalString cfg.webfinger ''
rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json last;
''}
'';
};
}
]);
meta.doc = ./nextcloud.xml;
}

View file

@ -0,0 +1,62 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.hacc.nftables.nat;
nats = config.networking.nat;
in {
options.hacc.nftables.nat = {
enable = mkEnableOption "Wrap NAT into nftables.";
forwardPorts = mkOption {
type = with types; listOf (submodule {
options = {
ports = mkOption {
type = types.listOf (types.either types.int (types.strMatching "[[:digit:]]+-[[:digit:]]+"));
};
destination = mkOption {
type = types.str;
example = "10.0.0.1";
};
proto = mkOption {
type = types.str;
default = "tcp";
example = "udp";
};
};
});
default = [];
example = [{ ports = [ 8080 "9100-9200" ]; destination = "192.168.100.2"; proto = "udp"; }];
};
};
config = mkIf cfg.enable {
networking.nat.enable = mkOverride 99 false;
boot = {
kernelModules = [ "nf_nat_ftp" ];
kernel.sysctl = {
"net.ipv4.conf.all.forwarding" = mkOverride 98 true;
"net.ipv4.conf.default.forwarding" = mkOverride 98 true;
};
};
petabyte.nftables = {
enable = true;
extraConfig = ''
table ip nat {
chain prerouting {
type nat hook prerouting priority -100
${concatMapStringsSep "\n" (rule: "iif ${nats.externalInterface} ${rule.proto} dport { ${concatStringsSep ", " (map (x: toString x) rule.ports)} } dnat ${rule.destination}") cfg.forwardPorts}
}
chain postrouting {
type nat hook postrouting priority 100
${concatMapStringsSep "\n" (iface: "iifname ${replaceStrings ["+"] ["*"] iface} oifname ${nats.externalInterface} masquerade") nats.internalInterfaces}
${concatMapStringsSep "\n" (addr: "ip saddr ${addr} oifname ${nats.externalInterface} masquerade") nats.internalIPs}
}
}
'';
};
};
}

View file

@ -1,52 +0,0 @@
{ config, lib, pkgs, modules, ... }:
with lib;
{
imports = [ modules.bindMounts ];
users.mutableUsers = false;
boot.initrd = mkIf (config.fileSystems."/".fsType or "notzfs" == "zfs") {
network.ssh.hostKeys = mkIf config.hacc.encboot.enable
(mkForce [ /persist/ssh/encboot_host ]);
postDeviceCommands = mkIf (!config.boot.initrd.systemd.enable)
(mkAfter ''
zfs rollback -r ${config.fileSystems."/".device}@blank
'');
systemd = mkIf config.boot.initrd.systemd.enable {
storePaths = [ pkgs.zfs ];
services.rollback = {
description = "Rollback ZFS datasets to a pristine state";
wantedBy = [ "initrd.target" ];
after = [ "zfs-import-${head (splitString "/" config.fileSystems."/".device)}.service" ];
before = [ "sysroot.mount" ];
path = [ pkgs.zfs ];
unitConfig.DefaultDependencies = "no";
serviceConfig.Type = "oneshot";
script = ''
zfs rollback -r ${config.fileSystems."/".device}@blank && echo "rollback complete"
'';
};
};
};
services.openssh = {
hostKeys = [
{
path = "/persist/ssh/ssh_host_ed25519_key";
type = "ed25519";
}
{
path = "/persist/ssh/ssh_host_rsa_key";
type = "rsa";
bits = 4096;
}
];
};
services.postgresql.dataDir =
"/persist/postgresql/${config.services.postgresql.package.psqlSchema}";
}

View file

@ -1,62 +0,0 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.hacc.websites;
in
{
options.hacc.websites = {
enable = mkOption {
type = types.bool;
default = false;
};
directory = mkOption {
type = types.path;
description = "all subdirectories of the given path are expected to contain a (static) website";
};
ignore = mkOption {
type = types.listOf types.str;
default = [];
description = "subdirectories that shouldn't be published";
};
builders = mkOption {
type = types.lazyAttrsOf types.package;
default = {};
description = "exposes website builders, for use with nix run";
};
};
config = let
subdirs =
let dirAttrs = filterAttrs
(n: v: v == "directory" || lists.elem n cfg.ignore)
(builtins.readDir cfg.directory);
in mapAttrsToList (n: v: n) dirAttrs;
mkWebsiteDrv = subdir:
pkgs.callPackage "${cfg.directory}/${subdir}" {};
mkWebsiteVHost = subdir: {
name = subdir;
# the nginx virtualhost config (for all sites) goes in here
value = {
enableACME = true;
forceSSL = true;
locations."/".root =
(mkWebsiteDrv subdir).outPath;
};
};
in mkIf cfg.enable {
services.nginx = {
enable = true;
virtualHosts =
listToAttrs (map mkWebsiteVHost subdirs);
};
hacc.websites.builders =
listToAttrs (map (subdir: {
name = subdir;
value = if (mkWebsiteDrv subdir) ? watch then (mkWebsiteDrv subdir).watch else null;
}) subdirs);
};
}

71
nix/sources.json Normal file
View file

@ -0,0 +1,71 @@
{
"home-manager": {
"branch": "release-20.09",
"description": "Manage a user environment using Nix [maintainer=@rycee] ",
"homepage": "https://nix-community.github.io/home-manager/",
"owner": "nix-community",
"repo": "home-manager",
"rev": "209566c752c4428c7692c134731971193f06b37c",
"sha256": "1canlfkm09ssbgm3hq0kb9d86bdh84jhidxv75g98zq5wgadk7jm",
"type": "tarball",
"url": "https://github.com/nix-community/home-manager/archive/209566c752c4428c7692c134731971193f06b37c.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"niv": {
"branch": "master",
"description": "Easy dependency management for Nix projects",
"homepage": "https://github.com/nmattia/niv",
"owner": "nmattia",
"repo": "niv",
"rev": "af958e8057f345ee1aca714c1247ef3ba1c15f5e",
"sha256": "1qjavxabbrsh73yck5dcq8jggvh3r2jkbr6b5nlz5d9yrqm9255n",
"type": "tarball",
"url": "https://github.com/nmattia/niv/archive/af958e8057f345ee1aca714c1247ef3ba1c15f5e.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"nix-hexchen": {
"branch": "main",
"repo": "https://gitlab.com/hexchen/nixfiles.git",
"rev": "431512d85fb08b2e9e5a73f39e23c0d0c1b8bc06",
"type": "git"
},
"nixos-mailserver": {
"ref": "nixos-20.09",
"repo": "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver",
"rev": "fb1cc04c0a517d4200237b02c3472bcaf9104afb",
"sha256": "0vsvgxxg5cgmzwj98171j7h5l028f1yq784alb3lxgbk8znfk51y",
"type": "tarball",
"url": "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/archive/fb1cc04c0a517d4200237b02c3472bcaf9104afb/nixos-mailserver-fb1cc04c0a517d4200237b02c3472bcaf9104afb.tar.gz",
"url_template": "<repo>/-/archive/<rev>.tar.gz"
},
"nixpkgs": {
"branch": "nixos-20.09",
"description": "Nix Packages collection",
"homepage": "",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "f8929dce13e729357f31d5b2950cbb097744bed7",
"sha256": "06ikqdb5038vkkyx4hi5lw4gksjjndjg7mz0spawnb1gpzhqkavs",
"type": "tarball",
"url": "https://github.com/nixos/nixpkgs/archive/f8929dce13e729357f31d5b2950cbb097744bed7.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"nixpkgs-unstable": {
"branch": "nixos-unstable",
"description": "Nix Packages collection",
"homepage": "",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "f5e8bdd07d1afaabf6b37afc5497b1e498b8046f",
"sha256": "1fmwkb2wjfrpx8fis4x457vslam0x8vqlpfwqii6p9vm33dyxhzk",
"type": "tarball",
"url": "https://github.com/nixos/nixpkgs/archive/f5e8bdd07d1afaabf6b37afc5497b1e498b8046f.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"pbb-nixfiles": {
"branch": "main",
"repo": "https://git.petabyte.dev/petabyteboy/nixfiles.git",
"rev": "de52bf8ed00f3857b2240e74dfb0244928890df0",
"type": "git"
}
}

174
nix/sources.nix Normal file
View file

@ -0,0 +1,174 @@
# This file has been generated by Niv.
let
#
# The fetchers. fetch_<type> fetches specs of type <type>.
#
fetch_file = pkgs: name: spec:
let
name' = sanitizeName name + "-src";
in
if spec.builtin or true then
builtins_fetchurl { inherit (spec) url sha256; name = name'; }
else
pkgs.fetchurl { inherit (spec) url sha256; name = name'; };
fetch_tarball = pkgs: name: spec:
let
name' = sanitizeName name + "-src";
in
if spec.builtin or true then
builtins_fetchTarball { name = name'; inherit (spec) url sha256; }
else
pkgs.fetchzip { name = name'; inherit (spec) url sha256; };
fetch_git = name: spec:
let
ref =
if spec ? ref then spec.ref else
if spec ? branch then "refs/heads/${spec.branch}" else
if spec ? tag then "refs/tags/${spec.tag}" else
abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!";
in
builtins.fetchGit { url = spec.repo; inherit (spec) rev; inherit ref; };
fetch_local = spec: spec.path;
fetch_builtin-tarball = name: throw
''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`.
$ niv modify ${name} -a type=tarball -a builtin=true'';
fetch_builtin-url = name: throw
''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`.
$ niv modify ${name} -a type=file -a builtin=true'';
#
# Various helpers
#
# https://github.com/NixOS/nixpkgs/pull/83241/files#diff-c6f540a4f3bfa4b0e8b6bafd4cd54e8bR695
sanitizeName = name:
(
concatMapStrings (s: if builtins.isList s then "-" else s)
(
builtins.split "[^[:alnum:]+._?=-]+"
((x: builtins.elemAt (builtins.match "\\.*(.*)" x) 0) name)
)
);
# The set of packages used when specs are fetched using non-builtins.
mkPkgs = sources: system:
let
sourcesNixpkgs =
import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) { inherit system; };
hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath;
hasThisAsNixpkgsPath = <nixpkgs> == ./.;
in
if builtins.hasAttr "nixpkgs" sources
then sourcesNixpkgs
else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then
import <nixpkgs> {}
else
abort
''
Please specify either <nixpkgs> (through -I or NIX_PATH=nixpkgs=...) or
add a package called "nixpkgs" to your sources.json.
'';
# The actual fetching function.
fetch = pkgs: name: spec:
if ! builtins.hasAttr "type" spec then
abort "ERROR: niv spec ${name} does not have a 'type' attribute"
else if spec.type == "file" then fetch_file pkgs name spec
else if spec.type == "tarball" then fetch_tarball pkgs name spec
else if spec.type == "git" then fetch_git name spec
else if spec.type == "local" then fetch_local spec
else if spec.type == "builtin-tarball" then fetch_builtin-tarball name
else if spec.type == "builtin-url" then fetch_builtin-url name
else
abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}";
# If the environment variable NIV_OVERRIDE_${name} is set, then use
# the path directly as opposed to the fetched source.
replace = name: drv:
let
saneName = stringAsChars (c: if isNull (builtins.match "[a-zA-Z0-9]" c) then "_" else c) name;
ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}";
in
if ersatz == "" then drv else
# this turns the string into an actual Nix path (for both absolute and
# relative paths)
if builtins.substring 0 1 ersatz == "/" then /. + ersatz else /. + builtins.getEnv "PWD" + "/${ersatz}";
# Ports of functions for older nix versions
# a Nix version of mapAttrs if the built-in doesn't exist
mapAttrs = builtins.mapAttrs or (
f: set: with builtins;
listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set))
);
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295
range = first: last: if first > last then [] else builtins.genList (n: first + n) (last - first + 1);
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257
stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1));
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269
stringAsChars = f: s: concatStrings (map f (stringToCharacters s));
concatMapStrings = f: list: concatStrings (map f list);
concatStrings = builtins.concatStringsSep "";
# https://github.com/NixOS/nixpkgs/blob/8a9f58a375c401b96da862d969f66429def1d118/lib/attrsets.nix#L331
optionalAttrs = cond: as: if cond then as else {};
# fetchTarball version that is compatible between all the versions of Nix
builtins_fetchTarball = { url, name ? null, sha256 }@attrs:
let
inherit (builtins) lessThan nixVersion fetchTarball;
in
if lessThan nixVersion "1.12" then
fetchTarball ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; }))
else
fetchTarball attrs;
# fetchurl version that is compatible between all the versions of Nix
builtins_fetchurl = { url, name ? null, sha256 }@attrs:
let
inherit (builtins) lessThan nixVersion fetchurl;
in
if lessThan nixVersion "1.12" then
fetchurl ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; }))
else
fetchurl attrs;
# Create the final "sources" from the config
mkSources = config:
mapAttrs (
name: spec:
if builtins.hasAttr "outPath" spec
then abort
"The values in sources.json should not have an 'outPath' attribute"
else
spec // { outPath = replace name (fetch config.pkgs name spec); }
) config.sources;
# The "config" used by the fetchers
mkConfig =
{ sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null
, sources ? if isNull sourcesFile then {} else builtins.fromJSON (builtins.readFile sourcesFile)
, system ? builtins.currentSystem
, pkgs ? mkPkgs sources system
}: rec {
# The sources, i.e. the attribute set of spec name to spec
inherit sources;
# The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers
inherit pkgs;
};
in
mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); }

View file

@ -1,93 +0,0 @@
{ config, lib, pkgs, sources, modules, ... }:
{
imports = [
../common
./hardware.nix
modules.encboot
modules.nopersist
./nftables.nix
./nextcloud.nix
./mattermost.nix
./murmur.nix
./hedgedoc-hacc.nix
./hedgedoc-i4f.nix
./mail.nix
./forgejo.nix
./nginx-pages.nix
./vaultwarden.nix
./tracktrain.nix
./uffd.nix
./lxc.nix
./monit.nix
];
hacc.bindToPersist = [ "/var/lib/acme" ];
hacc.encboot = {
enable = true;
dataset = "-a";
networkDrivers = [ "igb" ];
};
sops.defaultSopsFile = ../secrets.yaml;
sops.age.sshKeyPaths = [ "/persist/ssh/ssh_host_ed25519_key" ];
boot.loader.grub.enable = true;
boot.loader.grub.devices = [ "/dev/nvme0n1" "/dev/nvme1n1" ];
boot.supportedFilesystems = [ "zfs" ];
networking.hostId = "b2867696";
networking.useDHCP = true;
networking.nftables.enable = true;
networking.hostName = "parsons";
networking.interfaces.enp35s0.ipv6.addresses = [{
address = "2a01:4f9:3a:2ddb::1";
prefixLength = 64;
}];
networking.defaultGateway6 = {
address = "fe80::1";
interface = "enp35s0";
};
services.nginx = {
enable = true;
recommendedProxySettings = true;
virtualHosts = {
"parsons.hacc.space" = {
default = true;
locations."/".return = "404";
};
"hacc.space" = {
enableACME = true;
forceSSL = true;
locations."/".return = "302 https://hacc.earth";
};
};
};
networking.firewall.allowedTCPPorts = [ 80 443 ];
services.restic.backups.tardis = {
passwordFile = "/run/secrets/restic/system";
environmentFile = "/run/secrets/restic/s3creds.env";
paths = [
"/home"
"/persist"
];
pruneOpts = [
"--keep-daily 7"
"--keep-weekly 5"
"--keep-monthly 3"
];
repository = "b2:tardis-parsons:system";
};
sops.secrets = {
"restic/system" = {};
"restic/s3creds.env" = {};
};
system.stateVersion = "21.05";
}

View file

@ -1,86 +0,0 @@
{ config, lib, pkgs, ... }:
{
hacc.containers.forgejo = {
config = { lib, pkgs, ... }: {
system.stateVersion = "21.11";
environment.systemPackages = [ pkgs.forgejo ];
hacc.bindMounts."/var/lib/forgejo" = "/persist/forgejo";
services.forgejo = {
enable = true;
package = pkgs.forgejo;
lfs.enable = true;
database.type = "postgres";
settings = {
repository = {
DEFAULT_PRIVATE = "public";
PREFERRED_LICENSES = "Unlicense";
DEFAULT_BRANCH = "main";
};
oauth2_client = {
ACCOUNT_LINKING = "auto";
ENABLE_AUTO_REGISTRATION = true;
};
"repository.pull-requests" = {
DEFAULT_MERGE_STYLE = "merge";
DEFAULT_MERGE_MESSAGE_ALL_AUTHORS = true;
};
"repository.upload".FILE_MAX_SIZE = 1024;
server = {
LANDING_PAGE = "explore";
OFFLINE_MODE = true;
ROOT_URL = "https://git.infra4future.de";
HTTP_PORT = 3000;
HTTP_ADDR = "0.0.0.0";
};
security = { INSTALL_LOCK = true; };
other = {
SHOW_FOOTER_VERSION = false;
SHOW_FOOTER_TEMPLATE_LOAD_TIME = false;
};
cron = {
ENABLED = true;
NOTICE_ON_SUCCESS = true;
};
"cron.update_mirrors" = {
SCHEDULE = "@every 12h";
PULL_LIMIT = "-1";
PUSH_LIMIT = "-1";
};
"cron.git_gc_repos".ENABLED = true;
"cron.delete_old_actions".ENABLED = true;
log.LEVEL = "Info";
service.DISABLE_REGISTRATION = true;
session.COOKIE_SECURE = true;
default.APP_NAME = "0x0: git for all creatures";
};
};
services.postgresql.package = pkgs.postgresql_15;
services.postgresqlBackup = {
enable = true;
databases = [ "forgejo" ];
startAt = "*-*-* 23:45:00";
location = "/persist/backups/postgres";
};
services.openssh = {
enable = true;
settings = {
PasswordAuthentication = false;
AcceptEnv = "GIT_PROTOCOL";
};
};
};
};
services.nginx.virtualHosts."git.infra4future.de" = {
forceSSL = true;
enableACME = true;
locations."/" = {
proxyPass = "http://${config.containers.forgejo.localAddress}:3000";
};
};
}

View file

@ -1,61 +0,0 @@
{ config, lib, pkgs, modulesPath, ... }:
{
imports =
[ (modulesPath + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "sd_mod" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ "kvm-amd" ];
boot.extraModulePackages = [ ];
fileSystems."/" =
{ device = "zroot/local/root";
fsType = "zfs";
};
fileSystems."/boot" =
{ device = "/dev/disk/by-uuid/daf2a731-952f-45c7-9c25-49e1a2f56062";
fsType = "ext4";
};
fileSystems."/nix" =
{ device = "zroot/local/nix";
fsType = "zfs";
};
fileSystems."/persist" =
{ device = "zroot/safe/persist";
fsType = "zfs";
neededForBoot = true;
};
fileSystems."/home" =
{ device = "zroot/safe/home";
fsType = "zfs";
};
fileSystems."/root" =
{ device = "zroot/safe/root";
fsType = "zfs";
};
fileSystems."/var/cache/restic-backups-tardis" =
{ device = "zroot/safe/restic-cache";
fsType = "zfs";
};
fileSystems."/tmp" =
{ device = "zroot/local/tmp";
fsType = "zfs";
};
fileSystems."/persist/data" =
{ device = "dpool/safe/data";
fsType = "zfs";
};
swapDevices = [ ];
}

View file

@ -1,91 +0,0 @@
{ config, lib, pkgs, ... }:
{
sops.secrets = {
"hedgedoc-hacc/env" = {};
};
containers.pad-hacc.bindMounts = {
"/secrets".hostPath = "/run/secrets/hedgedoc-hacc";
};
hacc.containers.pad-hacc = {
config = { config, lib, ... }: {
services.hedgedoc = {
enable = true;
settings = {
allowAnonymous = true;
allowFreeURL = true;
allowGravatar = false;
allowOrigin = [ "localhost" "pad.hacc.space" "fff-muc.de" ];
db = {
host = "/run/postgresql";
username = "codimd";
dialect = "postgres";
database = "codimd";
};
defaultPermission = "limited";
domain = "pad.hacc.space";
host = "0.0.0.0";
protocolUseSSL = true;
hsts.preload = false;
email = false;
oauth2 = {
authorizationURL = "https://login.infra4future.de/oauth2/authorize";
tokenURL = "https://login.infra4future.de/oauth2/token";
clientID = "hedgedoc";
# must be set to make the NixOS module happy, but env var takes precedence
clientSecret = "lol nope";
};
};
environmentFile = "/secrets/env";
};
systemd.services.hedgedoc.environment = {
"CMD_LOGLEVEL" = "warn";
"CMD_OAUTH2_USER_PROFILE_URL" = "https://login.infra4future.de/oauth2/userinfo";
"CMD_OAUTH2_USER_PROFILE_USERNAME_ATTR" = "nickname";
"CMD_OAUTH2_USER_PROFILE_DISPLAY_NAME_ATTR" = "name";
"CMD_OAUTH2_USER_PROFILE_EMAIL_ATTR" = "email";
"CMD_OAUTH2_PROVIDERNAME" = "Infra4Future";
};
services.postgresql = {
enable = true;
ensureDatabases = [ "codimd" ];
ensureUsers = [{
name = "codimd";
ensureDBOwnership = true;
}];
authentication = ''
local all all trust
host codimd codimd 127.0.0.1/32 trust
'';
package = pkgs.postgresql_15;
};
services.postgresqlBackup = {
enable = true;
databases = [ "codimd" ];
startAt = "*-*-* 23:45:00";
location = "/persist/backups/postgres";
};
hacc.bindToPersist = [ "/var/lib/hedgedoc" ];
};
};
services.nginx.virtualHosts."pad.hacc.earth" = {
enableACME = true;
forceSSL = true;
globalRedirect = "pad.hacc.space";
};
services.nginx.virtualHosts."pad.hacc.space" = {
forceSSL = true;
enableACME = true;
locations."/" = {
proxyPass = "http://${config.containers.pad-hacc.localAddress}:3000";
extraConfig = ''
add_header Access-Control-Allow-Origin "*";
proxy_buffering off;
'';
};
};
}

View file

@ -1,63 +0,0 @@
{ config, lib, pkgs, ... }:
{
hacc.containers.pad-i4f = {
config = { config, lib, ... }: {
services.hedgedoc = {
enable = true;
settings = {
allowAnonymous = true;
allowFreeURL = true;
allowGravatar = false;
allowOrigin = [ "localhost" "pad.infra4future.de" "fff-muc.de" ];
db = {
host = "/run/postgresql";
dialect = "postgres";
database = "hedgedoc";
};
defaultPermission = "freely";
domain = "pad.infra4future.de";
host = "0.0.0.0";
protocolUseSSL = true;
hsts.preload = false;
email = false;
};
};
systemd.services.hedgedoc.environment = {
"CMD_LOGLEVEL" = "warn";
};
services.postgresql = {
enable = true;
package = pkgs.postgresql_15;
authentication = ''
local all all trust
host hedgedoc hedgedoc 127.0.0.1/32 trust
'';
ensureDatabases = [ "hedgedoc" ];
ensureUsers = [{
name = "hedgedoc";
ensureDBOwnership = true;
}];
};
services.postgresqlBackup = {
enable = true;
databases = [ "hedgedoc" ];
startAt = "*-*-* 23:45:00";
location = "/persist/backups/postgres";
};
hacc.bindToPersist = [ "/var/lib/hedgedoc" ];
};
};
services.nginx.virtualHosts."pad.infra4future.de" = {
forceSSL = true;
enableACME = true;
locations."/" = {
proxyPass = "http://${config.containers.pad-i4f.localAddress}:3000";
extraConfig = ''
add_header Access-Control-Allow-Origin "*";
proxy_buffering off;
'';
};
};
}

View file

@ -1,29 +0,0 @@
{ config, lib, pkgs, ... }:
{
networking.bridges.lxcbr0.interfaces = [];
networking.interfaces.lxcbr0.ipv4.addresses = [
{
address = "10.1.2.1";
prefixLength = 24;
}
];
virtualisation.lxc.enable = true;
virtualisation.lxc.systemConfig = ''
lxc.bdev.zfs.root = zroot/safe/containers/lxc
lxc.lxcpath = /persist/lxc
'';
users.users.root.subUidRanges = [{ count = 65536; startUid = 100000; }];
users.users.root.subGidRanges = [{ count = 65536; startGid = 100000; }];
environment.etc."lxc/share".source = "${pkgs.lxc}/share/lxc";
services.nginx.virtualHosts."onlyoffice.infra4future.de" = {
locations."/".proxyPass = "http://10.1.2.233:80";
enableACME = true;
forceSSL = true;
};
}

View file

@ -1,208 +0,0 @@
{ config, options, pkgs, lib, sources, ... }:
{
imports = [ sources.nixos-mailserver.outPath ];
# reduce log spam
systemd.services.rspamd.serviceConfig.LogLevelMax =
3; # this is set to error because rspamd regularly complains about not enough learns
systemd.services.dovecot2.serviceConfig.LogLevelMax = 5; # = notice
# stop postfix from dying if rspamd hiccups
systemd.services.postfix.unitConfig = {
Requires = lib.mkForce "dovecot2.service opendkim.service";
};
mailserver = {
mailDirectory = "/persist/mail";
enable = true;
fqdn = "mail.hacc.space";
monitoring = {
enable = true;
alertAddress = "admin@hacc.space";
};
domains = [
"hacc.space"
"muc.hacc.space"
"hacc.earth"
"4future.dev"
"4futu.re"
"infra4future.de"
];
loginAccounts = {
"hexchen@hacc.space".hashedPassword =
"$6$x9skYtRp4dgxC$1y8gPC2BuVqG3kJVSMGgzZv0Bg1T9qxcnBWLIDbANy1d//SQ23Y7s3IMYcEPd1/l/MYWD9Y/Qse6HbT5w5Xwq/";
"octycs@hacc.space".hashedPassword =
"$6$KceTivtJ$58jxhYF6ULfivNsb3Z0J7PnGea0Hs2wTWh3c9FrKRIAmuOD96u2IDgZRCn6P5NrXA0BL.n6HC2RS3r.4JnOmg.";
"octycs@hacc.space".aliases = [ "markus@hacc.space" ];
"raphael@hacc.space".hashedPassword =
"$6$QveHpwMcp9mkFVAU$EFuahOrJIxPg.c.WGFHtrP3.onwJYwvP7fiBHHGb9jhosewZ2tEUP.2D3uyDLhd9Cfny6Yp4jDk/Hkjk7/ME1/";
"moira@hacc.space".hashedPassword =
"$6$BpYhwcZNrkLhVqK$6FMqA/vUkdV4GBlHLSqS5DRCb/CaLDNeIsBcZ8G30heytS/tJj2Ag7b1ovSltTA4PUfhee3pJrz1BkwkA93vN1";
"zauberberg@hacc.space".hashedPassword =
"$6$ISAaU8X6D$oGKe9WXDWrRpGzHUTdxrxdtg9zuGOlBMuDc82IZhegpsv1bqd550FhZZrI40IjZTA5Hy2MZ8j/0efpnQ4fOQH0";
"zauberberg@hacc.space".aliases = [ "lukas@hacc.space" ];
"stuebinm@hacc.space".hashedPassword =
"$6$mjrMQG5smqLRlm$WzmbiZnGlEXGT7hj/n2qz0nvVzGyZfMToCyLRi0wErfVEHI7y7jtWoHqIWnpcHAM29UocsIFFsUCb3XqQCwwB.";
"lenny@hacc.space".hashedPassword =
"$6$EZpv9XImv5F3$p2NSoo5gLxh6NnB3/C6wF8knRTuMHqDXYF3BEscaQuk7qok2Z13xKT/6mFvvSKKBnFCuYptgnfGswmoqIzm/1/";
"lenny@hacc.space".aliases = [ "rinderhacc@hacc.space" ];
"peter@hacc.space".hashedPassword =
"$6$yvpfTC.7DDpqpsYy$7TrfmLvz/fRl.k5mSHhI67CNquJa3yEFbLuTJvpyJ8Dj7SaD2eoOHWqef.CNo.T08kYzaqMcM73whAxjXVEmc.";
"peter@hacc.space".aliases = [ "linmob@hacc.space" ];
"finance@muc.hacc.space".hashedPassword =
"$6$R3GRmvXwqnMM6q.R$Y9mrUAmMnCScsM6pKjxo2a2XPM7lHrV8FIgK0PzhYvZbxWczo7.O4dk1onYeV1mRx/nXZfkZNjqNCruCn0S2m.";
"noreply@hacc.space" = {
hashedPassword =
"$6$YsqMoItITZUzI5wo$5Lejf8XBHRx4LW4VuZ9wJCiBbT4kOV/EZaCdWQ07eVIrkRTZwXWZ5zfsh.olXEFwvpNWN.DBnU.dQc.cC0/ra/";
};
"noreply@infra4future.de" = {
hashedPassword =
"$6$uaD8bRcT1$gFqhFyu5RUsyUUOG5b.kN.JAJ1rVHvaYhpeRHoMvrERAMgBu1FHu2oDnjTsy.5NKoLc5xpI5uv4Gpy4YbmDmV.";
};
"mattermost@hacc.space" = {
hashedPassword =
"$6$uaD8bRcT1$gFqhFyu5RUsyUUOG5b.kN.JAJ1rVHvaYhpeRHoMvrERAMgBu1FHu2oDnjTsy.5NKoLc5xpI5uv4Gpy4YbmDmV.";
};
};
extraVirtualAliases = {
# address = forward address;
# -- International --
# info/contact: main entrypoint, anyone can read or reply to this.
"info@hacc.space" = [
"hexchen@hacc.space"
"octycs@hacc.space"
"raphael@hacc.space"
"moira@hacc.space"
"zauberberg@hacc.space"
"stuebinm@hacc.space"
"lenny@hacc.space"
"peter@hacc.space"
];
# admin: current people with access to the mail server and knowledge on how to use it™
"admin@hacc.space" = [
"hexchen@hacc.space"
"moira@hacc.space"
"zauberberg@hacc.space"
"stuebinm@hacc.space"
];
# voc: hacc video operation center, various streaming-related things
"voc@hacc.space" = [
"hexchen@hacc.space"
"moira@hacc.space"
"octycs@hacc.space"
"stuebinm@hacc.space"
"zauberberg@hacc.space"
"lenny@hacc.space"
"raphael@hacc.space"
];
# -- Regional: Germany --
# board of hacc e.V.
"vorstand@hacc.space" =
[ "raphael@hacc.space" "moira@hacc.space" "peter@hacc.space" ];
# members of hacc e.V.
"mitglieder@hacc.space" = [
"hexchen@hacc.space"
"raphael@hacc.space"
"moira@hacc.space"
"zauberberg@hacc.space"
"lenny@hacc.space"
"octycs@hacc.space"
"stuebinm@hacc.space"
"peter@hacc.space"
];
# -- Regional: Munich --
"muc@hacc.space" = [
"hexchen@hacc.space"
"octycs@hacc.space"
"raphael@hacc.space"
"moira@hacc.space"
"zauberberg@hacc.space"
"stuebinm@hacc.space"
"lenny@hacc.space"
"peter@hacc.space"
];
};
# Use Let's Encrypt certificates. Note that this needs to set up a stripped
# down nginx and opens port 80.
certificateScheme = "acme-nginx";
# Only allow implict TLS
enableImap = false;
enablePop3 = false;
# Enable the ManageSieve protocol
enableManageSieve = true;
};
services.postfix.submissionOptions.smtpd_sender_restrictions =
lib.mkForce "reject_non_fqdn_sender,reject_unknown_sender_domain,permit";
services.postfix.submissionsOptions.smtpd_sender_restrictions =
lib.mkForce "reject_non_fqdn_sender,reject_unknown_sender_domain,permit";
services.postfix.virtual = ''
postmaster@hacc.space admin@hacc.space
abuse@hacc.space admin@hacc.space
contact@hacc.space info@hacc.space
hello@hacc.space info@hacc.space
haccvoc@hacc.space voc@hacc.space
@4future.dev @hacc.space
@4futu.re @hacc.space
@hacc.earth @hacc.space
@infra4future.de @hacc.space
'';
services.alps = {
enable = true;
theme = "alps";
smtps = {
port = 465;
host = "mail.hacc.space";
};
imaps = {
port = 993;
host = "mail.hacc.space";
};
bindIP = "[::1]";
};
systemd.services.alps.after = [ "dovecot2.service" "postfix.service" ];
systemd.services.alps.bindsTo = [ "dovecot2.service" "postfix.service" ];
services.nginx.virtualHosts."mail.hacc.space" = {
enableACME = true;
forceSSL = true;
locations."/".proxyPass = "http://[::1]:1323";
};
hacc.bindToPersist = [
"/var/lib/rspamd"
"/var/lib/opendkim"
"/var/lib/postfix"
"/var/lib/dovecot"
"/var/sieve"
"/var/lib/redis-rspamd"
"/var/dkim"
];
}

View file

@ -1,64 +0,0 @@
{ config, options, lib, pkgs, ... }:
let
checkHash = pkgs.writeScriptBin "check-commit-hash" ''
#!${lib.getExe pkgs.fish}
set wanted (${lib.getExe pkgs.curl} -s https://git.infra4future.de/api/v1/repos/hacc/haccfiles/branches/main \
-H 'accept: application/json' | jq -r .commit.id)
if test $status != 0
echo "could not reach git.infra4future.de"
exit 2
end
set actual (cat /etc/haccfiles-commit)
if test $status != 0
echo "/etc/haccfiles-commit does not exist??"
exit 2
end
if test $actual != $wanted
echo "parsons was built on $actual, but commit on main is $wanted"
exit 1
end
'';
checkDeployAge = pkgs.writeScriptBin "check-deploy-age" ''
#!${lib.getExe pkgs.fish}
set date (date +%s)
# we do this indirection here so monit's config won't change on each deploy
set deploytimestamp (cat /etc/haccfiles-timestamp)
set age (expr $date - $deploytimestamp)
if test $age -ge (expr 3600 \* 24 \* 10)
echo "${config.networking.hostName} has not been deployed since 10 days, perhaps someone should do updates?"
exit 1
end
'';
in
{
mailserver.monitoring = {
enable = true;
alertAddress = "admin@hacc.space";
config = (lib.replaceStrings ["port 22"] ["port ${toString (lib.head config.services.openssh.ports)}"] options.mailserver.monitoring.config.default);
};
services.monit.config = ''
check host onlyoffice with address onlyoffice.infra4future.de
start program "/run/current-system/sw/bin/lxc-start -n onlyoffice -f /persist/lxc/onlyoffice/config"
stop program "/run/current-system/sw/bin/lxc-stop -n onlyoffice"
if failed port 443 protocol https status = 302
then restart
check program deployed-commit-on-main path ${lib.getExe checkHash}
if status == 1 for 64 cycles then alert
if status == 2 for 3 cycles then alert
check program is-system-running path ${pkgs.systemd}/bin/systemctl is-system-running
if status != 0 then alert
check program check-deploy-age path ${lib.getExe checkDeployAge}
if status == 1 then alert
'';
}

View file

@ -1,30 +0,0 @@
{ config, lib, pkgs, ... }:
{
services.murmur = {
enable = true;
logDays = -1;
registerName = "hackers against climate change";
welcometext = ''
<br>Welcome to <b>mumble4future</b>!<br>Brought to you by <b style="color:red">infra4future</b>.<br>On <a href=https://mumble.hacc.space>mumble.hacc.space</a><br>Not confusing at all!
'';
sslKey = "/var/lib/acme/mumble.hacc.space/key.pem";
sslCert = "/var/lib/acme/mumble.hacc.space/fullchain.pem";
bandwidth = 128000;
};
networking.firewall.allowedTCPPorts = [ config.services.murmur.port ];
networking.firewall.allowedUDPPorts = [ config.services.murmur.port ];
# the mumble cert has its own group so that both nginx and murmur can read it
users.groups.mumblecert = { };
security.acme.certs."mumble.hacc.space" = {
group = "mumblecert";
extraDomainNames = [ "mumble.infra4future.de" ];
reloadServices = [ "murmur" ];
};
users.users.nginx.extraGroups = [ "mumblecert" ];
users.users.murmur.extraGroups = [ "mumblecert" ];
hacc.bindToPersist = [ "/var/lib/murmur" ];
}

View file

@ -1,89 +0,0 @@
{ config, lib, pkgs, ... }:
{
containers.nextcloud.timeoutStartSec = "10 min";
hacc.containers.nextcloud = {
config = { config, lib, pkgs, ... }: {
environment.systemPackages = [ pkgs.htop ];
services.nextcloud = {
enable = true;
# must be set manually; may not be incremented by more than one at
# a time, otherwise nextcloud WILL break
package = pkgs.nextcloud30;
home = "/persist/nextcloud";
https = true;
hostName = "cloud.infra4future.de";
config = {
dbtype = "pgsql";
dbuser = "nextcloud";
dbhost = "/run/postgresql"; # nextcloud will add /.s.PGSQL.5432 by itself
dbname = "nextcloud";
# socket auth does not needs this, but the module insists it does
adminpassFile = "/persist/adminpassfile";
adminuser = "root";
};
# multiple pools may be doable using services.phpfpm.pools,
# but i have not tried this yet. The nextcloud module defines a
# pool "nextcloud"
poolSettings = {
pm = "dynamic";
"pm.max_children" = "32";
"pm.max_requests" = "500";
"pm.max_spare_servers" = "4";
"pm.min_spare_servers" = "2";
"pm.start_servers" = "2";
};
settings = {
instanceid = "ocxlphb7fbju";
datadirectory = "/persist/nextcloud/data";
loglevel = 0;
"overwrite.cli.url" = "https://cloud.infra4future.de";
};
};
services.postgresql = {
enable = true;
package = pkgs.postgresql_15;
ensureDatabases = [ "nextcloud" ];
ensureUsers = [
{ # by default, postgres has unix sockets enabled, and allows a
# system user `nextcloud` to log in without other authentication
name = "nextcloud";
ensureDBOwnership = true;
}
];
};
services.postgresqlBackup = {
enable = true;
databases = [ "nextcloud" ];
startAt = "*-*-* 23:45:00";
location = "/persist/backups/postgres";
};
# ensure that postgres is running *before* running the setup
systemd.services."nextcloud-setup" = {
requires = ["postgresql.service"];
after = ["postgresql.service"];
};
};
};
services.nginx.virtualHosts."cloud.infra4future.de" = {
locations."/".proxyPass = "http://${config.containers.nextcloud.localAddress}:80";
enableACME = true;
forceSSL = true;
extraConfig = ''
proxy_buffering off;
client_max_body_size 0;
add_header Cache-Control "no-store, no-cache, must-revalidate";
'';
};
}

View file

@ -1,23 +0,0 @@
{ config, lib, pkgs, ... }:
{
networking.firewall.enable = true;
networking.firewall.logRefusedConnections = false;
networking.nat.enable = true;
networking.nftables.enable = true;
networking.nftables.tables.nat = {
family = "ip";
content = ''
chain prerouting {
type nat hook prerouting priority -100
iifname enp35s0 tcp dport { 22 } dnat ${config.containers.forgejo.localAddress}:22
}
chain postrouting {
type nat hook postrouting priority 100
iifname lxcbr0 oifname enp35s0 masquerade
iifname ve-* oifname enp35s0 masquerade
}
'';
};
}

View file

@ -1,16 +0,0 @@
{ config, pkgs, ... }:
{
hacc.websites = {
enable = true;
directory = "${../.}/websites";
};
services.nginx.virtualHosts."parsons.hacc.space" = {
enableACME = true;
forceSSL = true;
locations."/~stuebinm/".root = "/persist/www/";
};
}

View file

@ -1,137 +0,0 @@
{ config, lib, pkgs, ... }:
{
sops.secrets = {
"s4f-conference/env" = {};
};
hacc.containers.s4f-conference = {
bindSecrets = true;
config = { config, lib, pkgs, ... }: {
systemd.services.mattermost.serviceConfig.EnvironmentFile =
lib.mkForce "/secrets/env";
services.mattermost = {
enable = true;
siteUrl = "https://s4f-conference.infra4future.de";
siteName = "Scientists for Future Chat";
listenAddress = "0.0.0.0:3000";
mutableConfig = false;
statePath = "/persist/mattermost";
extraConfig = {
ServiceSettings = {
TrustedProxyIPHeader = [ "X-Forwarded-For" "X-Real-Ip" ];
EnableEmailInvitations = true;
};
TeamSettings = {
EnableUserCreation = true;
MaxUsersPerTeam = 2500;
EnableUserDeactivation = true;
EnableOpenServer = false;
};
PasswordSettings = {
MinimumLength = 10;
};
FileSettings = {
EnableFileAttachments = true;
MaxFileSize = 52428800;
DriverName = "local";
Directory = "/persist/upload-storage";
EnablePublicLink = true;
PublicLinkSalt = "3k7p3yxdhz6798b3b9openfr9rn3ymwu";
};
EmailSettings = {
EnableSignUpWithEmail = true;
EnableSignInWithEmail = true;
EnableSignInWithUsername = true;
SendEmailNotifications = true;
FeedbackName = "mattermost";
FeedbackEmail = "mattermost@infra4future.de";
ReplyToAddress = "mattermost@infra4future.de";
FeedbackOrganization = "infra4future.de";
EnableSMTPAuth = true;
SMTPUsername = "noreply@infra4future.de";
SMTPServer = "mail.hacc.space";
SMTPPort = "465";
SMTPServerTimeout = 10;
ConnectionSecurity = "TLS";
};
RateLimitSettings.Enable = false;
PrivacySettings = {
ShowEmailAddress = false;
ShowFullName = true;
};
# to disable the extra landing page advertising the app
NativeAppSettings = {
AppDownloadLink = "";
AndroidAppDownloadLink = "";
IosAppDownloadLink = "";
};
LogSettings = {
EnableConsole = true;
ConsoleLevel = "ERROR";
EnableDiagnostics = false;
EnableWebhookDebugging = false;
};
SupportSettings = {
TermsOfServiceLink = "https://infra4future.de/nutzungsbedingungen.html";
PrivacyPolicyLink = "https://infra4future.de/nutzungsbedingungen.html";
AboutLink = "https://infra4future.de";
SupportEmail = "info@infra4future.de";
CustomTermsOfServiceEnabled = false;
EnableAskCommunityLink = true;
};
AnnouncementSettings.EnableBanner = false;
ComplianceSettings.Enable = false;
ClusterSettings.Enable = false;
MetricsSettings.Enable = false;
GuestAccountsSettings.Enable = true;
};
localDatabaseCreate = false;
};
services.postgresql = {
enable = lib.mkForce true; # mattermost sets this to false. wtf.
package = pkgs.postgresql_15;
ensureDatabases = [ "mattermost" ];
ensureUsers = [ {
name = "mattermost";
ensureDBOwnership = true;
} ];
authentication = lib.mkForce ''
# Generated file; do not edit!
local all all trust
host mattermost mattermost ::1/128 trust
'';
};
services.postgresqlBackup = {
enable = true;
databases = [ "mattermost" ];
startAt = "*-*-* 23:45:00";
location = "/persist/backups/postgres";
};
};
};
services.nginx.virtualHosts."s4f-conference.infra4future.de" = {
locations."/" = {
proxyPass = "http://${config.containers.s4f-conference.localAddress}:3000";
proxyWebsockets = true;
extraConfig = ''
# Mattermost CSR Patch
proxy_hide_header Content-Security-Policy;
proxy_hide_header X-Frame-Options;
proxy_redirect off;
client_max_body_size 100M;
'';
};
forceSSL = true;
enableACME = true;
};
}

View file

@ -1,105 +0,0 @@
{ config, lib, pkgs, ... }:
let
tracktrain-config = ''
dbstring: "dbname=tracktrain"
gtfs: /persist/gtfs.zip
assets: ${pkgs.tracktrain}/assets
warp:
port: 4000
login:
enable: true
url: https://login.infra4future.de
clientName: tracktrain
# clientSecret defined in env file
logging:
ntfyTopic: ping.stuebinm.eu/monit
name: ilztalbahn
'';
in
{
sops.secrets = {
"tracktrain/env" = {};
};
services.nginx.virtualHosts."tracktrain.ilztalbahn.eu" = {
enableACME = true;
forceSSL = true;
locations."/" = {
proxyPass = "http://${config.containers.tracktrain.localAddress}:4000";
proxyWebsockets = true;
};
# note: this shadows the /metrics endpoint of tracktrain
# in case you remove this, please consider putting something
# else here to keep it from being publicly scrapable
locations."/metrics/" = {
proxyPass = "http://${config.containers.tracktrain.localAddress}:2342";
proxyWebsockets = true;
extraConfig = ''
rewrite ^/metrics/(.*) /$1 break;
'';
};
};
hacc.containers.tracktrain = {
bindSecrets = true;
config = { config, lib, pkgs, ... }: {
systemd.services.tracktrain = {
enable = true;
description = "tracks trains, hopefully";
wantedBy = [ "multi-user.target" ];
requires = [ "network.target" ];
after = [ "network.target" ];
serviceConfig = {
Type = "simple";
EnvironmentFile = "/secrets/env";
DynamicUser = true;
};
path = [ pkgs.wget pkgs.ntfy-sh ];
script = ''
cd /tmp
ln -sf ${pkgs.writeText "tracktrain-config.yaml" tracktrain-config} config.yaml
sleep 3
${pkgs.tracktrain}/bin/tracktrain +RTS -T
'';
};
systemd.services.postgresql.wantedBy = [ "tracktrain.service" ];
services.postgresql = {
enable = true;
package = pkgs.postgresql_15;
ensureDatabases = [ "tracktrain" ];
ensureUsers = [ {
name = "tracktrain";
ensureDBOwnership = true;
} ];
authentication = ''
local all all trust
'';
};
services.prometheus = {
enable = true;
port = 9001;
scrapeConfigs = [ {
job_name = "tracktrain";
static_configs = [{
targets = [ "0.0.0.0:4000" ];
}];
} ];
};
systemd.services.grafana.serviceConfig.EnvironmentFile =
"/secrets/env";
hacc.bindToPersist = [ "/var/lib/grafana" ];
};
};
}

View file

@ -1,66 +0,0 @@
{ config, lib, pkgs, ... }:
{
hacc.containers.uffd = {
config = { config, lib, pkgs, ... }: {
services.uwsgi = {
enable = true;
plugins = [ "python3" ];
instance = {
type = "normal";
pythonPackages = _: [ pkgs.uffd ];
module = "uffd:create_app()";
# socket = "${config.services.uwsgi.runDir}/uwsgi.sock";
http = ":8080";
env = [
"CONFIG_PATH=/persist/uffd/uffd.conf"
];
hook-pre-app = "exec:FLASK_APP=${pkgs.uffd}/lib/python3.10/site-packages/uffd flask db upgrade";
};
};
};
};
services.nginx.virtualHosts."login.infra4future.de" = {
enableACME = true;
forceSSL = true;
locations = {
"/".proxyPass = "http://${config.containers.uffd.localAddress}:8080";
"/static".root = "${pkgs.uffd}/lib/python3.10/site-packages/uffd";
"/static/hacc.png".return = "302 https://infra4future.de/assets/img/logo_vernetzung.png";
"/static/infra4future.svg".return = "302 https://infra4future.de/assets/img/infra4future.svg";
"/static/hedgedoc.svg".return = "302 https://infra4future.de/assets/img/icons/hedgedoc.svg";
"/static/mattermost.svg".return = "302 https://infra4future.de/assets/img/icons/mattermost.svg";
"/static/nextcloud.svg".return = "302 https://infra4future.de/assets/img/icons/nextcloud.svg";
"/static/hot_shit.svg".return = "302 https://infra4future.de/assets/img/icons/hot_shit.svg";
};
};
systemd.services.auamost = {
enable = true;
description = "mattermost aua gruppensync";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
serviceConfig.Type = "simple";
path = [ pkgs.fish pkgs.curl pkgs.jq ];
script = "${pkgs.hacc-scripts}/bin/uffd-sync-mattermost-groups.fish";
startAt = "*:0/15";
};
systemd.services.uffd-account-expiry-notification = {
enable = true;
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
serviceConfig.Type = "simple";
path = [ pkgs.hacc-scripts pkgs.sqlite-interactive pkgs.postfix ];
script = ''
uffd-unused-accounts-notification.scm -v admin
'';
startAt = "weekly";
restartIfChanged = false;
};
sops.secrets."auamost/secrets.fish" = { };
environment.systemPackages = with pkgs; [ curl jq ];
}

View file

@ -1,55 +0,0 @@
{ config, lib, pkgs, ... }:
{
sops.secrets = {
"vaultwarden/env" = {};
};
services.vaultwarden = {
enable = true;
config = {
DATA_FOLDER="/persist/var/lib/vaultwarden/data";
LOG_LEVEL="error";
SIGNUPS_ALLOWED=false;
SIGNUPS_VERIFY=true;
SIGNUPS_DOMAINS_WHITELIST="hacc.space";
ORG_CREATION_USERS="admin@hacc.space";
INVITATIONS_ALLOWED=true;
INVITATION_ORG_NAME="haccwarden";
TRASH_AUTO_DELETE_DAYS=90;
DOMAIN="https://pw.hacc.space";
ROCKET_ADDRESS="127.0.0.1";
ROCKET_PORT=5354;
ROCKET_WORKERS=2;
SMTP_HOST="mail.hacc.space";
SMTP_FROM="vaultwarden@hacc.space";
SMTP_FROM_NAME="haccwarden";
SMTP_PORT=587;
SMTP_USERNAME="noreply@infra4future.de";
};
environmentFile = "/run/secrets/vaultwarden/env";
dbBackend = "sqlite";
backupDir = "/persist/data/vaultwarden_backups/";
};
#work around ProtectSystem=strict, cleanup
systemd.services.vaultwarden.serviceConfig = {
ReadWritePaths = [ "/persist/var/lib/vaultwarden" ];
StateDirectory = lib.mkForce "";
};
systemd.services.backup-vaultwarden.environment.DATA_FOLDER =
lib.mkForce "/persist/var/lib/vaultwarden/data";
services.nginx.virtualHosts."pw.hacc.space" = {
locations."/" = {
proxyPass = "http://127.0.0.1:5354";
proxyWebsockets = true;
};
forceSSL = true;
enableACME = true;
};
}

25
pkgs/alps/default.nix Normal file
View file

@ -0,0 +1,25 @@
{ lib, buildGoModule }:
buildGoModule rec {
pname = "alps";
version = "0.0.1";
src = fetchGit {
url = "https://git.sr.ht/~migadu/alps";
rev = "51498a2dc37987f55b022efb961b68a282be17ed";
};
vendorSha256 = "0wc8fb03zlc1gl4nxlsh149gvpvrs3lc0smzrnam9smigg9gw4in";
subPackages = [ "cmd/alps" ];
postInstall = ''
mkdir -p $out/share/alps
cp -r $src/themes $out/share/alps/
'';
meta = with lib; {
description = "A simple and extensible webmail.";
homepage = "https://git.sr.ht/~migadu/alps";
};
}

View file

@ -0,0 +1,49 @@
{ stdenv, requireFile, lib,
libcxx, libcxxabi
}:
stdenv.mkDerivation rec {
pname = "blackmagic-desktop-video";
version = "11.6";
buildInputs = [
libcxx libcxxabi
];
src = requireFile {
name = "Blackmagic_Desktop_Video_Linux_11.6.tar.gz";
url = "https://www.blackmagicdesign.com/support/download/d399ada95c2b49ffad3031bda413acb5/Linux";
sha256 = "0qwm1b3gy0k7j1bimkxwwr77g8hrsybs9jp90b46kzcy06mcp380";
};
setSourceRoot = ''
tar xf Blackmagic_Desktop_Video_Linux_11.6/other/x86_64/desktopvideo-11.6a26-x86_64.tar.gz
sourceRoot=$NIX_BUILD_TOP/desktopvideo-11.6a26-x86_64
'';
installPhase = ''
runHook preInstall
mkdir -p $out/{bin,share/doc,lib}
cp -r $sourceRoot/usr/share/doc/desktopvideo $out/share/doc
cp $sourceRoot/usr/lib/*.so $out/lib
ln -s ${libcxx}/lib/* ${libcxxabi}/lib/* $out/lib
cp $sourceRoot/usr/lib/blackmagic/DesktopVideo/libgcc_s.so.1 $out/lib/
cp $sourceRoot/usr/lib/blackmagic/DesktopVideo/DesktopVideoHelper $out/bin/
runHook postInstall
'';
postFixup = ''
patchelf --set-interpreter ${stdenv.cc.bintools.dynamicLinker} \
--set-rpath "$out/lib:${lib.makeLibraryPath [ libcxx libcxxabi ]}" \
$out/bin/DesktopVideoHelper
'';
meta = with stdenv.lib; {
homepage = "https://www.blackmagicdesign.com/support/family/capture-and-playback";
maintainers = [ maintainers.hexchen ];
license = licenses.unfree;
description = "Supporting applications for Blackmagic Decklink. Doesn't include the desktop applications, only the helper required to make the driver work.";
platforms = platforms.linux;
};
}

66
pkgs/decklink/default.nix Normal file
View file

@ -0,0 +1,66 @@
{ stdenv, requireFile, fetchpatch, kernel }:
stdenv.mkDerivation rec {
pname = "decklink";
version = "11.6";
src = requireFile {
name = "Blackmagic_Desktop_Video_Linux_11.6.tar.gz";
url = "https://www.blackmagicdesign.com/support/download/d399ada95c2b49ffad3031bda413acb5/Linux";
sha256 = "0qwm1b3gy0k7j1bimkxwwr77g8hrsybs9jp90b46kzcy06mcp380";
};
patches = [
(fetchpatch {
name = "01-fix-makefile.patch";
url = "https://aur.archlinux.org/cgit/aur.git/plain/01-fix-makefile.patch?h=decklink&id=8f19ef584c0603105415160d2ba4e8dfa47495ce";
sha256 = "1pk8zfi0clmysla25jmcqnq7sx2bnjflrarhqkqbkl8crigyspf5";
})
(fetchpatch {
name = "02-fix-get_user_pages-and-mmap_lock.patch";
url = "https://aur.archlinux.org/cgit/aur.git/plain/02-fix-get_user_pages-and-mmap_lock.patch?h=decklink&id=8f19ef584c0603105415160d2ba4e8dfa47495ce";
sha256 = "08m4qwrk0vg8rix59y591bjih95d2wp6bmm1p37nyfvhi2n9jw2m";
})
(fetchpatch {
name = "03-fix-have_unlocked_ioctl.patch";
url = "https://aur.archlinux.org/cgit/aur.git/plain/03-fix-have_unlocked_ioctl.patch?h=decklink&id=8f19ef584c0603105415160d2ba4e8dfa47495ce";
sha256 = "0j9p62qa4mc6ir2v4fzrdapdrvi1dabrjrx1c295pwa3vmsi1x4f";
})
];
KERNELDIR = "${kernel.dev}/lib/modules/${kernel.modDirVersion}/build";
INSTALL_MOD_PATH = placeholder "out";
nativeBuildInputs = kernel.moduleBuildDependencies;
setSourceRoot = ''
tar xf Blackmagic_Desktop_Video_Linux_11.6/other/x86_64/desktopvideo-11.6a26-x86_64.tar.gz
sourceRoot=$NIX_BUILD_TOP/desktopvideo-11.6a26-x86_64/usr/src
'';
buildPhase = ''
runHook preBuild
make -C $sourceRoot/blackmagic-11.6a26 -j$NIX_BUILD_CORES
make -C $sourceRoot/blackmagic-io-11.6a26 -j$NIX_BUILD_CORES
runHook postBuild
'';
installPhase = ''
runHook preInstall
make -C $KERNELDIR M=$sourceRoot/blackmagic-11.6a26 modules_install
make -C $KERNELDIR M=$sourceRoot/blackmagic-io-11.6a26 modules_install
runHook postInstall
'';
meta = with stdenv.lib; {
homepage = "https://www.blackmagicdesign.com/support/family/capture-and-playback";
maintainers = [ maintainers.hexchen ];
license = licenses.unfree;
description = "Kernel module for the Blackmagic Design Decklink cards";
platforms = platforms.linux;
};
}

View file

@ -1,32 +1,40 @@
{ sources, ... }@args:
{ config ? {}, system ? builtins.currentSystem, ... }@args:
let
sources = import ../nix/sources.nix;
pkgs = import sources.nixpkgs args;
oldstable = import sources.nixpkgs-oldstable args;
unstable = import sources.nixpkgs-unstable args;
callPackage = pkgs.lib.callPackageWith (pkgs // newpkgs);
newpkgs = {
alps = callPackage ./alps {};
mattermost = callPackage ./mattermost.nix {
buildGoModule = unstable.buildGo122Module;
};
docker = pkgs.docker.overrideAttrs (super: {
extraPath = super.extraPath + ":${pkgs.zfs}/bin";
});
morph = callPackage ./morph.nix {
buildGoModule = unstable.buildGo122Module;
};
linuxPackagesFor = kernel: (pkgs.linuxPackagesFor kernel).extend (_: ksuper: {
decklink = callPackage ./decklink { kernel = ksuper.kernel; };
});
tracktrain = import sources.tracktrain {
nixpkgs = unstable;
compiler = "default";
};
blackmagicDesktopVideo = callPackage ./blackmagic-desktop-video { };
uffd = oldstable.callPackage ./uffd { };
obs-studio = unstable.obs-studio.overrideAttrs (_: rec {
wrapLibraries = with (pkgs // newpkgs); [
xorg.libX11.out
libvlc
blackmagicDesktopVideo
libcxx
libcxxabi
];
postInstall = ''
wrapProgram $out/bin/obs \
--prefix "LD_LIBRARY_PATH" : "${pkgs.lib.makeLibraryPath wrapLibraries}"
'';
});
hacc-scripts = callPackage ./scripts {};
inherit (oldstable) uwsgi flask;
inherit (unstable) bottom;
};
in pkgs.extend(_: _: newpkgs)

View file

@ -1,85 +0,0 @@
{ lib
, buildGoModule
, fetchFromGitHub
, nix-update-script
, fetchurl
, nixosTests
}:
buildGoModule rec {
pname = "mattermost";
# ESR releases only.
# See https://docs.mattermost.com/upgrade/extended-support-release.html
# When a new ESR version is available (e.g. 8.1.x -> 9.5.x), update
# the version regex in passthru.updateScript as well.
version = "9.11.5";
src = fetchFromGitHub {
owner = "mattermost";
repo = "mattermost";
rev = "v${version}";
hash = "sha256-bLZFeG6kBVP0ws50wtBam/bO206sQnz6va8PATAoRAQ=";
};
# Needed because buildGoModule does not support go workspaces yet.
# We use go 1.22's workspace vendor command, which is not yet available
# in the default version of go used in nixpkgs, nor is it used by upstream:
# https://github.com/mattermost/mattermost/issues/26221#issuecomment-1945351597
overrideModAttrs = (_: {
buildPhase = ''
make setup-go-work
go work vendor -e
'';
});
webapp = fetchurl {
url = "https://releases.mattermost.com/${version}/mattermost-${version}-linux-amd64.tar.gz";
hash = "sha256-jyaJUN8wpuBivKNdm7f1mYwygO8xC+Zxy0SdkDovdsA=";
};
vendorHash = "sha256-Gwv6clnq7ihoFC8ox8iEM5xp/us9jWUrcmqA9/XbxBE=";
modRoot = "./server";
preBuild = ''
make setup-go-work
'';
subPackages = [ "cmd/mattermost" ];
offlineCache = webapp;
tags = [ "production" ];
ldflags = [
"-s"
"-w"
"-X github.com/mattermost/mattermost/server/public/model.Version=${version}"
"-X github.com/mattermost/mattermost/server/public/model.BuildNumber=${version}-nixpkgs"
"-X github.com/mattermost/mattermost/server/public/model.BuildDate=1970-01-01"
"-X github.com/mattermost/mattermost/server/public/model.BuildHash=v${version}"
"-X github.com/mattermost/mattermost/server/public/model.BuildHashEnterprise=none"
"-X github.com/mattermost/mattermost/server/public/model.BuildEnterpriseReady=false"
];
postInstall = ''
tar --strip 1 --directory $out -xf $webapp \
mattermost/{client,i18n,fonts,templates,config}
# For some reason a bunch of these files are executable
find $out/{client,i18n,fonts,templates,config} -type f -exec chmod -x {} \;
'';
passthru = {
updateScript = nix-update-script {
extraArgs = [ "--version-regex" "^v(9\.11\.([0-9.]+))" ];
};
tests.mattermost = nixosTests.mattermost;
};
meta = with lib; {
description = "Mattermost is an open source platform for secure collaboration across the entire software development lifecycle";
homepage = "https://www.mattermost.org";
license = with licenses; [ agpl3Only asl20 ];
maintainers = with maintainers; [ ryantm numinit kranzes mgdelacroix ];
mainProgram = "mattermost";
};
}

View file

@ -1,33 +0,0 @@
{ buildGoModule
, fetchFromGitHub
}:
buildGoModule rec {
pname = "mattermost-morph";
version = "1.1.0";
src = fetchFromGitHub {
owner = "mattermost";
repo = "morph";
rev = "v${version}";
hash = "sha256-Orh/a9OlUVIlDdLXRpDAnHUmWRiM1N2oO+dijbuJzx8=";
};
vendorHash = null;
subPackages = [ "cmd/morph" ];
tags = [ "production" ];
ldflags = [
"-s"
"-w"
"-X github.com/mattermost/mattermost/server/public/model.Version=${version}"
"-X github.com/mattermost/mattermost/server/public/model.BuildNumber=${version}-nixpkgs"
"-X github.com/mattermost/mattermost/server/public/model.BuildDate=1970-01-01"
"-X github.com/mattermost/mattermost/server/public/model.BuildHash=v${version}"
"-X github.com/mattermost/mattermost/server/public/model.BuildHashEnterprise=none"
"-X github.com/mattermost/mattermost/server/public/model.BuildEnterpriseReady=false"
];
}

View file

@ -1,16 +0,0 @@
{ stdenvNoCC, gauche, fish }:
stdenvNoCC.mkDerivation {
name = "hacc-utility-scripts";
src = ./.;
buildInputs = [ gauche fish ];
installPhase = ''
mkdir -p $out/bin
fish -n $out/bin/*.fish
cp *.{scm,fish} $out/bin
chmod +x $out/bin/*
'';
}

View file

@ -1,47 +0,0 @@
#!/usr/bin/env fish
source /run/secrets/auamost/secrets.fish
for i in (seq 1 (count $groups))
set team $teams[$i]
set group $groups[$i]
set users (curl -s -u $uffd_token --basic https://login.infra4future.de/api/v1/getusers -d group="$group")
set usernames (echo "$users" | jq -c "[.[] | .loginname]")
for user in (echo "$users" | jq -c ".[]")
set id (echo "$user" | jq .id)
set username (echo "$user" | jq .loginname)
set email (echo "$user" | jq .email)
curl -s -H $mattermost_token \
-H "Content-Type: application/json" https://mattermost.infra4future.de/api/v4/users \
-d '{"email": '"$email"', "username": '"$username"', "auth_service": "gitlab", "auth_data": "'"$id"'"}'
end
set userids (curl -s -H $mattermost_token \
-H "Content-Type: application/json" https://mattermost.infra4future.de/api/v4/users/usernames \
-d "$usernames" | jq '[.[] | {user_id: .id, team_id: "'$team'"} ]')
curl -s -H $mattermost_token \
-H "Content-Type: application/json" https://mattermost.infra4future.de/api/v4/teams/"$team"/members/batch \
-d "$userids"
if test "$group" = "hacc"
continue
end
set current_members (curl -s -H $mattermost_token \
-H "Content-Type: application/json" https://mattermost.infra4future.de/api/v4/teams/"$team"/members | jq '[.[] | .user_id]')
# membership relations don't contain e.g. usernames, so fetch those, too
set current_users (curl -s -H $mattermost_token \
-H "Content-Type: application/json" https://mattermost.infra4future.de/api/v4/users/ids \
-d "$current_members" | jq -c '.[]')
set userids (echo "$userids" | jq -c ".[].user_id")
for member in $current_users
set id (echo $member | jq .id)
if not contains -i $id $userids > /dev/null then
set id_unquoted (echo $member | jq -r .id)
echo removing $id_unquoted (echo $member | jq '.email') from $team \($group\)
curl -s -X DELETE -H $mattermost_token \
-H "Content-Type: application/json" https://mattermost.infra4future.de/api/v4/teams/"$team"/members/"$id_unquoted"
end
end
end

View file

@ -1,121 +0,0 @@
#!/usr/bin/env gosh
(use gauche.process)
(use text.csv)
(use scheme.list)
(use gauche.parseopt)
(use util.match)
(define cutoff-date "2023-01-01")
(define sqlite-path "/persist/containers/uffd/uffd/db.sqlite")
(define sqlite-query
"select displayname, mail, max(expires) as last_login from oauth2token join user on user_id=user.id group by user_id having last_login < '2023-01-01'
union all select displayname, mail, '2022' from user where not exists (select * from oauth2token where user_id = user.id);")
(define dry #f)
(define verbose #f)
(define very-verbose #f)
(define (main args)
(let-args (cdr args)
((averbose "v|verbose")
(averyverbose "very-verbose")
(adry "n|dry-run")
(help "h|help" => (cut show-help (car args)))
. restargs
)
(set! dry adry)
(set! verbose averbose)
(when averyverbose
(set! verbose #t)
(set! very-verbose #t))
(match restargs
[("admin") (do-admin-mail)]
[("send-reminder") (send-reminder-mails)]
[("list-accounts") (do-list-accounts)]
[_ (display "unknown command") (exit 1)]))
0)
(define (do-admin-mail)
(send-email "admin@hacc.space" "unused accounts list" (mk-admin-mail unused-accounts))
(when verbose
(display "done")))
(define (do-list-accounts)
(display (string-join
(map
(lambda (row) (format "~a (~a)" (list-ref row 0) (list-ref row 1)))
unused-accounts)
"\n")))
(define (send-reminder-mails)
(map (lambda (row)
(send-email (list-ref row 1) "Unbenutzter infra4future.de Account" (mk-email (list-ref row 0) (list-ref row 2))))
unused-accounts)
(when verbose
(display "done")))
(define csv-reader
(make-csv-reader #\,))
(define unused-accounts
(map (lambda (str) (with-input-from-string str csv-reader))
;; (process-output->string-list `(cat example.csv))))
(process-output->string-list `(sqlite3 -csv ,sqlite-path ,sqlite-query))))
(define (mk-email displayname last-login)
#"
Hallo ~|displayname|!
Wir haben schon lange (seit über einem Jahr; dein letzter Login war um ~|last-login|)
nichts mehr von dir gehört und würden demnächst deinen Account löschen wollen.
Solltest du ihn noch benötigen logge dich bitte einfach auf https://login.infra4future.de ein.
Falls nicht, musst du weiter nichts tun und wir werden deine Account in ca. 3 Monaten löschen.
Viele Grüße,
das Infra4Future Team
")
(define (mk-admin-mail rows)
(format #"
Meow!
this is the uffd-unused-accounts-notification.scm script. There are currently
~~s accounts which have not logged in since ~|cutoff-date|. To mass-send account
expiry reminders, invoke this script with the \"send-reminder\" option. To see a
list of these accounts, invoke it with the \"list-accounts\" option.
(invoke me,, 🥺)
" (length unused-accounts)))
; utility definitions
(define (send-email address subject text)
(when verbose
(display (format "sending email to ~a\n" address)))
(let ([text (string-append "from: admin@hacc.space\n" "subject: " subject "\n" text "\n")])
(when very-verbose
(display text))
(call-with-output-process
(if dry '(cat) `(sendmail ,address))
(lambda (port) (display text port))
:on-abnormal-exit :ignore)))
(define (show-help progname)
(display #"
~|progname|: unused account expiry helper script.
Invoke as `~|progname| [options] admin' to send a list of unused accounts to administrators.
Invoke as `~|progname| [options] send-reminder' to send a reminder email to all
currently unused accounts.
Options:
-v --verbose show which emails are being sent
--very-verbose also print emails to stdout
-n --dry-run print emails to stdout instead
-h --help show this help
"))

View file

@ -1,35 +0,0 @@
{ stdenv, lib, python3Packages, fetchzip }:
python3Packages.buildPythonPackage rec {
pname = "uffd";
version = "2.0.1";
PACKAGE_VERSION = version;
src = fetchzip {
url = "https://git.cccv.de/uffd/uffd/-/archive/v${version}/uffd-v${version}.tar.gz";
hash = "sha256-KP4J1bw5u7MklaPu2SBFRNyGgkKOBOpft5MMH+em5M4=";
};
patches = [ ./forgejo-magic.patch ./fix-setuppy.patch ./fix-userinfo.patch ];
propagatedBuildInputs = with python3Packages; [
flask
flask_sqlalchemy
flask_migrate
qrcode
fido2
oauthlib
flask-babel
argon2_cffi
itsdangerous
alembic
Mako
];
postPatch = ''
sed -i -e 's/==[0-9.]\+//g' setup.py
'';
doCheck = false;
doInstallCheck = false;
}

View file

@ -1,34 +0,0 @@
--- a/setup.py 2022-04-30 13:12:45.564651955 +0000
+++ b/setup.py 2022-04-30 13:17:02.545809513 +0000
@@ -41,31 +41,5 @@
'Flask-Babel==0.11.2',
'alembic==1.0.0',
'argon2-cffi==18.3.0',
-
- # The main dependencies on their own lead to version collisions and pip is
- # not very good at resolving them, so we pin the versions from Debian Buster
- # for all dependencies.
- 'certifi==2018.8.24',
- #cffi==1.12.2'
- 'cffi # v1.12.2 no longer works with python3.9. Newer versions seem to work fine.',
- 'chardet==3.0.4',
- 'click==7.0',
- 'cryptography==2.6.1',
- 'idna==2.6',
- 'itsdangerous==0.24',
- 'Jinja2==2.10',
- 'MarkupSafe==1.1.0',
- 'oauthlib==2.1.0',
- 'pyasn1==0.4.2',
- 'pycparser==2.19',
- 'requests==2.21.0',
- 'requests-oauthlib==1.0.0',
- 'six==1.12.0',
- 'SQLAlchemy==1.2.18',
- 'urllib3==1.24.1',
- 'Werkzeug==0.14.1',
- 'python-dateutil==2.7.3',
- #editor==1.0.3
- 'Mako==1.0.7',
],
)

View file

@ -1,10 +0,0 @@
--- a/uffd/oauth2/views.py 2022-04-30 20:39:53.825474990 +0000
+++ b/uffd/oauth2/views.py 2022-04-30 20:40:12.632389377 +0000
@@ -234,6 +234,7 @@
id=user.unix_uid,
name=user.displayname,
nickname=user.loginname,
+ username=user.loginname,
email=user.mail,
groups=[group.name for group in user.groups]
)

View file

@ -1,32 +0,0 @@
From e3c0995160a653ef6cd8784b255036585b273b82 Mon Sep 17 00:00:00 2001
From: stuebinm <stuebinm@disroot.org>
Date: Wed, 20 Jul 2022 18:02:15 +0200
Subject: [PATCH] magic gitea patch
---
uffd/oauth2/views.py | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/uffd/oauth2/views.py b/uffd/oauth2/views.py
index d13fd42..94352be 100644
--- a/uffd/oauth2/views.py
+++ b/uffd/oauth2/views.py
@@ -230,6 +230,15 @@ def oauth_required(*scopes):
@oauth_required('profile')
def userinfo():
user = request.oauth.user
+ client = request.oauth.client_id
+ if client == "forgejo":
+ return jsonify(
+ id=user.unix_uid,
+ full_name=user.displayname,
+ login=user.loginname,
+ email=user.mail,
+ groups=[group.name for group in user.groups]
+ )
return jsonify(
id=user.unix_uid,
name=user.displayname,
--
2.36.0

View file

@ -1,105 +0,0 @@
hedgedoc-hacc:
env: ENC[AES256_GCM,data:e2vSolxJNucya9QNs28gAVDBJQq5AJh7jS1nBh0UTkDnhNL8NPW1KTxcun4rM99EhiNZsz6Z9qHRMejmP4frQw==,iv:DqAGhGWYf/EpGnI79MxKmBlHMhK26zx50vXb1TbvESw=,tag:Xix499XAcAmxhNuGr2ApcA==,type:str]
mattermost:
env: ENC[AES256_GCM,data:ftWpGl6+sUMzJJKgfcPLvbFGGn16AKUPzPn8X6DNVMLrxZIkQ23Tk3ekKLKFpQEUtQfFjVlrTfFZezWKs4nVNLg2LmQqJNGMCCax5PRwAgoAsJ7pa9ewNmHT+EIXtZEjQgVfN5786Yno5n/6JJ1lz6EiGmdn7/0rF5TLGjzig17azazS1+lkIYY=,iv:SZvGGKpVRI/odHbmgY8M6t6zCk8RgM+7EQEgRiizglA=,tag:cInsVo/QD85m+LxldyRlnA==,type:str]
tracktrain:
env: ENC[AES256_GCM,data:W3+8qWomPgGJt5u50aAm9x/dilMpqKY11I2AdaIBTz5posc25ts0LB5S/Sxe1ROz4itpDK3QvjoFUTRhS39k4dwMr5lqXV8Ln4B+sPpvh7oBM8A5zydP8Jj1J1YqRt8++RTUmb4z41DIwb/yaZKMu6z0guXIu1yuYzcbCuk0xe/iOp6UUpfjOzzWTvxY54zY6kWcjHLiCSwD31Cd+MxMPfbUEkHt+0W+sBmYXGeEFI/6ULSB6FnGjNW6F9g=,iv:3ymah8HG+Yg6VYZZA/MRRjHDYvYJz01ezvhfQiftegg=,tag:trht+PRYfKgWJkg2wRwISQ==,type:str]
vaultwarden:
env: ENC[AES256_GCM,data:hdm91tI8WBd3es+IUbdBO69kh1pNZTNvZNFIdSZO8lm4yYMPE+Jm7EzVqwOaZRbpQaVDBg7uh5P4ODc=,iv:no7U0wQCwZOeL2pwXf2pUIgrEsEOYwqOT04LvpCl614=,tag:AGSu5M7H69x6pDM062bC6g==,type:str]
auamost:
secrets.fish: ENC[AES256_GCM,data:QBteJdVPSWa4cmu1BVWJ3AMWWH4zIv2+G83fK0QsbA/fYoIU5jobCT3USyujNz+jQaAAxA45jmQbCWNAFLl1q8hP4i9EIikVECx0VKVXPXILBND+w7zPSLldAbOugRYt2iAt1dDADZPtulKlkz7usdafbB+2igLXdyFRLfIxDTOrBuqQ+5yeofQe5k0XWRcmQQ/1AV0JrRrmLmr69VKsR932JWD8XxmI/HFyZPzWdExBSOmvnj+m4K+DV4cVmN4t6XOY0dM3gRQ95DglEuGlp/V2o3GqwY0mXCvhM1eh81u8mPALKp6Pv2i2yU35F01Puf5t1FHGDfzp0bW0xuKEywfGjAOifFkSE/3JFir434B6G0DiJNpOIl6QJ6DA8rSKfuPdccm6Or0zX8iJGRHDJmREQ05V9l0jHAAxLNuNdbsxg+8kCWVVnW+d1YDn9KW7LbFlP+sx4Ef5leUYft/lYhF4Z5Xp3arqVrlebWjWIBEuZeJTnkE3y+TdUUCs360zzWHqsipGmo1+/88CEqL52FfUOlJ4VCR45/7nYZ3RaRBWDGFW8RvwmWSFSstEcEXQ01U8lCwyn40+blfltme3KJ1f+pWMrZAKhPlOlMHCYfjd7esWI2sYcQbTZqxH49GnW6dsW/W+eiLs3zlD/Deb2CugHe63zRdlivmVPOz4zD1PXcCVpEZHoTTiJl7Om9K2mPYq9wQN41wsDUrNL9p8m9UlhWKbjBh5UU7p6F6OhF5rKH/Fs8fIaPi6B8uamTvEmiOGTUWl3vmQjBvhM8fJWoIkRB8hgCisr9OZ,iv:8jVAImjeXbXfiLKg9G0PyLMTV8cAyDmukeittqjKFpQ=,tag:fLIcsWKbdFQ/vPCgi/W3Zw==,type:str]
restic:
s3creds.env: ENC[AES256_GCM,data:9WNu5S4KmdMXdshSpawEjIexAKH6vZCPwb9xyq6xmerly1lxSfFZzgg60M0L3L+I4joLTVi23YBB8Eh6Xfx9GgxNww7w7BjMCQs/X16ecDWlb346TKf+,iv:Gu4CbXXJAlQYXRqOjIAUYmn8EU4mrvcOVc2eCh1Ikzs=,tag:1xpVIonHiAGHsXTY9liPQQ==,type:str]
system: ENC[AES256_GCM,data:RIgO0QHVjwp2D3LoU62vLzepASdsXxu0DqUTA6Voa3K1d4xFHX2u+UR8AcqR,iv:O0K8i5ivne7WU+ygDEUcrvKW6DIfXjVPY63gpfsxEFE=,tag:n/1atQ5qlyB0SMHrYiTCrA==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age:
- recipient: age1yql8qaf7upraqy4cq397tt4vgs046hq0v59qymla8t3x0ujqvu4sesgsvw
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBHd0Rrem03aWMwUGgwMlM2
dmRJdVYrRVNBTXZrVk5CdEFYcDRyN3VlcUhvCmE5L0lpbzdxanNBWFU1dEprUC9Y
eUZqdHVmWks2V1g0SHZRN1BsSU96OU0KLS0tIGl1ZUg2aDNtREZWeUE5UXlPeHNG
STcwOFgwK1lpWjdyTkd3c0dBTlAyK28KAKL7rPPH0DNRgL3qqCelAoUPnOy8MydL
t2ft9ZmzkoiSdSt0Ad1U5IImQt9ZzhPtYYnYbiEVNcfuFCnGcqdoPw==
-----END AGE ENCRYPTED FILE-----
- recipient: age1zgdegurzlr8cw9948wgf4q5qh3efltwhhzus5tt6az5xvvsux9us2v4tyd
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAvT0M2SmdwNmNyWWZ1V2o5
OHZ4RDlIbTZONXc5Z0FPMm03V3UzVWhaRnhBCjU5dzZlbkZHRkdacG1nUng4S0p6
Q1I5Vjg0Vk5wRzNGZTNONXdCMnpUTEEKLS0tIFo5K0tGdDZpLzNPb0llb0dJdk9u
c3p5UVBjZWlNVkxFMlVaQ3VMVFdhZVUKxcIL/JMBEojPRlDLHUIuxKcMPMEEsTkS
0zLjYVZL7YDS0dKdaZjaExHKrRzRpsY0qpDBHyhcyzRae1sWA4e5Kw==
-----END AGE ENCRYPTED FILE-----
- recipient: age18wkr3kjalalzrq9l05q32gnlaqr7t6rqqzde307m83rs9fp4xcfsdtj9gt
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAwUmFJc24xV2JGS3dzK25F
SVVXTjBaRUxJQ3hXZXlHYTRzaXZVNjVObEFZCmpPQUV1b0lySkUvcURObm1xNSt4
WVQrbnlvZkQrbzloQzc4NlJCWnlPeGMKLS0tIDBVa2lpUmcrWURwWW8rc3ZmUUU1
U0pGQjJackNhT0d4L2ZIOTdTUjBwcjQKCRWcpevMcv2HsWC4jyc/GzxxjkTEm+UF
4QdXjJAHh2QLxV9aXF/k/KogebCFkBTirmyOhRKtBRkt87d1D9FKUA==
-----END AGE ENCRYPTED FILE-----
- recipient: age1q88az2y5hnx8naqsvrurllqj6y5gtehrpa9emmrxy5ghwsr7pvnqf7tfpx
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBzWnZFOVFuTnFTMmpVMDFU
dkw4UFlUenZzNkRuNy90NWk4aVNEd2J2Ukc0Cm9mM2dpZEJpVVY4TVB0WUxmTjEw
VFJ3aHB6ZFh5YWptYTZ5cXVjTUNBVkEKLS0tIEx0dVRPVVVacHFCMDhFNE1NMnZy
cUxicklTUGtPeTlnSFV1TUZqR1VmRnMKtJ+Q80SgqW/Jad8aF7pViGANHCsTMNEM
7TbhITW+zWIhnviVS0xOqXrvQs4iBbMfiNnQbFS7tEX08AT2oAg6cw==
-----END AGE ENCRYPTED FILE-----
- recipient: age18nkru4pwvvapdw76nauv2xdtlj8cvyv3ugahe9kcxtvtsptx2eyqw7p0m6
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBzT3ZNenJKWTZ3NjdqNWpR
Zk9Ya3lsT1Jqd0RIWm8xdm16UjFzcFV1aGlBCkRuMllGSFVIUCs4UEJEQVVGQUxK
L1FGNGJwYkFIdU4wOXdFQWt6RSsyR28KLS0tIEgya2xORURncHlvNHJNTnIrb2da
emRETSt4WGFYeXR5UmNSajNpUStKUzAKxgDME0M1ewNE/BrL/wFjF4Yj7GupjRPF
Fuxae5U3phphzOkflQtreM1ScbUGge8WeiSVWY3Pl1azsYo/yqg8Ew==
-----END AGE ENCRYPTED FILE-----
- recipient: age1fm3e99tdyrsvztdchxxllt9nat35xzvd68d09y8scu9jfc7kvvuquhr49c
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAwVEdpZmdSdnBaYnV2RWhT
MmMxQW9PUUJ4enRqNjFIZ25kUEkvdHBpOXdRCmJkSTJyWklhTU5neUlybzR1Nkp6
YlVHczNwRzl0d0hGalpvTFdEUlV3UHMKLS0tIGhQZXEvd2F0aTlna0FNL2wyaEdC
U1oyWXcza08rTG1DS0dUYkZOVWZ4L1kKgpt6jG0lNBMdk/isa1A/tfKYjprnnIo5
pi4t1c7CktFBkhMlOv6VPJCsQlP0YtZUh/uut70Kecv48+YH5gC/8A==
-----END AGE ENCRYPTED FILE-----
- recipient: age16fk0m26n0fr2vmuxm2mjsmrawclde2mlyj6wg3ee9jvzmu5ru3ustgs5jq
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBHRzc5WHAzcWhGSU1kdE1E
Z1B0aFhqYUQzQ2ptK09YMm9odWh3U0w3bmtvCi9IcWFhOFhvYU5ISlVpTURMY2hX
RG5mL1gvNkZ1SDdMZTR4QWxtRG1VUlkKLS0tIFl5UUdIR0JOSmF4OWx1OHBuaFJj
N0FDY2xYRlpmaTgxWURGZWxWWktPV00KAHNeeqhzql4LInlJoD9u7ptFWZBgktvp
tju4cZ/78VgdZIfEfnlzw8lsqpRx1z5Fw8K4CcXRJJLRVfHuj2CHTA==
-----END AGE ENCRYPTED FILE-----
- recipient: age1l694a4xht7r0eza9r2vjncupmp6cxyk3k9x2ljwynnur4m2lc5jqmy3jut
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBscDFuL0ZsdWxoUFJBd2xr
ZXh3K0lSUnFmTVFTVHB5bGR2TC9lREdUczJrCnFSaGoyUnJjbXJ5d1lQd0RUcFJt
REkvdEY2NzcveHpQRWZ1STBSemx0SkkKLS0tIGtyN0svS3lYcmxUbVJiU1RaK21l
Ukh0VkVaeVBoOXQ1cmZ6WHNkYjQvTmsKG4914d+pSt1seoKiejoCvATOTaVFN4ih
Y74W+WXyaKoQP3Q9QrbSURpE+ICfblxHmkbsPB/agNzZVWrfyBaX1A==
-----END AGE ENCRYPTED FILE-----
- recipient: age1m374x78q9eykua32ldrqxh8rh36kz6jyre69a263krf28hcycsqsrmshl0
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBqR01XampvRE92VnZ3OTZs
YmJYaEN2eVJOVWt1OHE1bTdua1ArSC9oVm1ZClBsVFBSWWtLRUoyNDF0NlUwaUpo
b0kyazNwRUFhS0RYd1pGNHNENWxQb28KLS0tIDhzdHhRN1FYczZBMksrM09UWUtJ
bndBTXJhQVE2OVlKeGNTbzJlL0duUzAKIWdesesYvBIN/m36fhzxq30+IT8qp/pF
S6i7QqZF75y2BpEoupRCqNIAsHrouUE+U9ZQJZO8m9J591mWvbVJIw==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2024-07-26T13:05:44Z"
mac: ENC[AES256_GCM,data:9A8nX155dpCC1cvdH1hgeNKh0tt5FMaOKU7vZQ33jfWbiXOsJbp5iHKXxWOexFc70acyhdweoHwq61oJm2mzVufJIPA55ZAUItQcDXJCCeu6KswHug0tQtKHoCRSwdTdMTRNom4XjrpA/j4WWpuhoilyknycXqTpGHHVSdL2lYg=,iv:N0zwzGtGzAxhbmLzslbkXSr/iKmq5FeyT/iWeE4x2hQ=,tag:yIoLXpqlU2SlVRK5+S/qaw==,type:str]
pgp: []
unencrypted_suffix: _unencrypted
version: 3.8.1

View file

@ -1,44 +0,0 @@
# Markdown docs with zola.
[Zola](https://www.getzola.org/) is a static site generated written in Rust
(which you'll notice since sometimes it panics).
To run the site locally:
```
zola serve
```
## Directory Layout
All the important stuff goes into `content`. If you create subdirectories, make
sure you remembered to also create an `_index.md` file for it (if in doubt, just
copy the one at `content/_index.md`); otherwise pages in there won't work.
`templates` is *not* for site templates, but specifies how markdown files should
be turned into html. If an autogenerated link broke, you'll probably have to
change something in there. `sass` and `static` do exactly what they sound like.
It usually shouldn't be necessary to change `config.toml`, but if it is, [here
is the list of all available options](https://www.getzola.org/documentation/getting-started/configuration/).
## File Layout
Markdown files start with a frontmatter that should look something like so:
```markdown
+++
title = "blåhaj"
taxonomies.categories = [ "flausch" ]
+++
[actual markdown goes here]
```
The frontmatter is TOML; the `taxonomies.*` keys are special and can be used to
aggregate posts if enabled in `config.toml` (currently that's only the case for
`categories`, though). See also the [list of all available keys](https://www.getzola.org/documentation/content/page/).
Please don't repeat the page's title in markdown, otherwise it'll appear twice
in the html.

View file

@ -1,35 +0,0 @@
# Zola's configuration file,
#
# see https://www.getzola.org/documentation/getting-started/configuration/
# for available keys.
# The URL the site will be built for
base_url = "https://docs.hacc.space"
compile_sass = true
default_language = "en"
# might be useful — this isn't a blog, obviously, but updates for new entries
# could still be nice, I guess
generate_feeds = true
feed_filenames = [ "atom.xml" ]
build_search_index = true
taxonomies = [
{ name = "categories", feed = false},
]
[markdown]
highlight_code = true
[extra] # user-defined keys
# site title text
main_title = "haccfiles documentation"
# navbar entries
main_menu = [
{url = "$BASE_URL", name = "Home"},
{url = "$BASE_URL/categories", name = "Categories"}
]

View file

@ -1 +0,0 @@
../../docs

View file

@ -1,22 +0,0 @@
{ copyPathToStore, stdenvNoCC, zola, writeShellScriptBin }:
stdenvNoCC.mkDerivation rec {
name = "docs.hacc.space-static";
src = ./.;
content = copyPathToStore ../../docs;
phases = [ "buildPhase" ];
buildInputs = [ zola ];
buildPhase = ''
cp -r $src/* .
rm content
ln -s $content content
zola build --output-dir $out
'';
watch = writeShellScriptBin "watch" ''
cd $(git rev-parse --show-toplevel)/websites/docs.hacc.space
${zola}/bin/zola serve --output-dir /tmp/hacc-docs "$@"
'';
}

View file

@ -1,168 +0,0 @@
@font-face {
font-family: 'share-tech';
src: url('ShareTech-Regular.ttf') format('truetype');
}
html {
overflow: hidden;
height: 100%;
}
body {
background-color: #000;
color: #fff;
overflow-y: auto;
overflow-x: hidden;
height: 100%;
}
#content {
font-family: 'share-tech';
margin-left: auto;
margin-right: auto;
max-width: 60em;
font-size: 16pt;
position: relative;
}
p.subtitle {
font-size: 14pt;
font-style: normal;
color: gray;
}
article {
margin-bottom: 4em;
}
#searchresults {
width: 90%;
text-align: right;
right: 0;
position: absolute;
background-color: black;
top: 5em;
color: gray;
}
#searchresults div {
padding: 0.5em;
border-top: 1px dashed gray;
}
#searchresults div:last-child {
border-bottom: 1px dashed gray;
}
.searchresultprevtext {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
display: inline-block;
width: 40em;
float: left;
}
footer.content {
top: 50px;
color: #cccccc;
font-size: 14px;
margin-bottom: 4em;
}
footer a {
color: #cccccc;
}
.logo {
position: relative;
width: 100%;
}
.logo > img {
width: 300px;
max-width: 100%;
}
h1 {
font-size: 32pt;
}
#headernav {
text-align: right;
margin: 1em;
}
#headernav > a {
padding: 0.2em;
font-size: 20pt;
font-family: share-tech;
}
h1, h2, h3, h4, h5, h6{
font-weight: 600;
display: inline;
font-family: share-tech;
background: rgb(59,115,185);
background: linear-gradient(90deg, rgb(59, 115, 185) 0%, rgb(229, 35, 33) 100%);
background-clip: border-box;
color: transparent;
-webkit-background-clip: text;
background-clip: text;
}
/*
h4 {
//font-weight: 600;
//display: inline;
font-family: share-tech;
//background: rgb(59,115,185);
//background: linear-gradient(90deg, rgb(59, 115, 185) 0%, rgb(229, 35, 33) 100%);
//background-clip: border-box;
color: #fff;
//-webkit-background-clip: text;
//background-clip: text;
}
*/
a {
text-decoration: none;
color: #3b73b9;
transition: color .1s linear;
}
a:hover {
/*color: #e52321;*/
color: #4e9af9;
}
ul {
margin-top: 0;
}
pre {
padding: 1rem;
overflow: auto;
font-size: 16px;
}
// The line numbers already provide some kind of left/right padding
pre[data-linenos] {
padding: 1rem 0;
}
pre table td {
padding: 0;
}
// The line number cells
pre table td:nth-of-type(1) {
text-align: center;
user-select: none;
}
pre mark {
// If you want your highlights to take the full width.
display: block;
// The default background colour of a mark is bright yellow
background-color: rgba(254, 252, 232, 0.9);
}
pre table {
width: 100%;
border-collapse: collapse;
}

Some files were not shown because too many files have changed in this diff Show more