aboutsummaryrefslogtreecommitdiffstats
path: root/hosts/tammi
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/tammi
parent75c2af4aedd2ac5c2cfc74b346625fa4b265541d (diff)
downloadnixos-08297376a85a1719518507e54fca9de954d2376a.tar.zst
Agenix configuration
Diffstat (limited to 'hosts/tammi')
-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
8 files changed, 881 insertions, 0 deletions
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);