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]] - [[#step-2-updating-sops-and-re-encrypting-secrets][Step 2: Updating SOPS and Re-encrypting Secrets]]
- [[#optional-nixos-modules][Optional NixOS Modules]] - [[#optional-nixos-modules][Optional NixOS Modules]]
- [[#reverse-proxies][Reverse Proxies]] - [[#reverse-proxies][Reverse Proxies]]
- [[#file-servers][File Servers]]
- [[#notes-and-configuration-details][Notes and Configuration Details]] - [[#notes-and-configuration-details][Notes and Configuration Details]]
- [[#disko-configuration-for-proxmox-mbr-boot][Disko Configuration for Proxmox (MBR Boot)]] - [[#disko-configuration-for-proxmox-mbr-boot][Disko Configuration for Proxmox (MBR Boot)]]
- [[#generating-hardware-configuration][Generating Hardware Configuration]] - [[#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 ** Reverse Proxies
The following modules can be enabled to provide a reverse proxy. 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 *** NGINX
The initial switch to this configuration may be slow as it waits for ACME to issue SSL certificates. 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 #+end_src
*** Traefik *** Traefik
This module is currently considered to be in a broken state.
#+begin_src nix #+begin_src nix
dov = { dov = {
# Reverse Proxy # Reverse Proxy
@@ -138,6 +138,14 @@ dov = {
}; };
#+end_src #+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 *** Caddy
#+begin_src nix #+begin_src nix
dov = { dov = {
@@ -148,6 +156,22 @@ dov = {
}; };
#+end_src #+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 * Notes and Configuration Details
** Disko Configuration for Proxmox (MBR Boot) ** 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. 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 #+end_src
* TODOs * 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. - [ ] 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. - [ ] 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. - [ ] 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 disko.nixosModules.disko
home-manager.nixosModules.home-manager home-manager.nixosModules.home-manager
sops-nix.nixosModules.sops sops-nix.nixosModules.sops
inputs.copyparty.nixosModules.default
./main ./main
./modules ./modules
+4 -2
View File
@@ -137,7 +137,7 @@ in {
# Reverse Proxy # Reverse Proxy
reverse-proxy = { reverse-proxy = {
nginx.enable = false; # TODO does not work for some reason 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 caddy.enable = false; # TODO has issues retrieving certificate from duckdns
}; };
@@ -148,7 +148,9 @@ in {
social.matrix.enable = false; # TODO does not work :) 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! # 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] 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] 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] 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: sops:
age: age:
- recipient: age19wvqtn4ju6k4vs8fxr34unl6xx4cv04jw0lx9ps20xlde927zfssgl4qke - recipient: age19wvqtn4ju6k4vs8fxr34unl6xx4cv04jw0lx9ps20xlde927zfssgl4qke
@@ -31,7 +35,7 @@ sops:
NHdWQnlGbk43WS80VDkxV0o4TE5uSUUK0WSdFzR3u0pLUYHXaTMrtBm0sKKe9ZPG NHdWQnlGbk43WS80VDkxV0o4TE5uSUUK0WSdFzR3u0pLUYHXaTMrtBm0sKKe9ZPG
nF90b/jv66WGIH1n2oFaaohCkd7DZGzSpr0+KsqX6pkszYnp39YC5A== nF90b/jv66WGIH1n2oFaaohCkd7DZGzSpr0+KsqX6pkszYnp39YC5A==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
lastmodified: "2025-07-26T21:14:39Z" lastmodified: "2025-07-27T18:42:07Z"
mac: ENC[AES256_GCM,data:76/u+mXqsYQA0Y5rcUskN2Uh8nCKyZxPk3yLd4F/zXnfOe6eqLBAfwvZ2XGu1Y+KQEMidSvrd+7WJ9bPHFxbftglIIeU8NxdXqgQZrH2Bx6kMgGzSR72IzYOJvl5rPsYa3mjRIcaBdyE7oo3ZSQctHlf40zEaTNesNgjVPgvWhs=,iv:yYq5knPV7JdvnkC18/MFg1/6W1cx2d7zAtRCe/C2Txg=,tag:jc7grjZajT2TH3TzLVQ82Q==,type:str] mac: ENC[AES256_GCM,data:EP1ziiWZ3hPCbjLtPdLccL4csnNmLqtQkhwn8x5bwXuqIU9Q8U6+nXIorAG2Ck28hyjnAjHyYMbJcSSrNOVHroA5Xnlps65975WuKe3akNF6n6Nz+gTDQgEzIpxwYD2rEFNutCNN4EhESzh13lvsvdkxTCsFLjZzwQ4DSuVId24=,iv:f2jM71VXiShEkTUOtfONhMIeR6JnC3xpUN2zXJvdDLo=,tag:s62lb8GtrHHBj6ferphGog==,type:str]
unencrypted_suffix: _unencrypted unencrypted_suffix: _unencrypted
version: 3.10.2 version: 3.10.2
+1
View File
@@ -6,5 +6,6 @@
./virtualisation ./virtualisation
./social ./social
./file-server ./file-server
./samba
]; ];
} }
+87 -10
View File
@@ -1,19 +1,96 @@
{ config, lib, pkgs, ... }: { config, lib, pkgs, inputs, ... }:
with lib; with lib;
let let cfg = config.dov.file-server.copyparty;
cfg = config.dov.file-server.copyparty;
in { in {
options.dov.file-server.copyparty = { enable = mkEnableOption "copyparty config"; }; options.dov.file-server.copyparty = {
enable = mkEnableOption "copyparty config";
};
config = mkIf cfg.enable { config = mkIf cfg.enable {
# # add the copyparty overlay to expose the package to the module networking.firewall.allowedTCPPorts = config.services.copyparty.settings.p;
# nixpkgs.overlays = [ copyparty.overlays.default ];
# # (optional) install the package globally sops.secrets."copyparty/admin_password" = {
# environment.systemPackages = [ pkgs.copyparty ]; owner = "copyparty";
# # configure the copyparty module group = "copyparty";
# services.copyparty.enable = cfg.enable; };
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 let
cfg = config.dov.reverse-proxy.traefik; cfg = config.dov.reverse-proxy.traefik;
domain = "susano-nixos.duckdns.org";
configFile = pkgs.writeText "duckdns-options" configFile = pkgs.writeText "duckdns-options"
'' ''
DUCKDNS_PROPAGATION_TIMEOUT=120 DUCKDNS_PROPAGATION_TIMEOUT=120
@@ -71,17 +72,24 @@ in {
routers = { routers = {
# --- Router for the Traefik dashboard (optional) --- # --- Router for the Traefik dashboard (optional) ---
dashboard-router = { 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" ]; entryPoints = [ "websecure" ];
service = "api@internal"; # Special service for the dashboard service = "api@internal"; # Special service for the dashboard
tls.certResolver = "duckdns"; tls.certResolver = "duckdns";
}; };
immich-router = { immich-router = {
rule = "Host(`immich.susano-test.duckdns.org`)"; # 1. The new domain rule = "Host(`immich.${domain}`)";
entryPoints = [ "websecure" ]; # 2. Listen on HTTPS entryPoints = [ "websecure" ];
service = "immich-service"; # 3. Link to the new Immich service service = "immich-service";
tls.certResolver = "duckdns"; # 4. Use the same SSL resolver 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"; } { 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 = { 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"];
};
};
}