initial commit
This commit is contained in:
commit
47c42dc7a6
14 changed files with 490 additions and 0 deletions
18
.gitignore
vendored
Normal file
18
.gitignore
vendored
Normal 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
19
README.md
Normal 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
60
configuration.nix
Normal 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
36
disk-config.nix
Normal 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
102
flake.lock
generated
Normal 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
26
flake.nix
Normal 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
49
modules/caddy.nix
Normal 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
24
modules/forgejo.nix
Normal 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
28
modules/mail.nix
Normal 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
16
modules/matrix.nix
Normal 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
33
modules/minecraft.nix
Normal 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
35
modules/monitoring.nix
Normal 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
19
modules/searx.nix
Normal 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
25
secrets.nix.example
Normal 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";
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue