diff --git a/akkoma-static/favicon.png b/akkoma-static/favicon.png
new file mode 100644
index 0000000..da055e9
Binary files /dev/null and b/akkoma-static/favicon.png differ
diff --git a/akkoma-static/instance/panel.html b/akkoma-static/instance/panel.html
new file mode 100644
index 0000000..2811c9d
--- /dev/null
+++ b/akkoma-static/instance/panel.html
@@ -0,0 +1,6 @@
+This is the kemonomimi.pet akkoma instance!!
+Im am leinna, the admin and only user of this instance
+Hosted on a not very powerful nixos machine, if you have any problem with how it is configured pls let me know
+If you want to go back to the homepage here is a link: kemonomimi.pet
+The background image is an edited version of the triangulum galaxy captured by the VLT Survey Telescope in chile. Here is the source
+Have a good day! >~<
diff --git a/akkoma-static/static/bg.png b/akkoma-static/static/bg.png
new file mode 100644
index 0000000..27a7437
Binary files /dev/null and b/akkoma-static/static/bg.png differ
diff --git a/akkoma-static/static/logo.png b/akkoma-static/static/logo.png
new file mode 100644
index 0000000..da055e9
Binary files /dev/null and b/akkoma-static/static/logo.png differ
diff --git a/akkoma-static/static/styles.json b/akkoma-static/static/styles.json
new file mode 100644
index 0000000..94a111f
--- /dev/null
+++ b/akkoma-static/static/styles.json
@@ -0,0 +1,16 @@
+{
+ "pleroma-dark": [ "Pleroma Dark", "#121a24", "#182230", "#b9b9ba", "#d8a070", "#d31014", "#0fa00f", "#0095ff", "#ffa500" ],
+ "pleroma-light": [ "Pleroma Light", "#f2f4f6", "#dbe0e8", "#304055", "#f86f0f", "#d31014", "#0fa00f", "#0095ff", "#ffa500" ],
+ "classic-dark": [ "Classic Dark", "#161c20", "#282e32", "#b9b9b9", "#baaa9c", "#d31014", "#0fa00f", "#0095ff", "#ffa500" ],
+ "bird": [ "Bird", "#f8fafd", "#e6ecf0", "#14171a", "#0084b8", "#e0245e", "#17bf63", "#1b95e0", "#fab81e"],
+ "ir-black": [ "Ir Black", "#000000", "#242422", "#b5b3aa", "#ff6c60", "#FF6C60", "#A8FF60", "#96CBFE", "#FFFFB6" ],
+ "monokai": [ "Monokai", "#272822", "#383830", "#f8f8f2", "#f92672", "#F92672", "#a6e22e", "#66d9ef", "#f4bf75" ],
+
+ "redmond-xx": "/static/themes/redmond-xx.json",
+ "redmond-xx-se": "/static/themes/redmond-xx-se.json",
+ "redmond-xxi": "/static/themes/redmond-xxi.json",
+ "breezy-dark": "/static/themes/breezy-dark.json",
+ "breezy-light": "/static/themes/breezy-light.json",
+ "mammal": "/static/themes/mammal.json",
+ "kemonomimi-theme": "/static/themes/kemonomimi-theme.json"
+}
diff --git a/akkoma-static/static/terms-of-service.html b/akkoma-static/static/terms-of-service.html
new file mode 100644
index 0000000..6ab5f0c
--- /dev/null
+++ b/akkoma-static/static/terms-of-service.html
@@ -0,0 +1,3 @@
+TOS:
+
+I am not a lawyer, dont do anything illegal and be nice plss
diff --git a/akkoma-static/static/themes/kemonomimi-theme.json b/akkoma-static/static/themes/kemonomimi-theme.json
new file mode 100644
index 0000000..259d3d8
--- /dev/null
+++ b/akkoma-static/static/themes/kemonomimi-theme.json
@@ -0,0 +1,56 @@
+{
+ "_pleroma_theme_version": 2,
+ "name": "Kemonomimi Theme",
+ "theme": {
+ "fonts": {
+ "interface": {"family": "sans-serif"},
+ "input": {"family": "monospace"},
+ "post": {"family": "sans-serif"},
+ "postCode": {"family": "monospace"}
+ },
+ "opacity": {
+ "bg": "1",
+ "panel": "1",
+ "border": "1",
+ "btn": "1",
+ "input": "1"
+ },
+ "radii": {
+ "btn": "0",
+ "input": "0",
+ "checkbox": "0",
+ "panel": "0",
+ "avatar": "0",
+ "avatarAlt": "0",
+ "tooltip": "0",
+ "attachment": "0"
+ },
+ "colors": {
+ "bg": "#161616",
+ "fg": "#1E1E1E",
+ "text": "#B8B8B8",
+ "link": "#9141AC",
+ "fgText": "#B8B8B8",
+ "fgLink": "#9141AC",
+ "topBar": "#161616",
+ "topBarText": "#9141AC",
+ "btnText": "#9141AC",
+ "border": "#2E2E2E",
+ "cRed": "#FF5C5C",
+ "cBlue": "#5C9AFF",
+ "cGreen": "#5CFF8A",
+ "cOrange": "#FFAD5C"
+ },
+ "shadows": {
+ "panel": [{"x": 0, "y": 0, "blur": 0, "spread": 0, "color": "#000000", "alpha": 0}],
+ "button": [{"x": 0, "y": 0, "blur": 0, "spread": 1, "color": "#9141AC", "alpha": 0.7, "inset": false}],
+ "buttonHover": [{"x": 0, "y": 0, "blur": 0, "spread": 1, "color": "#AB5BC6", "alpha": 1}],
+ "buttonPressed": [{"x": 0, "y": 0, "blur": 0, "spread": 1, "color": "#9141AC", "alpha": 1, "inset": true}],
+ "avatar": [{"x": 0, "y": 0, "blur": 0, "spread": 0, "color": "#000000", "alpha": 0}],
+ "avatarStatus": [{"x": 0, "y": 0, "blur": 0, "spread": 0, "color": "#000000", "alpha": 0}],
+ "input": [{"x": 0, "y": 0, "blur": 0, "spread": 1, "color": "#9141AC", "alpha": 0.4, "inset": false}],
+ "panelHeader": [{"x": 0, "y": 0, "blur": 0, "spread": 0, "color": "#000000", "alpha": 0}],
+ "topBar": [{"x": 0, "y": 0, "blur": 0, "spread": 0, "color": "#000000", "alpha": 0}]
+ }
+ }
+}
diff --git a/configuration.nix b/configuration.nix
index 9bc1a83..19efedf 100644
--- a/configuration.nix
+++ b/configuration.nix
@@ -4,15 +4,25 @@
imports = [
./hardware-configuration.nix
./system.nix
+ ./power.nix
+
./services/caddy.nix
+ ./services/status.nix
+
+ ./services/wireguard.nix
+ ./services/qbittorrent.nix
+ ./services/starr.nix
+ ./services/jelly.nix
+
./services/immich.nix
./services/vaultwarden.nix
./services/forgejo.nix
+ ./services/fedi.nix
];
networking.firewall = {
enable = true;
- allowedTCPPorts = [ 22 80 443 ];
+ allowedTCPPorts = [ 22 80 443 8888 ];
};
systemd.tmpfiles.rules = [
@@ -22,6 +32,8 @@
environment.systemPackages = with pkgs; [
neovim
git
+ htop
+ inetutils
];
environment.shellAliases = {
diff --git a/flake.nix b/flake.nix
index 74ab420..ac61326 100644
--- a/flake.nix
+++ b/flake.nix
@@ -1,5 +1,5 @@
{
- description = "Headless server NixOS configuration";
+ description = "Home server NixOS configuration";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";
diff --git a/power.nix b/power.nix
new file mode 100644
index 0000000..6d25505
--- /dev/null
+++ b/power.nix
@@ -0,0 +1,21 @@
+{ config, pkgs, ... }:
+
+{
+ powerManagement.enable = true;
+
+ powerManagement.cpuFreqGovernor = "powersave";
+
+ services.tlp = {
+ enable = true;
+ settings = {
+ CPU_SCALING_GOVERNOR_ON_AC = "powersave";
+ CPU_ENERGY_PERF_POLICY_ON_AC = "power";
+
+ RUNTIME_PM_ON_AC = "auto";
+
+ DISK_DEVICES = "sda";
+ DISK_SPINDOWN_TIMEOUT_ON_AC = "120 120";
+ DISK_APM_LEVEL_ON_AC="128 128";
+ };
+ };
+}
diff --git a/services/backup.nix b/services/backup.nix
index a92eb24..cc82bc3 100644
--- a/services/backup.nix
+++ b/services/backup.nix
@@ -1,7 +1,5 @@
{ config, pkgs, ... }:
-
{
-
services.postgresql.backup = {
enable = true;
location = "/var/lib/data/backups/postgres";
@@ -13,7 +11,6 @@
paths = [
"/var/lib/data"
"/var/lib/vaultwarden"
- "/etc/nixos"
];
exclude = [
diff --git a/services/caddy.nix b/services/caddy.nix
index 9aba63f..a998253 100644
--- a/services/caddy.nix
+++ b/services/caddy.nix
@@ -1,10 +1,11 @@
{ config, pkgs, ... }:
{
+ # TODO: remove from user
users.users.caddy.extraGroups = [ "users" ];
systemd.tmpfiles.rules = [
- "d /var/www/website 0755 daniel users - -"
- "d /var/www/website/public 0755 daniel users - -"
+ "d /var/www/danielk.me 0755 daniel users - -"
+ "d /var/www/danielk.me/public 0755 daniel users - -"
];
services.caddy = {
enable = true;
@@ -24,12 +25,6 @@
root * /var/www/danielk.me/public
file_server browse
}
-
- handle_path /git/* {
- root * /var/www/danielk.me/git
- file_server
- }
- reverse_proxy localhost:3333
'';
};
};
diff --git a/services/fedi.nix b/services/fedi.nix
new file mode 100644
index 0000000..a4a23f7
--- /dev/null
+++ b/services/fedi.nix
@@ -0,0 +1,128 @@
+{ config, pkgs, ... }:
+let
+ frontendConfig = {
+ alwaysShowSubjectInput = true;
+ background = "/static/bg.png";
+ collapseMessageWithSubject = false;
+ greentext = false;
+ hideFilteredStatuses = false;
+ hideMutedPosts = false;
+ hidePostStats = false;
+ hideSitename = false;
+ hideUserStats = false;
+ loginMethod = "password";
+ logo = "/static/logo.png";
+ logoMargin = ".1em";
+ logoMask = true;
+ logoLeft = false;
+ nsfwCensorImage = "";
+ postContentType = "text/plain";
+ redirectRootLogin = "/main/friends";
+ redirectRootNoLogin = "/main/all";
+ showFeaturesPanel = true;
+ showInstanceSpecificPanel = true;
+ sidebarRight = false;
+ subjectLineBehavior = "email";
+ theme = "kemonomimi-theme";
+ webPushNotifications = true;
+ };
+in
+{
+ # probably move them out? atm they stay since they only serve kemonomimi
+ services.cloudflared.enable = true;
+ services.cloudflared.tunnels."65c093ce-a3ac-4369-b240-2169514be106" = {
+ credentialsFile = "/etc/secrets/65c093ce-a3ac-4369-b240-2169514be106.json";
+ ingress = {
+ "kemonomimi.pet" = "http://localhost:8679";
+ "fedi.kemonomimi.pet" = "http://localhost:8678";
+ "media.kemonomimi.pet" = "http://localhost:8678";
+ };
+ default = "http_status:404";
+ };
+
+ services.akkoma.enable = true;
+ # ill have to enable this
+ # services.akkoma.config.":pleroma".":media_proxy" = {
+ # enabled = true;
+ # proxy_opts.redirect_on_failure = true;
+ # };
+ services.akkoma.config = {
+ ":pleroma" = {
+ "Pleroma.Captcha".enabled = false;
+
+ ":instance" = {
+ name = "Kemonomimi.pet";
+ description = "Akkoma instance for kemonomimi.pet";
+ email = "admin@kemonomimi.pet";
+ registrations_open = false;
+ healthcheck = true;
+ allow_relay = true;
+ public = true;
+ };
+
+ "Pleroma.Web.Endpoint" = {
+ url.host = "fedi.kemonomimi.pet";
+ url.port = 443;
+ url.scheme = "https";
+ http.ip = "127.0.0.1";
+ http.port = 8678;
+ };
+ ":configurable_from_database" = false;
+ "Pleroma.Upload".base_url = "https://media.kemonomimi.pet:443/media";
+
+ ":frontend_configurations" = {
+ pleroma_fe = frontendConfig;
+ };
+ };
+ };
+ services.akkoma.frontends.admin.name = "admin-fe";
+ services.akkoma.frontends.admin.ref = "stable";
+ services.akkoma.frontends.admin.package = pkgs.akkoma-admin-fe;
+
+ services.akkoma.frontends.primary.name = "akkoma-fe";
+ services.akkoma.frontends.primary.ref = "stable";
+ services.akkoma.frontends.primary.package =
+ pkgs.runCommand "akkoma-fe"
+ {
+ config = builtins.toJSON frontendConfig;
+ nativeBuildInputs = with pkgs; [
+ jq
+ lndir
+ ];
+ passAsFile = [ "config" ];
+ }
+ ''
+ mkdir $out
+ lndir ${pkgs.akkoma-fe} $out
+
+ rm $out/static/config.json
+ jq -s add ${pkgs.akkoma-fe}/static/config.json $configPath \
+ > $out/static/config.json
+ '';
+
+ services.akkoma.extraStatic =
+ let
+ mkPackage = src: pkgs.runCommand "akkoma-asset" {} ''
+ cp -r ${src} $out
+ '';
+ in {
+ "favicon.png" = mkPackage ../akkoma-static/favicon.png;
+ "static" = mkPackage ../akkoma-static/static;
+ "instance" = mkPackage ../akkoma-static/instance;
+ };
+
+ systemd.services.local-static-http = {
+ description = "Temporary server for under construction";
+ wants = [ "network.target" ];
+ after = [ "network.target" ];
+ serviceConfig = {
+ ExecStart = "${pkgs.python3}/bin/python3 -m http.server 8679 --bind 127.0.0.1";
+ WorkingDirectory = "/var/www/kemonomimi.pet";
+ Restart = "on-failure";
+ User = "daniel";
+ };
+ wantedBy = [ "multi-user.target" ];
+ };
+
+}
+
diff --git a/services/immich.nix b/services/immich.nix
index ed0230a..aadd640 100644
--- a/services/immich.nix
+++ b/services/immich.nix
@@ -1,28 +1,33 @@
{ config, pkgs, ... }:
+let
+ domain = "photos.danielk.me";
+ bind = "127.0.0.1";
+ port = 2283;
+ data = "/var/lib/data/immich";
+in
{
services.immich = {
enable = true;
- mediaLocation = "/var/lib/data/immich";
- host = "127.0.0.1";
- port = 2283;
+ mediaLocation = data;
+ host = bind;
+ port = port;
machine-learning.environment.MACHINE_LEARNING_REQUEST_THREADS = "2";
};
- services.caddy.virtualHosts."photos.danielk.me" = {
+ services.caddy.virtualHosts."${domain}" = {
extraConfig = ''
- reverse_proxy 127.0.0.1:2283
+ reverse_proxy ${bind}:${toString port}
'';
};
- # Thumbnails on ssd for faster loading
fileSystems."/var/lib/data/immich/thumbs" = {
device = "/var/lib/immich-thumbnails";
options = [ "bind" ];
};
systemd.tmpfiles.rules = [
- "d /var/lib/data/immich 0750 immich immich -"
+ "d ${data} 0750 immich immich -"
"d /var/lib/immich-thumbnails 0750 immich immich -"
];
}
diff --git a/services/jelly.nix b/services/jelly.nix
new file mode 100644
index 0000000..e5d2ae5
--- /dev/null
+++ b/services/jelly.nix
@@ -0,0 +1,38 @@
+{ config, pkgs, ... }:
+{
+ users.users.jellyfin.extraGroups = [ "media" "render" ];
+ services.jellyfin = {
+ enable = true;
+ dataDir = "/var/lib/jellyfin";
+ };
+
+ services.caddy.virtualHosts."jelly.danielk.me" = {
+ extraConfig = ''
+ reverse_proxy 127.0.0.1:8096
+ '';
+ };
+
+ systemd.tmpfiles.rules = [
+ # not needed I think
+ # "d /var/lib/jellyfin 0750 jellyfin jellyfin -"
+ "d /var/lib/data/media 0770 daniel media -"
+ ];
+
+ environment.systemPackages = with pkgs; [
+ jellyfin
+ jellyfin-web
+ jellyfin-ffmpeg
+ ];
+
+ hardware.graphics = {
+ enable = true;
+ extraPackages = with pkgs; [
+ intel-media-driver
+ intel-compute-runtime
+ intel-vaapi-driver
+ libva-vdpau-driver
+ libva
+ libvdpau-va-gl
+ ];
+ };
+}
diff --git a/services/qbittorrent.nix b/services/qbittorrent.nix
new file mode 100644
index 0000000..769523d
--- /dev/null
+++ b/services/qbittorrent.nix
@@ -0,0 +1,61 @@
+{ config, pkgs, ... }:
+let
+ webUIport = 55555;
+ forwardPort = 8888;
+ torrentPort = 49114;
+ namespace = "wg-mullvad-namespace";
+ interface = "wg-mullvad";
+in
+{
+ users.users.qbittorrent.extraGroups = [ "media" ];
+ services.qbittorrent = {
+ enable = true;
+ webuiPort = webUIport;
+ serverConfig = {
+ LegalNotice.Accepted = true;
+ Preferences = {
+ WebUI = {
+ StatusbarExternalIPDisplayed = true;
+ HostHeaderValidation = false;
+ Username = "admin";
+ Password_PBKDF2 = "@ByteArray(WHjV8k2o78gWuL4xAUu0Ww==:eSOIQzJvNmW2JNbvC5DsS3h4JxAvkqJ0g0o1STTLplWLq9cDPjBME3/+dJ/c+p2crLIP2JEoO7KzD0JvLlU9TA==)";
+ };
+ General.Locale = "en";
+ };
+ BitTorrent = {
+ Session = {
+ Port = torrentPort;
+ GlobalMaxRatio = 5;
+ ShareLimitAction = "RemoveWithContent";
+ QueueingSystemEnabled = false;
+ DefaultSavePath = "/var/lib/torrents";
+ Interface = interface;
+ InterfaceName = interface;
+ MaxConnections = -1;
+ MaxConnectionsPerTorrent = -1;
+ MaxUploads = -1;
+ MaxUploadsPerTorrent = -1;
+ };
+ };
+ };
+ };
+
+ systemd.services.qbittorrent.serviceConfig = {
+ NetworkNamespacePath = "/var/run/netns/${namespace}";
+ BindReadOnlyPaths = [
+ "/etc/netns/${namespace}/resolv.conf:/etc/resolv.conf"
+ ];
+ };
+ systemd.services.qbittorrent.after = [ "wireguard-${interface}.target" ];
+
+ systemd.services.forward-namespace = {
+ description = "Proxy LAN to VPN namespace";
+ after = [ "network.target" ];
+ wantedBy = [ "multi-user.target" ];
+ script = "${pkgs.socat}/bin/socat TCP-LISTEN:${toString forwardPort},fork,reuseaddr TCP:10.200.200.2:${toString webUIport}";
+ };
+
+ systemd.tmpfiles.rules = [
+ "d /var/lib/torrents 0750 qbittorent qbittorrent -"
+ ];
+}
diff --git a/services/starr.nix b/services/starr.nix
new file mode 100644
index 0000000..400a4fa
--- /dev/null
+++ b/services/starr.nix
@@ -0,0 +1,10 @@
+{ config, pkgs, ... }:
+{
+ services.jackett.enable = true;
+ nixpkgs.overlays = [ (final: prev: { jackett = prev.jackett.overrideAttrs (_oldAttrs: {
+ doCheck = false; } ); } )
+ ];
+
+ users.users.sonarr.extraGroups = [ "media" ];
+ services.sonarr.enable = true;
+}
diff --git a/services/status.nix b/services/status.nix
new file mode 100644
index 0000000..68bb32e
--- /dev/null
+++ b/services/status.nix
@@ -0,0 +1,13 @@
+{ config, pkgs, ... }:
+{
+ services.glances = {
+ enable = true;
+ port = 61208;
+ };
+
+ services.caddy.virtualHosts."status.danielk.me" = {
+ extraConfig = ''
+ reverse_proxy 127.0.0.1:61208
+ '';
+ };
+}
diff --git a/services/wireguard.nix b/services/wireguard.nix
new file mode 100644
index 0000000..b5a994c
--- /dev/null
+++ b/services/wireguard.nix
@@ -0,0 +1,48 @@
+{ config, pkgs, ... }:
+{
+ networking.wireguard.enable = true;
+ networking.wireguard.interfaces = {
+ wg-mullvad = {
+ # Use a separate network namespace for the VPN.
+ # sudo ip netns exec wg-qbittorrent curl --interface wg-mullvad https://am.i.mullvad.net/connected
+
+ privateKeyFile = "/etc/secrets/vpn.txt";
+ ips = ["10.155.12.117/32" "fd7d:76ee:e68f:a993:3523:7cc2:943c:18a9/128"];
+ interfaceNamespace = "wg-mullvad-namespace";
+ mtu = 1320;
+
+ preSetup = ''
+ ip netns add wg-mullvad-namespace
+ ip -n wg-mullvad-namespace link set lo up
+
+ ip link add veth-host type veth peer name veth-vpn
+ ip link set veth-vpn netns wg-mullvad-namespace
+ ip addr add 10.200.200.1/24 dev veth-host
+ ip netns exec wg-mullvad-namespace ip addr add 10.200.200.2/24 dev veth-vpn
+ ip link set veth-host up
+ ip netns exec wg-mullvad-namespace ip link set veth-vpn up
+ ip netns exec wg-mullvad-namespace ip route add default via 10.200.200.1
+
+ mkdir -p /etc/netns/wg-mullvad-namespace
+ echo "nameserver 10.128.0.1" > /etc/netns/wg-mullvad-namespace/resolv.conf
+ echo "nameserver fd7d:76ee:e68f:a993::1" >> /etc/netns/wg-mullvad-namespace/resolv.conf
+ '';
+
+ postShutdown = ''
+ ip netns del wg-mullvad-namespace
+
+ ip link del veth-host
+ '';
+
+ peers = [
+ {
+ publicKey = "PyLCXAQT8KkM4T+dUsOQfn+Ub3pGxfGlxkIApuig+hk=";
+ presharedKey = "YAbLXCB/uuKPfulaFAylvGbh3nuE881GupBZ/HBULpQ=";
+ allowedIPs = ["0.0.0.0/0" "::0/0"];
+ endpoint = "europe3.vpn.airdns.org:1637";
+ persistentKeepalive = 15;
+ }
+ ];
+ };
+ };
+}
diff --git a/system.nix b/system.nix
index 87e9ca7..9711b90 100644
--- a/system.nix
+++ b/system.nix
@@ -1,5 +1,4 @@
{ config, pkgs, ... }:
-
{
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
@@ -14,9 +13,18 @@
users.users.daniel = {
isNormalUser = true;
description = "Daniel Kauss Serna";
- extraGroups = [ "networkmanager" "wheel" ];
+ extraGroups = [ "networkmanager" "wheel" "media"];
packages = [];
};
+ users.groups.media = {};
+
+ hardware.graphics.enable = true;
+ hardware.graphics.extraPackages = with pkgs; [
+ intel-media-driver
+ intel-vaapi-driver
+ libva-vdpau-driver
+ libvdpau-va-gl
+ ];
nix.settings.experimental-features = [ "nix-command" "flakes" ];