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" ];