petersweb-infra/nixos/linux.nix

364 lines
10 KiB
Nix
Raw Normal View History

2024-11-15 22:00:01 -09:00
{
config,
username,
hostname,
pkgs,
lib,
nix-index-database,
inputs,
specialArgs,
...
}: let
ddnsPkg = import ./invoke-ddns {inherit pkgs;};
startSeq = builtins.fromJSON ''"\u001b[7m"''; # Start inverted color
endSeq = builtins.fromJSON ''"\u001b[27m"''; # End inverted color
motd = "${startSeq} Welcome to the Peterson Mainframe! Look, touch, but DO NOT LICK. ${endSeq}";
nixPkgs = specialArgs.nixPkgs;
ourRustVersion = pkgs.rust-bin.selectLatestNightlyWith (toolchain: toolchain.complete);
ourRustPlatform = nixPkgs.makeRustPlatform {
rustc = ourRustVersion;
cargo = ourRustVersion;
};
pullomaticPkg = import ./pullomatic {
inherit lib pkgs;
rustPlatform = ourRustPlatform;
specialArgs = {};
};
pullomatic = "${pullomaticPkg}/bin/pullomatic";
2024-12-06 23:48:02 -09:00
2024-11-15 22:00:01 -09:00
in {
imports = [
(import ./cloned_repos {inherit pkgs pullomatic lib;})
(import ./firewall.nix {inherit pkgs;})
2024-12-24 02:49:21 -09:00
(import ./nginx.nix {inherit pkgs lib config;})
2024-11-15 22:00:01 -09:00
(import ./system/users.nix {inherit pkgs config lib nix-index-database;})
];
time.timeZone = "America/Anchorage";
2024-12-22 02:23:47 -09:00
age.secrets = {
nearlyfreespeech = {
file = ./secrets/nearlyfreespeech.age;
owner = "root";
};
webdav = {
file = ./secrets/webdav.age;
owner = "root";
};
2026-05-04 13:44:07 -08:00
anthropic-api-key = {
file = ./secrets/anthropic-api-key.age;
owner = "root";
};
2026-05-23 20:12:53 -08:00
postmark = {
file = ./secrets/postmark.age;
owner = "root";
};
2026-05-24 23:03:36 -08:00
forgejo-runner-token = {
file = ./secrets/forgejo-runner-token.age;
2026-05-24 23:31:05 -08:00
owner = "root";
2026-05-24 23:03:36 -08:00
};
vnc-password = {
file = ./secrets/vnc-password.age;
owner = "root";
};
vnc-htpasswd = {
file = ./secrets/vnc-htpasswd.age;
owner = "nginx";
};
2024-12-22 02:23:47 -09:00
};
2024-11-15 22:00:01 -09:00
environment.systemPackages = [
ddnsPkg
pullomaticPkg
pkgs.vim
pkgs.php
pkgs.rustc
pkgs.cargo
pkgs.util-linux
pkgs.iotop
pkgs.rust-bin.stable.latest.default
pkgs.wget
2026-05-24 00:27:15 -08:00
pkgs.tmux
2024-12-06 22:44:07 -09:00
2026-05-04 13:47:58 -08:00
pkgs.unstable.claude-code
2026-05-04 13:44:07 -08:00
2024-11-15 22:00:01 -09:00
];
swapDevices = [
{
device = "/swapfile";
size = 1 * 1024; # 1GB
}
];
2026-05-25 14:29:58 -08:00
virtualisation.arion = {
2026-05-25 17:25:54 -08:00
backend = "podman-socket";
2026-05-25 14:29:58 -08:00
projects.forgejo.settings = import ./arion/arion-compose.nix;
projects.riverside.settings = import ./arion-riverside/arion-compose.nix;
projects.vnc-desktop.settings = import ./arion-vnc/arion-compose.nix;
};
# The arion NixOS module sets backend = "podman-socket" but doesn't inject
# DOCKER_HOST into the service units; docker CLI falls back to /var/run/docker.sock
# (no daemon). Point it at the podman-compatible socket instead.
systemd.services.arion-forgejo.environment.DOCKER_HOST = "unix:///run/podman/podman.sock";
systemd.services.arion-riverside.environment.DOCKER_HOST = "unix:///run/podman/podman.sock";
systemd.services.arion-vnc-desktop.environment.DOCKER_HOST = "unix:///run/podman/podman.sock";
# Build the VNC desktop image locally from the Dockerfile — no registry push/pull needed.
# Nix copies the build context into the store; the hash changes when Dockerfile or
# start.sh change, triggering a rebuild on the next nixos-rebuild switch.
systemd.services.build-vnc-image = {
description = "Build VNC desktop container image from Dockerfile";
wantedBy = [ "arion-vnc-desktop.service" ];
before = [ "arion-vnc-desktop.service" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStart = pkgs.writeShellScript "build-vnc-image" ''
STAMP=/var/lib/build-vnc-image/context-hash
EXPECTED="${builtins.hashString "sha256"
(builtins.readFile ./vnc-desktop/Dockerfile +
builtins.readFile ./vnc-desktop/start.sh)}"
if [ -f "$STAMP" ] && [ "$(cat "$STAMP")" = "$EXPECTED" ]; then
echo "VNC image is up to date, skipping build"
exit 0
fi
echo "Building VNC desktop image..."
${pkgs.podman}/bin/podman build \
-t forge.quinefoundation.com/ironmagma/vnc-desktop:latest \
${./vnc-desktop}
mkdir -p "$(dirname "$STAMP")"
echo "$EXPECTED" > "$STAMP"
'';
};
};
2026-05-24 23:03:36 -08:00
services.gitea-actions-runner.instances."ubuntu" = {
enable = true;
2026-05-24 23:31:05 -08:00
name = "ubuntu";
2026-05-24 23:03:36 -08:00
url = "http://localhost:3000";
tokenFile = config.age.secrets.forgejo-runner-token.path;
labels = [
"ubuntu-latest:host"
"ubuntu-22.04:host"
"ubuntu-20.04:host"
2026-05-24 23:03:36 -08:00
];
};
users.users.gitea-runner = {
isSystemUser = true;
group = "gitea-runner";
2026-05-25 17:27:24 -08:00
extraGroups = [ "podman" ];
home = "/var/lib/gitea-runner";
createHome = true;
};
users.groups.gitea-runner = {};
systemd.services.gitea-runner-ubuntu = {
after = [ "arion-forgejo.service" ];
wants = [ "arion-forgejo.service" ];
environment.PATH = lib.mkForce (
2026-05-25 17:27:24 -08:00
"${pkgs.podman}/bin:${pkgs.git}/bin:${pkgs.nodejs}/bin:/run/current-system/sw/bin:/run/wrappers/bin"
);
serviceConfig = {
DynamicUser = lib.mkForce false;
User = lib.mkForce "gitea-runner";
Group = lib.mkForce "gitea-runner";
};
};
2024-11-15 22:00:01 -09:00
systemd.tmpfiles.rules = [
"d /home/ironmagma/.config 0755 ${username} users"
"d /root/.config 0755 ${username} users"
"d /var/riverside/files 0755 root root"
"d /var/riverside/postgres 0755 root root"
"d /var/lib/gitea-runner/ubuntu 0755 gitea-runner gitea-runner"
2024-11-15 22:00:01 -09:00
];
networking.hostName = "${hostname}";
# FIXME: change your shell here if you don't want zsh
programs.zsh.enable = true;
2026-05-04 13:52:47 -08:00
programs.zsh.shellInit = ''
2026-05-04 13:44:07 -08:00
export ANTHROPIC_API_KEY=$(cat ${config.age.secrets.anthropic-api-key.path})
'';
2024-11-15 22:00:01 -09:00
environment.pathsToLink = ["/share/zsh"];
environment.shells = [pkgs.zsh];
environment.enableAllTerminfo = true;
security.sudo.wheelNeedsPassword = false;
users.motd = motd;
system.stateVersion = "22.05";
2024-12-06 22:48:27 -09:00
virtualisation.podman = {
enable = true;
defaultNetwork.settings.dns_enabled = true;
2024-12-06 22:48:27 -09:00
};
2024-11-15 22:00:01 -09:00
virtualisation.oci-containers = {
2026-05-25 17:27:24 -08:00
backend = "podman";
2024-11-15 22:00:01 -09:00
containers = {
2024-12-07 01:54:11 -09:00
# Example:
# "hello" = {
# autoStart = true;
# image = "nginxdemos/hello";
# #user = "root:jellyfin";
# volumes = [
# ];
# ports = ["8081:80"];
# };
2024-11-15 22:00:01 -09:00
"navidrome" = {
autoStart = true;
environment = {
"TZ" = "America/Anchorage";
"PUID" = "1000";
"PGID" = "100";
"ND_SCANSCHEDULE" = "1h";
"ND_LOGLEVEL" = "info";
"ND_SESSIONTIMEOUT" = "24h";
"ND_BASEURL" = "";
};
ports = ["4533:4533"];
volumes = [
"/var/navidrome/data:/data"
"/var/navidrome/music:/music:ro"
];
image = "deluan/navidrome";
};
2025-01-14 20:43:46 -09:00
"nextcloud" = {
autoStart = true;
2025-01-14 21:13:17 -09:00
image = "quineglobal/ubuntu-with-ssh@sha256:64210887d48fae65bc4552503bf2d21a750ba0417ada530fd31254a8cc916746";
# image = "nextcloud/28-apache@sha256:ed95d344718ec86df96886b4b3465a9ce553c08b44b47306d399f0f201b04cb3";
2025-01-14 20:43:46 -09:00
volumes = [ ];
environment = { };
ports = ["8087:80"];
};
2025-01-14 21:13:17 -09:00
# "ubuntu" = {
# autoStart = true;
# image = "quineglobal/ubuntu-with-ssh@sha256:64210887d48fae65bc4552503bf2d21a750ba0417ada530fd31254a8cc916746";
# volumes = [ ];
# environment = {};
# ports = ["222:22"];
# };
2024-12-21 03:53:58 -09:00
"sync.io" = {
autoStart = true;
image = "quineglobal/sync.io@sha256:cbb180301fde42d8d22c26c952a4d4a487469d6491465302d8d79ebf194813b3";
2024-12-21 04:03:58 -09:00
volumes = [
"/var/syncio-cache:/sync.io-cache"
];
2024-12-21 03:53:58 -09:00
environment = {};
ports = ["9090:8080"];
2024-12-21 04:03:58 -09:00
user = "0"; # run as root
2024-12-21 03:53:58 -09:00
};
2025-01-04 01:12:38 -09:00
"blog-quine" = {
autoStart = true;
2025-06-15 23:45:34 -08:00
image = "quineglobal/blog-quine@sha256:3c2901f772c322d81f843c04d6982b9f50ff0b46d3cc457d9f868a7ff5a15497";
2025-01-04 01:12:38 -09:00
volumes = [];
environment = {};
ports = ["3010:8080"];
};
2026-05-23 20:12:53 -08:00
"coldairnetworks" = {
autoStart = true;
2026-05-23 22:19:31 -08:00
image = "quineglobal/coldairnetworks-com:latest";
2026-05-23 20:12:53 -08:00
volumes = [];
2026-05-23 22:30:47 -08:00
environment = {
POSTMARK_SERVER_TOKEN = "e718a146-c590-4550-a750-a3b925056e29";
};
2026-05-23 20:12:53 -08:00
environmentFiles = [ config.age.secrets.postmark.path ];
2026-05-23 22:28:08 -08:00
ports = ["3012:8081"];
2026-05-23 20:12:53 -08:00
};
2024-11-15 22:00:01 -09:00
};
};
nix = {
settings = {
trusted-users = [username];
accept-flake-config = true;
auto-optimise-store = true;
};
registry = {
nixpkgs = {
flake = inputs.nixpkgs;
};
};
nixPath = [
"nixpkgs=${inputs.nixpkgs.outPath}"
"nixos-config=/etc/nixos/configuration.nix"
"/nix/var/nix/profiles/per-user/root/channels"
];
2026-05-04 05:31:21 -08:00
package = pkgs.nixVersions.stable;
2024-11-15 22:00:01 -09:00
extraOptions = ''experimental-features = nix-command flakes'';
gc = {
automatic = true;
options = "--delete-older-than 7d";
};
};
# HTTPS
security.acme = {
acceptTerms = true;
defaults.email = "peterson@sent.com";
certs."philippeterson.com" = {
dnsProvider = "nearlyfreespeech";
environmentFile = config.age.secrets."nearlyfreespeech".path;
webroot = null;
};
2024-12-22 02:47:07 -09:00
certs."webdav.philippeterson.com" = {
dnsProvider = "nearlyfreespeech";
environmentFile = config.age.secrets."nearlyfreespeech".path;
webroot = null;
};
2024-11-15 22:00:01 -09:00
};
# Break the systemd ordering cycle that deadlocks nixos-rebuild switch.
# The cycle: nginx → After → acme-{philippeterson,webdav}.com (DNS challenge)
# → Wants → nginx-config-reload → After → acme-coldairnetworks (HTTP webroot)
# → After → nginx
# DNS-challenge certs don't need nginx running to provision; nginx only needs the
# selfsigned fallback cert before real certs arrive. Remove the real ACME services
# from nginx's After so the HTTP-webroot chain doesn't complete the loop.
systemd.services.nginx.after = lib.mkForce [
"network.target"
"acme-selfsigned-coldairnetworks.com.service"
"acme-selfsigned-fbksdigital.com.service"
"acme-selfsigned-forge.quinefoundation.com.service"
"acme-selfsigned-pdxdestiny.com.service"
"acme-selfsigned-philippeterson.com.service"
"acme-selfsigned-riverside.coldairnetworks.com.service"
"acme-selfsigned-vnc.quinefoundation.com.service"
"acme-selfsigned-webdav.philippeterson.com.service"
"acme-selfsigned-www.philippeterson.com.service"
];
2024-11-15 22:00:01 -09:00
}