Added copyparty+samba module, updated traefik

This commit is contained in:
Alexander Derevianko
2025-07-27 20:54:12 +02:00
parent db3c5bf12c
commit 84a20fa695
8 changed files with 176 additions and 22 deletions
+27 -3
View File
@@ -40,6 +40,7 @@ This guide documents the process for a minimal installation of NixOS on a Proxmo
- [[#step-2-updating-sops-and-re-encrypting-secrets][Step 2: Updating SOPS and Re-encrypting Secrets]]
- [[#optional-nixos-modules][Optional NixOS Modules]]
- [[#reverse-proxies][Reverse Proxies]]
- [[#file-servers][File Servers]]
- [[#notes-and-configuration-details][Notes and Configuration Details]]
- [[#disko-configuration-for-proxmox-mbr-boot][Disko Configuration for Proxmox (MBR Boot)]]
- [[#generating-hardware-configuration][Generating Hardware Configuration]]
@@ -114,7 +115,7 @@ The new AGE key must be added to your =.sops.yaml= configuration file. This allo
** Reverse Proxies
The following modules can be enabled to provide a reverse proxy.
*Note:* Currently, none of the available reverse proxy modules (NGINX, Traefik, Caddy) are functional. This is a known issue that needs to be investigated.
*Note:* Previously, all reverse proxy modules were considered non-functional. Recent troubleshooting has provided a fix for Traefik, but the other modules may still have issues.
*** NGINX
The initial switch to this configuration may be slow as it waits for ACME to issue SSL certificates.
@@ -128,7 +129,6 @@ dov = {
#+end_src
*** Traefik
This module is currently considered to be in a broken state.
#+begin_src nix
dov = {
# Reverse Proxy
@@ -138,6 +138,14 @@ dov = {
};
#+end_src
**** Troubleshooting Traefik ACME with DuckDNS
- *Context:* Issues getting an ACME certificate from DuckDNS with Traefik.
- *Roadblock:* The process was failing, but eventually succeeded.
- *Possible Solutions:*
- Setting =disablePropagationCheck = true;= for the DNS challenge.
- Extending the =delay= for the DNS challenge.
- *Notes:* It's unclear which specific option resolved the issue, but one of them, or a combination, allowed the certificate to be obtained. The first time Traefik tries to get a certificate it might fail, and a restart of the service is needed. After some time, the Let's Encrypt certificate will be received.
*** Caddy
#+begin_src nix
dov = {
@@ -148,6 +156,22 @@ dov = {
};
#+end_src
** File Servers
*** copyparty
Provides a web-based file manager.
#+begin_src nix
dov = {
file-server.copyparty.enable = true;
};
#+end_src
*Dependency:* For =copyparty= to function correctly in this configuration, it requires a Samba share to be mounted to the path =/MEDIA=. Therefore, the =samba= module must also be enabled:
#+begin_src nix
dov = {
samba.enable = true;
};
#+end_src
* Notes and Configuration Details
** Disko Configuration for Proxmox (MBR Boot)
A critical requirement for ensuring a NixOS VM can boot correctly in Proxmox is the disk partition scheme. Proxmox expects a Master Boot Record (MBR) compatible setup.
@@ -194,7 +218,7 @@ nix run github:nix-community/nixos-anywhere -- \
#+end_src
* TODOs
- [ ] Investigate and fix the issue preventing any of the reverse proxy modules (NGINX, Traefik, Caddy) from working correctly.
- [ ] Investigate and fix remaining issues with reverse proxy modules (NGINX, Caddy).
- [ ] Troubleshoot and fix an issue that occurs when reloading the NixOS configuration remotely, which breaks the SSH pipe and requires entering the root password three times.
- [ ] Investigate and resolve the issue where updating a user's password declaratively using a secret managed by =sops= failed after the initial installation.
- [ ] Refactor the =disko= configuration to make the disk device name (e.g., =/dev/sda=) a variable. This will avoid hardcoding the value and make the configuration more portable.
+1
View File
@@ -51,6 +51,7 @@
disko.nixosModules.disko
home-manager.nixosModules.home-manager
sops-nix.nixosModules.sops
inputs.copyparty.nixosModules.default
./main
./modules
+4 -2
View File
@@ -137,7 +137,7 @@ in {
# Reverse Proxy
reverse-proxy = {
nginx.enable = false; # TODO does not work for some reason
traefik.enable = true; # TODO has issues retrieving certificate from duckdns
traefik.enable = true;
caddy.enable = false; # TODO has issues retrieving certificate from duckdns
};
@@ -148,7 +148,9 @@ in {
social.matrix.enable = false; # TODO does not work :)
file-server.copyparty.enable = false;
file-server.copyparty.enable = true;
samba.enable = true;
};
# DO NOT CHANGE AT ANY POINT!
+6 -2
View File
@@ -11,6 +11,10 @@ example_booleans:
user_password: ENC[AES256_GCM,data:Q7rk67ylyjr5Sa+AYCxnQAPLbBP5Fy85wTGLZuqxBG3iJ+MmhEgfeatVA2tcsY7GSaU/vghny+TJtrvhDYYMqa10h/F0wPxUjId78qkhKbnRQs4mqAxA9heSi4ojp1kh/pXN7tj64wNyJA==,iv:FTUojVNz78tn/Uj1N8Oj5Iov9eEMRo5vz+mqHdewxjg=,tag:YF74hLXXUby0IjHrqdkBUQ==,type:str]
duckdns-token: ENC[AES256_GCM,data:Gf3kIpOO/X+ZVXV4w71Fp5qMuNedBBoobazAFpp22RC70xKb6xsJVffWdtFq0blDe5Y=,iv:SNq6wnhG6CuDwB3NQ/PryTgY3U/J2g1XfGCW7gSEYbo=,tag:MWqhrJRreGZ/SaapAaCXQA==,type:str]
matrix_secret: ENC[AES256_GCM,data:U1yPFsFeLA5tbFf/MMACrhmH/32zUMUg2HOHWdAtcm+ybg9KgjhQmbGDM/MTDoRaAa+Zqfs774gz3A6Rg4HLuvCr4cPotSCHH8qRPz+UDK4Bvf305EfLP22Rrhc=,iv:A9BSgw1hHg+y8x4GC4hWNBCaYZNlRfS1+jKKv38znXg=,tag:SkwEfez7TRhFuLEL4PkvZA==,type:str]
copyparty:
admin_password: ENC[AES256_GCM,data:VlHcQB1Z1/wSUi8yCEpcW+i8h3c=,iv:mystE6THTS50LzV/TPm+QtZ1C87Vxtx+W9jVzcGAnSM=,tag:8nxtbklHwJnI7VHjJA55dQ==,type:str]
alex_password: ENC[AES256_GCM,data:0X5AZH8tqJRd6er5w3oMaWI0jrE=,iv:/2aLquP4LVCKCozJsMGItqX9+L9pxSM4PRpn6QnDzbE=,tag:b1GRHEBwQNYBtERj1xqjoA==,type:str]
smb-secrets: ENC[AES256_GCM,data:RW8xaGU94jxE/iTocH3ylCP5uIpmnSg/MQDC+e5i9PhvlsNY+kfUiqQHoDXETgEPmNUbLr2qZSMLPhQ=,iv:5vkw0Qfa7UHYZ2ODOvFZgirehpY7muV6fvjWHAyHMu4=,tag:cuEzibaBZVf5HVlAF2xUIA==,type:str]
sops:
age:
- recipient: age19wvqtn4ju6k4vs8fxr34unl6xx4cv04jw0lx9ps20xlde927zfssgl4qke
@@ -31,7 +35,7 @@ sops:
NHdWQnlGbk43WS80VDkxV0o4TE5uSUUK0WSdFzR3u0pLUYHXaTMrtBm0sKKe9ZPG
nF90b/jv66WGIH1n2oFaaohCkd7DZGzSpr0+KsqX6pkszYnp39YC5A==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2025-07-26T21:14:39Z"
mac: ENC[AES256_GCM,data:76/u+mXqsYQA0Y5rcUskN2Uh8nCKyZxPk3yLd4F/zXnfOe6eqLBAfwvZ2XGu1Y+KQEMidSvrd+7WJ9bPHFxbftglIIeU8NxdXqgQZrH2Bx6kMgGzSR72IzYOJvl5rPsYa3mjRIcaBdyE7oo3ZSQctHlf40zEaTNesNgjVPgvWhs=,iv:yYq5knPV7JdvnkC18/MFg1/6W1cx2d7zAtRCe/C2Txg=,tag:jc7grjZajT2TH3TzLVQ82Q==,type:str]
lastmodified: "2025-07-27T18:42:07Z"
mac: ENC[AES256_GCM,data:EP1ziiWZ3hPCbjLtPdLccL4csnNmLqtQkhwn8x5bwXuqIU9Q8U6+nXIorAG2Ck28hyjnAjHyYMbJcSSrNOVHroA5Xnlps65975WuKe3akNF6n6Nz+gTDQgEzIpxwYD2rEFNutCNN4EhESzh13lvsvdkxTCsFLjZzwQ4DSuVId24=,iv:f2jM71VXiShEkTUOtfONhMIeR6JnC3xpUN2zXJvdDLo=,tag:s62lb8GtrHHBj6ferphGog==,type:str]
unencrypted_suffix: _unencrypted
version: 3.10.2
+1
View File
@@ -6,5 +6,6 @@
./virtualisation
./social
./file-server
./samba
];
}
+87 -10
View File
@@ -1,19 +1,96 @@
{ config, lib, pkgs, ... }:
{ config, lib, pkgs, inputs, ... }:
with lib;
let
cfg = config.dov.file-server.copyparty;
let cfg = config.dov.file-server.copyparty;
in {
options.dov.file-server.copyparty = { enable = mkEnableOption "copyparty config"; };
options.dov.file-server.copyparty = {
enable = mkEnableOption "copyparty config";
};
config = mkIf cfg.enable {
# # add the copyparty overlay to expose the package to the module
# nixpkgs.overlays = [ copyparty.overlays.default ];
# # (optional) install the package globally
# environment.systemPackages = [ pkgs.copyparty ];
# # configure the copyparty module
# services.copyparty.enable = cfg.enable;
networking.firewall.allowedTCPPorts = config.services.copyparty.settings.p;
sops.secrets."copyparty/admin_password" = {
owner = "copyparty";
group = "copyparty";
};
sops.secrets."copyparty/alex_password" = {
owner = "copyparty";
group = "copyparty";
};
# add the copyparty overlay to expose the package to the module
nixpkgs.overlays = [ inputs.copyparty.overlays.default ];
# (optional) install the package globally
environment.systemPackages = [ pkgs.copyparty ];
# configure the copyparty module
services.copyparty = {
enable = cfg.enable;
settings = {
p = [ 3923 ];
e2dsa = true; # enable file indexing and filesystem scanning
e2ts = true; # and enable multimedia indexing
z = true; # and zeroconf
qr = true; # and qrcode (you can comma-separate arguments)
};
accounts = {
admin.passwordFile = "/run/secrets/copyparty/admin_password";
alex.passwordFile = "/run/secrets/copyparty/alex_password";
};
# create a volume
volumes = {
"/" = {
# share the contents of "/MEDIA"
path = "/";
# see `copyparty --help-accounts` for available options
access = {
# everyone gets read-access, but
r = [ "admin" "alex" ];
# users "ed" and "k" get read-write
rw = [ "admin" ];
};
# see `copyparty --help-flags` for available options
flags = {
# "fk" enables filekeys (necessary for upget permission) (4 chars long)
fk = 4;
# scan for new files every 60sec
scan = 60;
# volflag "e2d" enables the uploads database
e2d = true;
# "d2t" disables multimedia parsers (in case the uploads are malicious)
d2t = true;
# skips hashing file contents if path matches *.iso
nohash = ".iso$";
};
};
"/MEDIA" = {
# share the contents of "/MEDIA"
path = "/MEDIA";
# see `copyparty --help-accounts` for available options
access = {
# everyone gets read-access, but
r = "alex";
# users "ed" and "k" get read-write
rw = [ "admin" "alex" ];
};
# see `copyparty --help-flags` for available options
flags = {
# "fk" enables filekeys (necessary for upget permission) (4 chars long)
fk = 4;
# scan for new files every 60sec
scan = 60;
# volflag "e2d" enables the uploads database
e2d = true;
# "d2t" disables multimedia parsers (in case the uploads are malicious)
d2t = true;
# skips hashing file contents if path matches *.iso
nohash = ".iso$";
};
};
};
};
};
}
+20 -5
View File
@@ -4,6 +4,7 @@ with lib;
let
cfg = config.dov.reverse-proxy.traefik;
domain = "susano-nixos.duckdns.org";
configFile = pkgs.writeText "duckdns-options"
''
DUCKDNS_PROPAGATION_TIMEOUT=120
@@ -71,17 +72,24 @@ in {
routers = {
# --- Router for the Traefik dashboard (optional) ---
dashboard-router = {
rule = "Host(`traefik.susano-test.duckdns.org`)"; # Example: A local-only subdomain
rule = "Host(`traefik.${domain}`)"; # Example: A local-only subdomain
entryPoints = [ "websecure" ];
service = "api@internal"; # Special service for the dashboard
tls.certResolver = "duckdns";
};
immich-router = {
rule = "Host(`immich.susano-test.duckdns.org`)"; # 1. The new domain
entryPoints = [ "websecure" ]; # 2. Listen on HTTPS
service = "immich-service"; # 3. Link to the new Immich service
tls.certResolver = "duckdns"; # 4. Use the same SSL resolver
rule = "Host(`immich.${domain}`)";
entryPoints = [ "websecure" ];
service = "immich-service";
tls.certResolver = "duckdns";
};
copyparty = mkIf config.dov.file-server.copyparty.enable {
rule = "Host(`copyparty.${domain}`)";
entryPoints = [ "websecure" ];
service = "copyparty-service";
tls.certResolver = "duckdns";
};
};
@@ -92,6 +100,13 @@ in {
{ url = "http://192.168.1.57:2283"; }
];
};
copyparty-service = mkIf config.dov.file-server.copyparty.enable {
loadBalancer.servers = [
# The backend URL for Immich
{ url = "http://192.168.1.85:3923"; }
];
};
};
middlewares = {
+30
View File
@@ -0,0 +1,30 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.dov.samba;
ip = "192.168.1.88";
in {
options.dov.samba = {
enable = mkEnableOption "samba share config";
};
config = mkIf cfg.enable {
sops.secrets.smb-secrets = {
};
environment.systemPackages = [ pkgs.cifs-utils ];
fileSystems."/MEDIA" = {
device = "//${ip}/MEDIA";
fsType = "cifs";
options = let
# this line prevents hanging on network split
automount_opts = "x-systemd.automount,noauto,x-systemd.idle-timeout=60,x-systemd.device-timeout=5s,x-systemd.mount-timeout=5s";
in ["${automount_opts},credentials=/run/secrets/smb-secrets"];
};
};
}