1
0
Fork 0

Migrate Haven's services from K3s to Nix

This commit is contained in:
Aires 2024-05-19 14:33:15 -04:00
parent af7bd3618a
commit 4d4bc1988d
7 changed files with 266 additions and 47 deletions

View file

@ -55,7 +55,14 @@ There are a few different actions for handling the update:
#### Using Remote builds
You can build any Nix or NixOS expression on a remote system before copying it over, as long as the root user on the local system has SSH access to the build target.
Nix can create builds for or on remote systems, and transfer them via SSH.
##### Generating a build on a remote system
You can run a build on a remote server, then pull it down to the local system. This is called a `distributedBuild`.
> [!NOTE]
> For distributed builds, the root user on the local system needs SSH access to the build target. This is done automatically.
To enable root builds on a host, add this to its config:
@ -65,6 +72,14 @@ nix.distributedBuilds = true;
For hosts where `nix.distributedBuilds` is true, this repo automatically gives the local root user SSH access to an unprivileged user on the build systems. This is configured in `nix-secrets`, but the build systems are defined in [`modules/base/nix.nix`](https://github.com/8bitbuddhist/nix-configuration/blob/b816d821636f9d30be905af80fe578c25ce74b92/modules/base/nix.nix#L41).
##### Pushing a build to a remote system
Conversely, you can run a build on the local host, then push it to a remote system.
```sh
NIX_SSHOPTS="-o RequestTTY=force" nixos-rebuild --target-host user@example.com --use-remote-sudo switch
```
### Testing without modifying the system
If you want to test without doing a whole build, or without modifying the current system, there are a couple additional tools to try.

View file

@ -250,11 +250,11 @@
"nix-secrets": {
"flake": false,
"locked": {
"lastModified": 1715904475,
"narHash": "sha256-5PyOjPdOhzX5qHq3ywwSsYCQT5OmWv870DlSYyuJBh4=",
"lastModified": 1716069971,
"narHash": "sha256-0YWdnb+RiMHW8vQ4siDIqYEo5OUdWvYq7xzQw7blBwE=",
"ref": "refs/heads/main",
"rev": "0bc545bf36759ca1ab67e2718bc5771eca72d02f",
"revCount": 23,
"rev": "b5c77dd4718a64ce7c8aef3752beed1144ea2693",
"revCount": 27,
"type": "git",
"url": "file:///home/aires/Development/nix-configuration/nix-secrets"
},
@ -313,11 +313,11 @@
},
"nixpkgs_2": {
"locked": {
"lastModified": 1715787315,
"narHash": "sha256-cYApT0NXJfqBkKcci7D9Kr4CBYZKOQKDYA23q8XNuWg=",
"lastModified": 1715961556,
"narHash": "sha256-+NpbZRCRisUHKQJZF3CT+xn14ZZQO+KjxIIanH3Pvn4=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "33d1e753c82ffc557b4a585c77de43d4c922ebb5",
"rev": "4a6b83b05df1a8bd7d99095ec4b4d271f2956b64",
"type": "github"
},
"original": {

View file

@ -6,7 +6,25 @@
...
}:
let
cfg = config.services.forgejo;
forgejo-cli = pkgs.writeScriptBin "forgejo-cli" ''
#!${pkgs.runtimeShell}
cd ${cfg.stateDir}
sudo=exec
if [[ "$USER" != forgejo ]]; then
sudo='exec /run/wrappers/bin/sudo -u ${cfg.user} -g ${cfg.group} --preserve-env=GITEA_WORK_DIR --preserve-env=GITEA_CUSTOM'
fi
# Note that these variable names will change
export GITEA_WORK_DIR=${cfg.stateDir}
export GITEA_CUSTOM=${cfg.customDir}
$sudo ${lib.getExe cfg.package} "$@"
'';
start-haven = pkgs.writeShellScriptBin "start-haven" (builtins.readFile ./start-haven.sh);
subdomains = map (subdomain: subdomain + ".${config.secrets.networking.primaryDomain}") [
"code"
"music"
];
in
{
imports = [ ./hardware-configuration.nix ];
@ -24,10 +42,6 @@ in
autostart = false;
environment = "${config.users.users.aires.home}";
};
k3s = {
enable = true;
role = "server";
};
msmtp.enable = true;
};
users = {
@ -44,16 +58,138 @@ in
};
};
# Enable BOINC (distributed research computing)
services.boinc = {
# TLS certificate renewal via Let's Encrypt
security.acme = {
acceptTerms = true;
defaults = {
email = "${config.secrets.users.aires.email}";
};
certs."${config.secrets.networking.primaryDomain}" = {
dnsProvider = "namecheap";
extraDomainNames = subdomains;
webroot = null; # Prevents an assertion error
credentialFiles = {
"NAMECHEAP_API_USER_FILE" = "${pkgs.writeText "namecheap-api-user" ''
${config.secrets.networking.namecheap.api.user}
''}";
"NAMECHEAP_API_KEY_FILE" = "${pkgs.writeText "namecheap-api-key" ''
${config.secrets.networking.namecheap.api.key}
''}";
};
};
};
# /var/lib/acme/.challenges must be writable by the ACME user
# and readable by the Nginx user. The easiest way to achieve
# this is to add the Nginx user to the ACME group.
users.users.nginx.extraGroups = [ "acme" ];
users.users.airsonic.extraGroups = [ "media" ];
services = {
nginx = {
enable = true;
# Use recommended settings per https://nixos.wiki/wiki/Nginx#Hardened_setup_with_TLS_and_HSTS_preloading
recommendedGzipSettings = true;
recommendedOptimisation = true;
#recommendedProxySettings = true; # Recommended settings break Airsonic
recommendedTlsSettings = true;
virtualHosts = {
# Base URL: make sure we've got Let's Encrypt running challenges here, and all other requests going to HTTPS
"${config.secrets.networking.primaryDomain}" = {
# Catchall vhost, will redirect users to HTTPS for all vhosts
default = true;
enableACME = true;
#serverAliases = subdomains;
locations."/" = {
return = "301 https://$host$request_uri";
};
};
# Forgejo
"code.${config.secrets.networking.primaryDomain}" = {
useACMEHost = "${config.secrets.networking.primaryDomain}";
forceSSL = true;
listen = [
{
port = 443;
addr = "0.0.0.0";
ssl = true;
}
];
locations."/" = {
proxyPass = "http://127.0.0.1:3000";
proxyWebsockets = true; # needed if you need to use WebSocket
extraConfig =
# required when the target is also TLS server with multiple hosts
"proxy_ssl_server_name on;";
};
};
# Airsonic
"music.${config.secrets.networking.primaryDomain}" = {
useACMEHost = "${config.secrets.networking.primaryDomain}";
forceSSL = true;
listen = [
{
port = 443;
addr = "0.0.0.0";
ssl = true;
}
];
locations."/" = {
proxyPass = "http://127.0.0.1:4040";
proxyWebsockets = true; # needed if you need to use WebSocket
};
};
};
};
# Enable Airsonic-Advanced (music streaming)
airsonic = {
enable = true;
war = "${
(pkgs.callPackage ../../packages/airsonic-advanced.nix { inherit lib; })
}/webapps/airsonic-advanced.war";
port = 4040;
jre = pkgs.jdk17_headless;
jvmOptions = [
"-Dserver.use-forward-headers=true"
"-Xmx4G"
];
home = "/storage/services/airsonic-advanced";
};
# Enable BOINC (distributed research computing)
boinc = {
enable = true;
package = pkgs.boinc-headless;
dataDir = "/var/lib/boinc";
extraEnvPackages = [ pkgs.ocl-icd ];
};
# Enable Forgejo / Gitea (code repository)
forgejo = {
enable = true;
stateDir = "/storage/services/forgejo";
# Enable support for Git Large File Storage
lfs.enable = true;
settings = {
server = {
DOMAIN = "${config.secrets.networking.primaryDomain}";
ROOT_URL = "https://code.${config.secrets.networking.primaryDomain}/";
HTTP_PORT = 3000;
SSH_PORT = config.secrets.services.forgejo.sshPort;
};
};
useWizard = true;
};
# Enable SSH
services.openssh = {
openssh = {
enable = true;
ports = [ 33105 ];
ports = [ config.secrets.hosts.haven.ssh.port ];
settings = {
# require public key authentication for better security
@ -65,12 +201,48 @@ in
};
};
# TODO: VPN (Check out Wireguard)
};
# Configure services
systemd.services = {
# Airsonic: Disable autostart and set environment variables. Started via start-haven script
airsonic = {
wantedBy = lib.mkForce [ ];
};
# Foregejo: Disable autostart. Started via start-haven script
forgejo = {
wantedBy = lib.mkForce [ ];
};
# Nginx: Disable autostart. Started via start-haven script
nginx = {
wantedBy = lib.mkForce [ ];
wants = [
"airsonic.service"
"forgejo.service"
];
};
};
# Open ports
networking.firewall = {
enable = true;
allowedTCPPorts = [
80
443
];
};
# Add extra packages:
# 1: forgejo CLI tool
# 2: Haven's startup script
environment.systemPackages = [
forgejo-cli
start-haven
];
# Allow Haven to be a build target for other architectures (mainly ARM64)
boot.binfmt.emulatedSystems = [ "aarch64-linux" ];
# Open port for OpenVPN
networking.firewall.allowedUDPPorts = [ 1194 ];
# Add script for booting Haven
environment.systemPackages = [ start-haven ];
}

