From e317f5cd55436bd2c6d545d53c9438cdf45a2178 Mon Sep 17 00:00:00 2001 From: System administrator Date: Mon, 11 May 2026 19:46:29 +0200 Subject: [PATCH 01/10] Flake added --- configuration.nix | 1 + flake.nix | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 flake.nix diff --git a/configuration.nix b/configuration.nix index efd83ac..dfbe8d0 100644 --- a/configuration.nix +++ b/configuration.nix @@ -5,6 +5,7 @@ ./hardware-configuration.nix # Add further modules here later, e.g.: ./programs.nix + ./flake.nix # ./modules/nextcloud.nix # ./modules/wireguard.nix # ./modules/docker.nix diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..82cb156 --- /dev/null +++ b/flake.nix @@ -0,0 +1,16 @@ +{ + description = "NixOS Konfiguration"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11"; + }; + + outputs = { self, nixpkgs, ... }: { + nixosConfigurations.nixos = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ + ./configuration.nix + ]; + }; + }; +} From 16d117f80b06eaebcc5e789f44b323129cccf1e3 Mon Sep 17 00:00:00 2001 From: System administrator Date: Mon, 11 May 2026 19:48:30 +0200 Subject: [PATCH 02/10] Flake added --- flake.lock | 27 +++++++++++++++++++++++++++ flake.nix | 3 +-- 2 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 flake.lock diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..986f695 --- /dev/null +++ b/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1778430510, + "narHash": "sha256-Ti+ZBvW6yrWWAg2szExVTwCd4qOJ3KlVr1tFHfyfi8Q=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "8fd9daa3db09ced9700431c5b7ad0e8ba199b575", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-25.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix index 82cb156..735e55d 100644 --- a/flake.nix +++ b/flake.nix @@ -1,6 +1,5 @@ { - description = "NixOS Konfiguration"; - + inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11"; }; From dfc8c1d132e536451223cdadbe6ca19d186ed238 Mon Sep 17 00:00:00 2001 From: System administrator Date: Mon, 11 May 2026 19:56:38 +0200 Subject: [PATCH 03/10] Flake --- configuration.nix | 1 - flake.lock | 8 ++++---- flake.nix | 3 ++- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/configuration.nix b/configuration.nix index dfbe8d0..efd83ac 100644 --- a/configuration.nix +++ b/configuration.nix @@ -5,7 +5,6 @@ ./hardware-configuration.nix # Add further modules here later, e.g.: ./programs.nix - ./flake.nix # ./modules/nextcloud.nix # ./modules/wireguard.nix # ./modules/docker.nix diff --git a/flake.lock b/flake.lock index 986f695..064ee7a 100644 --- a/flake.lock +++ b/flake.lock @@ -2,16 +2,16 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1778430510, - "narHash": "sha256-Ti+ZBvW6yrWWAg2szExVTwCd4qOJ3KlVr1tFHfyfi8Q=", + "lastModified": 1720535198, + "narHash": "sha256-zwVvxrdIzralnSbcpghA92tWu2DV2lwv89xZc8MTrbg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "8fd9daa3db09ced9700431c5b7ad0e8ba199b575", + "rev": "205fd4226592cc83fd4c0885a3e4c9c400efabb5", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-25.11", + "ref": "nixos-23.11", "repo": "nixpkgs", "type": "github" } diff --git a/flake.nix b/flake.nix index 735e55d..82cb156 100644 --- a/flake.nix +++ b/flake.nix @@ -1,5 +1,6 @@ { - + description = "NixOS Konfiguration"; + inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11"; }; From 44b2fe5a11e99e67b4682d6b409317c149bc1820 Mon Sep 17 00:00:00 2001 From: System administrator Date: Mon, 11 May 2026 20:02:24 +0200 Subject: [PATCH 04/10] Flake --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index 064ee7a..986f695 100644 --- a/flake.lock +++ b/flake.lock @@ -2,16 +2,16 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1720535198, - "narHash": "sha256-zwVvxrdIzralnSbcpghA92tWu2DV2lwv89xZc8MTrbg=", + "lastModified": 1778430510, + "narHash": "sha256-Ti+ZBvW6yrWWAg2szExVTwCd4qOJ3KlVr1tFHfyfi8Q=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "205fd4226592cc83fd4c0885a3e4c9c400efabb5", + "rev": "8fd9daa3db09ced9700431c5b7ad0e8ba199b575", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-23.11", + "ref": "nixos-25.11", "repo": "nixpkgs", "type": "github" } From dcd5d8ea1413089d0c9e60b3e989052af647d60e Mon Sep 17 00:00:00 2001 From: Nio Date: Tue, 12 May 2026 08:33:42 +0200 Subject: [PATCH 05/10] Nginx added --- programs.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/programs.nix b/programs.nix index 1c5162a..1634887 100644 --- a/programs.nix +++ b/programs.nix @@ -7,6 +7,7 @@ git htop ncdu + nginx ]; } From 4ab16345e1973ef83c136727837c1400e4d532f7 Mon Sep 17 00:00:00 2001 From: Nio Date: Tue, 12 May 2026 08:36:41 +0200 Subject: [PATCH 06/10] Language changed to english --- configuration.nix | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/configuration.nix b/configuration.nix index efd83ac..ab116ec 100644 --- a/configuration.nix +++ b/configuration.nix @@ -55,7 +55,19 @@ # ============================================================ time.timeZone = "Europe/Berlin"; - i18n.defaultLocale = "de_DE.UTF-8"; + i18n.defaultLocale = "en_US.UTF-8"; + + i18n.extraLocaleSettings = { + LC_ADDRESS = "de_DE.UTF-8"; + LC_IDENTIFICATION = "de_DE.UTF-8"; + LC_MEASUREMENT = "de_DE.UTF-8"; + LC_MONETARY = "de_DE.UTF-8"; + LC_NAME = "de_DE.UTF-8"; + LC_NUMERIC = "de_DE.UTF-8"; + LC_PAPER = "de_DE.UTF-8"; + LC_TELEPHONE = "de_DE.UTF-8"; + LC_TIME = "de_DE.UTF-8"; + }; # ============================================================ # SSH From a33c7c7762b04000e3d5b9815bee0308cfae75b3 Mon Sep 17 00:00:00 2001 From: nio17 Date: Tue, 12 May 2026 08:46:17 +0200 Subject: [PATCH 07/10] Pro --- project-skeleton.nix | 247 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 247 insertions(+) create mode 100644 project-skeleton.nix diff --git a/project-skeleton.nix b/project-skeleton.nix new file mode 100644 index 0000000..3b5a73c --- /dev/null +++ b/project-skeleton.nix @@ -0,0 +1,247 @@ +# ============================================================================== +# PROJECT SKELETON — NixOS Service Module +# ============================================================================== +# +# USAGE: +# 1. Copy this file into your project repo, e.g. ~/projects/my-project/my-project.nix +# 2. Replace every occurrence of: +# MY_PROJECT → your project name in camelCase (e.g. myRssReader) +# my-project → your project name in kebab-case (e.g. my-rss-reader) +# my-project.example.com → your actual domain +# 127.0.0.1:3000 → the address your app listens on internally +# 3. In /etc/nixos/configuration.nix, add: +# imports = [ /path/to/my-project.nix ]; +# services.MY_PROJECT.enable = true; +# +# ASSUMPTIONS: +# - Nginx global settings (recommendedTlsSettings etc.) and ACME email are +# configured centrally in configuration.nix (see bottom of this file). +# - Your app runs as a systemd service on a local port (reverse proxy setup). +# - You want HTTPS via Let's Encrypt. +# +# ============================================================================== + +{ config, pkgs, lib, ... }: + +let + # The internal port your application listens on. + # Nginx will forward public traffic here. + appPort = 3000; + + # Shorthand so you can reference the merged config of this module cleanly. + cfg = config.services.MY_PROJECT; + +in +{ + # ============================================================================ + # OPTIONS + # Define the knobs that other files (or configuration.nix) can turn. + # Nothing in `config` below runs until `enable` is set to true. + # ============================================================================ + + options.services.MY_PROJECT = { + + enable = lib.mkEnableOption "MY_PROJECT service"; + # Adds a boolean option `services.MY_PROJECT.enable` that defaults to false. + # Set it to true in configuration.nix to activate this module. + + domain = lib.mkOption { + type = lib.types.str; + default = "my-project.example.com"; + description = "The public domain name Nginx will serve and ACME will certify."; + }; + + port = lib.mkOption { + type = lib.types.port; + default = appPort; + description = "Internal port the application process listens on."; + }; + + dataDir = lib.mkOption { + type = lib.types.path; + default = "/var/lib/my-project"; + description = "Directory for persistent application data (database, uploads, etc.)."; + }; + + # Optional: expose an environment file path for secrets. + # The file should contain KEY=VALUE pairs and never be committed to git. + # Example content: + # DATABASE_URL=postgres://user:password@localhost/mydb + # SECRET_KEY=supersecret + environmentFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + description = '' + Path to a file containing secret environment variables. + This file is read by systemd at runtime and never stored in the Nix store. + Example: /run/secrets/my-project.env + ''; + }; + + }; + + # ============================================================================ + # CONFIG + # Everything below only takes effect when `services.MY_PROJECT.enable = true`. + # ============================================================================ + + config = lib.mkIf cfg.enable { + + # -------------------------------------------------------------------------- + # Systemd Service + # Runs your application as a background process. + # -------------------------------------------------------------------------- + + systemd.services.my-project = { + description = "MY_PROJECT application service"; + + # Start after the network and (if used) PostgreSQL are ready. + after = [ "network.target" "postgresql.service" ]; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + # --- Replace this with your actual start command --- + # Examples: + # Node.js: "${pkgs.nodejs}/bin/node ${cfg.dataDir}/server.js" + # Python: "${pkgs.python3}/bin/python ${cfg.dataDir}/app.py" + # Binary: "${pkgs.my-package}/bin/my-binary" + ExecStart = "${pkgs.nodejs}/bin/node ${cfg.dataDir}/server.js"; + + # Working directory for the process. + WorkingDirectory = cfg.dataDir; + + # DynamicUser: systemd creates an unprivileged user automatically. + # The user has no fixed UID and cannot log in. Good for most services. + # Set to false if you need a persistent user (e.g. for file ownership). + DynamicUser = true; + + # Give the dynamic user write access to the data directory. + StateDirectory = "my-project"; + StateDirectoryMode = "0750"; + + # Load secrets from a file at runtime (optional). + # The contents are injected as environment variables. + EnvironmentFile = lib.mkIf (cfg.environmentFile != null) cfg.environmentFile; + + # Hardening — remove lines you don't need, but keep as many as possible. + NoNewPrivileges = true; + PrivateTmp = true; # /tmp is isolated from other services + ProtectSystem = "strict"; + ProtectHome = true; + RestrictSUIDSGID = true; + LockPersonality = true; + RestrictNamespaces = true; + + # Restart automatically if the process crashes. + Restart = "on-failure"; + RestartSec = "5s"; + }; + + # Environment variables that are safe to be in the Nix store. + # For secrets, use environmentFile above instead. + environment = { + NODE_ENV = "production"; + PORT = toString cfg.port; + DATA_DIR = cfg.dataDir; + }; + }; + + # -------------------------------------------------------------------------- + # Nginx Virtual Host + # Terminates TLS and proxies requests to the local application port. + # -------------------------------------------------------------------------- + + services.nginx = { + # Nginx is enabled automatically when virtualHosts is non-empty, + # but being explicit is clearer. + enable = true; + + virtualHosts.${cfg.domain} = { + + # Redirect all plain HTTP to HTTPS. + forceSSL = true; + + # Let NixOS manage the Let's Encrypt certificate automatically. + # Renewal is handled by a systemd timer — no manual cron needed. + # Requires: security.acme.acceptTerms = true and defaults.email set + # in your central configuration.nix. + enableACME = true; + + # --- Main reverse proxy location --- + locations."/" = { + proxyPass = "http://127.0.0.1:${toString cfg.port}"; + + # Needed for apps that use WebSockets (e.g. live reload, chat). + # Remove these two lines if your app does not use WebSockets. + proxyWebsockets = true; + extraConfig = '' + proxy_read_timeout 60s; + ''; + }; + + # --- Optional: serve static files directly from Nginx --- + # Uncomment and adjust if your app has a public assets directory. + # Serving static files from Nginx is faster than going through Node/Python. + # + # locations."/static/" = { + # alias = "${cfg.dataDir}/static/"; + # extraConfig = '' + # expires 30d; + # add_header Cache-Control "public, immutable"; + # ''; + # }; + + # --- Optional: block access to sensitive paths --- + # locations."~ /\\." = { + # extraConfig = "deny all;"; + # }; + }; + }; + + # -------------------------------------------------------------------------- + # PostgreSQL Database (optional) + # Uncomment this block if your project needs a database. + # -------------------------------------------------------------------------- + + # services.postgresql = { + # enable = true; + # + # # Creates the database and user if they don't exist yet. + # ensureDatabases = [ "my-project" ]; + # ensureUsers = [{ + # name = "my-project"; + # ensureDBOwnership = true; + # }]; + # }; + + # -------------------------------------------------------------------------- + # Firewall + # Ports 80 and 443 must be open for Nginx and Let's Encrypt to work. + # If these are already opened in configuration.nix, remove this block. + # -------------------------------------------------------------------------- + + networking.firewall.allowedTCPPorts = [ 80 443 ]; + + }; + + # ============================================================================ + # CENTRAL CONFIGURATION.NIX REQUIREMENTS + # + # Make sure these are set somewhere in your configuration.nix (not here, + # so they are shared across all project modules without duplication): + # + # services.nginx = { + # recommendedGzipSettings = true; + # recommendedOptimisation = true; + # recommendedTlsSettings = true; + # recommendedProxySettings = true; + # }; + # + # security.acme = { + # acceptTerms = true; + # defaults.email = "your@email.com"; + # }; + # + # ============================================================================ + +} From cc60ac8fbd9150bc4d947d787282ff25a94c25c9 Mon Sep 17 00:00:00 2001 From: Nio Date: Tue, 12 May 2026 09:05:18 +0200 Subject: [PATCH 08/10] Nginx --- configuration.nix | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/configuration.nix b/configuration.nix index ab116ec..9522a31 100644 --- a/configuration.nix +++ b/configuration.nix @@ -50,6 +50,15 @@ }; }; + services.nginx = { + recommendedGzipSettings = true; + recommendedOptimisation = true; + recommendedTlsSettings = true; + recommendedProxySettings = true; + }; + + security.acme = { acceptTerms = true; defaults.email = "nio24@pm.me"; }; + # ============================================================ # TIMEZONE & LOCALISATION # ============================================================ From 3a7a4fcffab65f9e592ad111a19cbffdbb01e55f Mon Sep 17 00:00:00 2001 From: Nio Date: Tue, 12 May 2026 09:38:54 +0200 Subject: [PATCH 09/10] Forgejo --- configuration.nix | 1 + forgejo.nix | 94 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 forgejo.nix diff --git a/configuration.nix b/configuration.nix index 9522a31..6424a93 100644 --- a/configuration.nix +++ b/configuration.nix @@ -5,6 +5,7 @@ ./hardware-configuration.nix # Add further modules here later, e.g.: ./programs.nix + ./forgejo.nix # ./modules/nextcloud.nix # ./modules/wireguard.nix # ./modules/docker.nix diff --git a/forgejo.nix b/forgejo.nix new file mode 100644 index 0000000..b4755ce --- /dev/null +++ b/forgejo.nix @@ -0,0 +1,94 @@ +{ config, pkgs, lib, ... }: + +let + # Kurzreferenzen damit du nicht immer den vollen Pfad schreiben musst. + # "cfg" zeigt auf den gesamten forgejo-Konfigurationsblock. + # "srv" zeigt auf den server-Unterblock innerhalb von forgejo. + cfg = config.services.forgejo; + srv = cfg.settings.server; +in +{ + # ============================================================ + # FORGEJO SERVICE + # ============================================================ + + services.forgejo = { + enable = true; + + # PostgreSQL ist stabiler und performanter als SQLite für den echten Betrieb. + # NixOS legt die Datenbank und den User automatisch an. + database.type = "postgres"; + + # LFS = Large File Storage. Ermöglicht das Versionieren großer Dateien + # (z.B. Binaries, Bilder) über Git. Schadet nicht, also aktivieren. + lfs.enable = true; + + # Wo Forgejo seine Repositories auf dem Dateisystem speichert. + # Standardmäßig /var/lib/forgejo/repositories – das ist gut so. + # repositoryRoot = "/var/lib/forgejo/repositories"; # optional überschreiben + + settings = { + + server = { + DOMAIN = "git.nikolai-linschmann.de"; + # ROOT_URL muss gesetzt sein, sonst erscheint der Port in allen URLs im Web-UI. + # srv.DOMAIN referenziert den Wert der DOMAIN-Option direkt oben. + ROOT_URL = "https://${srv.DOMAIN}/"; + HTTP_PORT = 3000; # Interner Port, nach außen kommt nur Nginx + }; + + service = { + # Registrierung deaktivieren – du bist der einzige Nutzer. + # Nach dem ersten Start temporär auf false setzen (siehe Schritt 4), + # dann wieder auf true. + DISABLE_REGISTRATION = false; + }; + + # Sicherheit: Sessions und Tokens laufen nach 7 Tagen ab. + security = { + LOGIN_REMEMBER_DAYS = 7; + }; + + }; + }; + + # ============================================================ + # NGINX REVERSE PROXY + # ============================================================ + # Nginx nimmt HTTPS-Anfragen von außen entgegen und leitet + # sie intern an Forgejo auf Port 3000 weiter. + + services.nginx.virtualHosts.${srv.DOMAIN} = { + forceSSL = true; # HTTP → HTTPS Redirect + enableACME = true; # Let's Encrypt Zertifikat automatisch holen und erneuern + + extraConfig = '' + # Erlaubt große Uploads (z.B. Git-Pushes mit vielen Dateien). + # 512M ist ein guter Standardwert für eine persönliche Instanz. + client_max_body_size 512M; + ''; + + locations."/" = { + # srv.HTTP_PORT ist 3000 – toString wandelt die Zahl in einen String um. + proxyPass = "http://127.0.0.1:${toString srv.HTTP_PORT}"; + }; + }; + + # ============================================================ + # SSH-INTEGRATION + # ============================================================ + # Damit "git clone git@git.nikolai-linschmann.de:user/repo.git" funktioniert. + # Forgejo braucht zu wissen auf welchem Port OpenSSH läuft. + + services.forgejo.settings.server.SSH_PORT = + lib.head config.services.openssh.ports; + # lib.head nimmt das erste Element der Liste der SSH-Ports (normalerweise 22). + + # ============================================================ + # FIREWALL + # ============================================================ + # Port 80 (HTTP) und 443 (HTTPS) müssen offen sein. + # Falls das schon zentral in configuration.nix steht, diesen Block weglassen. + + networking.firewall.allowedTCPPorts = [ 80 443 ]; +} From 28daab5d65c6ac29bdb12f1108a6f339d25ebd30 Mon Sep 17 00:00:00 2001 From: Nio Date: Tue, 12 May 2026 09:46:44 +0200 Subject: [PATCH 10/10] Nginx enabled --- configuration.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/configuration.nix b/configuration.nix index 6424a93..f057788 100644 --- a/configuration.nix +++ b/configuration.nix @@ -52,6 +52,7 @@ }; services.nginx = { + enable = true; recommendedGzipSettings = true; recommendedOptimisation = true; recommendedTlsSettings = true;