Initial config for migration from old Arch host

This commit is contained in:
Agatha Lovelace 2023-02-10 18:34:46 +01:00
commit 855fc75d3b
Signed by: sorceress
GPG Key ID: 01D0B3AB10CED4F8
22 changed files with 873 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
secrets
ops/home/.gcroots

26
README.md Normal file
View File

@ -0,0 +1,26 @@
# Nix Infra Config
Using [morph](https://github.com/DBCDK/morph)
## Hosts
- `bloodletting`: Main server
## Manual setup on blank system/migrations
- `./ops/home/push` - deploy config
- `kitty +kitten ssh [hostname]` - fix terminfo
- `passwd` - set user passwords
- rsync state:
- `/var/lib`:
- `acme/.lego`
- `bin_rs`
- `fail2ban`
- `grafana`
- `homepage`
- `matterbridge`
- `mstdn-ebooks`
- `nyandroid`
- `prometheus2`
- `/home/ftp`
## Reference configs used
- https://github.com/Xe/nixos-configs
- https://git.nora.codes/nora/nixconfig

65
common/default.nix Normal file
View File

@ -0,0 +1,65 @@
{ pkgs, ... }: {
imports = [ ./users ];
## Optimizations
# Clean /tmp
boot.cleanTmpDir = true;
# Link identical files
nix.settings.auto-optimise-store = true;
# Limit journald logs
services.journald.extraConfig = ''
SystemMaxUse=100M
MaxFileSec=1month
'';
# Garbage collection
nix.gc = {
automatic = true;
dates = "weekly";
options = "--delete-older-than 30d";
};
## Other
# Allow unfree packages
nixpkgs.config.allowUnfree = true;
# Flakes
nix.settings.experimental-features = [ "nix-command" "flakes" ];
# Enable fish (needed for nix completions)
programs.fish.enable = true;
# Fix terminfo
environment.enableAllTerminfo = true;
environment.variables.COLORTERM = "truecolor";
# Packages used on all systems
environment.systemPackages = with pkgs; [ git wget xclip killall ];
## Locale/Timezone
time.timeZone = "Europe/Berlin";
i18n.defaultLocale = "en_US.UTF-8";
i18n.extraLocaleSettings = {
LC_ADDRESS = "de_DE.UTF-8";
LC_IDENTIFICATION = "de_DE.UTF-8";
LC_MEASUREMENT = "de_DE.UTF-8";
LC_MONETARY = "de_DE.UTF-8";
LC_NAME = "de_DE.UTF-8";
LC_NUMERIC = "de_DE.UTF-8";
LC_PAPER = "de_DE.UTF-8";
LC_TELEPHONE = "de_DE.UTF-8";
LC_TIME = "de_DE.UTF-8";
};
# Configure keymap in X11
services.xserver = {
layout = "us";
xkbVariant = "";
};
}

9
common/fragments/bin.nix Normal file
View File

@ -0,0 +1,9 @@
{ ... }: {
imports = [ ../../common/services/bin.nix ];
services.bin = {
enable = true;
address = "0.0.0.0";
port = 6162;
};
}

View File

@ -0,0 +1,9 @@
{ config, pkgs, ... }: {
services.fail2ban = {
enable = true;
maxretry = 5;
ignoreIP = [ "127.0.0.0/8" "10.0.0.0/8" "192.168.0.0/16" "78.94.116.222" ];
bantime-increment.enable = true;
};
}

View File

@ -0,0 +1,27 @@
{ config, pkgs, ... }: {
services.grafana = {
enable = true;
settings.server = {
domain = "grafana.technogothic.net";
http_port = 2342;
http_addr = "localhost";
};
};
networking.firewall.allowedTCPPorts =
[ config.services.grafana.settings.server.http_port ];
services.prometheus = {
enable = true;
port = 9001;
retentionTime = "365d";
scrapeConfigs = [{
job_name = "bloodletting";
static_configs = [{
targets = [
"localhost:${toString config.services.prometheus.exporters.node.port}"
];
}];
}];
};
}

View File

@ -0,0 +1,13 @@
{ pkgs, ... }: {
virtualisation.oci-containers.containers = {
"homepage" = {
image = "ghcr.io/benphelps/homepage:latest";
autoStart = true;
ports = [ "3000:3000" ];
volumes = [
"/var/lib/homepage:/app/config"
"/var/run/podman/podman.sock:/var/run/docker.sock"
];
};
};
}

View File

@ -0,0 +1,22 @@
{ pkgs, ... }: {
virtualisation.oci-containers.containers = {
"ebooks-agatha" = {
image = "agathasorceress/mstdn-ebooks:v1.2";
environment = {
POST_TIMINGS = "0 */6 * * *";
FETCH_TIMINGS = "5 * */1 * *";
};
autoStart = true;
volumes = [ "/var/lib/mstdn-ebooks/agatha:/ebooks/data" ];
};
"ebooks-amelia" = {
image = "agathasorceress/mstdn-ebooks:v1.2";
environment = {
POST_TIMINGS = "0 */5 * * *";
FETCH_TIMINGS = "0 14 */1 * *";
};
autoStart = true;
volumes = [ "/var/lib/mstdn-ebooks/amelia:/ebooks/data" ];
};
};
}

View File

@ -0,0 +1,6 @@
{ ... }: {
services.matterbridge = {
enable = true;
configPath = "/var/lib/matterbridge/matterbridge.toml";
};
}

View File

@ -0,0 +1,10 @@
{ ... }: {
virtualisation.oci-containers.containers = {
"nyandroid" = {
image = "registry.gitlab.com/xenua/nyandroid:latest";
autoStart = true;
volumes = [ "/var/lib/nyandroid:/nyandroid/code/data" ];
environmentFiles = [ "/var/lib/secrets/nyandroid-token" ];
};
};
}

View File

@ -0,0 +1,16 @@
{ config, pkgs, ... }: {
# Enable Prometheus exporters
services.prometheus = {
exporters = {
node = {
enable = true;
enabledCollectors = [ "systemd" ];
port = 9002;
};
};
};
networking.firewall.allowedTCPPorts =
[ config.services.prometheus.exporters.node.port ];
}

View File

@ -0,0 +1,11 @@
{ ... }: {
services.vsftpd = {
enable = true;
anonymousUser = true;
anonymousUserNoPassword = true;
extraConfig = ''
pasv_min_port=40000
pasv_max_port=40200
'';
};
}

View File

@ -0,0 +1,10 @@
{ pkgs, ... }: {
services.udev.packages = with pkgs; [ libu2f-host yubikey-personalization ];
programs.gnupg.agent = {
enable = true;
enableSSHSupport = true;
};
services.pcscd.enable = true;
}

View File

@ -0,0 +1,97 @@
{ pkgs, config, lib, ... }:
let
home-manager = builtins.fetchTarball
"https://github.com/nix-community/home-manager/archive/release-22.11.tar.gz";
in {
imports =
[ (import "${home-manager}/nixos") ../../common/home_manager/helix.nix ];
home-manager.useGlobalPkgs = true;
home-manager.users.agatha = {
home.username = "agatha";
home.homeDirectory = "/home/agatha";
home.stateVersion = config.system.stateVersion;
home.packages = with pkgs; [ gnupg fzf btop bat ripgrep tealdeer ouch exa ];
programs = {
home-manager.enable = true;
git = {
enable = true;
userName = "Agatha V. Lovelace";
userEmail = "agatha@technogothic.net";
signing.key = "33185E0D62AD7294379947D4C37ABADDB597BCA1";
signing.signByDefault = true;
aliases = {
plog =
"log --graph --pretty=format:'%h -%d %s -%an %n' --abbrev-commit --date=relative --branches";
pfusch = "push --force-with-lease";
stat = "diff --compact-summary";
};
extraConfig = { init = { defaultBranch = "mistress"; }; };
};
starship = {
enable = true;
settings = {
add_newline = false;
format = lib.concatStrings [
"[$hostname](bold red)"
"$character"
"$directory"
];
right_format =
lib.concatStrings [ "$git_branch" " " "$cmd_duration" ];
character = {
success_symbol = "";
error_symbol = "[ ](purple)";
};
directory = {
truncation_length = 2;
fish_style_pwd_dir_length = 1;
read_only = " ";
style = "cyan";
read_only_style = "cyan";
};
cmd_duration = { min_time = 10000; };
git_branch = {
format = "$symbol $branch";
symbol = "";
};
hostname = {
ssh_only = false;
format = "$hostname";
};
};
};
fish = {
enable = true;
# interactiveShellInit = builtins.readFile (pkgs.fetchurl
# "https://git.lain.faith/sorceress/dotfiles/raw/branch/mistress/.config/fish/config.fish");
plugins = [
{
name = "fzf";
src = pkgs.fetchFromGitHub {
owner = "jethrokuan";
repo = "fzf";
rev = "479fa67d7439b23095e01b64987ae79a91a4e283";
sha256 = "0k6l21j192hrhy95092dm8029p52aakvzis7jiw48wnbckyidi6v";
};
}
{
name = "pisces";
src = pkgs.fetchFromGitHub {
owner = "laughedelic";
repo = "pisces";
rev = "e45e0869855d089ba1e628b6248434b2dfa709c4";
sha256 = "073wb83qcn0hfkywjcly64k6pf0d7z5nxxwls5sa80jdwchvd2rs";
};
}
];
};
};
};
}

View File

@ -0,0 +1,280 @@
{ pkgs, config, ... }:
let
unstable = import
(builtins.fetchTarball "https://github.com/nixos/nixpkgs/tarball/master") {
config = config.nixpkgs.config;
};
in {
home-manager.users.agatha = {
# Formatters/Language Servers that Helix uses
home.packages = with pkgs; [ nixfmt ];
programs = {
helix = {
enable = true;
package = unstable.helix;
languages = [{
name = "nix";
auto-format = true;
formatter = { command = "nixfmt"; };
}];
settings = {
theme = "paramount-dark";
editor = {
middle-click-paste = false;
scroll-lines = 4;
shell = [ "fish" "-c" ];
bufferline = "multiple";
statusline = {
left = [ "mode" "spinner" "file-name" ];
right = [
"workspace-diagnostics"
"position"
"position-percentage"
"spacer"
"file-encoding"
"file-line-ending"
"file-type"
];
separator = " ";
};
cursor-shape = { insert = "bar"; };
whitespace.render = {
tab = "all";
space = "all";
newline = "none";
};
indent-guides = {
render = true;
character = "";
skip-levels = 1;
};
};
keys = {
insert = {
"C-left" = [ "move_prev_word_start" "collapse_selection" ];
"C-right" = [ "move_next_word_start" "collapse_selection" ];
};
normal = {
"C-left" = [ "move_prev_word_start" "collapse_selection" ];
"C-right" = [ "move_next_word_start" "collapse_selection" ];
};
};
};
themes = {
paramount-dark = let
medium_gray = "#767676";
lighter_black = "#4E4E4E";
lighter_gray = "#C6C6C6";
light_red = "#E32791";
orange = "#D75F5F";
light_green = "#5FD7A7";
dark_purple = "#af5fd7";
light_purple = "#a790d5";
dark_yellow = "#A89C14";
in {
inherits = "hex_lavender";
"ui.background" = { bg = "black"; };
"ui.gutter" = { bg = "black"; };
"ui.menu.selected" = {
fg = lighter_gray;
bg = light_purple;
};
"comment" = {
fg = lighter_black;
modifiers = [ "italic" ];
};
"constant" = light_purple;
"string" = light_purple;
"variable" = lighter_gray;
"function" = lighter_gray;
"keyword.function" = lighter_gray;
"keyword.control" = medium_gray;
"keyword.control.import" = medium_gray;
"operator" = {
fg = lighter_gray;
modifiers = [ "bold" ];
};
"function.special" = medium_gray;
"type" = lighter_gray;
"tag" = {
fg = medium_gray;
modifiers = [ "italic" ];
};
"punctuation" = { fg = medium_gray; };
"ui.linenr" = medium_gray;
"ui.linenr.selected" = { fg = light_purple; };
"string.special.url" = {
fg = lighter_gray;
underline = {
color = lighter_gray;
style = "line";
};
modifiers = [ "underlined" ];
};
"markup.link" = {
fg = lighter_gray;
underline = {
color = lighter_gray;
style = "line";
};
modifiers = [ "underlined" ];
};
"diagnostic.error" = {
underline = {
color = light_red;
style = "curl";
};
};
"error" = light_red;
"diagnostic.hint" = {
underline = {
color = lighter_gray;
style = "curl";
};
};
"hint" = lighter_gray;
"ui.selection" = {
fg = lighter_gray;
bg = light_purple;
};
"ui.selection.primary" = {
fg = lighter_gray;
bg = light_purple;
};
"warning" = orange;
"diagnostic.warning" = {
underline = {
color = orange;
style = "curl";
};
};
"diff.plus" = light_green;
"diff.minus" = light_red;
"diff.delta" = dark_yellow;
"ui.cursor" = { bg = lighter_gray; };
"ui.cursor.insert" = { bg = light_purple; };
"ui.cursor.select" = { bg = dark_purple; };
"ui.cursor.match" = {
fg = lighter_gray;
bg = medium_gray;
};
"namespace" = medium_gray;
};
paramount-light = let
medium_gray = "#767676";
actual_white = "#FFFFFF";
light_black = "#262626";
dark_red = "#C30771";
orange = "#D75F5F";
dark_green = "#10A778";
dark_purple = "#af5fd7";
dark_yellow = "#A89C14";
in {
inherits = "spacebones_light";
"ui.background" = { bg = actual_white; };
"ui.gutter" = { bg = actual_white; };
"ui.menu.selected" = {
fg = light_black;
bg = dark_purple;
};
"comment" = {
fg = "dark_gray";
modifiers = [ "italic" ];
};
"constant" = dark_purple;
"string" = dark_purple;
"variable" = light_black;
"variable.parameter" = light_black;
"function" = light_black;
"keyword" = medium_gray;
"keyword.function" = light_black;
"keyword.control" = medium_gray;
"keyword.control.import" = medium_gray;
"operator" = {
fg = light_black;
modifiers = [ "bold" ];
};
"function.special" = medium_gray;
"function.macro" = medium_gray;
"type" = light_black;
"type.builtin" = light_black;
"tag" = {
fg = medium_gray;
modifiers = [ "italic" ];
};
"punctuation" = { fg = medium_gray; };
"ui.linenr" = medium_gray;
"ui.linenr.selected" = { fg = dark_purple; };
"string.special.url" = {
fg = light_black;
underline = {
color = light_black;
style = "line";
};
modifiers = [ "underlined" ];
};
"markup.link" = {
fg = light_black;
underline = {
color = light_black;
style = "line";
};
modifiers = [ "underlined" ];
};
"diagnostic.error" = {
underline = {
color = dark_red;
style = "curl";
};
};
"error" = dark_red;
"diagnostic.hint" = {
underline = {
color = light_black;
style = "curl";
};
};
"hint" = light_black;
"ui.selection" = {
fg = light_black;
bg = dark_purple;
};
"ui.selection.primary" = {
fg = light_black;
bg = dark_purple;
};
"warning" = orange;
"diagnostic.warning" = {
underline = {
color = orange;
style = "curl";
};
};
"diff.plus" = dark_green;
"diff.minus" = dark_red;
"diff.delta" = dark_yellow;
"ui.cursor" = { bg = light_black; };
"ui.cursor.insert" = { bg = dark_purple; };
"ui.cursor.select" = { bg = dark_purple; };
"ui.cursor.match" = {
fg = light_black;
bg = medium_gray;
};
"namespace" = medium_gray;
"special" = medium_gray;
};
};
};
};
};
}

20
common/pkgs/bin.nix Normal file
View File

@ -0,0 +1,20 @@
{ rustPlatform, fetchFromGitHub }:
rustPlatform.buildRustPackage rec {
name = "bin";
version = "3bbd64611f2a5dee91528976f6db17ff9844315a";
src = fetchFromGitHub {
owner = "WantGuns";
repo = name;
rev = version;
sha256 = "0lyx8n4rpnyd7c6yjx8aa3zwxlfwj3db0ykrxdvlsaw4wrqlfk7i";
};
cargoLock = { lockFile = "${src}/Cargo.lock"; };
meta = {
description = "highly opinionated, minimal pastebin";
homepage = "https://github.com/WantGuns/bin";
};
}

61
common/services/bin.nix Normal file
View File

@ -0,0 +1,61 @@
{ config, lib, pkgs, ... }:
with lib;
let cfg = config.services.bin;
in {
options = {
services.bin = {
enable = mkEnableOption "Pastebin";
address = mkOption {
type = types.nullOr types.str;
default = "127.0.0.1";
description = "Address on which the webserver runs";
};
binaryUploadLimit = mkOption {
type = types.nullOr types.int;
default = 100;
description = "Binary uploads file size limit (in MiB)";
};
clientDesc = mkOption {
type = types.nullOr types.bool;
default = false;
description = "Include client description [env: CLIENT_DESC=]";
};
port = mkOption {
type = types.nullOr types.int;
default = 6162;
description = "Port on which the webserver runs";
};
upload = mkOption {
type = types.nullOr types.str;
default = "./upload";
description = "Path to the uploads folder";
};
};
};
config = mkIf cfg.enable {
networking.firewall.allowedTCPPorts = [ cfg.port ];
systemd.services.bin = {
wantedBy = [ "multi-user.target" ];
description = "Starts pastebin service.";
after = [ "network.target" ];
serviceConfig = {
Type = "simple";
ExecStart = "${pkgs.bin}/bin/bin -a ${toString cfg.address} -b ${
toString cfg.binaryUploadLimit
} -p ${toString cfg.port} -u ${toString cfg.upload}";
WorkingDirectory = "/var/lib/bin_rs";
Restart = "always";
};
};
};
}

