Initial commit: Ultimate Notetaking, Sync & Backup System
A NixOS-based system for managing personal data across three tiers: - Tier 1: Configuration (shareable via git) - Tier 2: Syncable data (nb + Syncthing) - Tier 3: Large data (self-hosted services + backup) Includes: - NixOS modules for nb, Syncthing, backup (restic) - Server modules for Forgejo, Immich, Jellyfin - Helper scripts (usync, ustatus) - Comprehensive documentation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
145
modules/server/forgejo.nix
Normal file
145
modules/server/forgejo.nix
Normal file
@@ -0,0 +1,145 @@
|
||||
# Forgejo Module
|
||||
#
|
||||
# Self-hosted Git forge (GitHub/Gitea alternative).
|
||||
# Used for hosting private nb notebook repositories.
|
||||
#
|
||||
# Usage:
|
||||
# services.forgejo-managed.enable = true;
|
||||
# services.forgejo-managed.domain = "git.yourdomain.com";
|
||||
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.services.forgejo-managed;
|
||||
in {
|
||||
options.services.forgejo-managed = {
|
||||
enable = mkEnableOption "managed Forgejo git forge";
|
||||
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
description = "Domain name for Forgejo.";
|
||||
example = "git.example.com";
|
||||
};
|
||||
|
||||
httpPort = mkOption {
|
||||
type = types.port;
|
||||
default = 3000;
|
||||
description = "HTTP port for Forgejo (behind reverse proxy).";
|
||||
};
|
||||
|
||||
sshPort = mkOption {
|
||||
type = types.port;
|
||||
default = 2222;
|
||||
description = "SSH port for git operations.";
|
||||
};
|
||||
|
||||
stateDir = mkOption {
|
||||
type = types.str;
|
||||
default = "/var/lib/forgejo";
|
||||
description = "State directory for Forgejo data.";
|
||||
};
|
||||
|
||||
enableLFS = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Enable Git LFS support.";
|
||||
};
|
||||
|
||||
disableRegistration = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Disable open user registration.";
|
||||
};
|
||||
|
||||
adminEmail = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = "Admin email address.";
|
||||
};
|
||||
|
||||
appName = mkOption {
|
||||
type = types.str;
|
||||
default = "Forgejo";
|
||||
description = "Application name shown in UI.";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
services.forgejo = {
|
||||
enable = true;
|
||||
stateDir = cfg.stateDir;
|
||||
|
||||
settings = {
|
||||
DEFAULT = {
|
||||
APP_NAME = cfg.appName;
|
||||
};
|
||||
|
||||
server = {
|
||||
DOMAIN = cfg.domain;
|
||||
HTTP_PORT = cfg.httpPort;
|
||||
ROOT_URL = "https://${cfg.domain}/";
|
||||
SSH_PORT = cfg.sshPort;
|
||||
SSH_DOMAIN = cfg.domain;
|
||||
START_SSH_SERVER = true; # Built-in SSH server
|
||||
LFS_START_SERVER = cfg.enableLFS;
|
||||
};
|
||||
|
||||
service = {
|
||||
DISABLE_REGISTRATION = cfg.disableRegistration;
|
||||
REQUIRE_SIGNIN_VIEW = false; # Allow viewing public repos
|
||||
};
|
||||
|
||||
repository = {
|
||||
DEFAULT_PRIVATE = "private"; # New repos are private by default
|
||||
ENABLE_PUSH_CREATE_USER = true; # Allow creating repos via push
|
||||
};
|
||||
|
||||
"repository.upload" = {
|
||||
ENABLED = true;
|
||||
FILE_MAX_SIZE = 100; # MB
|
||||
MAX_FILES = 10;
|
||||
};
|
||||
|
||||
session = {
|
||||
PROVIDER = "file";
|
||||
COOKIE_SECURE = true; # Require HTTPS
|
||||
};
|
||||
|
||||
log = {
|
||||
LEVEL = "Info";
|
||||
};
|
||||
|
||||
# Security
|
||||
security = {
|
||||
INSTALL_LOCK = true; # Prevent web-based install
|
||||
MIN_PASSWORD_LENGTH = 12;
|
||||
};
|
||||
|
||||
mailer = mkIf (cfg.adminEmail != null) {
|
||||
ENABLED = true;
|
||||
FROM = cfg.adminEmail;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Open SSH port
|
||||
networking.firewall.allowedTCPPorts = [ cfg.sshPort ];
|
||||
|
||||
# Create backup for Forgejo data
|
||||
services.backup.paths = mkIf config.services.backup.enable [
|
||||
cfg.stateDir
|
||||
];
|
||||
|
||||
# Reverse proxy with Caddy (optional, can use nginx)
|
||||
# Uncomment if using Caddy:
|
||||
#
|
||||
# services.caddy = {
|
||||
# enable = true;
|
||||
# virtualHosts."${cfg.domain}".extraConfig = ''
|
||||
# reverse_proxy localhost:${toString cfg.httpPort}
|
||||
# '';
|
||||
# };
|
||||
};
|
||||
}
|
||||
93
modules/server/immich.nix
Normal file
93
modules/server/immich.nix
Normal file
@@ -0,0 +1,93 @@
|
||||
# Immich Module
|
||||
#
|
||||
# Self-hosted photo and video backup (Google Photos alternative).
|
||||
# For Tier 3 photo management.
|
||||
#
|
||||
# Note: Immich is complex and changes frequently. This module provides
|
||||
# a starting point but may need updates. Check NixOS options for latest.
|
||||
#
|
||||
# Usage:
|
||||
# services.immich-managed.enable = true;
|
||||
# services.immich-managed.domain = "photos.yourdomain.com";
|
||||
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.services.immich-managed;
|
||||
in {
|
||||
options.services.immich-managed = {
|
||||
enable = mkEnableOption "managed Immich photo service";
|
||||
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
description = "Domain name for Immich.";
|
||||
example = "photos.example.com";
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.port;
|
||||
default = 2283;
|
||||
description = "Port for Immich web interface.";
|
||||
};
|
||||
|
||||
mediaLocation = mkOption {
|
||||
type = types.str;
|
||||
default = "/var/lib/immich";
|
||||
description = "Location for storing photos and videos.";
|
||||
};
|
||||
|
||||
externalLibraryPaths = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = "Additional paths for external photo libraries.";
|
||||
example = [ "/mnt/photos/archive" ];
|
||||
};
|
||||
|
||||
enableMachineLearning = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Enable ML features (face recognition, search).";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
# Immich service (NixOS 24.05+)
|
||||
services.immich = {
|
||||
enable = true;
|
||||
port = cfg.port;
|
||||
mediaLocation = cfg.mediaLocation;
|
||||
|
||||
# Machine learning (optional, resource-intensive)
|
||||
machine-learning.enable = cfg.enableMachineLearning;
|
||||
|
||||
# Settings
|
||||
settings = {
|
||||
# Add any Immich-specific settings here
|
||||
# Check Immich docs for available options
|
||||
};
|
||||
};
|
||||
|
||||
# Ensure media directory exists with correct permissions
|
||||
systemd.tmpfiles.rules = [
|
||||
"d ${cfg.mediaLocation} 0755 immich immich -"
|
||||
] ++ (map (path: "d ${path} 0755 immich immich -") cfg.externalLibraryPaths);
|
||||
|
||||
# Backup Immich data
|
||||
services.backup.paths = mkIf config.services.backup.enable [
|
||||
cfg.mediaLocation
|
||||
"/var/lib/immich" # Database and config
|
||||
];
|
||||
|
||||
# Memory recommendation
|
||||
warnings = mkIf (cfg.enableMachineLearning && config.hardware.cpu.intel.updateMicrocode or false) [
|
||||
"Immich ML features benefit from GPU acceleration. Consider enabling CUDA or OpenCL."
|
||||
];
|
||||
|
||||
# Reverse proxy example (Caddy)
|
||||
# services.caddy.virtualHosts."${cfg.domain}".extraConfig = ''
|
||||
# reverse_proxy localhost:${toString cfg.port}
|
||||
# '';
|
||||
};
|
||||
}
|
||||
91
modules/server/jellyfin.nix
Normal file
91
modules/server/jellyfin.nix
Normal file
@@ -0,0 +1,91 @@
|
||||
# Jellyfin Module
|
||||
#
|
||||
# Self-hosted media server (Plex alternative).
|
||||
# For Tier 3 media streaming.
|
||||
#
|
||||
# Usage:
|
||||
# services.jellyfin-managed.enable = true;
|
||||
# services.jellyfin-managed.domain = "media.yourdomain.com";
|
||||
# services.jellyfin-managed.mediaLibraries = [ "/mnt/media/movies" "/mnt/media/tv" ];
|
||||
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.services.jellyfin-managed;
|
||||
in {
|
||||
options.services.jellyfin-managed = {
|
||||
enable = mkEnableOption "managed Jellyfin media server";
|
||||
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
description = "Domain name for Jellyfin.";
|
||||
example = "media.example.com";
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.port;
|
||||
default = 8096;
|
||||
description = "HTTP port for Jellyfin.";
|
||||
};
|
||||
|
||||
mediaLibraries = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = "Paths to media libraries.";
|
||||
example = [ "/mnt/media/movies" "/mnt/media/tv" "/mnt/media/music" ];
|
||||
};
|
||||
|
||||
enableHardwareAcceleration = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Enable hardware transcoding (requires compatible GPU).";
|
||||
};
|
||||
|
||||
openFirewall = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Open firewall for Jellyfin ports.";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
services.jellyfin = {
|
||||
enable = true;
|
||||
openFirewall = cfg.openFirewall;
|
||||
};
|
||||
|
||||
# Give jellyfin access to media directories
|
||||
systemd.services.jellyfin.serviceConfig.SupplementaryGroups = [
|
||||
"render" # For hardware acceleration
|
||||
"video" # For hardware acceleration
|
||||
];
|
||||
|
||||
# Ensure media directories have correct permissions
|
||||
systemd.tmpfiles.rules = map (path:
|
||||
"d ${path} 0755 jellyfin jellyfin -"
|
||||
) cfg.mediaLibraries;
|
||||
|
||||
# Hardware acceleration (Intel VAAPI example)
|
||||
hardware.graphics = mkIf cfg.enableHardwareAcceleration {
|
||||
enable = true;
|
||||
extraPackages = with pkgs; [
|
||||
intel-media-driver # For Intel
|
||||
# nvidia-vaapi-driver # For NVIDIA
|
||||
libva
|
||||
];
|
||||
};
|
||||
|
||||
# Note: For hardware acceleration, jellyfin user needs access to /dev/dri
|
||||
users.users.jellyfin.extraGroups = mkIf cfg.enableHardwareAcceleration [
|
||||
"render"
|
||||
"video"
|
||||
];
|
||||
|
||||
# Reverse proxy example
|
||||
# services.caddy.virtualHosts."${cfg.domain}".extraConfig = ''
|
||||
# reverse_proxy localhost:${toString cfg.port}
|
||||
# '';
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user