View file

@ -11,25 +11,20 @@ fi
set -e
# Unlock and mount storage directory if we haven't already
if [ ! -f /dev/mapper/storage ]; then
echo "Unlocking storage partition:"
if [ -e "/dev/mapper/storage" ]; then
echo "Storage partition already mounted."
else
echo "Unlocking storage partition..."
cryptsetup luksOpen /dev/md/Sapana storage
mount /dev/mapper/storage /storage
echo "Storage partition mounted."
fi
#echo "Unlocking backup partition:"
# 4 TB HDD, partition #2
#cryptsetup luksOpen /dev/disk/by-uuid/8dc60329-d27c-4a4a-b76a-861b1e28400e backups --key-file /storage/backups_partition.key
#mount /dev/mapper/backups /backups
#echo "Storage and backup partitions mounted."
echo "Starting Duplicacy:"
systemctl start duplicacy-web.service
echo "Duplicacy started."
echo "Starting SyncThing:"
echo "Starting services..."
systemctl restart duplicacy-web.service
systemctl restart airsonic.service forgejo.service
systemctl --machine aires@.host --user start syncthing.service
echo "SyncThing started."
systemctl restart nginx.service
echo "Services started. Haven is ready to go!"
exit 0

View file

@ -63,6 +63,9 @@ in
};
};
# Install additional packages
environment.systemPackages = [ pkgs.boinc ];
# Move files into target system
systemd.tmpfiles.rules = [
# Use gremlin user's monitor config for GDM (defined above)

@ -1 +1 @@
Subproject commit 0bc545bf36759ca1ab67e2718bc5771eca72d02f
Subproject commit 9b1b7422848beee7137e74a18bf4f9551a1cf044

View file

@ -0,0 +1,34 @@
{
lib,
stdenv,
fetchurl,
nixosTests,
}:
stdenv.mkDerivation rec {
pname = "airsonic-advanced";
version = "11.1.4-SNAPSHOT.20240518150716";
src = fetchurl {
url = "https://github.com/kagemomiji/airsonic-advanced/releases/download/${version}/airsonic.war";
sha256 = "f4274fadd0acfe7f21d04e34ebb158238d8aaac06c0c76f6a4bf3d2d5bb41156";
};
buildCommand = ''
mkdir -p "$out/webapps"
cp "$src" "$out/webapps/airsonic-advanced.war"
'';
passthru.tests = {
airsonic-starts = nixosTests.airsonic;
};
meta = with lib; {
description = "Personal media streamer";
homepage = "https://airsonic.github.io";
sourceProvenance = with sourceTypes; [ binaryBytecode ];
license = lib.licenses.gpl3;
platforms = platforms.all;
maintainers = with maintainers; [ disassembler ];
};
}