Rebase to flake parts #9
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
{ config, ... }: {
|
||||
sops = {
|
||||
templates."atticd.env" = {
|
||||
owner = "root";
|
||||
group = "root";
|
||||
mode = "0400";
|
||||
content = ''
|
||||
ATTIC_SERVER_TOKEN_RS256_SECRET_BASE64=${config.sops.placeholder."attic/server-token-rs256-secret-base64"}
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
sops.secrets."attic/server-token-rs256-secret-base64" = {
|
||||
sopsFile = ../../../../secrets/attic-secrets.yaml;
|
||||
owner = "root";
|
||||
group = "root";
|
||||
mode = "0400";
|
||||
};
|
||||
|
||||
services.atticd = {
|
||||
enable = true;
|
||||
environmentFile = config.sops.templates."atticd.env".path;
|
||||
settings = {
|
||||
listen = "[::]:8080";
|
||||
jwt = { };
|
||||
};
|
||||
};
|
||||
|
||||
chiasson.system.networking.firewall.allowedTCPPorts = [ 8080 ];
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
# DDRM Flask backend (Widevine / PlayReady decrypt). Extension URL: http://<host>:58239
|
||||
{ pkgs, inputs, ... }:
|
||||
{
|
||||
services.ddrm-media-server = {
|
||||
enable = true;
|
||||
port = 58239;
|
||||
listenAddress = "0.0.0.0";
|
||||
openFirewall = true;
|
||||
package = inputs.ddrm.packages.${pkgs.stdenv.hostPlatform.system}.default;
|
||||
# State: /var/lib/ddrm-media (venv + configs + CDMs on first run — needs network for pip).
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{ ... }:
|
||||
{
|
||||
# FlareSolverr (Cloudflare / JS challenge solver for some indexers).
|
||||
# Typically used by Prowlarr as an HTTP proxy.
|
||||
#
|
||||
# UI/endpoint: http://<host>:8191
|
||||
services.flaresolverr.enable = true;
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ 8191 ];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
{ config, ... }:
|
||||
let
|
||||
secretFilePath = ../secrets.yaml;
|
||||
in
|
||||
{
|
||||
sops.secrets."immich/database-password".sopsFile = secretFilePath;
|
||||
|
||||
# Placeholders are expanded only inside template `content` (not in arbitrary Nix strings).
|
||||
sops.templates."immich-db.env" = {
|
||||
content = ''
|
||||
POSTGRES_PASSWORD=${config.sops.placeholder."immich/database-password"}
|
||||
DB_PASSWORD=${config.sops.placeholder."immich/database-password"}
|
||||
'';
|
||||
};
|
||||
|
||||
chiasson.system.services.immich = {
|
||||
enable = true;
|
||||
host = "0.0.0.0";
|
||||
port = 2283;
|
||||
timezone = "America/Moncton";
|
||||
uploadLocation = "/var/lib/immich/library";
|
||||
environmentFiles = [ config.sops.templates."immich-db.env".path ];
|
||||
postgres = {
|
||||
user = "postgres";
|
||||
#password = ""; # Defined in sops.templates."immich-db.env"
|
||||
database = "immich";
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
# NFS read-only mount of nixdesk (14900k) bulk storage for extra Jellyfin libraries.
|
||||
# Source: ssh inventory hostName for 14900k. Export is defined in
|
||||
# modules/hosts/14900k/_private/jellyfin-nfs-export.nix
|
||||
#
|
||||
# In Jellyfin (in addition to local /var/lib/media/...), add e.g.:
|
||||
# Movies → /mnt/nixdesk-jellyfin/movies
|
||||
# Shows → /mnt/nixdesk-jellyfin/tv
|
||||
{ ... }:
|
||||
let
|
||||
# Must match LAN IP of the NFS server (flake `sshInventory` → hosts."14900k".hostName).
|
||||
nfsExportHost = "192.168.2.25";
|
||||
in
|
||||
{
|
||||
fileSystems."/mnt/nixdesk-jellyfin" = {
|
||||
device = "${nfsExportHost}:/mnt/test/jellyfin";
|
||||
fsType = "nfs";
|
||||
options = [
|
||||
"rw"
|
||||
"noatime"
|
||||
"nofail"
|
||||
"_netdev"
|
||||
"x-systemd.automount"
|
||||
"x-systemd.idle-timeout=600"
|
||||
];
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
# Jellyfin (native NixOS service). Local media: /var/lib/media (group `media`; jellyfin + server).
|
||||
# Dashboard: Movies → /var/lib/media/movies, Shows → /var/lib/media/tv (see jellyfin-remote-storage.nix
|
||||
# for bulk libraries on nixdesk at /mnt/nixdesk-jellyfin/{movies,tv}).
|
||||
# Do not use "Mixed Movies and Shows" (deprecated): https://jellyfin.org/docs/general/server/media/mixed-movies-and-shows
|
||||
# Dedicated disk: fileSystems."/var/lib/media" in hardware.nix, then fix ownership.
|
||||
{ lib, ... }:
|
||||
{
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
jellyfin-web = prev.jellyfin-web.overrideAttrs (oldAttrs: {
|
||||
postInstall =
|
||||
(oldAttrs.postInstall or "")
|
||||
+ ''
|
||||
# Blank default Jellyfin banner assets (read-only store otherwise). Wildcards
|
||||
# track hashed filenames across jellyfin-web releases; bump if layout changes.
|
||||
find "$out" -type f \( -name 'banner-light.*.png' -o -name 'banner-dark.*.png' \) \
|
||||
-exec truncate -s 0 {} \;
|
||||
'';
|
||||
});
|
||||
})
|
||||
];
|
||||
|
||||
users.groups.media = { };
|
||||
|
||||
users.users.jellyfin.extraGroups = [ "media" ];
|
||||
users.users.server.extraGroups = [ "media" ];
|
||||
|
||||
systemd.tmpfiles.settings."nix-server-var-lib-media" = {
|
||||
"/var/lib/media"."d" = {
|
||||
mode = "0775";
|
||||
user = "root";
|
||||
group = "media";
|
||||
};
|
||||
"/var/lib/media/movies"."d" = {
|
||||
mode = "0775";
|
||||
user = "root";
|
||||
group = "media";
|
||||
};
|
||||
"/var/lib/media/tv"."d" = {
|
||||
mode = "0775";
|
||||
user = "root";
|
||||
group = "media";
|
||||
};
|
||||
};
|
||||
|
||||
services.jellyfin = {
|
||||
enable = true;
|
||||
openFirewall = true;
|
||||
};
|
||||
|
||||
# `users.users.jellyfin.extraGroups` does not affect systemd; the service must list
|
||||
# supplementary groups explicitly. Without `media`, directories mode 775 root:media are
|
||||
# not writable by uid jellyfin (it only had group `jellyfin`), so deletes fail.
|
||||
systemd.services.jellyfin.serviceConfig = {
|
||||
SupplementaryGroups = [ "media" ];
|
||||
# Jellyfin libraries may live on NFS (e.g. /mnt/nixdesk-jellyfin). PrivateUsers breaks
|
||||
# uid mapping for NFS auth in practice; disable so deletes use the real host jellyfin uid.
|
||||
PrivateUsers = lib.mkForce false;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
# Organizr — homelab dashboard (Docker). UI: http://<host>:8888
|
||||
# Official image: https://github.com/organizr/docker-organizr
|
||||
#
|
||||
# Wizard errors like "API … /default/ not writable" are almost always host permissions on
|
||||
# `/var/lib/organizr`: the first container run may leave root-owned files under `/config`.
|
||||
{ lib, pkgs, ... }:
|
||||
{
|
||||
users.groups.organizr = { gid = 950; };
|
||||
users.users.organizr = {
|
||||
isSystemUser = true;
|
||||
uid = 950;
|
||||
group = "organizr";
|
||||
};
|
||||
|
||||
systemd.tmpfiles.settings."nix-server-organizr-config" = {
|
||||
"/var/lib/organizr"."d" = {
|
||||
mode = "0755";
|
||||
user = "organizr";
|
||||
group = "organizr";
|
||||
};
|
||||
};
|
||||
|
||||
# Recursively reset ownership (handles root-owned files from an earlier container run).
|
||||
systemd.tmpfiles.settings."nix-server-organizr-config-perms" = {
|
||||
"/var/lib/organizr"."Z" = {
|
||||
mode = "0755";
|
||||
user = "organizr";
|
||||
group = "organizr";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.docker-organizr.preStart = lib.mkBefore ''
|
||||
${pkgs.coreutils}/bin/mkdir -p /var/lib/organizr
|
||||
${pkgs.coreutils}/bin/chown -R organizr:organizr /var/lib/organizr
|
||||
'';
|
||||
|
||||
virtualisation.oci-containers.containers.organizr = {
|
||||
image = "ghcr.io/organizr/organizr:latest";
|
||||
ports = [ "8888:80" ];
|
||||
volumes = [
|
||||
"/var/lib/organizr:/config"
|
||||
];
|
||||
environment = {
|
||||
PUID = "950";
|
||||
PGID = "950";
|
||||
TZ = "America/Moncton";
|
||||
# v2-master / master are stable v2; optional override:
|
||||
# branch = "v2-master";
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ 8888 ];
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{config, ...}: {
|
||||
virtualisation = {
|
||||
docker.enable = true;
|
||||
oci-containers = {
|
||||
backend = "docker";
|
||||
containers = {
|
||||
portainer = {
|
||||
image = "portainer/portainer-ce:latest";
|
||||
ports = [ "9443:9443" ];
|
||||
volumes = [
|
||||
"/var/run/docker.sock:/var/run/docker.sock"
|
||||
"/var/lib/portainer:/data"
|
||||
];
|
||||
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
networking.firewall.allowedTCPPorts = [ 9443 ];
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{ lib, ... }:
|
||||
{
|
||||
# Prowlarr (indexer manager). UI: http://<host>:9696
|
||||
# Data dir is /var/lib/prowlarr (see systemd unit ExecStart -data=…), not ~/.config/Prowlarr.
|
||||
services.prowlarr.enable = true;
|
||||
|
||||
# Useful when Prowlarr/Sonarr/Radarr need to write into shared areas (downloads, etc.).
|
||||
users.groups.prowlarr = { };
|
||||
users.users.prowlarr = {
|
||||
isSystemUser = true;
|
||||
group = "prowlarr";
|
||||
extraGroups = [ "media" ];
|
||||
};
|
||||
|
||||
systemd.services.prowlarr.preStart = lib.mkBefore ''
|
||||
mkdir -p /var/lib/prowlarr/Definitions/Custom
|
||||
ln -sf ${./prowlarr/torrent9-custom.yml} /var/lib/prowlarr/Definitions/Custom/torrent9-custom.yml
|
||||
'';
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ 9696 ];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
---
|
||||
id: torrent9-custom
|
||||
name: Torrent9 (Custom URL)
|
||||
description: "Torrent9 is a FRENCH Public site for MOVIES / TV / GENERAL"
|
||||
language: fr-FR
|
||||
type: public
|
||||
encoding: UTF-8
|
||||
followredirect: true
|
||||
testlinktorrent: false
|
||||
links:
|
||||
- https://www.torrent9.club/
|
||||
- https://www6.torrent9.to/
|
||||
legacylinks:
|
||||
- https://www.torrent9.pl/ # this is a proxy for torrent9clone
|
||||
- https://torrent9.black-mirror.xyz/ # this is a proxy for torrent9clone
|
||||
- https://torrent9.unblocked.casa/ # this is a proxy for torrent9clone
|
||||
- https://torrent9.proxyportal.fun/ # this is a proxy for torrent9clone
|
||||
- https://torrent9.uk-unblock.xyz/ # this is a proxy for torrent9clone
|
||||
- https://torrent9.ind-unblock.xyz/ # this is a proxy for torrent9clone
|
||||
- https://ww1.torrent9.to/
|
||||
- https://www.torrent9.is/
|
||||
- https://torrent9.li/ # not a proxy for torrent9 or torrent9clone
|
||||
- https://www.oxtorrent.me/
|
||||
- https://www.torrent9.gg/
|
||||
- https://www.torrent9.fi/ # this is the torrent9clone domain
|
||||
- https://www.torrent9.fm/
|
||||
- https://torrent9.se/ # redirect to www.
|
||||
- https://torrent9.ninjaproxy1.com/ # no response data
|
||||
- https://torrent9.proxyninja.org/ # Error 1007
|
||||
- https://www.torrent9.se/
|
||||
- https://torrent9.unblockninja.com/ # 403 forbidden
|
||||
- https://ww1.torrent9.fm/
|
||||
- https://www.torrent9.zone/ # clone? details links are broken
|
||||
- https://torrent9.to/
|
||||
- https://ww2.torrent9.to/
|
||||
- https://www5.torrent9.to/
|
||||
|
||||
caps:
|
||||
# dont forget to update the search fields category case block
|
||||
categorymappings:
|
||||
- {id: films, cat: Movies, desc: "Movies"}
|
||||
- {id: series, cat: TV, desc: "TV"}
|
||||
- {id: musique, cat: Audio, desc: "Music"}
|
||||
- {id: ebook, cat: Books, desc: "Books"}
|
||||
- {id: logiciels, cat: PC, desc: "Software"}
|
||||
- {id: jeux-pc, cat: PC/Games, desc: "PC Games"}
|
||||
- {id: other, cat: Other, desc: "Other"} # dummy cat for results missing icon
|
||||
|
||||
modes:
|
||||
search: [q]
|
||||
tv-search: [q, season, ep]
|
||||
movie-search: [q]
|
||||
music-search: [q]
|
||||
book-search: [q]
|
||||
allowrawsearch: true
|
||||
|
||||
settings:
|
||||
- name: info_flaresolverr
|
||||
type: info_flaresolverr
|
||||
- name: multilang
|
||||
type: checkbox
|
||||
label: Replace MULTi by another language in release name
|
||||
default: false
|
||||
- name: multilanguage
|
||||
type: select
|
||||
label: Replace MULTi by this language
|
||||
default: FRENCH
|
||||
options:
|
||||
FRENCH: FRENCH
|
||||
MULTi FRENCH: MULTi FRENCH
|
||||
ENGLISH: ENGLISH
|
||||
MULTi ENGLISH: MULTi ENGLISH
|
||||
VOSTFR: VOSTFR
|
||||
MULTi VOSTFR: MULTi VOSTFR
|
||||
- name: vostfr
|
||||
type: checkbox
|
||||
label: Replace VOSTFR and SUBFRENCH with ENGLISH
|
||||
default: false
|
||||
- name: sort
|
||||
type: select
|
||||
label: Sort requested from site (Only works for searches with Keywords)
|
||||
default: ".html"
|
||||
options:
|
||||
".html": best
|
||||
".html,trie-date-d": created desc
|
||||
".html,trie-date-a": created asc
|
||||
".html,trie-seeds-d": seeders desc
|
||||
".html,trie-seeds-a": seeders asc
|
||||
".html,trie-poid-d": size desc
|
||||
".html,trie-poid-a": size asc
|
||||
".html,trie-nom-d": title desc
|
||||
".html,trie-nom-a": title asc
|
||||
|
||||
download:
|
||||
selectors:
|
||||
- selector: a[href^="magnet:?"]
|
||||
attribute: href
|
||||
- selector: script:contains("magnet:?")
|
||||
filters:
|
||||
- name: regexp
|
||||
args: "\\s'(magnet:\\?.+?)';"
|
||||
|
||||
search:
|
||||
paths:
|
||||
- path: "{{ if .Keywords }}search_torrent/{{ .Keywords }}{{ .Config.sort }}{{ else }}home/{{ end }}"
|
||||
keywordsfilters:
|
||||
# if searching for season packs with S01 to saison 1 #9712
|
||||
- name: re_replace
|
||||
args: ["(?i)(S0)(\\d{1,2})$", "saison $2"]
|
||||
- name: re_replace
|
||||
args: ["(?i)(S)(\\d{1,3})$", "saison $2"]
|
||||
- name: replace
|
||||
args: [" ", "-"]
|
||||
|
||||
headers:
|
||||
# site blocks all Linux User-Agents, so use a slightly altered Windows Jackett UA here (e.g. Safari/537.36 > Safari/537.35)
|
||||
User-Agent: ["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.35"]
|
||||
|
||||
rows:
|
||||
selector: table.table-striped > tbody > tr
|
||||
filters:
|
||||
- name: andmatch
|
||||
|
||||
fields:
|
||||
category_optional:
|
||||
selector: td:nth-child(1) i
|
||||
optional: true
|
||||
case:
|
||||
i[class="fa fa-video-camera"]: films
|
||||
i[class="fa fa-tv"]: series # search by name
|
||||
i[class="fa fa-desktop"]: series # keywordless search
|
||||
i[class="fa fa-music"]: musique
|
||||
i[class="fa fa-gamepad"]: jeux-pc
|
||||
i[class="fa fa-laptop"]: logiciels
|
||||
i[class="fa fa-book"]: ebook
|
||||
category:
|
||||
text: "{{ if .Result.category_optional }}{{ .Result.category_optional }}{{ else }}other{{ end }}"
|
||||
title_default:
|
||||
selector: td:nth-child(1) a
|
||||
title_optional:
|
||||
selector: td:nth-child(1) a[title]
|
||||
attribute: title
|
||||
optional: true
|
||||
title_phase1:
|
||||
text: "{{ if .Result.title_optional }}{{ .Result.title_optional }}{{ else }}{{ .Result.title_default }}{{ end }}"
|
||||
filters:
|
||||
- name: re_replace
|
||||
args: ["(?i)\\b(FRENCH|MULTI|TRUEFRENCH|VOSTFR|SUBFRENCH)\\b(.+?)(\\b((19|20)\\d{2})\\b)$", "$3 $1$2"]
|
||||
title_vostfr:
|
||||
text: "{{ .Result.title_phase1 }}"
|
||||
filters:
|
||||
- name: re_replace
|
||||
args: ["(?i)\\b(vostfr|subfrench)\\b", "ENGLISH"]
|
||||
title_phase2:
|
||||
text: "{{ if .Config.vostfr }}{{ .Result.title_vostfr }}{{ else }}{{ .Result.title_phase1 }}{{ end }}"
|
||||
title_multilang:
|
||||
text: "{{ .Result.title_phase2 }}"
|
||||
filters:
|
||||
- name: re_replace
|
||||
args: ["(?i)\\b(MULTI(?!.*(?:FRENCH|ENGLISH|VOSTFR)))\\b", "{{ .Config.multilanguage }}"]
|
||||
title:
|
||||
text: "{{ if .Config.multilang }}{{ .Result.title_multilang }}{{ else }}{{ .Result.title_phase2 }}{{ end }}"
|
||||
details:
|
||||
selector: td:nth-child(1) a
|
||||
attribute: href
|
||||
download:
|
||||
selector: td:nth-child(1) a
|
||||
attribute: href
|
||||
date:
|
||||
selector: td:nth-child(2):contains("/")
|
||||
optional: true
|
||||
default: now
|
||||
filters:
|
||||
- name: dateparse
|
||||
args: "dd/MM/yyyy"
|
||||
size:
|
||||
selector: "{{ if .Keywords }}td:nth-child(3){{ else }}td:nth-child(2){{ end }}"
|
||||
filters:
|
||||
- name: re_replace
|
||||
args: ["(\\w)o", "$1B"]
|
||||
seeders:
|
||||
selector: "{{ if .Keywords }}td:nth-child(4){{ else }}td:nth-child(3){{ end }}"
|
||||
optional: true
|
||||
default: 0
|
||||
leechers:
|
||||
selector: "{{ if .Keywords }}td:nth-child(5){{ else }}td:nth-child(4){{ end }}"
|
||||
optional: true
|
||||
default: 0
|
||||
downloadvolumefactor:
|
||||
text: 0
|
||||
uploadvolumefactor:
|
||||
text: 1
|
||||
# engine n/a
|
||||
@@ -0,0 +1,36 @@
|
||||
{ config, lib, ... }:
|
||||
let
|
||||
webPort = 8081;
|
||||
btPort = 51413;
|
||||
downloadsDir = "/var/lib/downloads";
|
||||
in
|
||||
{
|
||||
# qBittorrent (headless). Web UI: http://<host>:8081
|
||||
services.qbittorrent = {
|
||||
enable = true;
|
||||
openFirewall = true;
|
||||
webuiPort = webPort;
|
||||
# Prefer a stable port for NAT/firewall and for easier debugging.
|
||||
torrentingPort = btPort;
|
||||
};
|
||||
|
||||
users.groups.qbittorrent = { };
|
||||
users.users.qbittorrent = {
|
||||
isSystemUser = true;
|
||||
group = "qbittorrent";
|
||||
extraGroups = [ "media" ];
|
||||
};
|
||||
|
||||
systemd.tmpfiles.settings."nix-server-downloads-dir" = {
|
||||
"${downloadsDir}"."d" = {
|
||||
mode = "2775";
|
||||
user = "root";
|
||||
group = "media";
|
||||
};
|
||||
};
|
||||
|
||||
# Some NixOS versions don't open UDP for torrenting even when openFirewall=true.
|
||||
networking.firewall.allowedTCPPorts = [ webPort btPort ];
|
||||
networking.firewall.allowedUDPPorts = [ btPort ];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
{ ... }:
|
||||
{
|
||||
# Radarr (movie automation). UI: http://<host>:7878
|
||||
services.radarr.enable = true;
|
||||
|
||||
# Keep permissions aligned with Jellyfin (/var/lib/media via group `media`).
|
||||
users.groups.radarr = { };
|
||||
users.users.radarr = {
|
||||
isSystemUser = true;
|
||||
group = "radarr";
|
||||
extraGroups = [ "media" ];
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ 7878 ];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
{ ... }:
|
||||
{
|
||||
# Blank default Seerr branding assets (read-only store otherwise).
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
seerr = prev.seerr.overrideAttrs (oldAttrs: {
|
||||
postInstall =
|
||||
(oldAttrs.postInstall or "")
|
||||
+ ''
|
||||
find "$out/share/public" -maxdepth 1 -type f \( -name 'logo_full.svg' -o -name 'logo_stacked.svg' \) \
|
||||
-exec truncate -s 0 {} \;
|
||||
'';
|
||||
});
|
||||
})
|
||||
];
|
||||
|
||||
# "Seerr" request management. For Jellyfin, Jellyseerr is the right choice.
|
||||
# UI: http://<host>:5055
|
||||
services.seerr.enable = true;
|
||||
|
||||
users.groups.jellyseerr = { };
|
||||
users.users.jellyseerr = {
|
||||
isSystemUser = true;
|
||||
group = "jellyseerr";
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ 5055 ];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
{ ... }:
|
||||
{
|
||||
# Sonarr (TV automation). UI: http://<host>:8989
|
||||
services.sonarr.enable = true;
|
||||
|
||||
# Ensure Sonarr can manage the same libraries as Jellyfin.
|
||||
users.groups.sonarr = { };
|
||||
users.users.sonarr = {
|
||||
isSystemUser = true;
|
||||
group = "sonarr";
|
||||
extraGroups = [ "media" ];
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ 8989 ];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
{ config, ... }:
|
||||
let
|
||||
secretFilePath = ../secrets.yaml;
|
||||
in
|
||||
{
|
||||
sops.secrets."swiftshare/ghcr-token".sopsFile = secretFilePath;
|
||||
sops.secrets."swiftshare/database-password".sopsFile = secretFilePath;
|
||||
sops.secrets."swiftshare/oauth-discord-client-secret".sopsFile = secretFilePath;
|
||||
sops.secrets."swiftshare/oauth-github-client-secret".sopsFile = secretFilePath;
|
||||
sops.secrets."swiftshare/auth-secret".sopsFile = secretFilePath;
|
||||
sops.secrets."swiftshare/oauth-google-client-id".sopsFile = secretFilePath;
|
||||
sops.secrets."swiftshare/oauth-google-client-secret".sopsFile = secretFilePath;
|
||||
sops.secrets."swiftshare/smtp-pass".sopsFile = secretFilePath;
|
||||
sops.secrets."swiftshare/minio-access-key".sopsFile = secretFilePath;
|
||||
sops.secrets."swiftshare/minio-secret-key".sopsFile = secretFilePath;
|
||||
|
||||
# Docker `--env-file` expects `KEY=value`. Separate snippets for DB/MinIO so only `swiftshare.env` hits the app container.
|
||||
sops.templates."swiftshare-postgres.env" = {
|
||||
content = ''
|
||||
POSTGRES_PASSWORD=${config.sops.placeholder."swiftshare/database-password"}
|
||||
'';
|
||||
};
|
||||
|
||||
sops.templates."swiftshare-minio.env" = {
|
||||
content = ''
|
||||
MINIO_ROOT_USER=${config.sops.placeholder."swiftshare/minio-access-key"}
|
||||
MINIO_ROOT_PASSWORD=${config.sops.placeholder."swiftshare/minio-secret-key"}
|
||||
'';
|
||||
};
|
||||
|
||||
sops.templates."swiftshare.env" = {
|
||||
content = ''
|
||||
DATABASE_URL=postgresql://swiftshare:${config.sops.placeholder."swiftshare/database-password"}@swiftshare-db:5432/swiftshare
|
||||
AUTH_SECRET=${config.sops.placeholder."swiftshare/auth-secret"}
|
||||
AUTH_DISCORD_SECRET=${config.sops.placeholder."swiftshare/oauth-discord-client-secret"}
|
||||
AUTH_GITHUB_SECRET=${config.sops.placeholder."swiftshare/oauth-github-client-secret"}
|
||||
AUTH_GOOGLE_SECRET=${config.sops.placeholder."swiftshare/oauth-google-client-secret"}
|
||||
AUTH_GOOGLE_ID=${config.sops.placeholder."swiftshare/oauth-google-client-id"}
|
||||
SMTP_PASS=${config.sops.placeholder."swiftshare/smtp-pass"}
|
||||
STORAGE_ACCESS_KEY=${config.sops.placeholder."swiftshare/minio-access-key"}
|
||||
STORAGE_SECRET_KEY=${config.sops.placeholder."swiftshare/minio-secret-key"}
|
||||
'';
|
||||
};
|
||||
|
||||
services.swiftshare = {
|
||||
enable = true;
|
||||
|
||||
app = {
|
||||
image = "ghcr.io/olivierchiasson/swiftshare:main";
|
||||
ghcr = {
|
||||
username = "olivierchiasson";
|
||||
passwordFile = config.sops.secrets."swiftshare/ghcr-token".path;
|
||||
};
|
||||
|
||||
origin = "https://swiftshare.cloud";
|
||||
port = 3000;
|
||||
uploadBodySizeLimit = "100mb";
|
||||
disableTelemetry = true;
|
||||
environmentFiles = [ config.sops.templates."swiftshare.env".path ];
|
||||
};
|
||||
|
||||
database = {
|
||||
user = "swiftshare";
|
||||
#password = ""; # Defined in sops.templates."swiftshare-postgres.env"
|
||||
name = "swiftshare";
|
||||
environmentFiles = [ config.sops.templates."swiftshare-postgres.env".path ];
|
||||
#exposePort.enable = true;
|
||||
};
|
||||
|
||||
auth = {
|
||||
#secret = "";
|
||||
|
||||
discord = {
|
||||
clientId = "1400660345068191855";
|
||||
#clientSecret = ""; # Defined in sops.templates."swiftshare.env"
|
||||
};
|
||||
|
||||
# GitHub OAuth App (https://github.com/settings/developers) — replace placeholders.
|
||||
github = {
|
||||
clientId = "Ov23lifcVKR6B1iYDicU";
|
||||
#clientSecret = ""; # Defined in sops.templates."swiftshare.env"
|
||||
};
|
||||
|
||||
# Google Cloud OAuth 2.0 client — replace placeholders.
|
||||
#google = {
|
||||
# clientId = ""; # Defined in sops.templates."swiftshare.env"
|
||||
# clientSecret = ""; # Defined in sops.templates."swiftshare.env"
|
||||
#};
|
||||
|
||||
# SMTP for Better Auth email verification / password reset.
|
||||
smtp = {
|
||||
host = "smtp.purelymail.com";
|
||||
port = 465;
|
||||
secure = true;
|
||||
user = "noreply@swiftshare.cloud";
|
||||
#pass = ""; # Defined in sops.templates."swiftshare.env"
|
||||
from = "noreply@swiftshare.cloud";
|
||||
};
|
||||
};
|
||||
|
||||
minio = {
|
||||
#accessKey = ""; # Defined in sops.templates."swiftshare-minio.env"
|
||||
#secretKey = ""; # Defined in sops.templates."swiftshare-minio.env"
|
||||
bucketName = "swiftshare-assets";
|
||||
environmentFiles = [ config.sops.templates."swiftshare-minio.env".path ];
|
||||
};
|
||||
|
||||
umami = {
|
||||
websiteId = "b4e1240d-a9d8-4075-b64d-0d3e0329cac8";
|
||||
scriptUrl = "https://analytics.chiasson.cloud/script.js";
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -9,14 +9,25 @@
|
||||
}:
|
||||
{
|
||||
imports = [
|
||||
inputs.ddrm.nixosModules.default
|
||||
self.nixosModules.nix-serverHardware
|
||||
inputs.sops-nix.nixosModules.sops
|
||||
self.nixosModules.system
|
||||
self.nixosModules.users
|
||||
./_services/attic-cache-server.nix
|
||||
./_services/portainer.nix
|
||||
./_services/organizr.nix
|
||||
./_services/swiftshare.nix
|
||||
./_services/immich.nix
|
||||
./_services/jellyfin.nix
|
||||
./_services/jellyfin-remote-storage.nix
|
||||
./_services/ddrm-media-server.nix
|
||||
./_services/sonarr.nix
|
||||
./_services/prowlarr.nix
|
||||
./_services/flaresolverr.nix
|
||||
./_services/radarr.nix
|
||||
./_services/qbittorrent.nix
|
||||
./_services/seerr.nix
|
||||
];
|
||||
|
||||
boot.loader.grub = {
|
||||
|
||||
Reference in New Issue
Block a user