aboutsummaryrefslogtreecommitdiffstats
path: root/hosts
diff options
context:
space:
mode:
authorPetri Hienonen <petri.hienonen@gmail.com>2024-05-23 13:56:00 +0300
committerPetri Hienonen <petri.hienonen@gmail.com>2025-11-30 12:29:57 +0200
commit08297376a85a1719518507e54fca9de954d2376a (patch)
tree3b9c58304b40248533bbb2bb5b7bad2da9da1ff0 /hosts
parent75c2af4aedd2ac5c2cfc74b346625fa4b265541d (diff)
downloadnixos-08297376a85a1719518507e54fca9de954d2376a.tar.zst
Agenix configuration
Diffstat (limited to 'hosts')
-rw-r--r--hosts/kataja/default.nix141
-rw-r--r--hosts/kataja/hardware-configuration.nix79
-rw-r--r--hosts/pihlaja/default.nix269
-rw-r--r--hosts/pihlaja/hardware-configuration.nix80
-rw-r--r--hosts/saarni/default.nix316
-rw-r--r--hosts/saarni/hardware-configuration.nix81
-rw-r--r--hosts/tammi/20-wired.network31
-rw-r--r--hosts/tammi/21-wired.network48
-rw-r--r--hosts/tammi/CM3588.md284
-rw-r--r--hosts/tammi/Caddyfile319
-rw-r--r--hosts/tammi/cgitrc47
-rw-r--r--hosts/tammi/feeds.opml118
-rw-r--r--hosts/tammi/iptable-nat.service11
-rw-r--r--hosts/tammi/syntax-highlighting.js23
14 files changed, 1615 insertions, 232 deletions
diff --git a/hosts/kataja/default.nix b/hosts/kataja/default.nix
new file mode 100644
index 0000000..f664cab
--- /dev/null
+++ b/hosts/kataja/default.nix
@@ -0,0 +1,141 @@
+# Edit this configuration file to define what should be installed on
+# your system. Help is available in the configuration.nix(5) man page
+# and in the NixOS manual (accessible by running ‘nixos-help’).
+
+{
+ inputs,
+ outputs,
+ lib,
+ config,
+ pkgs,
+ vars,
+ ...
+}:
+
+{
+ imports = [ ./hardware-configuration.nix ];
+ networking = {
+ hostName = "kataja";
+ interfaces.eno1.wakeOnLan.enable = true;
+ };
+
+ systemd = {
+ network = {
+ enable = true;
+ wait-online.enable = false;
+ config = {
+ networkConfig = {
+ SpeedMeter = true;
+ };
+ };
+ networks = {
+ "10-wlan" = {
+ matchConfig = {
+ MACAddress = "10:6f:d9:28:3f:b3";
+ };
+ linkConfig = {
+ Multicast = true;
+ };
+ networkConfig = {
+ DHCP = true;
+ IPv6AcceptRA = true;
+ MulticastDNS = true;
+ UseDomains = true;
+ };
+ dhcpV4Config = {
+ RouteMetric = 600;
+ UseMTU = true;
+ };
+ ipv6AcceptRAConfig = {
+ RouteMetric = 600;
+ UseMTU = true;
+ };
+ linkConfig.RequiredForOnline = "no";
+ };
+ "11-lan" = {
+ matchConfig = {
+ MACAddress = "70:70:fc:00:29:25";
+ };
+ linkConfig = {
+ Multicast = true;
+ };
+ networkConfig = {
+ DHCP = true;
+ IPv6AcceptRA = true;
+ MulticastDNS = true;
+ UseDomains = true;
+ };
+ dhcpV4Config = {
+ RouteMetric = 100;
+ UseMTU = true;
+ };
+ ipv6AcceptRAConfig = {
+ RouteMetric = 100;
+ UseMTU = true;
+ };
+ linkConfig.RequiredForOnline = "no";
+ };
+ "12-lan" = {
+ matchConfig = {
+ MACAddress = "70:70:fc:00:29:26";
+ };
+ networkConfig = {
+ DHCP = true;
+ IPv6AcceptRA = true;
+ UseDomains = true;
+ };
+ ipv6AcceptRAConfig = {
+ UseMTU = true;
+ };
+ linkConfig.RequiredForOnline = "no";
+ };
+ };
+ };
+ sleep.extraConfig = "HibernateDelaySec=90m";
+ };
+
+ environment = {
+ sessionVariables = {
+ LIBVA_DRIVER_NAME = "radeonsi";
+ };
+ };
+
+ services = {
+ godns = {
+ enable = true;
+ settings = {
+ domains = [
+ {
+ domain_name = "www.duckdns.org";
+ sub_domains = [ "kataja" ];
+ }
+ ];
+ ip_interface = "eno1";
+ interval = 300;
+ ip_type = "IPv6";
+ login_token_file = config.age.secrets.duckdns.path;
+ provider = "DuckDNS";
+ };
+ };
+ xserver = {
+ deviceSection = ''
+ Option "DRI" "3"
+ Option "VariableRefresh" "True"
+ Option "TearFree" "False"
+ '';
+ };
+ };
+
+ hardware = {
+ graphics = {
+ extraPackages = with pkgs; [
+ amdvlk
+ rocmPackages.clr.icd
+ ];
+ };
+
+ bluetooth.settings.General.Name = "kataja";
+ };
+
+ system.stateVersion = "24.05";
+}
diff --git a/hosts/kataja/hardware-configuration.nix b/hosts/kataja/hardware-configuration.nix
new file mode 100644
index 0000000..5d1d1b7
--- /dev/null
+++ b/hosts/kataja/hardware-configuration.nix
@@ -0,0 +1,79 @@
+# 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 + "/installer/scan/not-detected.nix") ];
+
+ boot = {
+ kernelPackages = pkgs.linuxPackages_zen;
+ initrd = {
+ luks.devices."luks-b3e9864c-2a40-43d7-b1a0-51f3b2ec42bc".device =
+ "/dev/disk/by-uuid/b3e9864c-2a40-43d7-b1a0-51f3b2ec42bc";
+ availableKernelModules = [
+ "ahci"
+ "amdgpu"
+ "mt7921e"
+ "nvme"
+ "r8169"
+ "sd_mod"
+ "usb_storage"
+ "usbhid"
+ "xhci_pci"
+ "cdc_acm"
+ ];
+ };
+ kernelParams = [
+ "amdgpu.modeset=1"
+ "default_hugepagesz=2M"
+ "mitigations=off"
+ "nospectre_v2"
+ "transparent_hugepage=always"
+ ];
+ kernelModules = [
+ "k10temp"
+ "kvm-amd"
+ "snd_hda_intel"
+ "tcp_bbr"
+ ];
+ extraModulePackages = [ ];
+ };
+
+ fileSystems."/" = {
+ device = "/dev/disk/by-uuid/3e7f6b6b-b656-4f42-b314-f447e2562718";
+ fsType = "ext4";
+ };
+
+ boot.initrd.luks.devices."luks-b9b738dc-8554-41d9-82f9-042663b52e79".device =
+ "/dev/disk/by-uuid/b9b738dc-8554-41d9-82f9-042663b52e79";
+
+ fileSystems."/boot" = {
+ device = "/dev/disk/by-uuid/4121-BEC3";
+ fsType = "vfat";
+ options = [
+ "fmask=0077"
+ "dmask=0077"
+ ];
+ };
+
+ swapDevices = [ { device = "/dev/disk/by-uuid/97641877-607c-46cd-853d-e431c8a90dc2"; } ];
+
+ # 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.eno1.useDHCP = lib.mkDefault true;
+ # networking.interfaces.enp2s0.useDHCP = lib.mkDefault true;
+ # networking.interfaces.wlp3s0.useDHCP = lib.mkDefault true;
+
+ nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
+ hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
+}
diff --git a/hosts/pihlaja/default.nix b/hosts/pihlaja/default.nix
new file mode 100644
index 0000000..8101815
--- /dev/null
+++ b/hosts/pihlaja/default.nix
@@ -0,0 +1,269 @@
+# Edit this configuration file to define what should be installed on
+# your system. Help is available in the configuration.nix(5) man page
+# and in the NixOS manual (accessible by running ‘nixos-help’).
+
+{
+ inputs,
+ outputs,
+ lib,
+ config,
+ pkgs,
+ vars,
+ ...
+}:
+
+{
+ imports = [ ./hardware-configuration.nix ];
+
+ hardware = {
+ bluetooth.enable = true;
+ keyboard.qmk.enable = true;
+ logitech.wireless.enable = true;
+ nvidia = {
+ modesetting.enable = true;
+ powerManagement = {
+ enable = true;
+ finegrained = false;
+ };
+ open = true;
+ nvidiaSettings = false;
+ package = config.boot.kernelPackages.nvidiaPackages.latest;
+ };
+ graphics = {
+ extraPackages = with pkgs; [
+ nvidia-vaapi-driver
+ cudatoolkit
+ ];
+ };
+
+ bluetooth.settings.General.Name = "pihlaja";
+ };
+
+ networking = {
+ hostName = "pihlaja";
+ interfaces.enp5s0.wakeOnLan.enable = true;
+ };
+
+ environment = {
+ sessionVariables = {
+ LIBVA_DRIVER_NAME = "nvidia";
+ VK_DRIVER_FILES = "/run/opengl-driver/share/vulkan/icd.d/nvidia_icd.x86_64.json";
+ GBM_BACKEND = "nvidia-drm";
+ __GLX_VENDOR_LIBRARY_NAME = "nvidia";
+ NVD_BACKEND = "direct";
+ };
+ systemPackages = with pkgs; [
+ logiops
+ qmk_hid
+ qmk
+ via
+ qmk-udev-rules
+ ];
+ };
+
+ services.hardware.openrgb = {
+ enable = true;
+ package = pkgs.openrgb-with-all-plugins;
+ motherboard = "amd";
+ server = {
+ port = 6742;
+ };
+ };
+
+ systemd = {
+ network = {
+ enable = true;
+ wait-online.enable = false;
+ config = {
+ networkConfig = {
+ SpeedMeter = true;
+ };
+ };
+ networks = {
+ "10-wlan" = {
+ matchConfig.MACAddress = "34:cf:f6:25:c7:db";
+ linkConfig = {
+ Multicast = true;
+ };
+ networkConfig = {
+ DHCP = "yes";
+ IPv6AcceptRA = true;
+ MulticastDNS = true;
+ LinkLocalAddressing = "ipv6";
+ DNSSEC = true;
+ UseDomains = true;
+ };
+ dhcpV4Config = {
+ RouteMetric = 100;
+ UseDNS = true;
+ UseMTU = true;
+ };
+ ipv6AcceptRAConfig = {
+ UseMTU = true;
+ };
+ linkConfig.RequiredForOnline = "yes";
+ };
+ "11-lan" = {
+ matchConfig.MACAddress = "18:c0:4d:04:cf:e9";
+ linkConfig = {
+ Multicast = true;
+ };
+ networkConfig = {
+ DHCP = "yes";
+ IPv6AcceptRA = true;
+ MulticastDNS = true;
+ LinkLocalAddressing = "ipv6";
+ DNSSEC = true;
+ UseDomains = true;
+ };
+ dhcpV4Config = {
+ RouteMetric = 90;
+ UseDNS = true;
+ UseMTU = true;
+ };
+ ipv6AcceptRAConfig = {
+ RouteMetric = 80;
+ UseMTU = true;
+ };
+ linkConfig.RequiredForOnline = "no";
+ };
+ };
+ };
+ services = {
+ logiops = {
+ enable = true;
+ description = "An unofficial userspace driver for HID++ Logitech devices";
+ serviceConfig = {
+ Type = "simple";
+ ExecStart = "${pkgs.logiops}/bin/logid";
+ };
+ wantedBy = [ "multi-user.target" ];
+ };
+ };
+ };
+
+ services = {
+ godns = {
+ enable = true;
+ settings = {
+ domains = [
+ {
+ domain_name = "www.duckdns.org";
+ sub_domains = [ "pihlaja" ];
+ }
+ ];
+ ip_interface = "enp5s0";
+ interval = 300;
+ ip_type = "IPv6";
+ login_token_file = config.age.secrets.duckdns.path;
+ provider = "DuckDNS";
+ };
+ };
+ xserver = {
+ videoDrivers = [ "nvidia" ];
+ };
+ udev.packages = with pkgs; [
+ qmk
+ qmk_hid
+ qmk-udev-rules
+ via
+ ];
+ llama-cpp = {
+ enable = false;
+ openFirewall = true;
+ model = "/home/petri/Programming/DeepSeek-R1-Distill-Qwen-32B-Q8_0.gguf";
+ host = "0.0.0.0";
+ };
+ };
+ fonts.fontconfig.subpixel.rgba = "bgr";
+
+ # Configuration for logiops
+ environment.etc."logid.cfg".text = ''
+ devices: ({
+ name: "Wireless Mouse MX Master 3";
+ smartshift: {
+ on: true;
+ threshold: 12;
+ };
+ hiresscroll: {
+ hires: true;
+ target: false;
+ };
+ thumbwheel: {
+ divert: true;
+ invert: false;
+ left: {
+ threshold: 1;
+ interval: 1;
+ direction: "Left";
+ mode: "OnInterval";
+ action = {
+ type: "Keypress";
+ keys: ["KEY_VOLUMEDOWN"];
+ };
+ };
+ right: {
+ threshold: 1;
+ interval: 1;
+ direction: "Right";
+ mode: "OnInterval";
+ action = {
+ type: "Keypress";
+ keys: ["KEY_VOLUMEUP"];
+ };
+ };
+ };
+ dpi: 1500;
+ buttons: ({
+ cid: 0xc3;
+ action = {
+ type: "Gestures";
+ gestures: ({
+ direction: "Left";
+ mode: "OnRelease";
+ action = {
+ type = "Keypress";
+ keys: ["KEY_F15"];
+ };
+ }, {
+ direction: "Right";
+ mode: "OnRelease";
+ action = {
+ type = "Keypress";
+ keys: ["KEY_F16"];
+ };
+ }, {
+ direction: "Down";
+ mode: "OnRelease";
+ action = {
+ type: "Keypress";
+ keys: ["KEY_F17"];
+ };
+ }, {
+ direction: "Up";
+ mode: "OnRelease";
+ action = {
+ type: "Keypress";
+ keys: ["KEY_F18"];
+ };
+ }, {
+ direction: "None";
+ mode: "OnRelease";
+ action = {
+ type = "Keypress";
+ keys: ["KEY_PLAYPAUSE"];
+ };
+ });
+ };
+ }, {
+ cid: 0xc4;
+ action = {
+ type: "Keypress";
+ keys: ["KEY_F19"];
+ };
+ });
+ });
+ '';
+
+ system.stateVersion = "24.05"; # Did you read the comment?
+}
diff --git a/hosts/pihlaja/hardware-configuration.nix b/hosts/pihlaja/hardware-configuration.nix
new file mode 100644
index 0000000..1e81932
--- /dev/null
+++ b/hosts/pihlaja/hardware-configuration.nix
@@ -0,0 +1,80 @@
+# 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 + "/installer/scan/not-detected.nix") ];
+
+ boot = {
+ kernelPackages = pkgs.linuxPackages;
+ kernelParams = [
+ "NVreg_PreserveVideoMemoryAllocations=1"
+ "mitigations=off"
+ "nospectre_v2"
+ "nvidia_drm.fbdev=1"
+ "nvidia_drm.modeset=1"
+ "transparent_hugepage=always"
+ ];
+ initrd = {
+ luks.devices."luks-a47a6087-e6bf-4e8d-a034-2229259c38f5".device =
+ "/dev/disk/by-uuid/a47a6087-e6bf-4e8d-a034-2229259c38f5";
+ availableKernelModules = [
+ "cdc_acm"
+ "ahci"
+ "iwldvm"
+ "iwlwifi"
+ "nvme"
+ "sd_mod"
+ "usb_storage"
+ "usbhid"
+ "xhci_pci"
+ "nvidia"
+ "nvidia_drm"
+ "nvidia_modeset"
+ "nvidia_uvm"
+ ];
+ luks.devices."luks-1efa1182-2964-49bf-a413-fb51bd7b107f".device =
+ "/dev/disk/by-uuid/1efa1182-2964-49bf-a413-fb51bd7b107f";
+ };
+ kernelModules = [
+ "tcp_bbr"
+ "iwldvm"
+ "iwlwifi"
+ "k10temp"
+ "kvm-amd"
+ ];
+ extraModulePackages = [ ];
+ };
+
+ fileSystems."/" = {
+ device = "/dev/disk/by-uuid/eecfd181-138c-4c90-add6-2ef528d5dbb4";
+ fsType = "ext4";
+ };
+
+ fileSystems."/data" = {
+ device = "/dev/disk/by-uuid/a02a4e78-32ea-40e6-8398-087bfd8dca93";
+ fsType = "ext4";
+ options = [ "nofail" ];
+ };
+
+ fileSystems."/boot" = {
+ device = "/dev/disk/by-uuid/A4F5-0899";
+ fsType = "vfat";
+ options = [
+ "fmask=0077"
+ "dmask=0077"
+ ];
+ };
+
+ swapDevices = [ { device = "/dev/disk/by-uuid/d0e5a93d-18a7-4d24-893c-d2417c3d5043"; } ];
+
+ nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
+ hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
+}
diff --git a/hosts/saarni/default.nix b/hosts/saarni/default.nix
index 010a8eb..5252e6f 100644
--- a/hosts/saarni/default.nix
+++ b/hosts/saarni/default.nix
@@ -2,249 +2,147 @@
# your system. Help is available in the configuration.nix(5) man page
# and in the NixOS manual (accessible by running ‘nixos-help’).
-{ inputs, outputs, lib, config, pkgs, vars, ... }:
+{
+ inputs,
+ outputs,
+ lib,
+ config,
+ pkgs,
+ vars,
+ ...
+}:
{
- imports = [
- ./hardware-configuration.nix
- inputs.home-manager.nixosModules.home-manager
- ];
+ imports = [ ./hardware-configuration.nix ];
- nix = {
- nixPath = [ "/etc/nix/path" ];
- gc = {
- automatic = true;
- };
- settings = {
- auto-optimise-store = true;
- experimental-features = "nix-command flakes";
+ hardware = {
+ graphics = {
+ extraPackages = with pkgs; [
+ libvpl
+ libvdpau-va-gl
+ sof-firmware
+ vpl-gpu-rt
+ ];
};
- registry = (lib.mapAttrs (_: flake: { inherit flake; }))
- ((lib.filterAttrs (_: lib.isType "flake")) inputs);
- };
- nixpkgs.config.allowUnfree = true;
- security.rtkit.enable = true;
-
- home-manager = {
- extraSpecialArgs = { inherit inputs outputs vars; };
- users = { ${vars.user} = import ../../home; };
- };
-
- powerManagement = {
- enable = true;
- powertop.enable = true;
- };
- # Bootloader.
- boot = {
- loader = {
- systemd-boot.enable = true;
- efi.canTouchEfiVariables = true;
- };
- kernelPackages = pkgs.linuxPackages_latest;
- plymouth.enable = true;
- kernelParams = [ "quiet" "splash" ];
+ bluetooth.settings.General.Name = "saarni";
};
networking = {
- nameservers = [ "1.1.1.1#one.one.one.one" "1.0.0.1#one.one.one.one" ];
hostName = "saarni";
- useNetworkd = true;
- wireless.iwd.enable = true;
};
systemd = {
- watchdog = {
- device = "/dev/watchdog";
- runtimeTime = "30s";
+ services."enable-wifi-on-boot" = {
+ description = "Enable wifi on boot";
+ wantedBy = [ "multi-user.target" ];
+ serviceConfig = {
+ ExecStart = "${pkgs.util-linux}/bin/rfkill unblock all";
+ Type = "oneshot";
+ };
};
- sleep.extraConfig = "HibernateDelaysSec=90m";
network = {
enable = true;
wait-online.enable = false;
+ config = {
+ networkConfig = {
+ SpeedMeter = true;
+ };
+ };
networks = {
"10-lan" = {
- matchConfig.Name = "enp0s20f0u9";
- networkConfig.DHCP = "yes";
+ matchConfig = {
+ Name = "enps0";
+ };
+ linkConfig = {
+ Multicast = true;
+ };
+ networkConfig = {
+ DHCP = true;
+ IPv6AcceptRA = true;
+ MulticastDNS = true;
+ LinkLocalAddressing = "ipv6";
+ DNSSEC = true;
+ UseDomains = true;
+ };
+ dhcpV4Config = {
+ RouteMetric = 20;
+ UseDNS = true;
+ UseMTU = true;
+ };
+ ipv6AcceptRAConfig = {
+ UseMTU = true;
+ };
};
- "11-lan" = {
- matchConfig.Name = "wlan0";
- networkConfig.DHCP = "yes";
+ "11-wlan" = {
+ matchConfig = {
+ MACAddress = "64:d6:9a:9e:06:60";
+ };
+ linkConfig = {
+ Multicast = true;
+ };
+ networkConfig = {
+ DHCP = true;
+ IPv6AcceptRA = true;
+ MulticastDNS = true;
+ LinkLocalAddressing = "ipv6";
+ DNSSEC = true;
+ UseDomains = true;
+ };
+ dhcpV4Config = {
+ RouteMetric = 100;
+ UseDNS = true;
+ UseMTU = true;
+ SendHostname = true;
+ };
+ dhcpV6Config = {
+ WithoutRA = "solicit";
+ };
+ ipv6AcceptRAConfig = {
+ UseMTU = true;
+ };
};
};
};
};
- system.autoUpgrade = {
- enable = true;
- };
-
- sound.enable = true;
-
- hardware = {
- opengl = {
- enable = true;
- driSupport = true;
- extraPackages = with pkgs; [
- intel-media-driver
- libvdpau-va-gl
- ];
- };
- bluetooth = {
- enable = true;
- powerOnBoot = true;
- };
- };
-
- # Set your time zone.
- time.timeZone = "Europe/Helsinki";
-
- # Select internationalisation properties.
- i18n = {
- defaultLocale = "en_US.UTF-8";
- extraLocaleSettings = {
- LC_ADDRESS = "fi_FI.UTF-8";
- LC_IDENTIFICATION = "fi_FI.UTF-8";
- LC_MEASUREMENT = "fi_FI.UTF-8";
- LC_MONETARY = "fi_FI.UTF-8";
- LC_NAME = "fi_FI.UTF-8";
- LC_NUMERIC = "fi_FI.UTF-8";
- LC_PAPER = "fi_FI.UTF-8";
- LC_TELEPHONE = "fi_FI.UTF-8";
- LC_TIME = "fi_FI.UTF-8";
- };
- };
-
- console.keyMap = "fi";
-
- # Define a user account. Don't forget to set a password with ‘passwd’.
- users.users.${vars.user} = {
- isNormalUser = true;
- description = "${vars.name}";
- extraGroups = [ "input" "network" "wheel" ];
- packages = with pkgs; [ ];
- ignoreShellProgramCheck = true;
- shell = pkgs.${vars.shell};
- };
-
- programs = {
- firefox.enable = true;
- hyprland.enable = true;
- gnupg.agent = {
- enable = true;
- enableSSHSupport = true;
- };
- mtr.enable = true;
- };
-
environment = {
- sessionVariables = {
- LIBVA_DRIVER_NAME = "iHD";
- };
- systemPackages = with pkgs; [
- fastfetch
- vulkan-tools
- libva-utils
- wget
- curl
- git
- gzip
- btop
- glxinfo
- sqlite
- openssh
- gnupg
- helix
- nixfmt
- ];
- etc = lib.mapAttrs' (name: value: {
- name = "nix/path/${name}";
- value.source = value.flake;
- }) config.nix.registry;
- };
-
- fonts = {
- enableDefaultPackages = true;
- packages = with pkgs; [ noto-fonts fira-code fira-code-symbols ];
- fontconfig = {
- defaultFonts = {
- serif = [ "Noto Serif" ];
- sansSerif = [ "Noto Sans" ];
- monospace = [ "Fira Code" ];
- };
- };
+ sessionVariables = { };
};
- # List services that you want to enable:
services = {
- getty.autologinUser = "petri";
- resolved = {
- enable = true;
- dnsovertls = "true";
- };
- xserver = {
- layout = "fi";
- xkbVariant = "normal";
- };
- pipewire = {
+ godns = {
enable = true;
- alsa.enable = true;
- pulse.enable = true;
- };
- openssh.enable = true;
- printing.enable = true;
- kmscon = {
- enable = true;
- hwRender = true;
- extraOptions = "--xkb-layout=fi";
- };
- blueman.enable = true;
- upower.enable = true;
- upower.criticalPowerAction = "Hibernate";
- fstrim.enable = false;
- thermald.enable = true;
- auto-cpufreq.enable = true;
- greetd = {
- enable = true;
- settings = rec {
- initial_session = {
- command = "${pkgs.hyprland}/bin/Hyprland";
- user = "petri";
- };
- default_session = initial_session;
+ settings = {
+ domains = [
+ {
+ domain_name = "www.duckdns.org";
+ sub_domains = [ "saarni" ];
+ }
+ ];
+ ip_interface = "wlan0";
+ interval = 300;
+ ip_type = "IPv6";
+ login_token_file = config.age.secrets.duckdns.path;
+ provider = "DuckDNS";
};
};
- };
-
- xdg.portal = {
- enable = true;
- xdgOpenUsePortal = true;
- extraPortals = [
- pkgs.xdg-desktop-portal-hyprland
- pkgs.xdg-desktop-portal-gtk
- ];
- wlr = {
+ tlp = {
enable = true;
settings = {
- screencast = {
- chooser_type = "simple";
- chooser_cmd = "${pkgs.slurp}/bin/slurp -f %o -ro";
- };
+ CPU_PERF_POLICY_ON_AC = "performance";
+ CPU_PERF_POLICY_ON_BAT = "power";
+ CPU_SCALING_GOVERNOR_ON_AC = "performance";
+ CPU_SCALING_GOVERNOR_ON_BAT = "powersave";
+ START_CHARGE_THRESH_BAT0 = 40;
+ STOP_CHARGE_TRESH_BAT0 = 20;
};
};
+ upower = {
+ enable = true;
+ criticalPowerAction = "Hibernate";
+ };
+ thermald.enable = true;
};
-
- # Open ports in the firewall.
- # networking.firewall.allowedTCPPorts = [ ... ];
- # networking.firewall.allowedUDPPorts = [ ... ];
- # Or disable the firewall altogether.
- # networking.firewall.enable = false;
-
- # 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. It‘s 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 = "23.11"; # Did you read the comment?
+ system.stateVersion = "24.05";
}
diff --git a/hosts/saarni/hardware-configuration.nix b/hosts/saarni/hardware-configuration.nix
index 6aef572..798aa7b 100644
--- a/hosts/saarni/hardware-configuration.nix
+++ b/hosts/saarni/hardware-configuration.nix
@@ -1,37 +1,72 @@
# 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 + "/installer/scan/not-detected.nix") ];
+ config,
+ lib,
+ pkgs,
+ modulesPath,
+ ...
+}:
- boot.initrd.availableKernelModules = [ "xhci_pci" "thunderbolt" "nvme" "usb_storage" "sd_mod" ];
- boot.initrd.kernelModules = [ ];
- boot.kernelModules = [ "kvm-intel" ];
- boot.extraModulePackages = [ ];
+{
+ imports = [ (modulesPath + "/installer/scan/not-detected.nix") ];
- fileSystems."/" =
- { device = "/dev/disk/by-uuid/3968a07a-5e37-4bdb-9e3a-6c74950fd03d";
- fsType = "ext4";
+ boot = {
+ kernelPackages = pkgs.linuxPackages_zen;
+ initrd = {
+ availableKernelModules = [
+ "xhci_pci"
+ "thunderbolt"
+ "nvme"
+ "usb_storage"
+ "sd_mod"
+ "i915"
+ "cdc_acm"
+ ];
};
+ kernelModules = [
+ "kvm-intel"
+ "iwlwifi"
+ "iwldvm"
+ "snd_hda_intel"
+ "snd_soc_avs"
+ "snd_sof_pci_intel_tgl"
+ "tcp_bbr"
+ ];
+ extraModulePackages = [ ];
+ kernelParams = [
+ "default_hugepagesz=2M"
+ "i915.enable_guc=3"
+ "i915.fastboot=1"
+ "mitigations=off"
+ "nospectre_v2"
+ "snd-intel-dspcfg.dsp_driver=3"
+ "transparent_hugepage=always"
+ "usbcore.blinkenlights=1"
+ ];
+ extraModprobeConfig = ''
+ options snd_hda_intel enable=0,1
+ '';
+ };
- fileSystems."/boot" =
- { device = "/dev/disk/by-uuid/9B7E-3D1B";
- fsType = "vfat";
- options = [ "fmask=0022" "dmask=0022" ];
- };
+ fileSystems."/" = {
+ device = "/dev/disk/by-uuid/3968a07a-5e37-4bdb-9e3a-6c74950fd03d";
+ fsType = "ext4";
+ };
- swapDevices = [ ];
+ fileSystems."/boot" = {
+ device = "/dev/disk/by-uuid/9B7E-3D1B";
+ fsType = "vfat";
+ options = [
+ "fmask=0022"
+ "dmask=0022"
+ ];
+ };
- # 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.wlan0.useDHCP = lib.mkDefault true;
+ hardware.firmware = [ pkgs.sof-firmware ];
+ swapDevices = [ ];
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}
diff --git a/hosts/tammi/20-wired.network b/hosts/tammi/20-wired.network
new file mode 100644
index 0000000..1a39f55
--- /dev/null
+++ b/hosts/tammi/20-wired.network
@@ -0,0 +1,31 @@
+# WAN
+[Match]
+Name=eth0
+
+[Network]
+DHCP=yes
+IPv6PrivacyExtensions=no
+IPv6AcceptRA=yes
+IPMasquerade=both
+DHCPPrefixDelegation=yes
+IPForward=yes
+
+[DHCPv4]
+UseMTU=yes
+UseDNS=false
+UseNTP=false
+
+[IPv6AcceptRA]
+UseMTU=yes
+UseDNS=false
+
+[DHCPv6]
+WithoutRA=solicit
+PrefixDelegationHint=::/56
+RapidCommit=yes
+
+[DHCPPrefixDelegation]
+UplinkInterface=auto
+SubnetId=auto
+Announce=yes
+Assign=yes
diff --git a/hosts/tammi/21-wired.network b/hosts/tammi/21-wired.network
new file mode 100644
index 0000000..4ab692d
--- /dev/null
+++ b/hosts/tammi/21-wired.network
@@ -0,0 +1,48 @@
+[Match]
+# Name=eth1 - LAN
+MACAddress=6c:1f:f7:1b:f2:6c
+
+[Link]
+Multicast=yes
+
+[Network]
+DNS=10.1.1.1#adguard.tammi.cc
+DNS=2001:14ba:a304:aff4::1#adguard.tammi.cc
+NTP=10.1.1.1
+DHCP=no
+LLDP=yes
+LLMNR=yes
+Address=10.1.1.1/24
+DHCPServer=true
+MulticastDNS=true
+IPv6SendRA=yes
+IPv6AcceptRA=no
+IPv6PrefixDelegation=yes
+DHCPPrefixDelegation=yes
+LinkLocalAddressing=yes
+LLMNR=yes
+IPForward=yes
+
+[DHCPServer]
+PoolOffset=100
+PoolSize=40
+EmitDNS=yes
+EmitNTP=yes
+EmitTimezone=yes
+DNS=_server_address
+NTP=_server_address
+DefaultLeaseTimeSec=3600
+MaxLeaseTimeSec=7200
+
+[IPv6SendRA]
+Managed=yes
+OtherInformation=yes
+EmitDNS=yes
+DNS=_link_local
+RouterPreference=high
+
+[DHCPPrefixDelegation]
+UplinkInterface=eth0
+SubnetId=0
+Announce=yes
+Assign=yes
diff --git a/hosts/tammi/CM3588.md b/hosts/tammi/CM3588.md
new file mode 100644
index 0000000..d62780a
--- /dev/null
+++ b/hosts/tammi/CM3588.md
@@ -0,0 +1,284 @@
+---
+title: "Running the gateway for testing"
+author: [Petri Hienonen]
+date: "2023-03-31"
+---
+
+# CM3588 setup guide for Debian Bookworm
+
+[CM3588](https://www.friendlyelec.com/index.php?route=product/product&product_id=294) works as our reference hardware.
+
+`SDCARD` to `EMMC` image [should be used](https://drive.google.com/file/d/1CrYDAZFwGdZoFIRfrQGEVd6SEu6f0PwU/view)
+
+[Wiki documents things related to the device installation](https://wiki.friendlyelec.com/wiki/index.php/NanoPi_R5S)
+
+## Basic configuration
+
+Login with SSH (Username: `pi`, Password: `pi`)
+
+`/etc/systemd/network/20-wired.network`
+
+```
+[Match]
+Name=eth0
+
+[Network]
+DHCP=yes
+DNS=8.8.8.8
+MulticastDNS=true
+
+[Link]
+MTUBytes=9000
+```
+
+`/etc/systemd/timesyncd.conf`
+
+```
+[Time]
+NTP=0.arch.pool.ntp.org 1.arch.pool.ntp.org 2.arch.pool.ntp.org 3.arch.pool.ntp.org
+FallbackNTP=0.pool.ntp.org 1.pool.ntp.org 0.fr.pool.ntp.org
+```
+
+```bash
+sudo apt update && sudo apt dist-upgrade -y && sudo apt autoremove -y
+sudo systemctl stop NetworkManager
+sudo systemctl disable NetworkManager
+sudo apt remove network-manager ntp wpa_supplicant
+sudo systemctl enable systemd-timesyncd.service
+sudo systemctl start systemd-timesyncd.service
+sudo timedatectl set-timezone Europe/Helsinki
+```
+
+Modify `/etc/hostname` to wanted (tammi.cc).
+
+Modify `/etc/systemd/journald.conf` (following keys):
+
+```
+[Journal]
+Storage=volatile
+SystemMaxUse=20M
+RuntimeMaxUse=20M
+MaxRetentionSec=2day
+```
+
+Wireless network configuration (`wlan0` with [`iwd`](https://iwd.wiki.kernel.org/))
+
+```bash
+sudo apt remove wpasupplicant
+sudo apt install iwd
+sudo mkdir -p /var/lib/iwd/
+```
+
+`/etc/systemd/network/20-wired.network`
+
+```
+[Match]
+Name=eth0
+
+[Network]
+DHCP=yes
+DNSSEC=allow-downgrade
+DNS=9.9.9.9 2620:fe::fe
+LinkLocalAddresssing=yes
+```
+
+`/etc/systemd/network/26-wireless.network`
+
+```
+[Match]
+Name=wlan0
+
+[Network]
+DHCP=yes
+DNSSEC=allow-downgrade
+DNS=9.9.9.9 2620:fe::fe
+LinkLocalAddresssing=yes
+```
+
+`/var/lib/iwd/example_network.psk`:
+
+```
+[Security]
+Passphrase=Relynx8WP
+```
+
+```bash
+sudo systemctl start iwd.service
+sudo systemctl enable iwd.service
+sudo systemctl restart systemd-networkd.service
+```
+
+Create petri user:
+
+```bash
+sudo useradd -m petri
+sudo passwd petri (password)
+sudo usermod -a -G sudo petri
+sudo usermod -a -G systemd-journal petri
+sudo chsh -s /bin/bash petri
+sudo reboot
+```
+
+Stop autologin for user `petri` by commenting out user `petri` in `/etc/lightdm/lightdm.conf`.
+
+Login with `petri` user.
+
+Check that network looks sane:
+
+```bash
+networkctl status --all
+```
+
+Delete `pi` user:
+
+```bash
+sudo userdel -r pi
+```
+
+Create necessary keys and clone and build rust packages:
+
+```bash
+sudo apt install llvm clang libssl-dev -y
+curl --proto '=https' --tlsv1.3 -sSf https://sh.rustup.rs | sh
+source "$HOME/.cargo/env"
+ssh-keygen -t ed25519
+cat .ssh/id_ed25519.pub
+```
+
+## Applications
+
+### SSH
+
+Guideline from: https://infosec.mozilla.org/guidelines/openssh
+
+```bash
+sudo apt install mosh
+```
+
+### Backports
+
+```bash
+echo "deb http://deb.debian.org/debian bookworm-backports main contrib non-free-firmware">/etc/apt/sources.list.d/debian-12-backports.list
+```
+
+### BTRFS
+
+```bash
+sudo apt install btrfs-progs
+sudo mkfs.btrfs -m raid1 -d raid1 /dev/nvme1n1 /dev/nvme0n1
+sudo mkdir /media/data
+echo "UUID=f566eaa0-f004-4acc-9d0d-f6fb97daca5e /media/data btrfs defaults,discard=async,compress=zstd 0 0">>/etc/fstab
+
+sudo mkdir /media/data/db
+sudo chattr -R +C /media/data/db # make the DB not COW
+
+sudo mkdir /media/data/logs
+sudo chattr -R +C /media/data/logs # make the DB not COW
+```
+
+/etc/systemd/system/btrfs-scrub@.service
+
+```systemd
+[Unit]
+Description=Btrfs scrub on %f
+ConditionPathIsMountPoint=%f
+RequiresMountsFor=%f
+
+[Service]
+Nice=19
+IOSchedulingClass=idle
+KillSignal=SIGINT
+ExecStart=/usr/bin/btrfs scrub start -B %f
+```
+
+/etc/systemd/system/btrfs-scrub@.timer
+
+```systemd
+[Unit]
+Description=Btrfs scrub on %f twice per month
+
+[Timer]
+OnCalendar=*-*-1,15
+AccuracySec=1d
+RandomizedDelaySec=1w
+Persistent=true
+
+[Install]
+WantedBy=timers.target
+```
+
+```bash
+sudo systemctl start btrfs-scrub@(systemd-escape -p /media/data).service
+sudo systemctl enable --now btrfs-scrub@(systemd-escape -p /media/data).timer
+```
+
+### Docker
+
+```bash
+sudo apt install docker.io docker-compose
+sudo usermod -aG docker $USER
+sudo systemctl enable docker.service
+```
+
+### Postgresql (edit the datapaths)
+
+```bash
+sudo apt install postgresql postgresql-contrib
+sudo mkdir /media/data/db/postgresql/16/main
+sudo vim /etc/postgresql/16/main/postgresql.conf
+sudo chown -R postgres:postgres postgresql/
+```
+Add Environment=PGDATA=/media/data/db/postgresql/%I/main to /lib/systemd/system/postgresql@.service under [Service]
+
+### Miniflux
+
+```bash
+echo "deb [trusted=yes] https://repo.miniflux.app/apt/ * *" | sudo tee /etc/apt/sources.list.d/miniflux.list > /dev/null
+apt update && apt install miniflux
+systemctl status miniflux.service
+
+sudo -u postgres psql
+CREATE USER miniflix with PASSWORD 'miniflux';
+CREATE DATABASE miniflux2 OWNER miniflux;
+```
+
+### Vaultwarden (/etc/vaultwarden):
+
+```bash
+wget -O /etc/apt/trusted.gpg.d/bananian-keyring.gpg https://bitwarden-deb.tech-network.de/bananian-keyring.gpg
+echo "deb http://bitwarden-deb.tech-network.de bookworm main" > /etc/apt/sources.list.d/vaultwarden.list
+apt update && apt install vaultwarden
+
+sudo -u postgres psql
+CREATE USER vaultwarden WITH ENCRYPTED PASSWORD 'yourpassword';
+CREATE DATABASE vaultwarden OWNER vaultwarden;
+
+(vaultwarden binary will have to be compiled with hand to enable postgresql, this is irritating)
+sudo apt install libpq-dev
+(add following systemd service environment variable)
+Environment="DATABASE_URL=postgresql://vaultwarden:yourpassword@127.0.0.1:5432/vaultwarden"
+systemctl enable vaultwarden.service
+```
+
+/etc/enviroment
+
+```bash
+PATH="/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/sbin"
+```
+
+### Webmin
+
+```bash
+curl -o setup-repos.sh https://raw.githubusercontent.com/webmin/webmin/master/setup-repos.sh
+sh setup-repos.sh
+apt install webmin
+
+(configure using /etc/webmin/miniserv.conf)
+```
+
+### Minio
+
+```bash
+wget https://dl.min.io/server/minio/release/linux-arm64/minio_20240611031330.0.0_arm64.deb -O minio.deb
+sudo dpkg -i minio.deb
+```
diff --git a/hosts/tammi/Caddyfile b/hosts/tammi/Caddyfile
new file mode 100644
index 0000000..fe9d437
--- /dev/null
+++ b/hosts/tammi/Caddyfile
@@ -0,0 +1,319 @@
+# The Caddyfile is an easy way to configure your Caddy web server.
+#
+# Unless the file starts with a global options block, the first
+# uncommented line is always the address of your site.
+#
+# To use your own domain name (with automatic HTTPS), first make
+# sure your domain's A/AAAA DNS records are properly pointed to
+# this machine's public IP, then replace ":80" below with your
+# domain name.
+(cors) {
+ @cors_preflight method OPTIONS
+
+ header {
+ Access-Control-Allow-Origin "{header.origin}"
+ Vary Origin
+ Access-Control-Expose-Headers "Authorization"
+ Access-Control-Allow-Credentials "true"
+ }
+
+ handle @cors_preflight {
+ header {
+ Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE"
+ Access-Control-Max-Age "3600"
+ }
+ respond "" 204
+ }
+}
+
+{
+ metrics
+ log {
+ output file /var/log/caddy/caddy_main.log {
+ roll_size 20MiB
+ roll_keep 5
+ roll_keep_for 100d
+ }
+ format json
+ level INFO
+ }
+}
+
+tammi.cc {
+ root * /media/data/hienotammi
+ file_server browse
+ encode zstd gzip
+ log {
+ output file /media/data/logs/tammi.log {
+ roll_size 1mb
+ roll_keep 1
+ }
+ }
+}
+
+holvi.tammi.cc {
+ root * /media/data/holvi
+ file_server browse
+ encode zstd gzip
+ log {
+ output file /media/data/logs/holvi.log {
+ roll_size 1mb
+ roll_keep 1
+ }
+ }
+}
+
+grafana.tammi.cc {
+ reverse_proxy 127.0.0.1:3010
+ encode zstd gzip
+ log {
+ output file /media/data/logs/grafana.log {
+ roll_size 1mb
+ roll_keep 1
+ }
+ }
+}
+
+ntfy.tammi.cc {
+ reverse_proxy 127.0.0.1:3070
+ encode zstd gzip
+ log {
+ output file /media/data/logs/ntfy.log {
+ roll_size 1mb
+ roll_keep 1
+ }
+ }
+}
+
+adguard.tammi.cc {
+ basic_auth {
+ petri $2a$14$1gj396cBvvMoC7kW0qSZBOF9Qzwt8ewyujua1EpdDJm9gXdBFsfEe
+ }
+ reverse_proxy 127.0.0.1:3000
+ encode zstd gzip
+ log {
+ output file /media/data/logs/adguard.log {
+ roll_size 1mb
+ roll_keep 1
+ }
+ }
+}
+
+n8n.tammi.cc {
+ reverse_proxy 127.0.0.1:5678
+ encode zstd gzip
+ log {
+ output file /media/data/logs/n8n.log {
+ roll_size 1mb
+ roll_keep 1
+ }
+ }
+}
+
+couch.tammi.cc {
+ reverse_proxy 127.0.0.1:5984
+ encode zstd gzip
+ log {
+ output file /media/data/logs/couch.log {
+ roll_size 1mb
+ roll_keep 1
+ }
+ }
+}
+
+shiori.tammi.cc {
+ reverse_proxy 127.0.0.1:7766
+ encode zstd gzip
+ log {
+ output file /media/data/logs/shiori.log {
+ roll_size 1mb
+ roll_keep 1
+ }
+ }
+}
+
+read.tammi.cc {
+ reverse_proxy 127.0.0.1:7767
+ encode zstd gzip
+ log {
+ output file /media/data/logs/read.log {
+ roll_size 1mb
+ roll_keep 1
+ }
+ }
+}
+
+atuin.tammi.cc {
+ reverse_proxy 127.0.0.1:4444
+ encode zstd gzip
+ log {
+ output file /media/data/logs/atuin.log {
+ roll_size 1mb
+ roll_keep 1
+ }
+ }
+}
+
+relationship.tammi.cc {
+ root * /media/data/relationship
+ file_server
+ encode zstd gzip
+ log {
+ output file /media/data/logs/relationship.log {
+ roll_size 1mb
+ roll_keep 1
+ }
+ }
+}
+
+start.tammi.cc {
+ basic_auth {
+ petri $2a$14$1gj396cBvvMoC7kW0qSZBOF9Qzwt8ewyujua1EpdDJm9gXdBFsfEe
+ }
+ reverse_proxy 127.0.0.1:5555
+ encode zstd gzip
+ log {
+ output file /media/data/logs/start.log {
+ roll_size 1mb
+ roll_keep 1
+ }
+ }
+}
+
+bin.tammi.cc {
+ reverse_proxy 127.0.0.1:8820
+ encode zstd gzip
+ import cors {header.origin}
+ log {
+ output file /media/data/logs/bin.log {
+ roll_size 1mb
+ roll_keep 1
+ }
+ }
+}
+
+llm.tammi.cc {
+ reverse_proxy 127.0.0.1:12500
+ encode zstd gzip
+ log {
+ output file /media/data/logs/llm.log {
+ roll_size 1mb
+ roll_keep 1
+ }
+ }
+}
+
+base.tammi.cc {
+ reverse_proxy 127.0.0.1:980
+ encode zstd gzip
+ log {
+ output file /media/data/logs/base.log {
+ roll_size 1mb
+ roll_keep 1
+ }
+ }
+}
+
+threat.tammi.cc {
+ reverse_proxy 127.0.0.1:3050
+ encode zstd gzip
+ log {
+ output file /media/data/logs/threat.log {
+ roll_size 1mb
+ roll_keep 1
+ }
+ }
+}
+
+flux.tammi.cc {
+ reverse_proxy 127.0.0.1:8080
+ encode zstd gzip
+ log {
+ output file /media/data/logs/flux.log {
+ roll_size 1mb
+ roll_keep 1
+ }
+ }
+}
+
+haku.tammi.cc {
+ reverse_proxy 127.0.0.1:8888
+ encode zstd gzip
+ log {
+ output file /media/data/logs/haku.log {
+ roll_size 1mb
+ roll_keep 1
+ }
+ }
+}
+
+memos.tammi.cc {
+ reverse_proxy 127.0.0.1:8081
+ encode zstd gzip
+ log {
+ output file /media/data/logs/memos.log {
+ roll_size 1mb
+ roll_keep 1
+ }
+ }
+}
+
+dav.tammi.cc {
+ reverse_proxy 127.0.0.1:5232
+ encode zstd gzip
+ log {
+ output file /media/data/logs/haku.log {
+ roll_size 1mb
+ roll_keep 1
+ }
+ }
+}
+
+admin.tammi.cc {
+ reverse_proxy 127.0.0.1:10000
+ encode zstd gzip
+ log {
+ output file /media/data/logs/webmin.log {
+ roll_size 1mb
+ roll_keep 1
+ }
+ }
+}
+
+minio.tammi.cc {
+ reverse_proxy localhost:9001
+}
+
+s3.tammi.cc {
+ reverse_proxy localhost:9199
+}
+
+vault.tammi.cc {
+ encode zstd gzip
+ reverse_proxy /notifications/hub/negotiate 127.0.0.1:8000
+ reverse_proxy /notifications/hub 127.0.0.1:3012
+ reverse_proxy 127.0.0.1:8000 {
+ header_up X-Real-IP {remote_host}
+ }
+ log {
+ output file /media/data/logs/vault.log {
+ roll_size 1mb
+ roll_keep 1
+ }
+ }
+}
+
+audio.tammi.cc {
+ reverse_proxy 127.0.0.1:3333
+ encode zstd gzip
+ log {
+ output file /media/data/logs/audio.log {
+ roll_size 1mb
+ roll_keep 1
+ }
+ }
+}
+
+import conf.d/*
+
+# Refer to the Caddy docs for more information:
diff --git a/hosts/tammi/cgitrc b/hosts/tammi/cgitrc
new file mode 100644
index 0000000..caa011d
--- /dev/null
+++ b/hosts/tammi/cgitrc
@@ -0,0 +1,47 @@
+#
+# cgit config
+#
+
+# The defaults
+#css=/cgit.css
+#logo=/cgit.png
+cache-size=0
+branch-sort=age
+commit-sort=date
+max-stats=quarter
+root-title=tammi.cc git repositories
+robots=noindex, nofollow
+snapshots=tar.zst
+clone-url=ssh://git@tammi.cc:/git/$CGIT_REPO_URL.git
+virtual-root=/
+
+# options
+enable-index-owner=true
+enable-index-links=true
+enable-commit-graph=1
+enable-log-filecount=1
+enable-log-linecount=1
+enable-html-serving=1
+enable-http-clone=1
+enable-blame=1
+
+# mimes
+mimetype.gif=image/gif
+mimetype.html=text/html
+mimetype.jpg=image/jpeg
+mimetype.webp=image/webp
+mimetype.jpeg=image/jpeg
+mimetype.pdf=application/pdf
+mimetype.png=image/png
+mimetype.svg=image/svg+xml
+
+# plugins
+head-include=/usr/local/lib/cgit/head_include.html
+source-filter=/usr/local/lib/cgit/filters/syntax-highlighting.js
+about-filter=/usr/local/lib/cgit/filters/about-formatting-custom.sh
+auth-filter=lua:/usr/local/lib/cgit/filters/simple-authentication-modified.lua
+
+# repositories
+readme=:README.adoc
+readme=:README.md
+remove-suffix=1
diff --git a/hosts/tammi/feeds.opml b/hosts/tammi/feeds.opml
new file mode 100644
index 0000000..b0ea84f
--- /dev/null
+++ b/hosts/tammi/feeds.opml
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<opml version="2.0">
+ <head>
+ <title>Miniflux</title>
+ <dateCreated>Wed, 29 Oct 2025 10:42:41 EET</dateCreated>
+ </head>
+ <body>
+ <outline text="All">
+ <outline title="Feeds" text="Feeds" xmlUrl="https://www.understandingwar.org/feeds.xml" htmlUrl="https://www.understandingwar.org/feeds2" type="rss"></outline>
+ <outline title="Starsector" text="Starsector" xmlUrl="https://fractalsoftworks.com/feed/" htmlUrl="https://fractalsoftworks.com" type="rss"></outline>
+ <outline title="Lua: news" text="Lua: news" xmlUrl="https://lua.org/news.rss" htmlUrl="https://www.lua.org/news.html" description="What&#39;s happening in the Lua world" type="rss"></outline>
+ <outline title="Command Line" text="Command Line" xmlUrl="https://www.reddit.com/r/commandline.rss" htmlUrl="https://www.reddit.com/r/commandline" description="This is for anything regarding the command line, in any operating system. All questions (including dumb ones), tips, and links to interesting programs/console applications you&#39;ve found or made yourself are welcome. Linux / BSD / OSX / Windows CLI and TUI apps or questions or comments, we&#39;re happy to take them all!" type="rss"></outline>
+ <outline title="cs.LG updates on arXiv.org" text="cs.LG updates on arXiv.org" xmlUrl="http://arxiv.org/rss/cs.LG" htmlUrl="http://arxiv.org/" type="rss"></outline>
+ <outline title="Joshua Weissman" text="Joshua Weissman" xmlUrl="https://www.youtube.com/feeds/videos.xml?channel_id=UChBEbMKI1eCcejTtmI32UEw" htmlUrl="https://www.youtube.com/channel/UChBEbMKI1eCcejTtmI32UEw" type="rss"></outline>
+ <outline title="Machine Learning" text="Machine Learning" xmlUrl="https://www.reddit.com/r/MachineLearning.rss" htmlUrl="https://www.reddit.com/r/MachineLearning" type="rss"></outline>
+ <outline title="Nautilus" text="Nautilus" xmlUrl="https://nautil.us/feed/" htmlUrl="https://nautil.us/" type="rss"></outline>
+ <outline title="network, branch master" text="network, branch master" xmlUrl="https://git.tammi.cc/network/atom" htmlUrl="https://git.tammi.cc/network/" description="Network configration to learn to configure networks" type="rss"></outline>
+ <outline title="NixOS Announcements" text="NixOS Announcements" xmlUrl="https://nixos.org/blog/announcements-rss.xml" htmlUrl="https://nixos.org/blog/" type="rss"></outline>
+ <outline title="NixOS Newsletters" text="NixOS Newsletters" xmlUrl="https://nixos.org/blog/newsletters-rss.xml" htmlUrl="https://nixos.org/blog/" type="rss"></outline>
+ <outline title="NVIDIA Blog" text="NVIDIA Blog" xmlUrl="http://feeds.feedburner.com/nvidiablog" htmlUrl="https://blogs.nvidia.com" type="rss"></outline>
+ <outline title="Relesoft Activity Feed" text="Relesoft Activity Feed" xmlUrl="https://events.tammi.cc/relesoft/activity.atom" htmlUrl="https://events.tammi.cc/relesoft/activity.atom" description="Activity feed for Relesoft organization" type="rss"></outline>
+ <outline title="Self-Hosted Alternatives to Popular Services" text="Self-Hosted Alternatives to Popular Services" xmlUrl="https://www.reddit.com/r/selfhosted.rss" htmlUrl="https://www.reddit.com/r/selfhosted" type="rss"></outline>
+ <outline title="Very Bad Wizards" text="Very Bad Wizards" xmlUrl="https://feeds.libsyn.com/474285/rss" htmlUrl="http://sites.libsyn.com/474285/site" type="rss"></outline>
+ <outline title="Writing an OS in Rust" text="Writing an OS in Rust" xmlUrl="https://os.phil-opp.com/rss.xml" htmlUrl="https://os.phil-opp.com" type="rss"></outline>
+ </outline>
+ <outline text="Economics">
+ <outline title="Ajatuspaja Libera" text="Ajatuspaja Libera" xmlUrl="https://www.libera.fi/feed" htmlUrl="https://www.libera.fi" type="rss"></outline>
+ <outline title="ECB - European Central Bank" text="ECB - European Central Bank" xmlUrl="https://www.ecb.europa.eu/rss/press.html" htmlUrl="https://www.ecb.europa.eu/" type="rss"></outline>
+ <outline title="inderesTV" text="inderesTV" xmlUrl="https://www.youtube.com/feeds/videos.xml?channel_id=UCA8t6FufzhadZJZBXiYW8jQ" htmlUrl="https://www.youtube.com/channel/UCA8t6FufzhadZJZBXiYW8jQ" type="rss"></outline>
+ <outline title="John Kay" text="John Kay" xmlUrl="https://www.johnkay.com/feed" htmlUrl="https://www.johnkay.com" type="rss"></outline>
+ <outline title="Microeconomic Insights" text="Microeconomic Insights" xmlUrl="https://microeconomicinsights.org/feed/" htmlUrl="https://microeconomicinsights.org" type="rss"></outline>
+ <outline title="SalkunRakentaja" text="SalkunRakentaja" xmlUrl="https://www.salkunrakentaja.fi/feed/rss/" htmlUrl="https://www.salkunrakentaja.fi" type="rss"></outline>
+ <outline title="Stochastic Trend" text="Stochastic Trend" xmlUrl="http://feeds.feedburner.com/StochasticTrend" htmlUrl="http://stochastictrend.blogspot.com/" type="rss"></outline>
+ <outline title="The Demand Side" text="The Demand Side" xmlUrl="https://www.thedemandside.com/blog-feed.xml" htmlUrl="https://www.thedemandside.com/blog" type="rss"></outline>
+ <outline title="Vesa Vihriälä" text="Vesa Vihriälä" xmlUrl="https://www.vesavihriala.fi/feed" htmlUrl="https://www.vesavihriala.fi" type="rss"></outline>
+ <outline title="Wolf Street" text="Wolf Street" xmlUrl="https://wolfstreet.com/feed/" htmlUrl="https://wolfstreet.com" type="rss"></outline>
+ </outline>
+ <outline text="Meditations">
+ <outline title="Andrej Karpathy blog" text="Andrej Karpathy blog" xmlUrl="https://karpathy.github.io/feed.xml" htmlUrl="http://karpathy.github.io/" type="rss"></outline>
+ <outline title="Blog – Hackaday" text="Blog – Hackaday" xmlUrl="http://hackaday.com/blog/feed/" htmlUrl="https://hackaday.com" type="rss"></outline>
+ <outline title="Edge.org" text="Edge.org" xmlUrl="http://www.edge.org/feed" htmlUrl="https://www.edge.org/" type="rss"></outline>
+ <outline title="Evil Mad Scientist Laboratories" text="Evil Mad Scientist Laboratories" xmlUrl="https://www.evilmadscientist.com/feed/" htmlUrl="https://www.evilmadscientist.com" description="Making the world a better place, one Evil Mad Scientist at a time." type="rss"></outline>
+ <outline title="Insight" text="Insight" xmlUrl="https://zeynep.substack.com/feed" htmlUrl="https://zeynep.substack.com" type="rss"></outline>
+ <outline title="LessWrong" text="LessWrong" xmlUrl="https://www.lesswrong.com/feed.xml?view=curated-rss" htmlUrl="https://www.lesswrong.com" type="rss"></outline>
+ <outline title="LessWrong" text="LessWrong" xmlUrl="https://lesswrong.substack.com/feed" htmlUrl="https://lesswrong.substack.com" type="rss"></outline>
+ <outline title="LessWrong" text="LessWrong" xmlUrl="https://www.lesswrong.com/feed.xml?view=frontpage-rss&amp;karmaThreshold=2" htmlUrl="https://www.lesswrong.com" type="rss"></outline>
+ <outline title="LocalLlama" text="LocalLlama" xmlUrl="https://www.reddit.com/r/LocalLLaMA.rss" htmlUrl="https://www.reddit.com/r/LocalLLaMA" type="rss"></outline>
+ <outline title="Nature - Issue - nature.com science feeds" text="Nature - Issue - nature.com science feeds" xmlUrl="http://feeds.nature.com/nature/rss/current" htmlUrl="http://feeds.nature.com/nature/rss/current" type="rss"></outline>
+ <outline title="Stephen Wolfram Blog" text="Stephen Wolfram Blog" xmlUrl="https://writings.stephenwolfram.com/feed/" htmlUrl="https://writings.stephenwolfram.com" type="rss"></outline>
+ <outline title="TED Talks Daily (SD video)" text="TED Talks Daily (SD video)" xmlUrl="http://feeds.feedburner.com/tedtalks_video" htmlUrl="https://www.ted.com/talks" type="rss"></outline>
+ <outline title="The Berkeley Artificial Intelligence Research Blog" text="The Berkeley Artificial Intelligence Research Blog" xmlUrl="https://bair.berkeley.edu/blog/feed.xml" htmlUrl="http://bair.berkeley.edu/blog/" type="rss"></outline>
+ <outline title="The Unofficial Google Data Science Blog" text="The Unofficial Google Data Science Blog" xmlUrl="http://www.unofficialgoogledatascience.com/feeds/posts/default" htmlUrl="http://www.unofficialgoogledatascience.com/" type="rss"></outline>
+ <outline title="vahtera.blog" text="vahtera.blog" xmlUrl="https://www.vahtera.blog/blog-feed.xml" htmlUrl="https://www.vahtera.blog/blog" type="rss"></outline>
+ </outline>
+ <outline text="News">
+ <outline title="Ars Technica" text="Ars Technica" xmlUrl="http://feeds.arstechnica.com/arstechnica/index" htmlUrl="https://arstechnica.com" type="rss"></outline>
+ <outline title="DER SPIEGEL - International" text="DER SPIEGEL - International" xmlUrl="http://www.spiegel.de/international/index.rss" htmlUrl="https://www.spiegel.de/" type="rss"></outline>
+ <outline title="Hacker News" text="Hacker News" xmlUrl="https://news.ycombinator.com/rss" htmlUrl="https://news.ycombinator.com/" type="rss"></outline>
+ <outline title="Helsingin Kaupungin Uutiset" text="Helsingin Kaupungin Uutiset" xmlUrl="https://www.hel.fi/fi/uutiset/rss" htmlUrl="https://www.hel.fi/fi" type="rss"></outline>
+ <outline title="IEEE Spectrum Recent Content full text" text="IEEE Spectrum Recent Content full text" xmlUrl="http://feeds.feedburner.com/IeeeSpectrumFullText" htmlUrl="https://spectrum.ieee.org" type="rss"></outline>
+ <outline title="Neovim" text="Neovim" xmlUrl="https://neovim.io/news.xml" htmlUrl="https://neovim.io/" description="vim out of the box" type="rss"></outline>
+ <outline title="Newsletter - European Parliament" text="Newsletter - European Parliament" xmlUrl="https://www.europarl.europa.eu/rss/doc/newsletters/en.xml" htmlUrl="https://www.europarl.europa.eu/news/en/agenda/briefing" type="rss"></outline>
+ <outline title="Phoronix" text="Phoronix" xmlUrl="http://www.phoronix.com/rss.php" htmlUrl="https://www.phoronix.com/" type="rss"></outline>
+ <outline title="POLITICO" text="POLITICO" xmlUrl="https://www.politico.eu/feed/" htmlUrl="https://www.politico.eu" type="rss"></outline>
+ <outline title="Press releases - European Parliament" text="Press releases - European Parliament" xmlUrl="https://www.europarl.europa.eu/rss/doc/press-releases/en.xml" htmlUrl="https://www.europarl.europa.eu/news/en" type="rss"></outline>
+ <outline title="Slashdot" text="Slashdot" xmlUrl="http://rss.slashdot.org/Slashdot/slashdot" htmlUrl="https://slashdot.org/" type="rss"></outline>
+ <outline title="Yle Uutiset | Pääuutiset" text="Yle Uutiset | Pääuutiset" xmlUrl="https://feeds.yle.fi/uutiset/v1/majorHeadlines/YLE_UUTISET.rss" htmlUrl="https://yle.fi/uutiset/" type="rss"></outline>
+ </outline>
+ <outline text="Podcast">
+ <outline title="Common Sense with Dan Carlin" text="Common Sense with Dan Carlin" xmlUrl="https://feeds.feedburner.com/dancarlin/commonsense?format=xml" htmlUrl="http://www.dancarlin.com" type="rss"></outline>
+ <outline title="Dan Carlin&#39;s Hardcore History" text="Dan Carlin&#39;s Hardcore History" xmlUrl="https://feeds.feedburner.com/dancarlin/history?format=xml" htmlUrl="http://www.dancarlin.com" type="rss"></outline>
+ <outline title="Dan Carlin&#39;s Hardcore History: Addendum" text="Dan Carlin&#39;s Hardcore History: Addendum" xmlUrl="https://dchhaddendum.libsyn.com/rss" htmlUrl="http://dchhaddendum.libsyn.com/website" type="rss"></outline>
+ <outline title="inderesPodi" text="inderesPodi" xmlUrl="http://feeds.soundcloud.com/users/soundcloud:users:319162419/sounds.rss" htmlUrl="http://soundcloud.com/inderes" type="rss"></outline>
+ <outline title="Lex Fridman Podcast" text="Lex Fridman Podcast" xmlUrl="https://lexfridman.com/feed/podcast/" htmlUrl="https://lexfridman.com/podcast" type="rss"></outline>
+ <outline title="Making Sense with Sam Harris" text="Making Sense with Sam Harris" xmlUrl="http://wakingup.libsyn.com/rss" htmlUrl="http://www.samharris.org" type="rss"></outline>
+ <outline title="Microsoft Research" text="Microsoft Research" xmlUrl="https://www.microsoft.com/en-us/research/feed/" htmlUrl="https://www.microsoft.com/en-us/research" type="rss"></outline>
+ <outline title="Politiikkaradio" text="Politiikkaradio" xmlUrl="https://feeds.yle.fi/areena/v1/series/1-1485162.rss?lang=fi&amp;downloadable=true" htmlUrl="https://areena.yle.fi/1-1485162" type="rss"></outline>
+ <outline title="#rahapodi" text="#rahapodi" xmlUrl="http://feeds.soundcloud.com/users/soundcloud:users:156278369/sounds.rss" htmlUrl="https://blogi.nordnet.fi/rahapodi/" type="rss"></outline>
+ <outline title="The Art of Manliness" text="The Art of Manliness" xmlUrl="https://feeds2.feedburner.com/TheArtOfManliness" htmlUrl="https://www.artofmanliness.com/" type="rss"></outline>
+ <outline title="The Fall of Rome Podcast" text="The Fall of Rome Podcast" xmlUrl="https://rss.art19.com/the-fall-of-rome-podcast" htmlUrl="https://fallofromepodcast.wordpress.com/" type="rss"></outline>
+ <outline title="The Peter Attia Drive" text="The Peter Attia Drive" xmlUrl="http://peterattiadrive.libsyn.com/rss" htmlUrl="http://www.PeterAttiaMD.com" type="rss"></outline>
+ <outline title="The Psychology Podcast with Scott Barry Kaufman" text="The Psychology Podcast with Scott Barry Kaufman" xmlUrl="https://anchor.fm/s/2f55bfc0/podcast/rss" htmlUrl="https://anchor.fm/the-psychology-podcast" type="rss"></outline>
+ <outline title="The Tim Ferriss Show" text="The Tim Ferriss Show" xmlUrl="https://tim.blog/feed/" htmlUrl="https://tim.blog/podcast" type="rss"></outline>
+ <outline title="Tides of History" text="Tides of History" xmlUrl="https://rss.art19.com/tides-of-history" htmlUrl="http://wondery.com/shows/tides-of-history/" type="rss"></outline>
+ </outline>
+ <outline text="Programming">
+ <outline title="Devlog" text="Devlog" xmlUrl="https://vonheikemen.github.io/devlog/atom.xml" htmlUrl="https://vonheikemen.github.io/devlog/" type="rss"></outline>
+ <outline title="Hoverbear" text="Hoverbear" xmlUrl="https://hoverbear.org/rss.xml" htmlUrl="https://hoverbear.org" type="rss"></outline>
+ <outline title="Deepmind Latest Post" text="Deepmind Latest Post" xmlUrl="https://deepmind.com/blog/feed/basic/" htmlUrl="https://deepmind.com/blog/" type="rss"></outline>
+ <outline title="Forgejo News" text="Forgejo News" xmlUrl="https://forgejo.org/rss.xml" htmlUrl="https://forgejo.org/" type="rss"></outline>
+ <outline title="Inside Rust Blog" text="Inside Rust Blog" xmlUrl="https://blog.rust-lang.org/inside-rust/feed.xml" htmlUrl="https://blog.rust-lang.org/inside-rust/" type="rss"></outline>
+ <outline title="Mike Blumenkrantz" text="Mike Blumenkrantz" xmlUrl="https://www.supergoodcode.com/feed.xml" htmlUrl="https://www.supergoodcode.com/" type="rss"></outline>
+ <outline title="NixOS Weekly" text="NixOS Weekly" xmlUrl="https://weekly.nixos.org/feeds/all.rss.xml" htmlUrl="https://weekly.nixos.org/" type="rss"></outline>
+ <outline title="Rust Blog" text="Rust Blog" xmlUrl="https://blog.rust-lang.org/feed.xml" htmlUrl="https://blog.rust-lang.org/" type="rss"></outline>
+ <outline title="Vaxry&#39;s Blog" text="Vaxry&#39;s Blog" xmlUrl="https://blog.vaxry.net/feed" htmlUrl="https://blog.vaxry.net/" type="rss"></outline>
+ </outline>
+ <outline text="Software releases">
+ <outline title="matrix.org" text="matrix.org" xmlUrl="https://matrix.org/blog/feed" htmlUrl="https://matrix.org" type="rss"></outline>
+ <outline title="Recent Commits to nixos-config:master" text="Recent Commits to nixos-config:master" xmlUrl="https://github.com/jakubgs/nixos-config/commits/master.atom" htmlUrl="https://github.com/jakubgs/nixos-config/commits/master" type="rss"></outline>
+ <outline title="Release notes from AdGuardHome" text="Release notes from AdGuardHome" xmlUrl="https://github.com/AdguardTeam/AdGuardHome/releases.atom" htmlUrl="https://github.com/AdguardTeam/AdGuardHome/releases" type="rss"></outline>
+ <outline title="Release notes from ashell" text="Release notes from ashell" xmlUrl="https://github.com/MalpenZibo/ashell/releases.atom" htmlUrl="https://github.com/MalpenZibo/ashell/releases" type="rss"></outline>
+ <outline title="Release notes from audiobookshelf" text="Release notes from audiobookshelf" xmlUrl="https://github.com/advplyr/audiobookshelf/releases.atom" htmlUrl="https://github.com/advplyr/audiobookshelf/releases" type="rss"></outline>
+ <outline title="Release notes from esp-hal" text="Release notes from esp-hal" xmlUrl="https://github.com/esp-rs/esp-hal/releases.atom" htmlUrl="https://github.com/esp-rs/esp-hal/releases" type="rss"></outline>
+ <outline title="Release notes from glance" text="Release notes from glance" xmlUrl="https://github.com/glanceapp/glance/releases.atom" htmlUrl="https://github.com/glanceapp/glance/releases" type="rss"></outline>
+ <outline title="Release notes from Hyprland" text="Release notes from Hyprland" xmlUrl="https://github.com/hyprwm/Hyprland/releases.atom" htmlUrl="https://github.com/hyprwm/Hyprland/releases" type="rss"></outline>
+ <outline title="Release notes from lean4" text="Release notes from lean4" xmlUrl="https://github.com/leanprover/lean4/releases.atom" htmlUrl="https://github.com/leanprover/lean4/releases" type="rss"></outline>
+ <outline title="Release notes from llama.cpp" text="Release notes from llama.cpp" xmlUrl="https://github.com/ggerganov/llama.cpp/releases.atom" htmlUrl="https://github.com/ggerganov/llama.cpp/releases" type="rss"></outline>
+ <outline title="Release notes from Miniflux" text="Release notes from Miniflux" xmlUrl="https://github.com/miniflux/v2/releases.atom" htmlUrl="https://github.com/miniflux/v2/releases" type="rss"></outline>
+ <outline title="Release notes from mini.nvim" text="Release notes from mini.nvim" xmlUrl="https://github.com/nvim-mini/mini.nvim/releases.atom" htmlUrl="https://github.com/nvim-mini/mini.nvim/releases" type="rss"></outline>
+ <outline title="Release notes from neovim" text="Release notes from neovim" xmlUrl="https://github.com/neovim/neovim/releases.atom" htmlUrl="https://github.com/neovim/neovim/releases" type="rss"></outline>
+ <outline title="Release notes from nom" text="Release notes from nom" xmlUrl="https://github.com/guyfedwards/nom/releases.atom" htmlUrl="https://github.com/guyfedwards/nom/releases" type="rss"></outline>
+ <outline title="Release notes from shiori" text="Release notes from shiori" xmlUrl="https://github.com/go-shiori/shiori/releases.atom" htmlUrl="https://github.com/go-shiori/shiori/releases" type="rss"></outline>
+ <outline title="Release notes from synapse" text="Release notes from synapse" xmlUrl="https://github.com/element-hq/synapse/releases.atom" htmlUrl="https://github.com/element-hq/synapse/releases" type="rss"></outline>
+ <outline title="Release notes from walker" text="Release notes from walker" xmlUrl="https://github.com/abenz1267/walker/releases.atom" htmlUrl="https://github.com/abenz1267/walker/releases" type="rss"></outline>
+ <outline title="Releases for readeck/readeck" text="Releases for readeck/readeck" xmlUrl="https://codeberg.org/readeck/readeck/releases.rss" htmlUrl="https://codeberg.org/readeck/readeck/release" type="rss"></outline>
+ </outline>
+ </body>
+</opml>
diff --git a/hosts/tammi/iptable-nat.service b/hosts/tammi/iptable-nat.service
new file mode 100644
index 0000000..f5ecd63
--- /dev/null
+++ b/hosts/tammi/iptable-nat.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=Apply NAT rules for IPv4
+After=network.target
+
+[Service]
+Type=oneshot
+ExecStart=/sbin/iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
+RemainAfterExit=yes
+
+[Install]
+WantedBy=multi-user.target
diff --git a/hosts/tammi/syntax-highlighting.js b/hosts/tammi/syntax-highlighting.js
new file mode 100644
index 0000000..362994a
--- /dev/null
+++ b/hosts/tammi/syntax-highlighting.js
@@ -0,0 +1,23 @@
+#!/usr/bin/node
+// Server side syntax highlight with Shiki https://shiki.matsu.io/
+// This script is replacement for pygments/highlight for cgit
+// Shiki is installed with `npm install -g shiki`
+// input: filename, stdin - source file. Outputs the highligted html to stdout.
+import { argv, stdin, stdout } from 'node:process';
+import { codeToHtml } from "/usr/lib/node_modules/shiki/dist/index.mjs";
+
+async function highlight(syntax) {
+ stdin.on("data", async (data) => {
+ const text = Buffer.from(data).toString("utf8");
+ const html = await codeToHtml(text, {
+ lang: syntax,
+ theme: "gruvbox-dark-soft"
+ });
+ stdout.write(html);
+ });
+ return true
+}
+
+const filename = argv[1];
+const lang = filename.split(".")[1];
+highlight(lang);