28
common/users/default.nix Normal file
View File

@ -0,0 +1,28 @@
{ config, pkgs, ... }: {
users.users = {
agatha = {
isNormalUser = true;
description = "Agatha Valentine Lovelace";
extraGroups = [ "networkmanager" "wheel" "docker" ];
shell = pkgs.fish;
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGGYqCcDg9hTINHyf8S56/P83+ZzqwV2t9gUsVYyajjR"
];
};
julia = {
isNormalUser = true;
shell = pkgs.fish;
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIa/G3M13aVJpOIX8U/5duiGiNNGmM88/0k0+o0EUGRI cardno:20 876 680"
];
};
};
users.users.root.openssh.authorizedKeys.keys =
config.users.users.agatha.openssh.authorizedKeys.keys;
}

View File

@ -0,0 +1,79 @@
{ config, pkgs, ... }: {
imports = [
./hardware-configuration.nix
../../common/fragments/bin.nix
../../common/fragments/fail2ban.nix
../../common/fragments/grafana.nix
../../common/fragments/homepage.nix
../../common/fragments/mastodon-ebooks.nix
../../common/fragments/matterbridge.nix
../../common/fragments/nyandroid.nix
../../common/fragments/prometheus_exporters.nix
../../common/home_manager/common.nix
];
nixpkgs.overlays = [
(self: super: { bin = self.callPackage ../../common/pkgs/bin.nix { }; })
];
# Bootloader.
boot.loader.grub.enable = true;
boot.loader.grub.device = "/dev/sda";
boot.loader.grub.useOSProber = true;
networking.hostName = "bloodletting";
# Enable networking
networking.networkmanager.enable = true;
# System packages
environment.systemPackages = with pkgs; [ bin matterbridge vsftpd ];
environment.variables.EDITOR = "helix";
# Enable the OpenSSH daemon.
services.openssh = {
enable = true;
banner = ''
Hello mistress ^,,^
'';
passwordAuthentication = false;
};
# Open ports in the firewall.
networking.firewall = {
allowedTCPPorts = [ 80 443 20 21 22 990 6162 ];
allowedTCPPortRanges = [{
from = 40000;
to = 40200;
}];
};
virtualisation = {
podman = {
enable = true;
dockerCompat = true;
defaultNetwork.dnsname.enable = true;
};
oci-containers = { backend = "podman"; };
};
# SSL/TLS Certificates
security.acme.acceptTerms = true;
security.acme.defaults.email = "letsencrypt@technogothic.net";
security.acme.certs."technogothic.net" = {
domain = "*.technogothic.net";
dnsProvider = "rfc2136";
credentialsFile = "/var/lib/secrets/rfc2136-technogothic-net";
};
# 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 = "22.11"; # Did you read the comment?
}

