initial commit

This commit is contained in:
Jet 2026-02-16 21:29:21 -08:00
commit 47c42dc7a6
14 changed files with 490 additions and 0 deletions

18
.gitignore vendored Normal file
View file

@ -0,0 +1,18 @@
# NixOS Build artifacts
result
result-*
# Secrets (Untracked)
secrets/secrets.nix
secrets/tailscale-auth
secrets/forgejo-db-pass
secrets/stalwart-admin-pass
secrets/searx-secret-key
secrets/rcon-pass
# Only track the example file
!secrets.nix.example
# IDEs
.idea
.vscode

19
README.md Normal file
View file

@ -0,0 +1,19 @@
# extremist software
nixos config for the hetzner vps.
services:
- forgejo (git)
- stalwart (mail)
- searx (search)
- conduit (matrix)
- minecraft (fabric + optimization mods)
- caddy (reverse proxy)
- grafana/prometheus (monitoring)
deploy:
`nix run github:nix-community/nixos-anywhere -- --flake .#extremist-software --impure root@<ip>`
secrets:
copy `secrets.nix.example` to `secrets/secrets.nix` and fill it in.
repo uses impure build cause i dont want to manage encrypted secret files in git right now.

60
configuration.nix Normal file
View file

@ -0,0 +1,60 @@
{ config, pkgs, modulesPath, ... }:
{
imports = [
./modules/caddy.nix
./modules/forgejo.nix
./modules/mail.nix
./modules/searx.nix
./modules/matrix.nix
./modules/minecraft.nix
./modules/monitoring.nix
# Impure Secrets
./secrets/secrets.nix
];
# ... (rest of imports block replaced by ./secrets/secrets.nix being added to imports)
# Bootloader
boot.loader.grub.enable = true;
boot.loader.grub.efiSupport = true;
boot.loader.grub.efiInstallAsRemovable = true;
# Networking
networking.hostName = "extremist-software";
networking.firewall.allowedTCPPorts = [ 80 443 25565 ]; # HTTP, HTTPS, Minecraft
networking.firewall.allowedUDPPorts = [ 25565 ]; # Minecraft
# Tailscale
services.tailscale.enable = true;
# We assume the user will authenticate manually or via a one-time key service
# For now, let's enable it and allow the user to run `tailscale up` or provision via key
# Users
users.users.root.openssh.authorizedKeys.keys = [
# User should add their key here
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5..."
];
# SSH - Secure it
services.openssh = {
enable = true;
settings.PasswordAuthentication = false;
settings.PermitRootLogin = "prohibit-password";
};
# System
system.stateVersion = "24.05";
nix.settings.experimental-features = [ "nix-command" "flakes" ];
nixpkgs.config.allowUnfree = true; # Allow unfree packages (Minecraft, etc.)
# Time
time.timeZone = "UTC";
# ZRAM for limited RAM
zramSwap.enable = true;
zramSwap.memoryPercent = 50;
# Secrets handled via ./secrets/secrets.nix import
}

36
disk-config.nix Normal file
View file

@ -0,0 +1,36 @@
{
disko.devices = {
disk = {
main = {
device = "/dev/sda"; # Usually /dev/sda or /dev/vda on Hetzner VPS
type = "disk";
content = {
type = "gpt";
partitions = {
boot = {
size = "1M";
type = "EF02"; # for grub MBR
};
ESP = {
size = "512M";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
};
};
root = {
size = "100%";
content = {
type = "filesystem";
format = "ext4";
mountpoint = "/";
};
};
};
};
};
};
};
}

102
flake.lock generated Normal file
View file

