Migrate Haven's services from K3s to Nix
This commit is contained in:
parent
af7bd3618a
commit
4d4bc1988d
17
README.md
17
README.md
|
@ -55,7 +55,14 @@ There are a few different actions for handling the update:
|
||||||
|
|
||||||
#### Using Remote builds
|
#### 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:
|
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).
|
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
|
### 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.
|
If you want to test without doing a whole build, or without modifying the current system, there are a couple additional tools to try.
|
||||||
|
|
14
flake.lock
14
flake.lock
|
@ -250,11 +250,11 @@
|
||||||
"nix-secrets": {
|
"nix-secrets": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1715904475,
|
"lastModified": 1716069971,
|
||||||
"narHash": "sha256-5PyOjPdOhzX5qHq3ywwSsYCQT5OmWv870DlSYyuJBh4=",
|
"narHash": "sha256-0YWdnb+RiMHW8vQ4siDIqYEo5OUdWvYq7xzQw7blBwE=",
|
||||||
"ref": "refs/heads/main",
|
"ref": "refs/heads/main",
|
||||||
"rev": "0bc545bf36759ca1ab67e2718bc5771eca72d02f",
|
"rev": "b5c77dd4718a64ce7c8aef3752beed1144ea2693",
|
||||||
"revCount": 23,
|
"revCount": 27,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "file:///home/aires/Development/nix-configuration/nix-secrets"
|
"url": "file:///home/aires/Development/nix-configuration/nix-secrets"
|
||||||
},
|
},
|
||||||
|
@ -313,11 +313,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1715787315,
|
"lastModified": 1715961556,
|
||||||
"narHash": "sha256-cYApT0NXJfqBkKcci7D9Kr4CBYZKOQKDYA23q8XNuWg=",
|
"narHash": "sha256-+NpbZRCRisUHKQJZF3CT+xn14ZZQO+KjxIIanH3Pvn4=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "33d1e753c82ffc557b4a585c77de43d4c922ebb5",
|
"rev": "4a6b83b05df1a8bd7d99095ec4b4d271f2956b64",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
@ -6,7 +6,25 @@
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
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);
|
start-haven = pkgs.writeShellScriptBin "start-haven" (builtins.readFile ./start-haven.sh);
|
||||||
|
|
||||||
|
subdomains = map (subdomain: subdomain + ".${config.secrets.networking.primaryDomain}") [
|
||||||
|
"code"
|
||||||
|
"music"
|
||||||
|
];
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [ ./hardware-configuration.nix ];
|
imports = [ ./hardware-configuration.nix ];
|
||||||
|
@ -24,10 +42,6 @@ in
|
||||||
autostart = false;
|
autostart = false;
|
||||||
environment = "${config.users.users.aires.home}";
|
environment = "${config.users.users.aires.home}";
|
||||||
};
|
};
|
||||||
k3s = {
|
|
||||||
enable = true;
|
|
||||||
role = "server";
|
|
||||||
};
|
|
||||||
msmtp.enable = true;
|
msmtp.enable = true;
|
||||||
};
|
};
|
||||||
users = {
|
users = {
|
||||||
|
@ -44,33 +58,191 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# Enable BOINC (distributed research computing)
|
# TLS certificate renewal via Let's Encrypt
|
||||||
services.boinc = {
|
security.acme = {
|
||||||
enable = true;
|
acceptTerms = true;
|
||||||
dataDir = "/var/lib/boinc";
|
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
|
||||||
|
openssh = {
|
||||||
|
enable = true;
|
||||||
|
ports = [ config.secrets.hosts.haven.ssh.port ];
|
||||||
|
|
||||||
|
settings = {
|
||||||
|
# require public key authentication for better security
|
||||||
|
PasswordAuthentication = false;
|
||||||
|
KbdInteractiveAuthentication = false;
|
||||||
|
PubkeyAuthentication = true;
|
||||||
|
|
||||||
|
PermitRootLogin = "without-password";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# TODO: VPN (Check out Wireguard)
|
||||||
};
|
};
|
||||||
|
|
||||||
# Enable SSH
|
# Configure services
|
||||||
services.openssh = {
|
systemd.services = {
|
||||||
enable = true;
|
# Airsonic: Disable autostart and set environment variables. Started via start-haven script
|
||||||
ports = [ 33105 ];
|
airsonic = {
|
||||||
|
wantedBy = lib.mkForce [ ];
|
||||||
|
};
|
||||||
|
|
||||||
settings = {
|
# Foregejo: Disable autostart. Started via start-haven script
|
||||||
# require public key authentication for better security
|
forgejo = {
|
||||||
PasswordAuthentication = false;
|
wantedBy = lib.mkForce [ ];
|
||||||
KbdInteractiveAuthentication = false;
|
};
|
||||||
PubkeyAuthentication = true;
|
|
||||||
|
|
||||||
PermitRootLogin = "without-password";
|
# 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)
|
# Allow Haven to be a build target for other architectures (mainly ARM64)
|
||||||
boot.binfmt.emulatedSystems = [ "aarch64-linux" ];
|
boot.binfmt.emulatedSystems = [ "aarch64-linux" ];
|
||||||
|
|
||||||
# Open port for OpenVPN
|
|
||||||
networking.firewall.allowedUDPPorts = [ 1194 ];
|
|
||||||
|
|
||||||
# Add script for booting Haven
|
|
||||||
environment.systemPackages = [ start-haven ];
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,25 +11,20 @@ fi
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# Unlock and mount storage directory if we haven't already
|
# Unlock and mount storage directory if we haven't already
|
||||||
if [ ! -f /dev/mapper/storage ]; then
|
if [ -e "/dev/mapper/storage" ]; then
|
||||||
echo "Unlocking storage partition:"
|
echo "Storage partition already mounted."
|
||||||
|
else
|
||||||
|
echo "Unlocking storage partition..."
|
||||||
cryptsetup luksOpen /dev/md/Sapana storage
|
cryptsetup luksOpen /dev/md/Sapana storage
|
||||||
mount /dev/mapper/storage /storage
|
mount /dev/mapper/storage /storage
|
||||||
echo "Storage partition mounted."
|
echo "Storage partition mounted."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#echo "Unlocking backup partition:"
|
echo "Starting services..."
|
||||||
# 4 TB HDD, partition #2
|
systemctl restart duplicacy-web.service
|
||||||
#cryptsetup luksOpen /dev/disk/by-uuid/8dc60329-d27c-4a4a-b76a-861b1e28400e backups --key-file /storage/backups_partition.key
|
systemctl restart airsonic.service forgejo.service
|
||||||
#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:"
|
|
||||||
systemctl --machine aires@.host --user start syncthing.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
|
exit 0
|
||||||
|
|
|
@ -63,6 +63,9 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Install additional packages
|
||||||
|
environment.systemPackages = [ pkgs.boinc ];
|
||||||
|
|
||||||
# Move files into target system
|
# Move files into target system
|
||||||
systemd.tmpfiles.rules = [
|
systemd.tmpfiles.rules = [
|
||||||
# Use gremlin user's monitor config for GDM (defined above)
|
# Use gremlin user's monitor config for GDM (defined above)
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 0bc545bf36759ca1ab67e2718bc5771eca72d02f
|
Subproject commit 9b1b7422848beee7137e74a18bf4f9551a1cf044
|
34
packages/airsonic-advanced.nix
Normal file
34
packages/airsonic-advanced.nix
Normal 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 ];
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in a new issue