Reorganization

This commit is contained in:
Lucas Thelen 2025-10-04 00:49:49 +00:00
parent 2821a76450
commit aa3b8519f9
21 changed files with 241 additions and 204 deletions

View file

@ -0,0 +1,25 @@
{ pkgs, ... }: {
users.users.lucas.extraGroups = [ "multimedia" ];
networking.firewall.allowedTCPPorts = [ 8083 ];
systemd.tmpfiles.rules = [
"d /data/calibre 0770 - multimedia - -"
"d /data/calibre/library 0770 - multimedia - -"
"d /data/calibre/config 0770 - multimedia - -"
];
services.calibre-web = {
enable = true;
listen = {
ip = "0.0.0.0";
port = 8083;
};
options = { calibreLibrary = "/data/calibre/library"; };
user = "calibre-web";
group = "multimedia";
};
environment.systemPackages = with pkgs; [ calibre ];
}

View file

@ -0,0 +1,18 @@
{ pkgs, ... }: {
services.forgejo = {
enable = true;
settings = {
server = {
ROOT_URL = "https://git.per-aspera.space";
HTTP_ADDR = "0.0.0.0";
HTTP_PORT = 3000;
SSH_DOMAIN = "git.per-aspera.space";
SSH_PORT = 2222;
};
service = { DISABLE_REGISTRATION = false; };
};
};
networking.firewall.allowedTCPPorts = [ 3000 2222 ];
}

View file

@ -0,0 +1,29 @@
# Jellyfin media server with Deluge torrent client
{ config, pkgs, ... }:
{
systemd.tmpfiles.rules = [
"d /data - - - - -"
"d /data/media 0770 - ${config.homelab.mediaGroup} - -"
"d /data/shows 0770 - ${config.homelab.mediaGroup} - -"
];
services.jellyfin = {
enable = true;
openFirewall = true;
group = config.homelab.mediaGroup;
};
environment.systemPackages = with pkgs; [
jellyfin
jellyfin-web
jellyfin-ffmpeg
];
services.deluge = {
enable = true;
web.enable = true;
web.openFirewall = true;
group = config.homelab.mediaGroup;
};
}

131
modules/services/site.nix Normal file
View file

@ -0,0 +1,131 @@
# Website hosting with Nginx reverse proxy and Route53 DDNS
{ config, pkgs, inputs, lib, ... }:
let
domain = config.homelab.domain;
hostedZoneId = config.homelab.aws.hostedZoneId;
# Configurable list of DNS records to update
dnsRecords = [
domain
"jellyfin.${domain}"
"git.${domain}"
# Add more records here as needed
# "api.${domain}"
# "mail.${domain}"
];
updateRoute53 = pkgs.writeShellScript "update-route53" ''
#!/usr/bin/env bash
set -euo pipefail
HOSTED_ZONE_ID="${hostedZoneId}"
DNS_RECORDS=(${lib.concatStringsSep " " (map lib.escapeShellArg dnsRecords)})
# Get current public IP
CURRENT_IP=$(${pkgs.curl}/bin/curl -s https://ifconfig.me)
# Validate IP format
if ! echo "$CURRENT_IP" | grep -qE '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$'; then
echo "[$(date)] ERROR: Invalid IP format: $CURRENT_IP" >&2
exit 1
fi
# Function to update a DNS record
update_record() {
local RECORD_NAME=$1
local DNS_IP=$(${pkgs.dig}/bin/dig +short "$RECORD_NAME" @8.8.8.8 | tail -n1)
if [ "$CURRENT_IP" != "$DNS_IP" ]; then
echo "[$(date)] $RECORD_NAME IP changed: $DNS_IP -> $CURRENT_IP"
${pkgs.awscli2}/bin/aws route53 change-resource-record-sets \
--hosted-zone-id "$HOSTED_ZONE_ID" \
--change-batch "{
\"Changes\": [{
\"Action\": \"UPSERT\",
\"ResourceRecordSet\": {
\"Name\": \"$RECORD_NAME\",
\"Type\": \"A\",
\"TTL\": 300,
\"ResourceRecords\": [{\"Value\": \"$CURRENT_IP\"}]
}
}]
}"
echo "[$(date)] $RECORD_NAME DNS updated successfully to $CURRENT_IP"
else
echo "[$(date)] $RECORD_NAME IP unchanged: $CURRENT_IP"
fi
}
# Update all configured records
for record in "''${DNS_RECORDS[@]}"; do
update_record "$record"
done
'';
in {
networking.firewall.allowedTCPPorts = [ 80 443 ];
services.nginx = {
enable = true;
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;
virtualHosts."${domain}" = {
forceSSL = true;
enableACME = true;
root = "${inputs.thelenlucas.packages.${pkgs.system}.default}";
};
virtualHosts."jellyfin.${domain}" = {
forceSSL = true;
enableACME = true;
locations."/" = { proxyPass = "http://localhost:8096"; };
};
virtualHosts."git.${domain}" = {
forceSSL = true;
enableACME = true;
locations."/" = { proxyPass = "http://localhost:3000"; };
};
# Local git access to avoid NAT hairpinning
virtualHosts."git.homelab" = {
locations."/" = { proxyPass = "http://localhost:3000"; };
};
};
security.acme = {
acceptTerms = true;
defaults.email = "thelenlucas@gmail.com";
};
environment.systemPackages = [ pkgs.awscli2 ];
systemd.services.route53-ddns = {
description = "Update Route 53 with current IP periodically";
after = [ "network-online.target" ];
wants = [ "network-online.target" ];
serviceConfig = {
Type = "oneshot";
ExecStart = updateRoute53;
};
};
systemd.timers.route53-ddns = {
description = "Route 53 DDNS Update Timer";
wantedBy = [ "timers.target" ];
timerConfig = {
OnBootSec = "1min";
OnUnitActiveSec = "5min";
Persistent = true;
};
};
}