@ -0,0 +1,102 @@
{
"nodes": {
"disko": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1771271879,
"narHash": "sha256-Vn32sMuvV35ChjVGZE4d8NNmCq3E/6HjaK2uVUUp2JI=",
"owner": "nix-community",
"repo": "disko",
"rev": "e963ed5aea88ad0c093adde7c1c2abd4e1b48beb",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "disko",
"type": "github"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1747046372,
"narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"nix-minecraft": {
"inputs": {
"flake-compat": "flake-compat",
"nixpkgs": [
"nixpkgs"
],
"systems": "systems"
},
"locked": {
"lastModified": 1771296409,
"narHash": "sha256-p0fEFcqNnhYBKsHTint5pwkcnQk1b68OeQJh95B9Adg=",
"owner": "Infinidoge",
"repo": "nix-minecraft",
"rev": "22cb60087e549a90f6b0347e84ac178c0c9085ad",
"type": "github"
},
"original": {
"owner": "Infinidoge",
"repo": "nix-minecraft",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1771008912,
"narHash": "sha256-gf2AmWVTs8lEq7z/3ZAsgnZDhWIckkb+ZnAo5RzSxJg=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "a82ccc39b39b621151d6732718e3e250109076fa",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"disko": "disko",
"nix-minecraft": "nix-minecraft",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

26
flake.nix Normal file
View file

@ -0,0 +1,26 @@
{
description = "NixOS Configuration for extremist.software Hetzner VPS";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
disko.url = "github:nix-community/disko";
disko.inputs.nixpkgs.follows = "nixpkgs";
nix-minecraft.url = "github:Infinidoge/nix-minecraft";
nix-minecraft.inputs.nixpkgs.follows = "nixpkgs";
};
outputs = { self, nixpkgs, disko, nix-minecraft, ... }@inputs: {
nixosConfigurations.extremist-software = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
specialArgs = { inherit inputs; };
modules = [
disko.nixosModules.disko
nix-minecraft.nixosModules.minecraft-servers
./disk-config.nix
./configuration.nix
];
};
};
}

49
modules/caddy.nix Normal file
View file

@ -0,0 +1,49 @@
{ config, pkgs, ... }:
{
services.caddy = {
enable = true;
virtualHosts = {
"extremist.software" = {
extraConfig = ''
respond "Hi"
'';
};
"git.extremist.software" = {
extraConfig = ''
reverse_proxy localhost:3000
'';
};
"mail.extremist.software" = {
# Stalwart handles its own certs usually, or we can proxy UI here
# Stalwart UI is usually on 8080
extraConfig = ''
reverse_proxy localhost:8080
'';
};
"search.extremist.software" = {
extraConfig = ''
reverse_proxy localhost:8082
'';
};
"status.extremist.software" = {
extraConfig = ''
reverse_proxy localhost:3001 # Grafana
'';
};
"matrix.extremist.software" = {
extraConfig = ''
reverse_proxy /_matrix/* localhost:6167
reverse_proxy /_synapse/client/* localhost:6167
'';
};
};
};
networking.firewall.allowedTCPPorts = [ 80 443 ];
}

24
modules/forgejo.nix Normal file
View file

@ -0,0 +1,24 @@
{ config, pkgs, ... }:
{
services.forgejo = {
enable = true;
database.type = "postgres";
# Enable support for Large File Storage
lfs.enable = true;
settings = {
server = {
DOMAIN = "git.extremist.software";
ROOT_URL = "https://git.extremist.software/";
HTTP_PORT = 3000;
};
# You can configure SMTP here using secrets if needed
};
# Secret for DB password set in secrets.nix
};
services.postgresql = {
enable = true;
package = pkgs.postgresql_15;
};
}

28
modules/mail.nix Normal file
View file

@ -0,0 +1,28 @@
{ config, pkgs, ... }:
{
services.stalwart = {
enable = true;
settings = {
server = {
hostname = "mail.extremist.software";
tls = {
enable = true;
implicit = false; # StartTLS usually on 587
};
};
# authentication.fallback-admin set in secrets.nix
# Stalwart configuration is quite extensive.
# By default it listens on standard ports (25, 465, 587, 993, 4190)
# and provides a web admin UI on 8080.
};
};
# Open Firewalls for Mail
networking.firewall.allowedTCPPorts = [
25 465 587 # SMTP
993 # IMAP (Secure)
4190 # Sieve
8080 # Admin UI (Reverse proxied, but good to double check loopback)
];
}

16
modules/matrix.nix Normal file
View file

@ -0,0 +1,16 @@
{ config, pkgs, ... }:
{
services.matrix-conduit = {
enable = true;
settings = {
global = {
server_name = "matrix.extremist.software";
allow_registration = true; # Disable after creating first user
port = 6167;
};
};
};
networking.firewall.allowedTCPPorts = [ 6167 8448 ];
}

33
modules/minecraft.nix Normal file
View file

@ -0,0 +1,33 @@
{ config, pkgs, inputs, ... }:
{
imports = [ inputs.nix-minecraft.nixosModules.minecraft-servers ];
nixpkgs.overlays = [ inputs.nix-minecraft.overlay ];
services.minecraft-servers = {
enable = true;
eula = true;
servers = {
fabric = {
enable = true;
# Use fetchPackwizModpack to get the server with mods
package = pkgs.fetchPackwizModpack {
url = "https://raw.githubusercontent.com/Fabulously-Optimized/fabulously-optimized/main/Packwiz/1.20.1/pack.toml";
packHash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; # User must update this hash!
};
serverProperties = {
motd = "Extremist Software Optimized Server";
difficulty = "hard";
view-distance = 10;
simulation-distance = 10;
max-players = 5;
enable-rcon = true;
# "rcon.password" set in secrets.nix
};
jvmOpts = "-Xms2G -Xmx2500M -XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:MaxGCPauseMillis=200 -XX:+UnlockExperimentalVMOptions -XX:+DisableExplicitGC -XX:+AlwaysPreTouch -XX:G1NewSizePercent=30 -XX:G1MaxNewSizePercent=40 -XX:G1HeapRegionSize=8M -XX:G1ReservePercent=20 -XX:G1HeapWastePercent=5 -XX:G1MixedGCCountTarget=4 -XX:InitiatingHeapOccupancyPercent=15 -XX:G1MixedGCLiveThresholdPercent=90 -XX:G1RSetUpdatingPauseTimePercent=5 -XX:SurvivorRatio=32 -XX:+PerfDisableSharedMem -XX:MaxTenuringThreshold=1 -Dusing.aikars.flags=https://mcflags.emc.gs -Daikars.new.flags=true";
};
};
};
}

35
modules/monitoring.nix Normal file
View file

@ -0,0 +1,35 @@
{ config, pkgs, ... }:
{
services.prometheus = {
enable = true;
port = 9090;
exporters = {
node = {
enable = true;
enabledCollectors = [ "systemd" ];
port = 9100;
};
# Stalwart and Conduit might have exporters too
};
scrapeConfigs = [
{
job_name = "node";
static_configs = [{
targets = [ "127.0.0.1:9100" ];
}];
}
];
};
services.grafana = {
enable = true;
settings = {
server = {
http_port = 3001;
http_addr = "127.0.0.1";
domain = "status.extremist.software";
};
};
};
}

19
modules/searx.nix Normal file
View file

@ -0,0 +1,19 @@
{ config, pkgs, ... }:
{
services.searx = {
enable = true;
# settings.server.secret_key set in secrets.nix
settings = {
server = {
port = 8082;
bind_address = "127.0.0.1";
# secret_key = ...; # Set via env var in file
};
};
};
# Inject secret via env vars or file substitution if possible
# Or use `environment.etc` to place config file if service allows.
# For now, simplistic setup.
}

25
secrets.nix.example Normal file
View file

@ -0,0 +1,25 @@
{ pkgs, config, lib, ... }:
{
# Forgejo
services.forgejo.settings.database.PASSWORD = "changeme_forgejo_db";
# Stalwart Mail
services.stalwart.settings.authentication.fallback-admin.secret = "changeme_stalwart_admin";
# Searx
services.searx.settings.server.secret_key = "changeme_searx_secret";
# Minecraft RCON
services.minecraft-servers.servers.fabric.serverProperties."rcon.password" = "changeme_rcon";
# Tailscale Auth Key (needs to be a file for the service usually, or use pre-auth)
# For Tailscale, standard module uses 'authKeyFile'.
# We can create a file in the store for it since this is an impure secrets file anyway.
# For Tailscale, let's just write valid one-liner to a file via environment.etc if needed,
# or use the 'authKey' option if available (it is not, usually).
# We will stick to environment.etc JUST for Tailscale or file-based secrets.
environment.etc."secrets/tailscale-auth".text = "tskey-auth-PLACEHOLDER";
services.tailscale.authKeyFile = "/etc/secrets/tailscale-auth";
}