Merge remote-tracking branch 'origin/master' into ente-public
This commit is contained in:
7
modules/acme.nix
Normal file
7
modules/acme.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
security.acme = {
|
||||
acceptTerms = true;
|
||||
# Replace the email here!
|
||||
defaults.email = "7265381+Kropatz@users.noreply.github.com";
|
||||
};
|
||||
}
|
||||
92
modules/adguard.nix
Normal file
92
modules/adguard.nix
Normal file
@@ -0,0 +1,92 @@
|
||||
{ config, pkgs, inputs, vars, ... }:
|
||||
let
|
||||
ip = vars.ipv4;
|
||||
wireguardIp = vars.wireguardIp;
|
||||
in
|
||||
{
|
||||
networking.firewall.allowedTCPPorts = [ 53 ];
|
||||
networking.firewall.allowedUDPPorts = [ 53 ];
|
||||
|
||||
services.adguardhome = {
|
||||
enable = true;
|
||||
settings = {
|
||||
users = [
|
||||
{
|
||||
name = "admin";
|
||||
password = "$2y$15$iPzjmUJPTwWUOsDp46GOPO/LYor/jDJjndwy2QlPddaKSD4QXvq9W";
|
||||
}
|
||||
];
|
||||
dns = {
|
||||
bind_hosts = [ "127.0.0.1" ip wireguardIp ];
|
||||
port = 53;
|
||||
protection_enabled = true;
|
||||
filtering_enabled = true;
|
||||
upstream_dns = [
|
||||
"https://doh.tiar.app/dns-query"
|
||||
"tls://getdnsapi.net"
|
||||
"https://dns.adguard-dns.com/dns-query"
|
||||
"tls://dot.seby.io"
|
||||
];
|
||||
use_http3_upstreams = true;
|
||||
rewrites = [
|
||||
{
|
||||
"domain" = "kopatz.ddns.net";
|
||||
"answer" = ip;
|
||||
}
|
||||
{
|
||||
"domain" = "server.home";
|
||||
"answer" = ip;
|
||||
}
|
||||
{
|
||||
"domain" = "server.local";
|
||||
"answer" = ip;
|
||||
}
|
||||
{
|
||||
"domain" = "adguard.local";
|
||||
"answer" = ip;
|
||||
}
|
||||
{
|
||||
"domain" = "nextcloud.local";
|
||||
"answer" = ip;
|
||||
}
|
||||
{
|
||||
"domain" = "turnserver.local";
|
||||
"answer" = "192.168.2.1";
|
||||
}
|
||||
{
|
||||
"domain" = "inverter.local";
|
||||
"answer" = "192.168.0.9";
|
||||
}
|
||||
];
|
||||
};
|
||||
querylog = {
|
||||
enabled = false;
|
||||
};
|
||||
filters = [
|
||||
{
|
||||
enabled = true;
|
||||
url = "https://adguardteam.github.io/HostlistsRegistry/assets/filter_1.txt";
|
||||
name = "adguard dns list";
|
||||
id = 1;
|
||||
}
|
||||
{
|
||||
enabled = true;
|
||||
url = "https://adguardteam.github.io/HostlistsRegistry/assets/filter_2.txt";
|
||||
name = "adguard block list";
|
||||
id = 2;
|
||||
}
|
||||
{
|
||||
enabled = true;
|
||||
url = "https://dbl.oisd.nl/";
|
||||
name = "big block list";
|
||||
id = 3;
|
||||
}
|
||||
];
|
||||
dhcp = { enabled = false; };
|
||||
dhcpv6 = { enabled = false; };
|
||||
tls = {
|
||||
enabled = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
108
modules/backup.nix
Normal file
108
modules/backup.nix
Normal file
@@ -0,0 +1,108 @@
|
||||
{ config, pkgs, lib, inputs, ... }:
|
||||
{
|
||||
age.secrets.restic-pw = {
|
||||
file = ../secrets/restic-pw.age;
|
||||
};
|
||||
age.secrets.restic-s3 = {
|
||||
file = ../secrets/restic-s3.age;
|
||||
};
|
||||
age.secrets.restic-gdrive = {
|
||||
file = ../secrets/restic-gdrive.age;
|
||||
};
|
||||
services.restic = {
|
||||
backups = {
|
||||
localbackup = {
|
||||
exclude = [
|
||||
"/home/**/Cache"
|
||||
"/home/**/.cache"
|
||||
"/home/**/__pycache__"
|
||||
"/home/**/node_modules"
|
||||
"/home/**/venv"
|
||||
];
|
||||
initialize = true;
|
||||
passwordFile = config.age.secrets.restic-pw.path;
|
||||
paths = [
|
||||
"/home"
|
||||
"/var/backup/postgresql"
|
||||
"/mnt/250ssd/matrix-synapse/media_store/"
|
||||
"/mnt/250ssd/nextcloud"
|
||||
"/mnt/250ssd/paperless"
|
||||
"/mnt/250ssd/kavita"
|
||||
];
|
||||
pruneOpts = [ "--keep-daily 7" "--keep-weekly 10" "--keep-monthly 12" "--keep-yearly 75" ];
|
||||
repository = "/mnt/2tb/restic";
|
||||
};
|
||||
localbackup-1tb = {
|
||||
initialize = true;
|
||||
passwordFile = config.age.secrets.restic-pw.path;
|
||||
paths = [
|
||||
"/home"
|
||||
"/var/backup/postgresql"
|
||||
"/mnt/250ssd/matrix-synapse/media_store/"
|
||||
"/mnt/250ssd/nextcloud"
|
||||
"/mnt/250ssd/paperless"
|
||||
"/mnt/250ssd/kavita"
|
||||
];
|
||||
exclude = [
|
||||
"/home/**/Cache"
|
||||
"/home/**/.cache"
|
||||
"/home/**/__pycache__"
|
||||
"/home/**/node_modules"
|
||||
"/home/**/venv"
|
||||
];
|
||||
repository = "/mnt/1tb/restic";
|
||||
pruneOpts = [ "--keep-daily 5" "--keep-weekly 5" "--keep-monthly 12" "--keep-yearly 75" ];
|
||||
timerConfig = {
|
||||
OnCalendar = "*-*-03,06,09,12,15,18,21,24,27,30 02:00:00";
|
||||
Persistent = true;
|
||||
};
|
||||
};
|
||||
remotebackup-gdrive = {
|
||||
initialize = true;
|
||||
passwordFile = config.age.secrets.restic-pw.path;
|
||||
paths = [
|
||||
"/home"
|
||||
"/var/backup/postgresql"
|
||||
"/mnt/250ssd/matrix-synapse/media_store/"
|
||||
"/mnt/250ssd/nextcloud"
|
||||
"/mnt/250ssd/paperless"
|
||||
];
|
||||
exclude = [
|
||||
"/home/**/Cache"
|
||||
"/home/**/.cache"
|
||||
"/home/**/__pycache__"
|
||||
"/home/**/node_modules"
|
||||
"/home/**/venv"
|
||||
];
|
||||
rcloneConfigFile = config.age.secrets.restic-gdrive.path;
|
||||
repository = "rclone:it-experts:backup";
|
||||
pruneOpts = [ "--keep-daily 5" "--keep-weekly 5" "--keep-monthly 12" "--keep-yearly 75" ];
|
||||
timerConfig = {
|
||||
OnCalendar = "*-*-03,06,09,12,15,18,21,24,27,30 02:00:00";
|
||||
Persistent = true;
|
||||
};
|
||||
};
|
||||
remotebackup = {
|
||||
exclude = [
|
||||
"/home/**/Cache"
|
||||
"/home/**/.cache"
|
||||
"/home/**/__pycache__"
|
||||
"/home/**/node_modules"
|
||||
"/home/**/venv"
|
||||
];
|
||||
initialize = true;
|
||||
passwordFile = config.age.secrets.restic-pw.path;
|
||||
environmentFile = config.age.secrets.restic-s3.path;
|
||||
paths = [
|
||||
"/home"
|
||||
];
|
||||
pruneOpts = [ "--keep-daily 5" "--keep-weekly 5" "--keep-monthly 12" "--keep-yearly 75" ];
|
||||
timerConfig = {
|
||||
OnCalendar = "*-*-03,06,09,12,15,18,21,24,27,30 00:00:00";
|
||||
Persistent = true;
|
||||
};
|
||||
repository = "s3:s3.us-west-002.backblazeb2.com/kop-bucket";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
73
modules/coturn.nix
Normal file
73
modules/coturn.nix
Normal file
@@ -0,0 +1,73 @@
|
||||
{ config, pkgs, lib, inputs, ... }:
|
||||
{
|
||||
age.secrets.coturn-secret = {
|
||||
file = ../secrets/coturn-secret.age;
|
||||
owner = "turnserver";
|
||||
group = "turnserver";
|
||||
};
|
||||
|
||||
networking.firewall.allowedUDPPortRanges = [ { from = 49000; to=50000; } ];
|
||||
networking.firewall.allowedUDPPorts = [ 3478 ]; #5349 ];
|
||||
networking.firewall.allowedTCPPorts = [ 3478 ]; #5349 ];
|
||||
|
||||
|
||||
services.coturn = {
|
||||
enable = true;
|
||||
no-cli = true;
|
||||
#tls-listening-port = 5349;
|
||||
listening-port = 3478;
|
||||
min-port = 49000;
|
||||
max-port = 50000;
|
||||
use-auth-secret = true;
|
||||
static-auth-secret-file = config.age.secrets.coturn-secret.path;
|
||||
relay-ips = [
|
||||
"192.168.2.1"
|
||||
];
|
||||
listening-ips = [
|
||||
"192.168.2.1"
|
||||
];
|
||||
realm = "kopatz.ddns.net";
|
||||
#cert = "${config.security.acme.certs."kopatz.ddns.net".directory}/full.pem";
|
||||
#pkey = "${config.security.acme.certs."kopatz.ddns.net".directory}/key.pem";
|
||||
extraConfig = ''
|
||||
no-sslv3
|
||||
no-tlsv1
|
||||
no-tlsv1_1
|
||||
no-tlsv1_2
|
||||
# for debugging
|
||||
verbose
|
||||
# ban private IP ranges
|
||||
no-multicast-peers
|
||||
allowed-peer-ip=192.168.2.0-192.168.2.255
|
||||
denied-peer-ip=0.0.0.0-0.255.255.255
|
||||
denied-peer-ip=10.0.0.0-10.255.255.255
|
||||
denied-peer-ip=100.64.0.0-100.127.255.255
|
||||
denied-peer-ip=127.0.0.0-127.255.255.255
|
||||
denied-peer-ip=169.254.0.0-169.254.255.255
|
||||
denied-peer-ip=172.16.0.0-172.31.255.255
|
||||
denied-peer-ip=192.0.0.0-192.0.0.255
|
||||
denied-peer-ip=192.0.2.0-192.0.2.255
|
||||
denied-peer-ip=192.168.0.0-192.168.255.255
|
||||
denied-peer-ip=192.88.99.0-192.88.99.255
|
||||
denied-peer-ip=198.18.0.0-198.19.255.255
|
||||
denied-peer-ip=198.51.100.0-198.51.100.255
|
||||
denied-peer-ip=203.0.113.0-203.0.113.255
|
||||
denied-peer-ip=240.0.0.0-255.255.255.255
|
||||
denied-peer-ip=::1
|
||||
denied-peer-ip=64:ff9b::-64:ff9b::ffff:ffff
|
||||
denied-peer-ip=::ffff:0.0.0.0-::ffff:255.255.255.255
|
||||
denied-peer-ip=100::-100::ffff:ffff:ffff:ffff
|
||||
denied-peer-ip=2001::-2001:1ff:ffff:ffff:ffff:ffff:ffff:ffff
|
||||
denied-peer-ip=2002::-2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff
|
||||
denied-peer-ip=fc00::-fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
|
||||
denied-peer-ip=fe80::-febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff
|
||||
'';
|
||||
};
|
||||
|
||||
#systemd.services.coturn = {
|
||||
# serviceConfig = {
|
||||
# User = lib.mkForce "root";
|
||||
# Group = lib.mkForce "root";
|
||||
# };
|
||||
# };
|
||||
}
|
||||
5
modules/cron.nix
Normal file
5
modules/cron.nix
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
services.cron = {
|
||||
enable = true;
|
||||
};
|
||||
}
|
||||
7
modules/docker.nix
Normal file
7
modules/docker.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
{ config, pkgs, lib, inputs, ... }:
|
||||
{
|
||||
virtualisation.docker.enable = true;
|
||||
environment.systemPackages = with pkgs; [
|
||||
docker-compose
|
||||
];
|
||||
}
|
||||
12
modules/dyndns.nix
Normal file
12
modules/dyndns.nix
Normal file
@@ -0,0 +1,12 @@
|
||||
{ config, pkgs, lib, inputs, ... }:
|
||||
{
|
||||
age.secrets.duckdns = {
|
||||
file = ../secrets/duckdns.age;
|
||||
};
|
||||
services.ddclient = {
|
||||
enable = true;
|
||||
protocol = "duckdns";
|
||||
passwordFile = config.age.secrets.duckdns.path;
|
||||
domains = ["wachbirn.duckdns.org"];
|
||||
};
|
||||
}
|
||||
15
modules/fail2ban.nix
Normal file
15
modules/fail2ban.nix
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
services.fail2ban = {
|
||||
enable = true;
|
||||
ignoreIP = [
|
||||
"192.168.0.0/16"
|
||||
];
|
||||
bantime = "24h";
|
||||
bantime-increment = {
|
||||
enable = true; # Enable increment of bantime after each violation
|
||||
multipliers = "1 2 4 8 16 32 64";
|
||||
maxtime = "168h"; # Do not ban for more than 1 week
|
||||
overalljails = true; # Calculate the bantime based on all the violations
|
||||
};
|
||||
};
|
||||
}
|
||||
7
modules/firewall.nix
Normal file
7
modules/firewall.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
{ config, pkgs, lib, inputs, vars, ... }:
|
||||
let
|
||||
allowedUDPPortRanges = vars.udpRanges;
|
||||
in
|
||||
{
|
||||
networking.firewall.allowedUDPPortRanges = allowedUDPPortRanges;
|
||||
}
|
||||
3
modules/flatpak.nix
Normal file
3
modules/flatpak.nix
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
services.flatpak.enable = true;
|
||||
}
|
||||
3
modules/git.nix
Normal file
3
modules/git.nix
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
programs.git.enable = true;
|
||||
}
|
||||
42
modules/github-runner.nix
Normal file
42
modules/github-runner.nix
Normal file
@@ -0,0 +1,42 @@
|
||||
{ config, pkgs, lib, inputs, ... }:
|
||||
{
|
||||
nixpkgs.config.permittedInsecurePackages = [
|
||||
"nodejs-16.20.2"
|
||||
];
|
||||
|
||||
users.groups.github-actions-runner = {};
|
||||
users.users.github-actions-runner = {
|
||||
isSystemUser = true;
|
||||
passwordFile = config.age.secrets.github-runner-pw.path;
|
||||
group = "github-actions-runner";
|
||||
extraGroups = [ "docker" ];
|
||||
};
|
||||
age.secrets.github-runner-token = {
|
||||
file = ../secrets/github-runner-token.age;
|
||||
owner = "github-actions-runner";
|
||||
group = "github-actions-runner";
|
||||
};
|
||||
age.secrets.github-runner-pw = {
|
||||
file = ../secrets/github-runner-pw.age;
|
||||
owner = "github-actions-runner";
|
||||
group = "github-actions-runner";
|
||||
};
|
||||
systemd.tmpfiles.rules = [
|
||||
"d /github-actions-runner 0770 github-actions-runner github-actions-runner -"
|
||||
"d /data 0770 github-actions-runner nginx -"
|
||||
"d /data/website 0770 github-actions-runner nginx -"
|
||||
];
|
||||
services.github-runner = {
|
||||
enable = true;
|
||||
name = "nixos-server";
|
||||
tokenFile = config.age.secrets.github-runner-token.path;
|
||||
url = "https://github.com/oberprofis";
|
||||
user = "github-actions-runner";
|
||||
workDir = "/github-actions-runner";
|
||||
extraPackages = with pkgs; [ rsync nodePackages.pnpm nodejs_18 ];
|
||||
serviceOverrides = {
|
||||
BindPaths= [ "/github-actions-runner" "/data/website" ];
|
||||
UMask = "022";
|
||||
};
|
||||
};
|
||||
}
|
||||
13
modules/gpg.nix
Normal file
13
modules/gpg.nix
Normal file
@@ -0,0 +1,13 @@
|
||||
{pkgs, ...}:
|
||||
{
|
||||
#services.pcscd.enable = true;
|
||||
|
||||
programs.gnupg.agent = {
|
||||
enable = true;
|
||||
enableSSHSupport = true;
|
||||
pinentryFlavor = "qt";
|
||||
};
|
||||
#environment.systemPackages = with pkgs; [
|
||||
# pinentry-curses
|
||||
# ];
|
||||
}
|
||||
59
modules/graphical/gnome.nix
Normal file
59
modules/graphical/gnome.nix
Normal file
@@ -0,0 +1,59 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
services.xserver = {
|
||||
layout = "at";
|
||||
xkbVariant = "";
|
||||
enable = true;
|
||||
displayManager.gdm.enable = true;
|
||||
desktopManager.gnome.enable = true;
|
||||
};
|
||||
|
||||
# Workaround for GNOME autologin: https://github.com/NixOS/nixpkgs/issues/103746#issuecomment-945091229
|
||||
systemd.services."getty@tty1".enable = false;
|
||||
systemd.services."autovt@tty1".enable = false;
|
||||
|
||||
environment.sessionVariables.NIXOS_OZONE_WL = "1";
|
||||
|
||||
environment.gnome.excludePackages = (with pkgs; [
|
||||
gnome-photos
|
||||
gnome-tour
|
||||
]) ++ (with pkgs.gnome; [
|
||||
cheese # webcam tool
|
||||
gnome-music
|
||||
gnome-terminal
|
||||
gedit # text editor
|
||||
epiphany # web browser
|
||||
#geary # email reader
|
||||
evince # document viewer
|
||||
gnome-characters
|
||||
totem # video player
|
||||
tali # poker game
|
||||
iagno # go game
|
||||
hitori # sudoku game
|
||||
atomix # puzzle game
|
||||
]);
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
wmctrl
|
||||
gnome.mutter
|
||||
gnome.adwaita-icon-theme
|
||||
gnome.gnome-settings-daemon
|
||||
gnome.gnome-tweaks
|
||||
gnome.dconf-editor
|
||||
gruvbox-gtk-theme
|
||||
colloid-icon-theme
|
||||
gnomeExtensions.appindicator
|
||||
gnomeExtensions.just-perfection
|
||||
gnomeExtensions.system-monitor
|
||||
gnomeExtensions.dash2dock-lite
|
||||
gnomeExtensions.dash-to-dock
|
||||
gnomeExtensions.vitals
|
||||
gnomeExtensions.rounded-window-corners
|
||||
gnomeExtensions.wallpaper-switcher
|
||||
gnomeExtensions.backslide
|
||||
gnomeExtensions.nextcloud-folder
|
||||
gnomeExtensions.tray-icons-reloaded
|
||||
gnomeExtensions.blur-my-shell
|
||||
];
|
||||
}
|
||||
11
modules/graphical/plasma.nix
Normal file
11
modules/graphical/plasma.nix
Normal file
@@ -0,0 +1,11 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
services.xserver = {
|
||||
layout = "at";
|
||||
xkbVariant = "";
|
||||
enable = true;
|
||||
displayManager.sddm.enable = true;
|
||||
desktopManager.plasma5.enable = true;
|
||||
};
|
||||
}
|
||||
83
modules/graphical/shared.nix
Normal file
83
modules/graphical/shared.nix
Normal file
@@ -0,0 +1,83 @@
|
||||
{ config, pkgs, inputs, ... }:
|
||||
|
||||
let
|
||||
keepassWithPlugins = pkgs.keepass.override {
|
||||
plugins = [
|
||||
pkgs.keepass-keepassrpc
|
||||
];
|
||||
};
|
||||
in
|
||||
{
|
||||
programs.steam = {
|
||||
enable = true;
|
||||
remotePlay.openFirewall = true; # Open ports in the firewall for Steam Remote Play
|
||||
dedicatedServer.openFirewall = true; # Open ports in the firewall for Source Dedicated Server
|
||||
};
|
||||
|
||||
programs.kdeconnect.enable = true;
|
||||
|
||||
fonts.fontDir.enable = true;
|
||||
fonts.fonts = with pkgs; [
|
||||
nerdfonts
|
||||
];
|
||||
|
||||
networking.firewall = {
|
||||
enable = true;
|
||||
allowedTCPPortRanges = [
|
||||
{ from = 1714; to = 1764; } # KDE Connect
|
||||
];
|
||||
allowedUDPPortRanges = [
|
||||
{ from = 1714; to = 1764; } # KDE Connect
|
||||
];
|
||||
};
|
||||
|
||||
# Allow unfree packages
|
||||
nixpkgs.config.allowUnfree = true;
|
||||
nix.settings.experimental-features = [ "nix-command" "flakes" ];
|
||||
|
||||
# List packages installed in system profile. To search, run:
|
||||
# $ nix search wget
|
||||
environment.systemPackages = with pkgs; [
|
||||
# vim # Do not forget to add an editor to edit configuration.nix! The Nano editor is also installed by default.
|
||||
# wget
|
||||
wget
|
||||
nixos-option
|
||||
kate
|
||||
keepassWithPlugins
|
||||
jetbrains.idea-ultimate
|
||||
jetbrains.rider
|
||||
dotnet-sdk_7
|
||||
dotnet-runtime_7
|
||||
neovim
|
||||
htop
|
||||
btop
|
||||
git
|
||||
xfce.thunar
|
||||
killall
|
||||
xclip
|
||||
usbutils
|
||||
bun
|
||||
inputs.agenix.packages."x86_64-linux".default
|
||||
insomnia
|
||||
remmina
|
||||
nextcloud-client
|
||||
#podman-compose
|
||||
#arion # docker
|
||||
neofetch
|
||||
thunderbird
|
||||
rofi
|
||||
pdfgrep
|
||||
taisei
|
||||
ncdu
|
||||
localsend
|
||||
element-desktop
|
||||
tetrio-desktop
|
||||
];
|
||||
|
||||
environment.sessionVariables = {
|
||||
DOTNET_ROOT = "${pkgs.dotnet-sdk_7}";
|
||||
};
|
||||
|
||||
### docker
|
||||
virtualisation.docker.enable = true;
|
||||
}
|
||||
7
modules/hdd-spindown.nix
Normal file
7
modules/hdd-spindown.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
{ pkgs, ...}:
|
||||
{
|
||||
powerManagement.powerUpCommands = ''
|
||||
${pkgs.hdparm}/sbin/hdparm -B 127 /dev/sd[ab]
|
||||
${pkgs.hdparm}/sbin/hdparm -S 120 /dev/sd[ab]
|
||||
'';
|
||||
}
|
||||
19
modules/home-assistant.nix
Normal file
19
modules/home-assistant.nix
Normal file
@@ -0,0 +1,19 @@
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
services.home-assistant = {
|
||||
enable = true;
|
||||
extraComponents = [
|
||||
# Components required to complete the onboarding
|
||||
"esphome"
|
||||
"met"
|
||||
"radio_browser"
|
||||
"fronius"
|
||||
"adguard"
|
||||
];
|
||||
config = {
|
||||
# Includes dependencies for a basic setup
|
||||
# https://www.home-assistant.io/integrations/default_config/
|
||||
default_config = {};
|
||||
};
|
||||
};
|
||||
}
|
||||
31
modules/kavita.nix
Normal file
31
modules/kavita.nix
Normal file
@@ -0,0 +1,31 @@
|
||||
{ config, pkgs, lib, inputs, ... }:
|
||||
{
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ 5000 ];
|
||||
age.secrets.kavita = {
|
||||
file = ../secrets/kavita.age;
|
||||
owner = "kavita";
|
||||
group = "kavita";
|
||||
};
|
||||
services.kavita = {
|
||||
enable = true;
|
||||
user = "kavita";
|
||||
port = 5000;
|
||||
dataDir = "/mnt/250ssd/kavita";
|
||||
tokenKeyFile = config.age.secrets.kavita.path;
|
||||
};
|
||||
#todo: base url needs new kavita version
|
||||
systemd.services.kavita = {
|
||||
preStart = ''
|
||||
umask u=rwx,g=rx,o=
|
||||
cat > "/mnt/250ssd/kavita/config/appsettings.json" <<EOF
|
||||
{
|
||||
"TokenKey": "$(cat ${config.age.secrets.kavita.path})",
|
||||
"Port": 5000,
|
||||
"BaseUrl" : "/books",
|
||||
"IpAddresses": "${lib.concatStringsSep "," ["0.0.0.0" "::"]}"
|
||||
}
|
||||
EOF
|
||||
'';
|
||||
};
|
||||
}
|
||||
9
modules/minecraft-server.nix
Normal file
9
modules/minecraft-server.nix
Normal file
@@ -0,0 +1,9 @@
|
||||
{ pkgs, ...}:
|
||||
{
|
||||
services.minecraft-server = {
|
||||
enable = true;
|
||||
eula = true;
|
||||
openFirewall = true;
|
||||
package = pkgs.unstable.papermc;
|
||||
};
|
||||
}
|
||||
52
modules/motd.nix
Normal file
52
modules/motd.nix
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
users.motd = ''
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣴⣾⣿⣿⣿⣿⣿⠟⡅⠠⢀⢠⡾⠋⠀⣀⣠⣴⠶⠛⠋⠉⢀⣀⣠⡴⠋⠁⡆⢌⠉⠙⢦⠀⠀⠈⠉⠉⠉⠓⠫⢝⡓⠦⣤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣠⣄⣤⣤⣤⣤⣤⣤⣤⣴⣾⣿⢿⣻⣿⣿⣿⡿⠟⣱⠃⡄⢣⣰⣿⣗⣾⡿⠟⠉⠀⣀⠤⠒⠉⠁⣼⠋⠀⠀⢸⠀⠈⣆⠀⠀⠳⣤⣀⠀⠀⠀⠀⠀⠀⠈⠀⣀⣙⣻⣶⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⢃⣤⣼⣦⣷⣮⣷⣿⣿⣿⣿⣿⣿⣿⣿⡿⠛⠉⣠⡾⢡⠚⡤⣷⡿⣻⠟⠉⣀⣤⠞⠋⠀⠀⠀⠀⣼⢻⠀⠀⠀⠈⠀⠀⢸⡄⠀⠀⢣⠀⠉⠒⠶⣶⣿⣍⣉⣭⣡⣤⠀⠉⠛⢿⣷⣦⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡿⢠⣿⣟⣿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠚⠁⠀⢀⣴⡟⡔⣣⢹⣼⣿⠞⢁⣠⡾⠋⠀⠀⠀⠀⢀⣤⢾⠃⡏⠀⠀⠀⠀⠀⠀⠀⡇⢀⠀⠘⣦⠀⠀⠀⢄⠙⠺⣿⢿⣿⣿⣧⠀⢀⠀⠙⢮⡳⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠⣧⢣⣿⣿⢾⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡞⠛⠛⠛⠙⢻⠟⣀⣴⠟⠋⠀⠀⣠⡴⠊⣡⠞⠁⡟⢰⠁⠀⠀⠀⠀⠀⠀⠀⡇⢈⠆⠀⢿⡀⠀⠀⠀⠑⡀⠀⠙⠽⢿⣿⣧⠀⠣⠀⠀⠙⢶⡹⢷⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡠⠊⠀⢹⣯⢿⣿⣻⣧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⡀⠀⠀⠀⠀⢧⡽⠋⠀⠀⡠⠊⠁⠀⡴⠃⠀⠀⡇⠸⠀⠀⠀⠀⠀⠀⠀⠀⡜⢸⢠⠀⡘⢷⡀⠀⠀⠠⡈⠆⠀⠀⠀⠘⢿⣧⠰⠁⠀⠀⠀⠙⢮⣳⢧⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣶⣷⡀⠀⠀⠀⠸⡀⡀⡰⠊⠀⠀⢀⠞⠀⠀⠀⠈⡇⠘⠀⠀⠀⠀⠀⠀⠀⠀⡇⣼⠎⠀⡅⠈⢳⡀⠀⠀⠈⠻⣄⠀⠀⠀⠸⣿⡄⢣⠀⠀⠀⠀⠈⠻⣦⡈⠑⠒⢤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢄⠀⠀⣰⣿⣿⣿⣿⣿⠟⠀⠀⠀⠀⠀⠀⢀⣀⣴⣮⡿⣿⣿⣷⠀⠀⠀⠘⣿⠚⠀⠀⠀⢠⠋⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⣸⣷⡇⠀⢀⡇⠀⡀⢳⡀⠀⠀⠀⠈⠢⡀⠀⠀⣿⣧⠈⣧⠀⠀⠀⠀⠀⠙⢿⣦⡀⠀⠙⠗⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢦⣴⡿⣽⣿⣿⣿⡟⠀⠠⠤⠤⠤⣴⣶⣾⣿⡿⠟⣡⠿⣿⣿⣆⠀⠀⠀⢻⡆⠀⠀⠀⡜⢢⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⣠⡿⡻⠁⠀⣼⠃⠀⠱⡈⢇⠀⠀⠀⠀⠀⠳⡀⠀⢹⣿⠀⢻⡆⠀⠀⠀⠀⢀⠈⠻⣷⣄⠀⠀⠙⢅⠢⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣽⣿⣿⣿⣿⣴⣶⣶⣾⣿⡿⢟⡹⣿⣯⣤⣾⣁⡀⡽⣿⣿⣄⠀⠀⠀⢿⡀⠀⡜⠀⠠⡙⠦⣄⡀⠀⣧⠀⠀⠀⠀⣀⠠⠞⢉⠜⠁⠀⢰⠏⡠⠀⠀⢱⠈⡄⠀⠀⠀⠀⠀⠘⢄⢸⣿⡀⠘⠻⡄⠀⠀⠀⠈⡄⠀⢻⣿⡻⢦⡀⠀⠑⢌⠢⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣟⣾⣿⣿⣿⠋⠈⣉⢭⡽⣟⡛⣬⠣⡗⢿⣿⡿⣿⣻⢿⣷⣿⣿⣿⣄⠀⠀⠸⣇⡸⠀⠀⠀⠈⠑⠬⣕⣢⣍⣉⠉⠉⠁⣀⣠⣴⠏⠀⠀⢠⡇⠀⠀⠀⠀⠸⣃⠸⡀⠀⠀⠀⠀⠀⠈⢚⣿⡇⠀⡀⠹⡀⠀⠀⠀⢱⠀⠀⢯⡻⣄⠈⠒⢄⡀⠱⡄⠑⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⢻⣾⣿⣿⠿⠁⠲⠟⡺⣍⠶⡡⢏⣴⣳⣽⣿⣿⣷⣭⣓⡏⡞⡽⣻⢿⣿⣦⣄⠀⢹⡁⠀⠀⠀⠀⠀⢠⠀⢩⠏⣯⠉⠛⠋⠉⡠⠊⠀⠀⣰⡟⠀⠀⠀⠀⠀⠀⠘⡀⢳⡀⠀⠀⠀⠀⠀⠀⣿⡇⠀⡇⠀⢡⡀⠀⠀⠸⡇⠀⠸⢿⣟⣦⠀⠀⠙⡆⢼⣦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣫⠟⠋⠁⠀⠀⠀⠰⣉⣶⡼⠶⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣽⣞⣿⣿⣿⣷⣌⣇⠀⠀⠀⠀⢠⡏⢀⡞⠀⠸⡆⠀⢀⠔⠁⠀⢠⣾⠋⠀⠀⠀⠀⠀⠀⠀⠀⠇⠘⣿⡄⠀⠀⠀⠀⠀⣿⢳⠀⠇⠈⢄⠱⡀⠀⠀⢿⠀⠀⠸⡜⢿⣷⡄⠀⠈⢆⠈⠳⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⠗⠁⠀⠀⠀⣀⡤⠖⠛⠉⠀⠀⢠⣾⣿⣿⡿⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⠋⠀⠀⠀⠀⡸⠀⣼⠒⢆⢀⡹⠔⠁⠀⣠⣶⠟⢧⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⢇⠹⣄⠀⠀⠀⠀⣿⠈⠀⠀⠀⠈⢦⠈⢂⠀⢸⡇⠀⠀⢣⠘⣟⣷⡀⠀⠀⠡⡀⠈⠢⡀⠑⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡾⠋⢀⡠⠤⠒⠉⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⠏⠀⢠⣿⡟⠀⠀⢸⠁⠀⠀⠀⠀⢀⠅⠀⡟⠀⠤⡀⠀⠀⠀⡇⣼⠃⡀⠜⠋⣀⣤⣴⠿⠋⠀⠀⠈⢆⠀⠀⠀⠀⠀⠀⠀⠀⠸⡄⢸⠀⠹⣆⠀⠀⢠⡟⠐⠀⣆⠀⠀⠈⣷⢄⠑⢼⣗⠀⠀⠈⡄⠘⣟⣧⠀⠀⠀⠡⡀⠀⠐⠄⠘⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⡿⢋⠞⡏⢀⠴⠋⣼⠃⠀⠀⡎⠀⠀⠀⠀⠀⡜⠀⠀⡇⠠⣀⠀⠉⠐⣺⠟⡏⡻⣗⣉⣉⣀⠸⡙⡄⠀⠀⡀⢆⠈⢢⠀⠀⠀⠀⠀⠀⠀⢀⠇⠐⡀⠀⠘⡆⠀⢸⠇⠐⠀⠉⡄⠀⠀⢸⡄⠑⠤⡈⠢⢄⡀⠃⠀⠘⣿⣇⡀⠀⠀⠱⡀⠀⠈⢆⠈⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣻⢧⠏⣸⠔⠉⣠⠎⣾⠀⠀⠀⠇⠀⠀⠀⠀⣰⠁⠀⢸⠁⠀⠀⠉⠉⣸⣿⡷⠟⠛⠉⠉⠀⠈⢾⡇⠹⡄⠀⠱⠈⣦⠀⠑⡄⢀⠀⠀⠀⠀⠈⠉⠘⠗⠠⢀⣸⡄⣸⡀⠃⢠⠀⢰⠀⠀⠀⣧⠀⠀⣿⠑⠢⠬⢷⡲⠦⠼⣿⡅⠀⠀⠀⢱⠀⠀⠀⢣⢥⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡾⢡⣏⠔⠁⠀⠴⠃⡜⢸⠀⠀⢈⠀⠀⠀⠀⢠⡟⠀⠀⢸⠀⣀⠄⠂⣁⡽⢸⡄⠀⠀⠀⠀⠀⠀⠘⣧⠀⢻⡄⠀⢣⠘⡳⣄⠀⠙⢆⠀⠀⠀⠀⠀⠀⠂⠀⠀⠈⣿⣷⠀⡀⡸⠀⠀⣆⠀⠀⢸⡀⠀⣿⠆⠀⠀⡀⠆⠀⠀⢿⣿⠀⠀⠀⠀⠆⠀⠀⠈⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⢾⣇⡾⠉⠀⣠⣤⠀⡸⠀⢸⡀⠀⠠⠀⠀⠀⢀⣾⠇⠀⠀⢸⡏⠀⠀⡰⢣⠟⢸⡇⠀⠀⠀⠀⠀⠀⠀⢹⡄⠈⣿⡄⠈⣆⠁⠈⢳⣤⡀⠑⠠⣀⢀⠀⠐⠀⠀⠀⠀⢈⣧⠀⢀⠇⠀⠀⢼⠀⠀⠈⡇⠀⣿⡅⠀⠀⢧⠸⠀⠀⠈⢿⡇⠀⠀⠀⢡⠀⠀⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡜⢸⠋⠀⢀⣾⣿⠇⢠⠁⠀⢸⡀⠀⠐⠀⠀⢀⣾⣼⠁⠀⠀⢸⠅⢀⣼⡷⠋⠀⢸⣷⣃⣀⣀⣀⣀⠀⠀⢈⡇⠀⢳⢹⡄⠀⢃⠀⠀⢻⡛⠷⣤⣀⣉⠒⢤⣀⡀⠀⠀⡞⠸⡏⡈⢀⠤⠊⠈⡆⠀⠀⣿⠀⣿⠆⠀⠀⣾⡀⡇⢠⠀⠈⠏⢆⠀⠀⡐⠀⠀⣰⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣃⠂⢀⠔⣻⣿⡏⠀⠀⠀⠀⢸⡇⠀⠈⠀⠀⣼⣿⣿⢀⠀⠀⢸⣴⣿⡟⠁⢀⣨⣽⣿⣿⣾⣧⣍⣙⠿⠂⠀⣧⠀⡜⠈⢿⡄⢸⠀⠀⠘⡷⡄⠈⢿⣿⡿⣷⣶⣻⢟⣾⠓⣶⣷⠋⠁⠀⠀⠀⢣⠀⠀⣿⡀⢹⠇⠀⢀⠿⣇⢁⠀⡆⠀⠈⠄⠢⡴⠥⡴⠞⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠃⢠⡎⢰⣿⣿⠀⠀⠀⠀⢠⠸⣧⠀⠀⡃⢰⣿⡿⢻⡎⠀⠀⢹⠻⠃⣬⣿⣿⣿⣿⣿⣿⣿⣿⠿⢿⣿⠀⠀⣾⠀⡆⠀⠈⣯⠽⡀⠀⠀⢱⠘⣤⣿⣟⠀⠙⣿⣯⣨⠏⢩⣿⢿⡀⠀⠀⠀⠀⠸⡀⠀⢹⣧⢸⠀⠀⢸⠀⣿⢈⠀⢡⠀⠀⠘⡄⠑⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢠⣿⣆⣿⣿⡇⠀⠀⠀⠀⡘⠀⣿⢇⠀⢣⣾⣿⣿⢿⡄⠀⠀⢹⣦⣿⡿⠋⢻⣿⣿⣿⣿⣿⣿⣤⡤⠈⠀⠀⣿⣰⠁⠀⠀⣾⣷⠰⠀⢀⣸⡾⠟⣇⠘⣦⣀⠘⣿⣿⣤⠋⠁⢸⣧⣀⠀⠀⠀⠀⡇⠀⢸⣿⣿⠀⢀⡇⠀⢸⡄⡀⠸⡀⠀⠀⠈⢆⠈⢷⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⡏⠙⣿⣿⣿⠀⠀⠀⠀⠀⡇⠀⢹⡼⡄⠘⣿⣿⡏⣀⣻⠀⠘⢿⣿⡟⠀⣴⣿⣿⣿⡿⣭⣽⣿⣿⣿⠀⠀⢰⣿⡞⠀⠀⠀⣿⠋⡆⣇⠀⠀⡇⠈⣿⣷⣿⣿⣄⡈⣿⣿⣦⠀⠀⣿⣀⠉⠀⠀⢰⣷⠀⣿⣿⡇⠀⡞⠀⠀⠈⡇⠅⠀⡇⠀⠆⠀⠈⢳⣀⠙⢭⣒⢤⣀⡀⢀⣀⣀⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢣⢀⢿⣿⣿⠀⠀⠀⠀⢠⣗⠀⠘⣇⢷⠀⢻⣿⣷⠛⢿⡆⠀⠸⣿⠁⠀⣿⣿⣿⣿⣷⢯⣿⣿⣿⡏⠀⠀⢸⡿⠁⠀⠀⣰⡟⠀⣷⢹⠀⠀⡇⠀⣿⣿⣿⡿⣽⣷⣯⣿⣿⣄⠀⢹⣋⠀⠀⠀⢸⣿⡄⢿⣿⠁⡰⠁⢀⠀⠀⡇⡄⠀⢱⠀⠐⡀⠀⠈⠍⠢⢌⡙⠚⠭⠥⠾⠟⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠄⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣹⢻⣿⣿⠀⠀⠀⠀⢠⡛⠀⠀⠹⣾⣧⡀⢿⣿⣇⠀⣿⡀⠀⠻⡃⠀⠸⠿⣿⣏⠋⠛⢫⣽⡿⠁⠀⣠⠟⠁⠀⠀⣠⠟⠀⠀⣿⣘⡇⠀⢡⠀⠈⣿⣎⠽⠇⣛⣻⣿⡿⠁⠑⡞⠀⠀⠀⠀⣞⣿⣧⣸⢃⡜⠀⠀⠀⠆⠀⡇⡄⠀⠘⡄⠀⠹⣄⠀⠈⢆⠀⠈⢋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⠋⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠇⣸⣿⣿⠀⠀⠀⠀⠠⣇⠀⠀⠀⢹⣿⣷⡌⢿⣿⣿⣻⣷⣀⠀⠙⡶⠤⣄⣿⡾⠥⠴⠚⠛⠒⢁⡤⠋⠀⠀⣠⠜⠁⠀⠀⠀⠟⢻⣇⠀⡼⠀⠈⠙⠛⠦⠦⠬⣷⣿⣤⠴⢺⡇⠀⠀⠀⢠⣿⣿⣿⣣⣾⡇⠀⠀⠀⢃⢀⡧⡇⠀⠀⢃⠀⠀⢻⡦⠀⠀⠢⠀⠈⢆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠⠁⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠰⠀⠀⠀⠀⠀⠀⠀⣾⡇⣼⣿⣿⠀⠀⠀⠀⠐⣧⠀⠀⠀⢸⣿⣿⣿⣶⣿⣿⣿⣿⣿⣷⣄⠈⠢⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⠀⠻⠼⠶⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⡿⠀⠀⢀⣾⣿⣿⣯⣿⣿⣿⡇⠀⢘⠀⢨⢸⢱⠃⠀⠀⠘⡀⠀⠈⡇⠡⡀⠀⢃⠀⠀⠁⠀⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⢰⢫⡇⢹⡿⣿⣇⠀⠀⠀⠀⣿⡀⠀⠀⢸⣿⣿⣯⣿⣿⣿⣿⣿⣿⣿⡮⢿⣲⣬⣑⠢⠀⠀⠀⠀⠀⠀⢀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣟⠥⢶⣾⣿⣾⣿⣿⣿⣿⣿⣿⡇⠀⢸⠀⢸⣞⠎⠀⠀⠀⠀⡇⠀⠀⡅⠀⠱⡀⠈⢆⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠄⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⠀⠀⠀⠀⠀⢸⡀⣷⣸⡇⢹⣿⡀⠀⠀⠀⠸⣧⡆⠀⠘⣿⣿⡿⣿⣾⣟⡿⣿⣿⣿⣷⠈⠒⠉⠉⠛⠛⠛⠒⠀⠀⠀⢯⠉⠑⠒⠒⠤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠤⠾⠭⠔⠂⣼⣿⣿⣿⣿⣿⣿⣿⡿⣽⠀⢀⡏⠀⣼⠋⠀⠀⠀⢀⠀⠰⠀⠀⠀⠀⠀⠑⡀⠈⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⢄⡀⠀⠘⡆⠀⠀⠀⠀⠀⢳⣯⣿⣽⠀⢿⣿⠀⠀⠀⠀⢿⣻⠀⠀⢹⣿⢿⣿⣻⣿⣿⣿⣿⢿⣿⣆⠙⠢⠤⠀⠀⠀⠀⠀⠀⠀⠈⠳⡀⠀⠀⠀⠈⠳⠤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⣿⡿⣿⣿⣼⠇⠀⣼⡇⠊⣸⠀⠀⠀⠀⠈⡄⠸⠀⠀⠀⠀⠀⠀⢠⠀⢱⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠢⡀⢡⠀⠀⠀⠀⠀⠀⠻⣾⣏⢇⠀⢙⣷⠘⡀⠀⠘⣿⣄⠄⠀⠹⣿⣿⣟⣷⣿⡾⣽⡻⣞⡿⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢷⠀⠀⠀⠣⡀⠀⠈⢦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⣿⣟⣯⣿⣳⣿⢿⣿⣿⠏⢀⣼⣿⠁⠀⣿⠀⠀⠀⠀⠀⢡⠀⡆⠀⠀⠀⠀⠀⠀⢇⠀⣯⢀⠔⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠳⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠺⡆⠀⠀⠀⠀⠀⠀⠘⣿⠈⢄⠐⣿⣧⡘⡄⠀⠘⣯⠿⣶⣄⣈⣳⣿⣾⢯⡻⣵⢻⣬⢷⣻⡽⣆⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣇⠀⠀⠀⠱⡀⠀⠀⢣⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣾⣟⡷⢯⣟⣾⣿⡿⣿⣿⣃⣴⢿⣿⡿⠀⢸⡗⠀⠀⠀⠀⠀⠈⠀⢡⡄⠀⠀⠀⠀⠀⢸⢠⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠞⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠒⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠱⡀⠀⠀⠀⠀⠀⠀⠹⣧⠀⠣⠘⡌⢻⣜⣆⡀⠈⠻⣬⣉⠻⣬⣛⣿⢯⣓⢭⢻⣼⡧⣗⡯⣝⣻⣦⣄⣠⣤⣶⣶⣿⣿⣿⠿⢦⡀⠀⠀⠘⠀⠀⠀⢻⣿⣶⣶⣤⣄⣀⣀⣠⣶⡟⣯⠷⣞⡽⣻⣾⢻⡿⣿⡿⣟⣿⣽⣿⡿⠇⢠⣿⡅⠀⢀⠀⠀⠀⠀⡇⢸⠀⠀⠀⠀⠀⠀⣼⠎⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠⠒⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⡄⠀⠀⠀⠀⠀⠀⠘⢧⡀⠀⠈⠢⡈⠻⣟⠶⣶⣶⡿⣍⣹⣾⣏⢧⡙⠆⢫⣷⣽⣷⣿⣿⡿⠿⠿⠛⠛⠋⠉⣁⣀⣤⣤⣤⣇⠀⠀⠀⠀⠀⠀⢸⠉⠉⠛⠛⠻⠿⠿⣿⣷⣿⣾⣿⣞⣋⠑⡡⠋⣼⣏⢷⣻⣿⡷⠋⠃⣰⡿⣳⠁⠀⡌⠀⠀⠀⠀⣧⠸⡀⠀⠀⠀⣀⣾⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠠⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠐⠢⠬⣢⣀⠀⠀⠀⠀⠀⠀⠙⠢⠤⠀⠈⠢⣘⠿⡳⣷⡹⣿⣯⠻⣟⢮⣉⢿⣿⡿⣿⣟⣿⣶⣤⣤⣴⣶⣾⣿⣿⣿⣿⣿⣿⣿⡿⢇⠀⠀⠀⡀⠀⣼⣿⣿⣿⣶⣶⣤⣤⣀⡈⠉⠙⠛⠿⣿⣿⣷⣾⣳⣾⠟⣿⣋⣀⣠⣼⣟⣿⡟⠀⢠⠃⠀⠀⠀⠀⣿⢄⠈⠑⠒⢊⣽⠥⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠒⠤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠳⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠁⠋⠀⠉⠋⠘⠧⠛⠚⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣾⣿⣿⣿⣿⣿⡇⠀⠄⠀⠀⠁⠀⡽⣿⣯⣭⣝⣛⣛⠻⠿⢿⣿⣷⣾⣶⣤⣬⠇⠀⠈⠱⠋⠀⠀⠘⠁⢈⣈⠀⠀⠀⡞⠀⠀⠀⠀⣠⠟⢸⢀⣤⠞⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠢⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢮⣑⠦⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡀⠈⠀⠈⠀⡸⣰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⣭⣝⣻⡟⠀⠀⠀⠀⠀⠀⠀⠀⡠⠊⣼⠋⢀⡞⠁⠀⠀⠀⣴⣯⢴⣼⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡠⠜⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠀⠠⠒⢈⠇⠀⠙⠳⢦⣤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣉⠘⣌⡙⢳⠦⣤⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠔⠚⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⠡⡀⠐⡄⠜⡡⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡗⠤⣀⠀⠀⠐⠒⠂⠉⠀⣰⠃⢠⠞⠁⠀⠀⢠⣞⡿⢡⣿⣏⡠⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⡴⠞⠉⠀⠀⡉⠒⠤⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠂⠀⠀⠀⠀⠀⡈⠙⠥⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠻⢾⣵⣚⠦⣝⢮⣛⡟⣶⣶⣶⠶⠦⠒⠊⠉⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣟⢂⠁⢠⠗⠊⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠇⠀⠈⠑⠒⠤⣤⣤⣴⡶⠃⡠⠃⠀⢀⣠⠞⣣⣿⠼⢻⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⢄⡀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠘⣄⠀⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠋⠀⠀⠀⠀⠀⡔⠁⠀⠀⠀⢀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠻⢶⣹⣎⡯⠷⠛⠉⠉⠀⠀⠀⡀⠀⠀⠀⠀⡈⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠾⣄⠞⠀⣀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠏⠀⠀⠀⠀⢀⣴⣿⡿⠟⣁⣴⣡⡤⣶⣾⣯⡶⠟⢉⣠⠞⠁⠀⠀⠀⠀⠀⠀⠤⣀⠀⠀⠈⠑⠠⡀⠀⠀⠀⠈⠢⡀⠀⠀⠀⠀⠙⡆⠀⠀⠠⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠃⠀⠀⠀⠀⠄⣊⠄⠀⠀⠀⣀⠮⠤⠤⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⡤⢶⣾⠉⠀⡇⠀⠀⠀⠀⠀⠀⠀⠈⠓⠌⠲⠦⣄⢣⢹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠋⠁⡀⠀⠈⠒⢾⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠃⠀⠀⠀⣠⣴⣿⣯⣽⣶⣾⠿⠛⡡⠔⢛⠀⢻⢹⠒⢦⣀⠀⠀⠀⣄⠀⠀⠀⠀⠀⠈⠙⠷⠶⠦⠤⠼⢀⠀⠀⠉⠢⣝⠢⢄⣀⡀⡀⠘⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠲⠤⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠼⠁⠀⢤⠔⠊⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⠴⡾⣿⠀⢸⠸⡀⠀⢱⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠲⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣏⣀⣠⣾⣿⣶⣄⠀⠀⠉⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⠓⠒⠒⠒⠛⠛⠛⠛⠛⠋⠛⠉⠉⠁⠀⠀⡞⠀⡇⡜⠀⢸⠙⣿⠶⣄⣈⠙⠶⣤⣤⣀⣤⡠⠄⠀⠀⠀⠀⠀⠉⠒⡤⢄⡈⠦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠠⣀⠀⠀⠀⠀⠀⠈⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡰⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠄⠀⠀⠴⠚⠉⢠⠟⠀⢹⠀⠈⡆⡇⠀⠸⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⡴⠒⠒⠒⠓⠚⠛⠿⢿⣿⣿⣿⣿⣿⣿⡿⠛⠞⠻⠿⠿⣷⣷⡀⠀⠀⠀⠙⢻⣿⣿⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠂⠀⠀⠀⠀⣸⠁⢰⢡⠇⠀⢸⠀⣺⣯⡝⡭⢷⢶⣤⡀⠣⣄⡀⠀⠀⡀⠀⠀⠀⠀⠀⠈⢆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠑⠦⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡰⠁⠀⠀⠀⠀⠠⠀⠀⠀⠀⠀⠀⠀⠀⡠⠞⠁⠀⡏⠀⡇⢸⠀⠀⢳⢸⠀⠀⢷⠀⠀⠀⠀⠀⠀⠀⠀⢠⣇⡀⠀⠀⠀⠀⠀⠀⠀⠈⠳⢯⣟⣿⣿⣃⠀⠀⠀⠀⠀⠀⠀⠉⠙⠲⠄⠀⠀⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠎⠀⠀⠀⠀⢠⡏⠀⡜⡜⠀⠀⡇⠀⡇⣿⣞⡱⣯⢷⣄⡀⠀⠘⢯⢓⠒⠚⠒⠦⣄⣀⠀⠀⠈⢆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡀⣠⠤⠊
|
||||
⠀⠀⠀⠀⠀⠈⠉⠙⠒⠶⠤⢤⣄⣀⠀⡀⠀⢀⠀⠀⠄⠀⠈⠁⠀⠐⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⢡⠈⡆⠀⠘⡆⡇⠀⠈⣇⠀⠀⠀⠀⠀⠀⠀⣸⠌⣷⡀⠀⠀⠄⠀⠠⠀⢀⠀⠀⢿⣿⣏⠀⠈⠉⠀⠀⠀⠀⠤⠠⠤⠀⠀⠀⠀⣿⡿⠛⠛⠛⠲⠤⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠀⠀⠀⠀⠀⡼⠀⢠⢳⠃⠀⢠⠃⣸⠀⢸⣧⣏⢿⡌⢷⡹⣳⣄⠈⢯⠙⠦⣅⡐⠀⠀⠉⠉⠀⠈⠢⠤⠄⣀⠀⢀⢀⡀⡀⠠⠔⠒⠒⠀⠈⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡰⢃⠀⠘⢆⢣⠀⠀⠹⡸⡀⠀⠸⡄⠀⠀⠀⠀⠀⠀⣿⠄⡐⢻⠀⠀⠀⢀⠀⠠⠀⠀⠂⢘⣿⡿⠶⠒⠂⠉⠉⠉⠑⠒⠀⠐⣒⡶⠀⠀⢿⣳⣤⡀⠀⠀⠀⠀⠉⠑⠢⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠃⠀⡞⡏⠀⠀⡰⢰⡇⠀⢸⡏⢧⣋⢷⡈⢷⡈⠙⠛⠓⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠈⠀⠀⠈⢿⡆⠀⠀⢣⢣⠀⠀⢱⡀⠀⠀⠀⠀⢀⣿⡇⣌⠃⠀⠀⠈⠀⠀⠀⠀⠁⠐⣾⡟⠀⢀⣤⣴⡶⠿⠿⠚⠒⠒⠊⠉⠀⠀⠀⢸⡄⠀⠙⠶⡀⠀⢀⠀⢀⠀⠀⠙⠲⢤⣀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⠁⠀⣠⣿⡿⠇⠀⣻⠀⠀⠀⠧⣹⢮⣳⡈⠲⠄⠀⠀⠀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
'';
|
||||
}
|
||||
59
modules/netdata.nix
Normal file
59
modules/netdata.nix
Normal file
@@ -0,0 +1,59 @@
|
||||
{ vars, ... }:
|
||||
let
|
||||
ip = vars.ipv4;
|
||||
wireguardIp = vars.wireguardIp;
|
||||
in
|
||||
{
|
||||
networking.firewall.allowedTCPPorts = [ 19999 ];
|
||||
services.netdata = {
|
||||
enable = true;
|
||||
configText = ''
|
||||
[global]
|
||||
update every = 2
|
||||
|
||||
[web]
|
||||
default port = 19999
|
||||
bind to = ${ip} ${wireguardIp}
|
||||
allow connections from = localhost 192.168.0.* 192.168.2.*
|
||||
|
||||
[db]
|
||||
# number of tiers used (1 to 5, 3 being default)
|
||||
storage tiers = 3
|
||||
|
||||
# Tier 0, per second data
|
||||
dbengine multihost disk space MB = 256
|
||||
|
||||
# Tier 1, per minute data
|
||||
dbengine tier 1 multihost disk space MB = 128
|
||||
dbengine tier 1 update every iterations = 60
|
||||
|
||||
# Tier 2, per hour data
|
||||
dbengine tier 2 multihost disk space MB = 64
|
||||
dbengine tier 2 update every iterations = 60
|
||||
|
||||
[logs]
|
||||
error = syslog
|
||||
|
||||
[plugins]
|
||||
timex = no
|
||||
idlejitter = no
|
||||
# netdata monitoring = yes
|
||||
tc = no
|
||||
# diskspace = yes
|
||||
# proc = yes
|
||||
# cgroups = yes
|
||||
statsd = no
|
||||
#enable running new plugins = yes
|
||||
#check for new plugins every = 60
|
||||
slabinfo = no
|
||||
nfacct = no
|
||||
charts.d = no
|
||||
python.d = no
|
||||
go.d = no
|
||||
ioping = no
|
||||
perf = no
|
||||
freeipmi = no
|
||||
apps = yes
|
||||
'';
|
||||
};
|
||||
}
|
||||
3
modules/networkmanager.nix
Normal file
3
modules/networkmanager.nix
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
networking.networkmanager.enable = true;
|
||||
}
|
||||
89
modules/nextcloud.nix
Normal file
89
modules/nextcloud.nix
Normal file
@@ -0,0 +1,89 @@
|
||||
{ config, pkgs, lib, inputs, vars, ... }:
|
||||
let
|
||||
wireguardIp = vars.wireguardIp;
|
||||
in
|
||||
{
|
||||
age.secrets.nextcloud-cert = {
|
||||
file = ../secrets/nextcloud-cert.age;
|
||||
owner = "nginx";
|
||||
group = "nginx";
|
||||
};
|
||||
age.secrets.nextcloud-key = {
|
||||
file = ../secrets/nextcloud-key.age;
|
||||
owner = "nginx";
|
||||
group = "nginx";
|
||||
};
|
||||
# Enable Nginx
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
|
||||
# Use recommended settings
|
||||
recommendedGzipSettings = true;
|
||||
recommendedOptimisation = true;
|
||||
recommendedProxySettings = true;
|
||||
recommendedTlsSettings = true;
|
||||
|
||||
# Only allow PFS-enabled ciphers with AES256
|
||||
sslCiphers = "AES256+EECDH:AES256+EDH:!aNULL";
|
||||
|
||||
# Setup Nextcloud virtual host to listen on ports
|
||||
virtualHosts = {
|
||||
"nextcloud.local" = {
|
||||
serverAliases = [ wireguardIp ];
|
||||
## Force HTTP redirect to HTTPS
|
||||
forceSSL = true;
|
||||
locations."~ ^\\/(?:index|remote|public|cron|core\\/ajax\\/update|status|ocs\\/v[12]|updater\\/.+|oc[s]-provider\\/.+|.+\\/richdocumentscode\\/proxy)\\.php(?:$|\\/)".extraConfig = ''
|
||||
client_max_body_size 5G;
|
||||
'';
|
||||
#sslTrustedCertificate = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
|
||||
sslCertificate = config.age.secrets.nextcloud-cert.path;
|
||||
sslCertificateKey = config.age.secrets.nextcloud-key.path;
|
||||
## LetsEncrypt
|
||||
#enableACME = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
age.secrets.nextcloud-admin = {
|
||||
file = ../secrets/nextcloud-admin.age;
|
||||
owner = "nextcloud";
|
||||
group = "nextcloud";
|
||||
};
|
||||
services.nextcloud = {
|
||||
enable = true;
|
||||
package = pkgs.nextcloud27;
|
||||
https = true;
|
||||
hostName = "nextcloud.local";
|
||||
config.adminpassFile = config.age.secrets.nextcloud-admin.path;
|
||||
config.dbtype = "pgsql";
|
||||
database.createLocally = true;
|
||||
config.extraTrustedDomains = [ wireguardIp ];
|
||||
home = "/mnt/250ssd/nextcloud";
|
||||
extraApps = with config.services.nextcloud.package.packages.apps; {
|
||||
inherit keeweb onlyoffice calendar mail;
|
||||
spreed = pkgs.fetchNextcloudApp rec {
|
||||
url = "https://github.com/nextcloud-releases/spreed/releases/download/v17.1.1/spreed-v17.1.1.tar.gz";
|
||||
sha256 = "sha256-LaUG0maatc2YtWQjff7J54vadQ2RE4X6FcW8vFefBh8=";
|
||||
};
|
||||
};
|
||||
|
||||
phpOptions = {
|
||||
upload_max_filesize = "5G";
|
||||
post_max_size = "5G";
|
||||
};
|
||||
extraAppsEnable = true;
|
||||
extraOptions.enabledPreviewProviders = [
|
||||
"OC\\Preview\\BMP"
|
||||
"OC\\Preview\\GIF"
|
||||
"OC\\Preview\\JPEG"
|
||||
"OC\\Preview\\Krita"
|
||||
"OC\\Preview\\MarkDown"
|
||||
"OC\\Preview\\MP3"
|
||||
"OC\\Preview\\OpenDocument"
|
||||
"OC\\Preview\\PNG"
|
||||
"OC\\Preview\\TXT"
|
||||
"OC\\Preview\\XBitmap"
|
||||
"OC\\Preview\\HEIC"
|
||||
];
|
||||
};
|
||||
}
|
||||
93
modules/nginx.nix
Normal file
93
modules/nginx.nix
Normal file
@@ -0,0 +1,93 @@
|
||||
{
|
||||
networking.firewall.allowedTCPPorts = [ 80 443 ];
|
||||
|
||||
systemd.tmpfiles.rules = [
|
||||
"d /data 0770 github-actions-runner nginx -"
|
||||
"d /data/website 0770 github-actions-runner nginx -"
|
||||
];
|
||||
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
|
||||
# Use recommended settings
|
||||
recommendedGzipSettings = true;
|
||||
recommendedOptimisation = true;
|
||||
recommendedProxySettings = true;
|
||||
recommendedTlsSettings = true;
|
||||
|
||||
# Only allow PFS-enabled ciphers with AES256
|
||||
sslCiphers = "AES256+EECDH:AES256+EDH:!aNULL";
|
||||
|
||||
# Setup Nextcloud virtual host to listen on ports
|
||||
virtualHosts = {
|
||||
"kopatz.ddns.net" = {
|
||||
#serverAliases = [
|
||||
# "www.kopatz.ddns.net"
|
||||
# "server.home"
|
||||
# "server.local"
|
||||
# "192.168.0.6"
|
||||
#];
|
||||
root = "/data/website";
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
locations."~* \\.(jpg)$".extraConfig= ''
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
'';
|
||||
locations."~ ^/(stash|resources|css)".extraConfig=''
|
||||
client_max_body_size 5000M;
|
||||
proxy_redirect off;
|
||||
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-NginX-Proxy true;
|
||||
proxy_pass http://localhost:5091;
|
||||
'';
|
||||
locations."/tracker-site" = {
|
||||
tryFiles = "$uri $uri/ /tracker-site/index.html =404";
|
||||
};
|
||||
locations."/tracker-site/api" = {
|
||||
extraConfig =''
|
||||
rewrite /tracker-site/api/(.*) /$1 break;
|
||||
'';
|
||||
proxyPass = "http://127.0.0.1:8080";
|
||||
};
|
||||
|
||||
#locations."~/books(.*)$" = {
|
||||
# proxyPass = "http://127.0.0.1:5000";
|
||||
#};
|
||||
},
|
||||
#discord bot for tracking useractivity public version
|
||||
"activitytracker.site" = {
|
||||
root = "/data/website";
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
locations."~* \\.(jpg)$".extraConfig= ''
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
'';
|
||||
locations."~ ^/(stash|resources|css)".extraConfig=''
|
||||
client_max_body_size 5000M;
|
||||
proxy_redirect off;
|
||||
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-NginX-Proxy true;
|
||||
proxy_pass http://localhost:5092;
|
||||
'';
|
||||
locations."/" = {
|
||||
tryFiles = "$uri $uri/ /tracker-site/index.html =404";
|
||||
};
|
||||
locations."/api" = {
|
||||
extraConfig =''
|
||||
rewrite /api/(.*) /$1 break;
|
||||
'';
|
||||
proxyPass = "http://127.0.0.1:8080";
|
||||
};
|
||||
};
|
||||
"adguard.local" = {
|
||||
locations."/".proxyPass = "http://127.0.0.1:3000";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
7
modules/nix/index.nix
Normal file
7
modules/nix/index.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
programs.command-not-found.enable = false;
|
||||
programs.nix-index = {
|
||||
enable = true;
|
||||
enableZshIntegration=true;
|
||||
};
|
||||
}
|
||||
3
modules/nix/ld.nix
Normal file
3
modules/nix/ld.nix
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
programs.nix-ld.enable = true;
|
||||
}
|
||||
4
modules/nix/settings.nix
Normal file
4
modules/nix/settings.nix
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
nix.optimise.automatic = true;
|
||||
nix.settings.experimental-features = [ "nix-command" "flakes" ];
|
||||
}
|
||||
4
modules/no-sleep-lid-closed.nix
Normal file
4
modules/no-sleep-lid-closed.nix
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
{
|
||||
services.logind.lidSwitchExternalPower = "ignore";
|
||||
}
|
||||
20
modules/paperless.nix
Normal file
20
modules/paperless.nix
Normal file
@@ -0,0 +1,20 @@
|
||||
{ config, pkgs, lib, inputs, vars, ... }:
|
||||
let
|
||||
ip = vars.ipv4;
|
||||
wireguardIp = vars.wireguardIp;
|
||||
in
|
||||
{
|
||||
networking.firewall.allowedTCPPorts = [ 28981 ];
|
||||
age.secrets.paperless = {
|
||||
file = ../secrets/paperless.age;
|
||||
owner = "paperless";
|
||||
group = "paperless";
|
||||
};
|
||||
services.paperless = {
|
||||
enable = true;
|
||||
port = 28981;
|
||||
passwordFile = config.age.secrets.paperless.path;
|
||||
address = wireguardIp;
|
||||
mediaDir = "/mnt/250ssd/paperless";
|
||||
};
|
||||
}
|
||||
22
modules/postgres.nix
Normal file
22
modules/postgres.nix
Normal file
@@ -0,0 +1,22 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
services.postgresql = {
|
||||
enable = true;
|
||||
authentication = pkgs.lib.mkOverride 10 ''
|
||||
#type database DBuser auth-method optional_ident_map
|
||||
local sameuser all peer map=superuser_map
|
||||
'';
|
||||
identMap = ''
|
||||
# ArbitraryMapName systemUser DBUser
|
||||
superuser_map root postgres
|
||||
superuser_map postgres postgres
|
||||
# Let other names login as themselves
|
||||
superuser_map /^(.*)$ \1
|
||||
'';
|
||||
};
|
||||
services.postgresqlBackup = {
|
||||
enable = true;
|
||||
location = "/var/backup/postgresql";
|
||||
backupAll = true;
|
||||
};
|
||||
}
|
||||
9
modules/rdp.nix
Normal file
9
modules/rdp.nix
Normal file
@@ -0,0 +1,9 @@
|
||||
{ config, pkgs, lib, vars, ... }:
|
||||
let
|
||||
wm = vars.wm;
|
||||
in
|
||||
{
|
||||
services.xrdp.enable = true;
|
||||
services.xrdp.defaultWindowManager = wm;
|
||||
services.xrdp.openFirewall = true;
|
||||
}
|
||||
37
modules/samba.nix
Normal file
37
modules/samba.nix
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
#services.samba-wsdd.enable = true; # make shares visible for windows 10 clients
|
||||
#networking.firewall.allowedTCPPorts = [
|
||||
#5357 # wsdd
|
||||
#];
|
||||
#networking.firewall.allowedUDPPorts = [
|
||||
#3702 # wsdd
|
||||
#];
|
||||
services.samba.openFirewall = true;
|
||||
services.samba = {
|
||||
enable = true;
|
||||
securityType = "user";
|
||||
invalidUsers = [
|
||||
"root"
|
||||
];
|
||||
extraConfig = ''
|
||||
disable netbios = yes
|
||||
smb ports = 445
|
||||
workgroup = WORKGROUP
|
||||
server string = smbnix
|
||||
security = user
|
||||
#use sendfile = yes
|
||||
#max protocol = smb2
|
||||
# note: localhost is the ipv6 localhost ::1
|
||||
hosts allow = 192.168.0. 192.168.174.1 127.0.0.1 localhost
|
||||
hosts deny = 0.0.0.0/0
|
||||
guest account = nobody
|
||||
map to guest = bad user
|
||||
'';
|
||||
shares = {
|
||||
homes = {
|
||||
browseable = "no";
|
||||
writable = "yes";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
10
modules/ssh.nix
Normal file
10
modules/ssh.nix
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
networking.firewall.allowedTCPPorts = [ 22 ];
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
settings.PasswordAuthentication = false;
|
||||
settings.KbdInteractiveAuthentication = false;
|
||||
settings.PermitRootLogin = "no";
|
||||
settings.X11Forwarding = true;
|
||||
};
|
||||
}
|
||||
29
modules/static-ip.nix
Normal file
29
modules/static-ip.nix
Normal file
@@ -0,0 +1,29 @@
|
||||
{ config, vars, ...}:
|
||||
let
|
||||
ip = vars.ipv4;
|
||||
dns = vars.dns;
|
||||
interface = vars.interface;
|
||||
in
|
||||
{
|
||||
networking = {
|
||||
defaultGateway = "192.168.0.1";
|
||||
useDHCP = false;
|
||||
firewall = {
|
||||
enable = true;
|
||||
allowedUDPPorts = [ 5000 ];
|
||||
};
|
||||
nameservers = [
|
||||
dns
|
||||
"1.1.1.1"
|
||||
];
|
||||
interfaces = {
|
||||
${interface} = {
|
||||
name = "eth0";
|
||||
ipv4.addresses = [{
|
||||
address = ip;
|
||||
prefixLength = 24;
|
||||
}];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
3
modules/support/ntfs.nix
Normal file
3
modules/support/ntfs.nix
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
boot.supportedFilesystems = [ "ntfs" ];
|
||||
}
|
||||
92
modules/synapse.nix
Normal file
92
modules/synapse.nix
Normal file
@@ -0,0 +1,92 @@
|
||||
{ pkgs, lib, config, ... }:
|
||||
let
|
||||
fqdn = "${config.networking.domain}";
|
||||
baseUrl = "https://${fqdn}";
|
||||
clientConfig."m.homeserver".base_url = baseUrl;
|
||||
serverConfig."m.server" = "${fqdn}:443";
|
||||
mkWellKnown = data: ''
|
||||
add_header Content-Type application/json;
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
return 200 '${builtins.toJSON data}';
|
||||
'';
|
||||
in {
|
||||
networking.domain = "kopatz.ddns.net";
|
||||
networking.firewall.allowedTCPPorts = [ 80 443 ];
|
||||
|
||||
services.postgresql.enable = true;
|
||||
services.postgresql.initialScript = pkgs.writeText "synapse-init.sql" ''
|
||||
CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse';
|
||||
CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse"
|
||||
TEMPLATE template0
|
||||
LC_COLLATE = "C"
|
||||
LC_CTYPE = "C";
|
||||
'';
|
||||
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
recommendedTlsSettings = true;
|
||||
recommendedOptimisation = true;
|
||||
recommendedGzipSettings = true;
|
||||
recommendedProxySettings = true;
|
||||
virtualHosts = {
|
||||
# If the A and AAAA DNS records on example.org do not point on the same host as the
|
||||
# records for myhostname.example.org, you can easily move the /.well-known
|
||||
# virtualHost section of the code to the host that is serving example.org, while
|
||||
# the rest stays on myhostname.example.org with no other changes required.
|
||||
# This pattern also allows to seamlessly move the homeserver from
|
||||
# myhostname.example.org to myotherhost.example.org by only changing the
|
||||
# /.well-known redirection target.
|
||||
"${config.networking.domain}" = {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
# This section is not needed if the server_name of matrix-synapse is equal to
|
||||
# the domain (i.e. example.org from @foo:example.org) and the federation port
|
||||
# is 8448.
|
||||
# Further reference can be found in the docs about delegation under
|
||||
# https://matrix-org.github.io/synapse/latest/delegate.html
|
||||
locations."= /.well-known/matrix/server".extraConfig = mkWellKnown serverConfig;
|
||||
# This is usually needed for homeserver discovery (from e.g. other Matrix clients).
|
||||
# Further reference can be found in the upstream docs at
|
||||
# https://spec.matrix.org/latest/client-server-api/#getwell-knownmatrixclient
|
||||
locations."= /.well-known/matrix/client".extraConfig = mkWellKnown clientConfig;
|
||||
# Forward all Matrix API calls to the synapse Matrix homeserver. A trailing slash
|
||||
# *must not* be used here.
|
||||
locations."/_matrix".proxyPass = "http://[::1]:8008";
|
||||
# Forward requests for e.g. SSO and password-resets.
|
||||
locations."/_synapse/client".proxyPass = "http://[::1]:8008";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
age.secrets.matrix-registration = {
|
||||
file = ../secrets/matrix-registration.age;
|
||||
owner = "matrix-synapse";
|
||||
group = "matrix-synapse";
|
||||
};
|
||||
|
||||
services.matrix-synapse = {
|
||||
enable = true;
|
||||
dataDir = "/mnt/250ssd/matrix-synapse";
|
||||
settings.server_name = config.networking.domain;
|
||||
# The public base URL value must match the `base_url` value set in `clientConfig` above.
|
||||
# The default value here is based on `server_name`, so if your `server_name` is different
|
||||
# from the value of `fqdn` above, you will likely run into some mismatched domain names
|
||||
# in client applications.
|
||||
settings.public_baseurl = baseUrl;
|
||||
extraConfigFiles = [
|
||||
config.age.secrets.matrix-registration.path
|
||||
];
|
||||
settings.listeners = [
|
||||
{ port = 8008;
|
||||
bind_addresses = [ "::1" ];
|
||||
type = "http";
|
||||
tls = false;
|
||||
x_forwarded = true;
|
||||
resources = [ {
|
||||
names = [ "client" "federation" ];
|
||||
compress = true;
|
||||
} ];
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
7
modules/thunderbolt.nix
Normal file
7
modules/thunderbolt.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
services.udev.extraRules = ''
|
||||
# Always authorize thunderbolt connections when they are plugged in.
|
||||
# This is to make sure the USB hub of Thunderbolt is working.
|
||||
ACTION=="add", SUBSYSTEM=="thunderbolt", ATTR{authorized}=="0", ATTR{authorized}="1"
|
||||
'';
|
||||
}
|
||||
6
modules/virt-manager.nix
Normal file
6
modules/virt-manager.nix
Normal file
@@ -0,0 +1,6 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
virtualisation.libvirtd.enable = true;
|
||||
programs.dconf.enable = true; # virt-manager requires dconf to remember settings
|
||||
environment.systemPackages = with pkgs; [ virt-manager virtiofsd ];
|
||||
}
|
||||
8
modules/vmware-guest.nix
Normal file
8
modules/vmware-guest.nix
Normal file
@@ -0,0 +1,8 @@
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
## shared clipboard
|
||||
virtualisation.vmware.guest.enable = true;
|
||||
environment.systemPackages = with pkgs; [
|
||||
open-vm-tools
|
||||
];
|
||||
}
|
||||
7
modules/wake-on-lan.nix
Normal file
7
modules/wake-on-lan.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
{ config, pkgs, lib, vars, ... }:
|
||||
let
|
||||
interface = vars.interface;
|
||||
in
|
||||
{
|
||||
networking.interfaces.${interface}.wakeOnLan.enable = true;
|
||||
}
|
||||
98
modules/wireguard.nix
Normal file
98
modules/wireguard.nix
Normal file
@@ -0,0 +1,98 @@
|
||||
{ config, pkgs, lib, inputs, vars, ... }:
|
||||
let
|
||||
wireguardIp = vars.wireguardIp;
|
||||
in
|
||||
{
|
||||
|
||||
age.secrets.wireguard-private = {
|
||||
file = ../secrets/wireguard-private.age;
|
||||
};
|
||||
|
||||
networking.nat.enable = true;
|
||||
networking.nat.externalInterface = "eth0";
|
||||
networking.nat.internalInterfaces = [ "wg0" ];
|
||||
networking.firewall.allowedUDPPorts = [ 51820 ];
|
||||
|
||||
networking.wg-quick.interfaces = {
|
||||
wg0 = {
|
||||
autostart = true;
|
||||
listenPort = 51820;
|
||||
address = [
|
||||
"${wireguardIp}/24"
|
||||
];
|
||||
peers = [
|
||||
{
|
||||
allowedIPs = [
|
||||
"192.168.2.2/32"
|
||||
];
|
||||
persistentKeepalive = 25;
|
||||
publicKey = "dUBPIEnAiHIZCMjqV0ya8qotN3UnMhlEVyGNQcR3gVI=";
|
||||
}
|
||||
{
|
||||
allowedIPs = [
|
||||
"192.168.2.3/32"
|
||||
];
|
||||
persistentKeepalive = 25;
|
||||
publicKey = "Eg5ZS3zN05mJ/gct6wJlwVAHTlXpkhxFfUd7yscANV0=";
|
||||
}
|
||||
{
|
||||
allowedIPs = [
|
||||
"192.168.2.4/32"
|
||||
];
|
||||
persistentKeepalive = 25;
|
||||
publicKey = "8Eigfs+k2k2WPaMn+SqDmlSHdMv+I+xcBr/2qhtpGzI=";
|
||||
}
|
||||
{
|
||||
allowedIPs = [
|
||||
"192.168.2.20/32"
|
||||
];
|
||||
persistentKeepalive = 25;
|
||||
publicKey = "25u1RSfjsx3wb1DMeTm0pvUfUkG7zTjGaN+m0w6ZjCw=";
|
||||
}
|
||||
{
|
||||
allowedIPs = [
|
||||
"192.168.2.21/32"
|
||||
];
|
||||
persistentKeepalive = 25;
|
||||
publicKey = "S+8F+yxSQvjjoU44LRYqRv1YulqmOKumUtYo/YIh7X8=";
|
||||
}
|
||||
{
|
||||
allowedIPs = [
|
||||
"192.168.2.22/32"
|
||||
];
|
||||
persistentKeepalive = 25;
|
||||
publicKey = "/dIW7K49vB9HOghFeXvcY7wu2utQltuv6RfgCbxZwlk=";
|
||||
}
|
||||
{
|
||||
allowedIPs = [
|
||||
"192.168.2.23/32"
|
||||
];
|
||||
persistentKeepalive = 25;
|
||||
publicKey = "89rjQXNcyCRUCihqfqcOnctWmhiNR8snpRFF6dyHAmk=";
|
||||
}
|
||||
{
|
||||
allowedIPs = [
|
||||
"192.168.2.24/32"
|
||||
];
|
||||
persistentKeepalive = 25;
|
||||
publicKey = "adaWtboVz3UhpNBKFirs7slbU2+Y3GaV5yS2EoafwVU=";
|
||||
}
|
||||
{
|
||||
allowedIPs = [
|
||||
"192.168.2.5/32"
|
||||
];
|
||||
persistentKeepalive = 25;
|
||||
publicKey = "g5uTlA1IciXgtSbECjhVis0dajRAc53Oa7Hz6dUI+0Q=";
|
||||
}
|
||||
{
|
||||
allowedIPs = [
|
||||
"192.168.2.6/32"
|
||||
];
|
||||
persistentKeepalive = 25;
|
||||
publicKey = "5ClF2HcqndpXS7nVgDn2unWFUYcKo5fbudV6xX2OIVE=";
|
||||
}
|
||||
];
|
||||
privateKeyFile = config.age.secrets.wireguard-private.path;
|
||||
};
|
||||
};
|
||||
}
|
||||
5
modules/wireshark.nix
Normal file
5
modules/wireshark.nix
Normal file
@@ -0,0 +1,5 @@
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
programs.wireshark.enable = true;
|
||||
programs.wireshark.package = pkgs.wireshark;
|
||||
}
|
||||
31
modules/wooting.nix
Normal file
31
modules/wooting.nix
Normal file
@@ -0,0 +1,31 @@
|
||||
{ pkgs, lib, ...}:
|
||||
let
|
||||
wooting-udev = pkgs.stdenv.mkDerivation rec {
|
||||
pname = "wooting-udev-rules";
|
||||
version = "unstable-2023-03-31";
|
||||
|
||||
# Source: https://help.wooting.io/en/article/wootility-configuring-device-access-for-wootility-under-linux-udev-rules-r6lb2o/
|
||||
src = [ ./wooting.rules ];
|
||||
|
||||
dontUnpack = true;
|
||||
|
||||
installPhase = ''
|
||||
install -Dpm644 $src $out/lib/udev/rules.d/70-wooting.rules
|
||||
'';
|
||||
|
||||
meta = with lib; {
|
||||
homepage = "https://help.wooting.io/en/article/wootility-configuring-device-access-for-wootility-under-linux-udev-rules-r6lb2o/";
|
||||
description = "udev rules that give NixOS permission to communicate with Wooting keyboards";
|
||||
platforms = platforms.linux;
|
||||
license = "unknown";
|
||||
maintainers = with maintainers; [ davidtwco ];
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
services.udev.packages = [ wooting-udev ];
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
wootility
|
||||
];
|
||||
}
|
||||
12
modules/wooting.rules
Normal file
12
modules/wooting.rules
Normal file
@@ -0,0 +1,12 @@
|
||||
# Wooting Two HE (ARM)
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="31e3", ATTRS{idProduct}=="1230", MODE:="0666", GROUP="input"
|
||||
SUBSYSTEM=="usb", ATTRS{idVendor}=="31e3", ATTRS{idProduct}=="1230", MODE:="0666", GROUP="input"
|
||||
# Wooting Two HE Alt-gamepad mode
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="31e3", ATTRS{idProduct}=="1231", MODE:="0666", GROUP="input"
|
||||
SUBSYSTEM=="usb", ATTRS{idVendor}=="31e3", ATTRS{idProduct}=="1231", MODE:="0666", GROUP="input"
|
||||
# Wooting Two HE 2nd Alt-gamepad mode
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="31e3", ATTRS{idProduct}=="1232", MODE:="0666", GROUP="input"
|
||||
SUBSYSTEM=="usb", ATTRS{idVendor}=="31e3", ATTRS{idProduct}=="1232", MODE:="0666", GROUP="input"
|
||||
|
||||
# Wooting Two HE (ARM) update mode
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="31e3", ATTRS{idProduct}=="123f", MODE:="0666", GROUP="input"
|
||||
Reference in New Issue
Block a user