View File

@ -0,0 +1,34 @@
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, modulesPath, ... }:
{
imports = [ (modulesPath + "/profiles/qemu-guest.nix") ];
boot.initrd.availableKernelModules =
[ "ata_piix" "uhci_hcd" "virtio_pci" "virtio_scsi" "sd_mod" "sr_mod" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
fileSystems."/" = {
device = "/dev/disk/by-uuid/d3b27484-78b8-4d21-905d-93ecef11a832";
fsType = "ext4";
};
swapDevices =
[{ device = "/dev/disk/by-uuid/2f352b38-8769-4413-8f06-3b47a64d172f"; }];
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
networking.useDHCP = lib.mkDefault true;
# networking.interfaces.ens18.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.intel.updateMicrocode =
lib.mkDefault config.hardware.enableRedistributableFirmware;
}

36
ops/home/network.nix Normal file
View File

@ -0,0 +1,36 @@
{
network = { description = "Agatha's Nix Infra"; };
"bloodletting" = { config, pkgs, lib, ... }: {
imports = [ ../../common ../../hosts/bloodletting/configuration.nix ];
deployment = {
targetUser = "root";
targetHost = "bloodletting";
secrets = {
"nyandroid-token" = {
source = "../../secrets/nyandroid-token";
destination = "/var/lib/secrets/nyandroid-token";
};
"rfc2136-technogothic-net" = {
source = "../../secrets/rfc2136-technogothic-net";
destination = "/var/lib/secrets/rfc2136-technogothic-net";
};
};
healthChecks.cmd = let
testService = name: {
cmd = [ "systemctl" "is-active" "--quiet" name ];
description = "Checking if ${name} is running";
};
in [
(testService "bin")
(testService "matterbridge")
(testService "grafana")
(testService "prometheus")
(testService "fail2ban")
];
};
};
}

12
ops/home/push Executable file
View File

@ -0,0 +1,12 @@
#!/usr/bin/env nix-shell
#! nix-shell -p morph -i bash
set -e
pushd $(dirname ${BASH_SOURCE[0]}) > /dev/null
morph build --keep-result $@ ./network.nix
morph push $@ ./network.nix
morph deploy --upload-secrets $@ ./network.nix switch
popd > /dev/null