test
This commit is contained in:
@@ -44,7 +44,7 @@ in
|
|||||||
|
|
||||||
# Example of using these functions together
|
# Example of using these functions together
|
||||||
nixosConfigurations = lib.mapAttrs' (
|
nixosConfigurations = lib.mapAttrs' (
|
||||||
name:
|
_name:
|
||||||
{ system, hostname, ... }:
|
{ system, hostname, ... }:
|
||||||
{
|
{
|
||||||
name = hostname;
|
name = hostname;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Example usage of the reverse proxy utilities
|
# Example usage of the reverse proxy utilities
|
||||||
{ inputs, lib, ... }:
|
{ lib, ... }:
|
||||||
let
|
let
|
||||||
inherit (lib.mjallen-lib.reverseproxy)
|
inherit (lib.mjallen-lib.reverseproxy)
|
||||||
mkReverseProxy
|
mkReverseProxy
|
||||||
@@ -89,7 +89,11 @@ in
|
|||||||
domain = "example.com";
|
domain = "example.com";
|
||||||
priority = 20;
|
priority = 20;
|
||||||
rule = "Host(`custom.example.com`) && PathPrefix(`/api`)";
|
rule = "Host(`custom.example.com`) && PathPrefix(`/api`)";
|
||||||
middlewares = [ "crowdsec" "whitelist-geoblock" "rate-limit" ];
|
middlewares = [
|
||||||
|
"crowdsec"
|
||||||
|
"whitelist-geoblock"
|
||||||
|
"rate-limit"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
# Example usage in a Traefik configuration:
|
# Example usage in a Traefik configuration:
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ in
|
|||||||
nixosSystems = inputs.self.mjallen-lib.file.filterNixOSSystems allSystems;
|
nixosSystems = inputs.self.mjallen-lib.file.filterNixOSSystems allSystems;
|
||||||
in
|
in
|
||||||
inputs.nixpkgs.lib.mapAttrs' (
|
inputs.nixpkgs.lib.mapAttrs' (
|
||||||
name:
|
_name:
|
||||||
{ system, hostname, ... }:
|
{ system, hostname, ... }:
|
||||||
let
|
let
|
||||||
# Create extended lib with mjallen-lib
|
# Create extended lib with mjallen-lib
|
||||||
@@ -86,7 +86,7 @@ in
|
|||||||
allHomes = inputs.self.mjallen-lib.file.scanHomes ../homes;
|
allHomes = inputs.self.mjallen-lib.file.scanHomes ../homes;
|
||||||
in
|
in
|
||||||
inputs.nixpkgs.lib.mapAttrs' (
|
inputs.nixpkgs.lib.mapAttrs' (
|
||||||
name:
|
_name:
|
||||||
{
|
{
|
||||||
system,
|
system,
|
||||||
username,
|
username,
|
||||||
|
|||||||
@@ -1,77 +1,112 @@
|
|||||||
{ inputs }:
|
{ inputs }:
|
||||||
let
|
let
|
||||||
inherit (inputs.nixpkgs.lib)
|
inherit (inputs.nixpkgs.lib)
|
||||||
mkOption
|
|
||||||
types
|
|
||||||
listToAttrs
|
listToAttrs
|
||||||
nameValuePair
|
nameValuePair
|
||||||
;
|
;
|
||||||
in
|
in
|
||||||
rec {
|
rec {
|
||||||
# Create a service configuration for Traefik
|
# Create a service configuration for Traefik
|
||||||
mkService = {
|
mkService =
|
||||||
|
{
|
||||||
name,
|
name,
|
||||||
url,
|
url,
|
||||||
loadBalancer ? { },
|
loadBalancer ? { },
|
||||||
}: {
|
}:
|
||||||
|
{
|
||||||
inherit name url;
|
inherit name url;
|
||||||
config = {
|
config = {
|
||||||
loadBalancer = {
|
loadBalancer = {
|
||||||
servers = [ { inherit url; } ];
|
servers = [ { inherit url; } ];
|
||||||
} // loadBalancer;
|
}
|
||||||
|
// loadBalancer;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# Create a router configuration for Traefik
|
# Create a router configuration for Traefik
|
||||||
mkRouter = {
|
mkRouter =
|
||||||
|
{
|
||||||
subdomain,
|
subdomain,
|
||||||
domain ? "mjallen.dev",
|
domain ? "mjallen.dev",
|
||||||
service,
|
service,
|
||||||
entryPoints ? [ "websecure" ],
|
entryPoints ? [ "websecure" ],
|
||||||
middlewares ? [ "crowdsec" "whitelist-geoblock" ],
|
middlewares ? [
|
||||||
|
"crowdsec"
|
||||||
|
"whitelist-geoblock"
|
||||||
|
],
|
||||||
priority ? null,
|
priority ? null,
|
||||||
rule ? null,
|
rule ? null,
|
||||||
tls ? { certResolver = "letsencrypt"; },
|
tls ? {
|
||||||
}: {
|
certResolver = "letsencrypt";
|
||||||
inherit subdomain service entryPoints middlewares;
|
},
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
inherit
|
||||||
|
subdomain
|
||||||
|
service
|
||||||
|
entryPoints
|
||||||
|
middlewares
|
||||||
|
;
|
||||||
config = {
|
config = {
|
||||||
inherit entryPoints service middlewares tls;
|
inherit
|
||||||
|
entryPoints
|
||||||
|
service
|
||||||
|
middlewares
|
||||||
|
tls
|
||||||
|
;
|
||||||
rule = if rule != null then rule else "Host(`${subdomain}.${domain}`)";
|
rule = if rule != null then rule else "Host(`${subdomain}.${domain}`)";
|
||||||
} // (if priority != null then { inherit priority; } else { });
|
}
|
||||||
|
// (if priority != null then { inherit priority; } else { });
|
||||||
};
|
};
|
||||||
|
|
||||||
# Create both service and router for a simple reverse proxy setup
|
# Create both service and router for a simple reverse proxy setup
|
||||||
mkReverseProxy = {
|
mkReverseProxy =
|
||||||
|
{
|
||||||
name,
|
name,
|
||||||
subdomain,
|
subdomain,
|
||||||
url,
|
url,
|
||||||
domain ? "mjallen.dev",
|
domain ? "mjallen.dev",
|
||||||
entryPoints ? [ "websecure" ],
|
entryPoints ? [ "websecure" ],
|
||||||
middlewares ? [ "crowdsec" "whitelist-geoblock" ],
|
middlewares ? [
|
||||||
|
"crowdsec"
|
||||||
|
"whitelist-geoblock"
|
||||||
|
],
|
||||||
priority ? null,
|
priority ? null,
|
||||||
rule ? null,
|
rule ? null,
|
||||||
tls ? { certResolver = "letsencrypt"; },
|
tls ? {
|
||||||
|
certResolver = "letsencrypt";
|
||||||
|
},
|
||||||
loadBalancer ? { },
|
loadBalancer ? { },
|
||||||
}: {
|
}:
|
||||||
|
{
|
||||||
service = mkService {
|
service = mkService {
|
||||||
inherit name url loadBalancer;
|
inherit name url loadBalancer;
|
||||||
};
|
};
|
||||||
router = mkRouter {
|
router = mkRouter {
|
||||||
inherit subdomain domain entryPoints middlewares priority rule tls;
|
inherit
|
||||||
|
subdomain
|
||||||
|
domain
|
||||||
|
entryPoints
|
||||||
|
middlewares
|
||||||
|
priority
|
||||||
|
rule
|
||||||
|
tls
|
||||||
|
;
|
||||||
service = name;
|
service = name;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# Convert a list of services to the format expected by Traefik module
|
# Convert a list of services to the format expected by Traefik module
|
||||||
servicesToConfig = services:
|
servicesToConfig =
|
||||||
listToAttrs (map (service: nameValuePair service.name service.config) services);
|
services: listToAttrs (map (service: nameValuePair service.name service.config) services);
|
||||||
|
|
||||||
# Convert a list of routers to the format expected by Traefik module
|
# Convert a list of routers to the format expected by Traefik module
|
||||||
routersToConfig = routers:
|
routersToConfig =
|
||||||
listToAttrs (map (router: nameValuePair router.subdomain router.config) routers);
|
routers: listToAttrs (map (router: nameValuePair router.subdomain router.config) routers);
|
||||||
|
|
||||||
# Helper to create multiple reverse proxies at once
|
# Helper to create multiple reverse proxies at once
|
||||||
mkReverseProxies = proxies:
|
mkReverseProxies =
|
||||||
|
proxies:
|
||||||
let
|
let
|
||||||
results = map mkReverseProxy proxies;
|
results = map mkReverseProxy proxies;
|
||||||
services = map (result: result.service) results;
|
services = map (result: result.service) results;
|
||||||
@@ -93,22 +128,38 @@ rec {
|
|||||||
auth = [ "authentik" ];
|
auth = [ "authentik" ];
|
||||||
|
|
||||||
# Basic security (default)
|
# Basic security (default)
|
||||||
basic = [ "crowdsec" "whitelist-geoblock" ];
|
basic = [
|
||||||
|
"crowdsec"
|
||||||
|
"whitelist-geoblock"
|
||||||
|
];
|
||||||
|
|
||||||
# Internal only access
|
# Internal only access
|
||||||
internal = [ "crowdsec" "whitelist-geoblock" "internal-ipallowlist" ];
|
internal = [
|
||||||
|
"crowdsec"
|
||||||
|
"whitelist-geoblock"
|
||||||
|
"internal-ipallowlist"
|
||||||
|
];
|
||||||
|
|
||||||
# WebSocket support
|
# WebSocket support
|
||||||
websocket = [ "crowdsec" "whitelist-geoblock" "onlyoffice-websocket" ];
|
websocket = [
|
||||||
|
"crowdsec"
|
||||||
|
"whitelist-geoblock"
|
||||||
|
"onlyoffice-websocket"
|
||||||
|
];
|
||||||
|
|
||||||
# Authenticated with basic security
|
# Authenticated with basic security
|
||||||
authBasic = [ "crowdsec" "whitelist-geoblock" "authentik" ];
|
authBasic = [
|
||||||
|
"crowdsec"
|
||||||
|
"whitelist-geoblock"
|
||||||
|
"authentik"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
# Common service URL builders
|
# Common service URL builders
|
||||||
urls = {
|
urls = {
|
||||||
# Local container service
|
# Local container service
|
||||||
container = containerName: port: "http://\${config.containers.${containerName}.localAddress}:${toString port}";
|
container =
|
||||||
|
containerName: port: "http://\${config.containers.${containerName}.localAddress}:${toString port}";
|
||||||
|
|
||||||
# Local host service
|
# Local host service
|
||||||
localhost = port: "http://127.0.0.1:${toString port}";
|
localhost = port: "http://127.0.0.1:${toString port}";
|
||||||
@@ -123,31 +174,47 @@ rec {
|
|||||||
# Pre-configured reverse proxy templates
|
# Pre-configured reverse proxy templates
|
||||||
templates = {
|
templates = {
|
||||||
# Standard web application
|
# Standard web application
|
||||||
webapp = { name, subdomain, port, ... }@args:
|
webapp =
|
||||||
mkReverseProxy ({
|
{ port, ... }@args:
|
||||||
|
mkReverseProxy (
|
||||||
|
{
|
||||||
url = urls.localhost port;
|
url = urls.localhost port;
|
||||||
middlewares = middlewares.basic;
|
middlewares = middlewares.basic;
|
||||||
} // args);
|
}
|
||||||
|
// args
|
||||||
|
);
|
||||||
|
|
||||||
# Authenticated web application
|
# Authenticated web application
|
||||||
authWebapp = { name, subdomain, port, ... }@args:
|
authWebapp =
|
||||||
mkReverseProxy ({
|
{ port, ... }@args:
|
||||||
|
mkReverseProxy (
|
||||||
|
{
|
||||||
url = urls.localhost port;
|
url = urls.localhost port;
|
||||||
middlewares = middlewares.authBasic;
|
middlewares = middlewares.authBasic;
|
||||||
} // args);
|
}
|
||||||
|
// args
|
||||||
|
);
|
||||||
|
|
||||||
# Container-based service
|
# Container-based service
|
||||||
containerService = { name, subdomain, containerName, port, ... }@args:
|
containerService =
|
||||||
mkReverseProxy ({
|
{ containerName, port, ... }@args:
|
||||||
|
mkReverseProxy (
|
||||||
|
{
|
||||||
url = urls.container containerName port;
|
url = urls.container containerName port;
|
||||||
middlewares = middlewares.basic;
|
middlewares = middlewares.basic;
|
||||||
} // args);
|
}
|
||||||
|
// args
|
||||||
|
);
|
||||||
|
|
||||||
# Internal-only service
|
# Internal-only service
|
||||||
internalService = { name, subdomain, port, ... }@args:
|
internalService =
|
||||||
mkReverseProxy ({
|
{ port, ... }@args:
|
||||||
|
mkReverseProxy (
|
||||||
|
{
|
||||||
url = urls.localhost port;
|
url = urls.localhost port;
|
||||||
middlewares = middlewares.internal;
|
middlewares = middlewares.internal;
|
||||||
} // args);
|
}
|
||||||
|
// args
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
160
modules/nixos/disko/default.nix
Normal file
160
modules/nixos/disko/default.nix
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
namespace,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
cfg = config.${namespace}.hardware.disko;
|
||||||
|
|
||||||
|
defaultBtrfsMountOptions = [
|
||||||
|
"compress=${cfg.compression}"
|
||||||
|
"noatime"
|
||||||
|
];
|
||||||
|
defaultBcachefsMountOptions = [
|
||||||
|
"noatime"
|
||||||
|
];
|
||||||
|
|
||||||
|
subvolumes =
|
||||||
|
let
|
||||||
|
make =
|
||||||
|
name: subvolume:
|
||||||
|
nameValuePair "${name}" {
|
||||||
|
mountOptions =
|
||||||
|
if subvolume.mountOptions == null then
|
||||||
|
if cfg.filesystem == "btrfs" then defaultBtrfsMountOptions else defaultBcachefsMountOptions
|
||||||
|
else
|
||||||
|
subvolume.mountOptions;
|
||||||
|
mountpoint = if subvolume.mountPoint == null then "/${name}" else subvolume.mountPoint;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
mapAttrs' make cfg.subvolumes;
|
||||||
|
|
||||||
|
# BTRFS root partition configuration
|
||||||
|
root = {
|
||||||
|
name = "${cfg.filesystem}-root";
|
||||||
|
size = "100%";
|
||||||
|
content = {
|
||||||
|
type = cfg.filesystem;
|
||||||
|
# Subvolumes must set a mountpoint in order to be mounted,
|
||||||
|
# unless their parent is mounted
|
||||||
|
subvolumes = subvolumes;
|
||||||
|
}
|
||||||
|
// (
|
||||||
|
if cfg.filesystem == "btrfs" then
|
||||||
|
{
|
||||||
|
extraArgs = [ "-f" ]; # Override existing partition
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
# This refers to a filesystem in the `bcachefs_filesystems` attrset below.
|
||||||
|
filesystem = "mounted_subvolumes_in_multi";
|
||||||
|
label = "ssd.ssd1";
|
||||||
|
extraFormatArgs = [
|
||||||
|
"--discard"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
# Luks root partition configuration
|
||||||
|
luksRoot = {
|
||||||
|
name = "cryptroot";
|
||||||
|
size = "100%";
|
||||||
|
content = {
|
||||||
|
type = "luks";
|
||||||
|
name = "cryptroot";
|
||||||
|
extraOpenArgs = [
|
||||||
|
"--allow-discards"
|
||||||
|
"--perf-no_read_workqueue"
|
||||||
|
"--perf-no_write_workqueue"
|
||||||
|
];
|
||||||
|
settings = {
|
||||||
|
crypttabExtraOpts = [
|
||||||
|
"fido2-device=auto"
|
||||||
|
"token-timeout=10"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
content = {
|
||||||
|
type = cfg.filesystem;
|
||||||
|
# Subvolumes must set a mountpoint in order to be mounted,
|
||||||
|
# unless their parent is mounted
|
||||||
|
subvolumes = subvolumes;
|
||||||
|
}
|
||||||
|
// (
|
||||||
|
if cfg.filesystem == "btrfs" then
|
||||||
|
{
|
||||||
|
extraArgs = [ "-f" ]; # Override existing partition
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
# This refers to a filesystem in the `bcachefs_filesystems` attrset below.
|
||||||
|
filesystem = "mounted_subvolumes_in_multi";
|
||||||
|
label = "ssd.ssd1";
|
||||||
|
extraFormatArgs = [
|
||||||
|
"--discard"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
imports = [ ./options.nix ];
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
disko.devices = lib.mkMerge [
|
||||||
|
{
|
||||||
|
nodev."/" = {
|
||||||
|
fsType = "tmpfs";
|
||||||
|
mountOptions = [
|
||||||
|
"mode=755"
|
||||||
|
"defaults"
|
||||||
|
"size=25%"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
disk = {
|
||||||
|
main = {
|
||||||
|
device = cfg.rootDisk;
|
||||||
|
type = "disk";
|
||||||
|
imageSize = "32G";
|
||||||
|
content = {
|
||||||
|
type = "gpt";
|
||||||
|
partitions = {
|
||||||
|
ESP = {
|
||||||
|
type = "EF00";
|
||||||
|
size = "500M";
|
||||||
|
content = {
|
||||||
|
type = "filesystem";
|
||||||
|
format = "vfat";
|
||||||
|
mountpoint = "/boot";
|
||||||
|
mountOptions = [ "umask=0077" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
swap = lib.mkIf cfg.enableSwap {
|
||||||
|
type = "8200";
|
||||||
|
size = cfg.swapSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
root = if cfg.enableLuks then luksRoot else root;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# configure Bcachefs
|
||||||
|
bcachefs_filesystems = lib.mkIf (cfg.filesystem == "bcachefs") {
|
||||||
|
mounted_subvolumes_in_multi = {
|
||||||
|
type = "bcachefs_filesystem";
|
||||||
|
# passwordFile = "/etc/nixos/pool.jwe";
|
||||||
|
extraFormatArgs = [
|
||||||
|
"--compression=${cfg.compression}"
|
||||||
|
];
|
||||||
|
subvolumes = subvolumes;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -20,5 +20,30 @@ in
|
|||||||
enableLuks = mkBoolOpt false "Enable Luks";
|
enableLuks = mkBoolOpt false "Enable Luks";
|
||||||
|
|
||||||
swapSize = mkOpt types.str "16G" "size of swap part";
|
swapSize = mkOpt types.str "16G" "size of swap part";
|
||||||
|
|
||||||
|
rootDisk = mkOpt types.str "/dev/nvme0n1" "Root disk";
|
||||||
|
|
||||||
|
compression = mkOpt types.str "zstd" "Type of compression to enable";
|
||||||
|
|
||||||
|
subvolumes =
|
||||||
|
mkOpt
|
||||||
|
(types.attrsOf (
|
||||||
|
types.submodule {
|
||||||
|
options = {
|
||||||
|
mountPoint = mkOpt (types.nullOr types.path) null "Mountpoint of the subvolume";
|
||||||
|
mountOptions = mkOpt (types.nullOr (types.listOf types.str)) null "Extra mount options";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
))
|
||||||
|
{
|
||||||
|
"home" = { };
|
||||||
|
"etc" = { };
|
||||||
|
"nix" = { };
|
||||||
|
"root" = { };
|
||||||
|
"log" = {
|
||||||
|
mountPoint = "/var/log";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
"Subvolumes on root disk";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,23 +95,25 @@ let
|
|||||||
middlewares = cfg.reverseProxy.middlewares;
|
middlewares = cfg.reverseProxy.middlewares;
|
||||||
};
|
};
|
||||||
|
|
||||||
actualContainer = (lib.${namespace}.mkContainer {
|
actualContainer =
|
||||||
|
(lib.${namespace}.mkContainer {
|
||||||
name = "actual";
|
name = "actual";
|
||||||
localAddress = cfg.localAddress;
|
localAddress = cfg.localAddress;
|
||||||
port = cfg.port;
|
port = cfg.port;
|
||||||
bindMounts = bindMounts;
|
bindMounts = bindMounts;
|
||||||
config = actualConfig;
|
config = actualConfig;
|
||||||
}) { inherit lib; };
|
})
|
||||||
|
{ inherit lib; };
|
||||||
|
|
||||||
fullConfig = {
|
fullConfig = {
|
||||||
${namespace}.services.traefik = lib.mkIf cfg.reverseProxy.enable {
|
${namespace}.services.traefik = lib.mkIf cfg.reverseProxy.enable {
|
||||||
reverseProxies = [ reverseProxyConfig ];
|
reverseProxies = [ reverseProxyConfig ];
|
||||||
};
|
};
|
||||||
} // actualContainer;
|
}
|
||||||
|
// actualContainer;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [ ./options.nix ];
|
imports = [ ./options.nix ];
|
||||||
|
|
||||||
config = mkIf cfg.enable fullConfig;
|
config = mkIf cfg.enable fullConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
{
|
{
|
||||||
config,
|
config,
|
||||||
lib,
|
lib,
|
||||||
pkgs,
|
|
||||||
namespace,
|
namespace,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
with lib;
|
|
||||||
let
|
let
|
||||||
cfg = config.${namespace}.services.crowdsec;
|
cfg = config.${namespace}.services.crowdsec;
|
||||||
in
|
in
|
||||||
@@ -71,6 +69,7 @@ in
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
settings = {
|
settings = {
|
||||||
|
# general.api.server.enable = true;
|
||||||
capi.credentialsFile = cfg.apiKey;
|
capi.credentialsFile = cfg.apiKey;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -95,19 +95,22 @@ let
|
|||||||
middlewares = cfg.reverseProxy.middlewares;
|
middlewares = cfg.reverseProxy.middlewares;
|
||||||
};
|
};
|
||||||
|
|
||||||
containerConfig = (lib.${namespace}.mkContainer {
|
containerConfig =
|
||||||
|
(lib.${namespace}.mkContainer {
|
||||||
name = "gitea";
|
name = "gitea";
|
||||||
localAddress = cfg.localAddress;
|
localAddress = cfg.localAddress;
|
||||||
port = cfg.httpPort;
|
port = cfg.httpPort;
|
||||||
bindMounts = bindMounts;
|
bindMounts = bindMounts;
|
||||||
config = serviceConfig;
|
config = serviceConfig;
|
||||||
}) { inherit lib; };
|
})
|
||||||
|
{ inherit lib; };
|
||||||
|
|
||||||
giteaConfig = {
|
giteaConfig = {
|
||||||
${namespace}.services.traefik = lib.mkIf cfg.reverseProxy.enable {
|
${namespace}.services.traefik = lib.mkIf cfg.reverseProxy.enable {
|
||||||
reverseProxies = [ reverseProxyConfig ];
|
reverseProxies = [ reverseProxyConfig ];
|
||||||
};
|
};
|
||||||
} // containerConfig;
|
}
|
||||||
|
// containerConfig;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [ ./options.nix ];
|
imports = [ ./options.nix ];
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
{ config, lib, namespace, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
namespace,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
inherit (lib.${namespace}) mkOpt mkReverseProxyOpt;
|
inherit (lib.${namespace}) mkOpt mkReverseProxyOpt;
|
||||||
cfg = config.${namespace}.services.glance;
|
cfg = config.${namespace}.services.glance;
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
{ config, lib, namespace, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
namespace,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
inherit (lib.${namespace}) mkOpt mkReverseProxyOpt;
|
inherit (lib.${namespace}) mkOpt mkReverseProxyOpt;
|
||||||
cfg = config.${namespace}.services.matrix;
|
cfg = config.${namespace}.services.matrix;
|
||||||
@@ -19,10 +24,16 @@ let
|
|||||||
port = cfg.port;
|
port = cfg.port;
|
||||||
tls = false;
|
tls = false;
|
||||||
x_forwarded = true;
|
x_forwarded = true;
|
||||||
bind_addresses = [ "::1" "0.0.0.0" ];
|
bind_addresses = [
|
||||||
|
"::1"
|
||||||
|
"0.0.0.0"
|
||||||
|
];
|
||||||
resources = [
|
resources = [
|
||||||
{
|
{
|
||||||
names = [ "client" "federation" ];
|
names = [
|
||||||
|
"client"
|
||||||
|
"federation"
|
||||||
|
];
|
||||||
compress = false;
|
compress = false;
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
@@ -135,19 +146,22 @@ let
|
|||||||
middlewares = cfg.reverseProxy.middlewares;
|
middlewares = cfg.reverseProxy.middlewares;
|
||||||
};
|
};
|
||||||
|
|
||||||
matrixContainer = (lib.${namespace}.mkContainer {
|
matrixContainer =
|
||||||
|
(lib.${namespace}.mkContainer {
|
||||||
name = "matrix-synapse";
|
name = "matrix-synapse";
|
||||||
localAddress = cfg.localAddress;
|
localAddress = cfg.localAddress;
|
||||||
port = cfg.port;
|
port = cfg.port;
|
||||||
bindMounts = bindMounts;
|
bindMounts = bindMounts;
|
||||||
config = matrixConfig;
|
config = matrixConfig;
|
||||||
}) { inherit lib; };
|
})
|
||||||
|
{ inherit lib; };
|
||||||
|
|
||||||
fullConfig = {
|
fullConfig = {
|
||||||
${namespace}.services.traefik = lib.mkIf cfg.reverseProxy.enable {
|
${namespace}.services.traefik = lib.mkIf cfg.reverseProxy.enable {
|
||||||
reverseProxies = [ reverseProxyConfig ];
|
reverseProxies = [ reverseProxyConfig ];
|
||||||
};
|
};
|
||||||
} // matrixContainer;
|
}
|
||||||
|
// matrixContainer;
|
||||||
in
|
in
|
||||||
with lib;
|
with lib;
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -96,7 +96,8 @@ in
|
|||||||
secretFile = secretsFile;
|
secretFile = secretsFile;
|
||||||
|
|
||||||
extraApps = {
|
extraApps = {
|
||||||
inherit (pkgs.nextcloud31Packages.apps) app_api
|
inherit (pkgs.nextcloud31Packages.apps)
|
||||||
|
app_api
|
||||||
bookmarks
|
bookmarks
|
||||||
mail
|
mail
|
||||||
calendar
|
calendar
|
||||||
@@ -109,11 +110,14 @@ in
|
|||||||
previewgenerator
|
previewgenerator
|
||||||
recognize
|
recognize
|
||||||
richdocuments
|
richdocuments
|
||||||
user_oidc;
|
user_oidc
|
||||||
|
;
|
||||||
|
|
||||||
inherit nextcloudPhotos
|
inherit
|
||||||
|
nextcloudPhotos
|
||||||
nextcloudPdfViewer
|
nextcloudPdfViewer
|
||||||
nextcloudAssist;
|
nextcloudAssist
|
||||||
|
;
|
||||||
};
|
};
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
{ config, lib, namespace, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
namespace,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
inherit (lib.${namespace}) mkOpt mkReverseProxyOpt;
|
inherit (lib.${namespace}) mkOpt mkReverseProxyOpt;
|
||||||
cfg = config.${namespace}.services.ntfy;
|
cfg = config.${namespace}.services.ntfy;
|
||||||
@@ -66,19 +71,22 @@ let
|
|||||||
middlewares = cfg.reverseProxy.middlewares;
|
middlewares = cfg.reverseProxy.middlewares;
|
||||||
};
|
};
|
||||||
|
|
||||||
ntfyContainer = (lib.${namespace}.mkContainer {
|
ntfyContainer =
|
||||||
|
(lib.${namespace}.mkContainer {
|
||||||
name = "ntfy";
|
name = "ntfy";
|
||||||
localAddress = cfg.localAddress;
|
localAddress = cfg.localAddress;
|
||||||
port = cfg.port;
|
port = cfg.port;
|
||||||
bindMounts = bindMounts;
|
bindMounts = bindMounts;
|
||||||
config = ntfyConfig;
|
config = ntfyConfig;
|
||||||
}) { inherit lib; };
|
})
|
||||||
|
{ inherit lib; };
|
||||||
|
|
||||||
fullConfig = {
|
fullConfig = {
|
||||||
${namespace}.services.traefik = lib.mkIf cfg.reverseProxy.enable {
|
${namespace}.services.traefik = lib.mkIf cfg.reverseProxy.enable {
|
||||||
reverseProxies = [ reverseProxyConfig ];
|
reverseProxies = [ reverseProxyConfig ];
|
||||||
};
|
};
|
||||||
} // ntfyContainer;
|
}
|
||||||
|
// ntfyContainer;
|
||||||
in
|
in
|
||||||
with lib;
|
with lib;
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,196 +0,0 @@
|
|||||||
# Tabby Web Service Module
|
|
||||||
|
|
||||||
This module provides a NixOS service for running the Tabby Web terminal application server.
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
- Systemd service with automatic startup
|
|
||||||
- User and group management
|
|
||||||
- Database migration on startup
|
|
||||||
- Configurable environment variables
|
|
||||||
- Security hardening
|
|
||||||
- Firewall integration
|
|
||||||
- Support for PostgreSQL and SQLite databases
|
|
||||||
- Social authentication configuration
|
|
||||||
|
|
||||||
## Basic Usage
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{
|
|
||||||
mjallen.services.tabby-web = {
|
|
||||||
enable = true;
|
|
||||||
port = 9000;
|
|
||||||
openFirewall = true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Advanced Configuration
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{
|
|
||||||
mjallen.services.tabby-web = {
|
|
||||||
enable = true;
|
|
||||||
port = 8080;
|
|
||||||
openFirewall = true;
|
|
||||||
|
|
||||||
# Use PostgreSQL instead of SQLite
|
|
||||||
databaseUrl = "postgresql://tabby:password@localhost:5432/tabby";
|
|
||||||
|
|
||||||
# Use S3 for app distribution storage
|
|
||||||
appDistStorage = "s3://my-bucket/tabby-dist";
|
|
||||||
|
|
||||||
# Configure social authentication
|
|
||||||
socialAuth = {
|
|
||||||
github = {
|
|
||||||
key = "your-github-oauth-key";
|
|
||||||
secret = "your-github-oauth-secret";
|
|
||||||
};
|
|
||||||
gitlab = {
|
|
||||||
key = "your-gitlab-oauth-key";
|
|
||||||
secret = "your-gitlab-oauth-secret";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# Performance tuning
|
|
||||||
workers = 8;
|
|
||||||
timeout = 300;
|
|
||||||
|
|
||||||
# Additional environment variables
|
|
||||||
extraEnvironment = {
|
|
||||||
DEBUG = "0";
|
|
||||||
LOG_LEVEL = "info";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configuration Options
|
|
||||||
|
|
||||||
### Basic Options
|
|
||||||
|
|
||||||
- `enable`: Enable the tabby-web service
|
|
||||||
- `port`: Port to run the server on (default: 9000)
|
|
||||||
- `openFirewall`: Whether to open the firewall port (default: false)
|
|
||||||
- `user`: User to run the service as (default: "tabby-web")
|
|
||||||
- `group`: Group to run the service as (default: "tabby-web")
|
|
||||||
- `dataDir`: Data directory (default: "/var/lib/tabby-web")
|
|
||||||
|
|
||||||
### Database Configuration
|
|
||||||
|
|
||||||
- `databaseUrl`: Database connection URL
|
|
||||||
- SQLite: `"sqlite:///var/lib/tabby-web/tabby.db"` (default)
|
|
||||||
- PostgreSQL: `"postgresql://user:password@host:port/database"`
|
|
||||||
|
|
||||||
### Storage Configuration
|
|
||||||
|
|
||||||
- `appDistStorage`: Storage URL for app distributions
|
|
||||||
- Local: `"file:///var/lib/tabby-web/dist"` (default)
|
|
||||||
- S3: `"s3://bucket-name/path"`
|
|
||||||
- GCS: `"gcs://bucket-name/path"`
|
|
||||||
|
|
||||||
### Social Authentication
|
|
||||||
|
|
||||||
Configure OAuth providers:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
socialAuth = {
|
|
||||||
github = {
|
|
||||||
key = "oauth-key";
|
|
||||||
secret = "oauth-secret";
|
|
||||||
};
|
|
||||||
gitlab = {
|
|
||||||
key = "oauth-key";
|
|
||||||
secret = "oauth-secret";
|
|
||||||
};
|
|
||||||
microsoftGraph = {
|
|
||||||
key = "oauth-key";
|
|
||||||
secret = "oauth-secret";
|
|
||||||
};
|
|
||||||
googleOauth2 = {
|
|
||||||
key = "oauth-key";
|
|
||||||
secret = "oauth-secret";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### Performance Options
|
|
||||||
|
|
||||||
- `workers`: Number of gunicorn worker processes (default: 4)
|
|
||||||
- `timeout`: Worker timeout in seconds (default: 120)
|
|
||||||
|
|
||||||
### Additional Configuration
|
|
||||||
|
|
||||||
- `extraEnvironment`: Additional environment variables as an attribute set
|
|
||||||
|
|
||||||
## Service Management
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Start the service
|
|
||||||
sudo systemctl start tabby-web
|
|
||||||
|
|
||||||
# Enable automatic startup
|
|
||||||
sudo systemctl enable tabby-web
|
|
||||||
|
|
||||||
# Check service status
|
|
||||||
sudo systemctl status tabby-web
|
|
||||||
|
|
||||||
# View logs
|
|
||||||
sudo journalctl -u tabby-web -f
|
|
||||||
|
|
||||||
# Run management commands
|
|
||||||
sudo -u tabby-web tabby-web-manage migrate
|
|
||||||
sudo -u tabby-web tabby-web-manage add_version 1.0.156-nightly.2
|
|
||||||
```
|
|
||||||
|
|
||||||
## Security
|
|
||||||
|
|
||||||
The service runs with extensive security hardening:
|
|
||||||
|
|
||||||
- Dedicated user and group
|
|
||||||
- Restricted filesystem access
|
|
||||||
- No new privileges
|
|
||||||
- Protected system directories
|
|
||||||
- Private temporary directory
|
|
||||||
- Memory execution protection
|
|
||||||
- Namespace restrictions
|
|
||||||
|
|
||||||
## Database Setup
|
|
||||||
|
|
||||||
### PostgreSQL
|
|
||||||
|
|
||||||
If using PostgreSQL, ensure the database and user exist:
|
|
||||||
|
|
||||||
```sql
|
|
||||||
CREATE USER tabby WITH PASSWORD 'your-password';
|
|
||||||
CREATE DATABASE tabby OWNER tabby;
|
|
||||||
```
|
|
||||||
|
|
||||||
### SQLite
|
|
||||||
|
|
||||||
SQLite databases are created automatically in the data directory.
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
1. **Service fails to start**: Check logs with `journalctl -u tabby-web`
|
|
||||||
2. **Database connection issues**: Verify database URL and credentials
|
|
||||||
3. **Permission errors**: Ensure data directory has correct ownership
|
|
||||||
4. **Port conflicts**: Check if another service is using the configured port
|
|
||||||
|
|
||||||
## Integration with Reverse Proxy
|
|
||||||
|
|
||||||
Example Nginx configuration:
|
|
||||||
|
|
||||||
```nginx
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name tabby.example.com;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
proxy_pass http://localhost:9000;
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
namespace,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
with lib;
|
|
||||||
let
|
|
||||||
cfg = config.${namespace}.services.tabby-web;
|
|
||||||
|
|
||||||
# Build environment variables from configuration
|
|
||||||
environmentVars = {
|
|
||||||
DATABASE_URL = cfg.databaseUrl;
|
|
||||||
APP_DIST_STORAGE = cfg.appDistStorage;
|
|
||||||
PORT = toString cfg.port;
|
|
||||||
}
|
|
||||||
// optionalAttrs (cfg.socialAuth.github.key != null) {
|
|
||||||
SOCIAL_AUTH_GITHUB_KEY = cfg.socialAuth.github.key;
|
|
||||||
}
|
|
||||||
// optionalAttrs (cfg.socialAuth.github.secret != null) {
|
|
||||||
SOCIAL_AUTH_GITHUB_SECRET = cfg.socialAuth.github.secret;
|
|
||||||
}
|
|
||||||
// optionalAttrs (cfg.socialAuth.gitlab.key != null) {
|
|
||||||
SOCIAL_AUTH_GITLAB_KEY = cfg.socialAuth.gitlab.key;
|
|
||||||
}
|
|
||||||
// optionalAttrs (cfg.socialAuth.gitlab.secret != null) {
|
|
||||||
SOCIAL_AUTH_GITLAB_SECRET = cfg.socialAuth.gitlab.secret;
|
|
||||||
}
|
|
||||||
// optionalAttrs (cfg.socialAuth.microsoftGraph.key != null) {
|
|
||||||
SOCIAL_AUTH_MICROSOFT_GRAPH_KEY = cfg.socialAuth.microsoftGraph.key;
|
|
||||||
}
|
|
||||||
// optionalAttrs (cfg.socialAuth.microsoftGraph.secret != null) {
|
|
||||||
SOCIAL_AUTH_MICROSOFT_GRAPH_SECRET = cfg.socialAuth.microsoftGraph.secret;
|
|
||||||
}
|
|
||||||
// optionalAttrs (cfg.socialAuth.googleOauth2.key != null) {
|
|
||||||
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = cfg.socialAuth.googleOauth2.key;
|
|
||||||
}
|
|
||||||
// optionalAttrs (cfg.socialAuth.googleOauth2.secret != null) {
|
|
||||||
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = cfg.socialAuth.googleOauth2.secret;
|
|
||||||
}
|
|
||||||
// cfg.extraEnvironment;
|
|
||||||
|
|
||||||
in
|
|
||||||
{
|
|
||||||
imports = [ ./options.nix ];
|
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
|
||||||
# Create user and group
|
|
||||||
users.users.${cfg.user} = {
|
|
||||||
isSystemUser = true;
|
|
||||||
group = cfg.group;
|
|
||||||
home = cfg.dataDir;
|
|
||||||
createHome = true;
|
|
||||||
description = "Tabby Web service user";
|
|
||||||
};
|
|
||||||
|
|
||||||
users.groups.${cfg.group} = { };
|
|
||||||
|
|
||||||
# Ensure data directory exists with correct permissions
|
|
||||||
systemd.tmpfiles.rules = [
|
|
||||||
"d '${cfg.dataDir}' 0750 ${cfg.user} ${cfg.group} - -"
|
|
||||||
"d '${cfg.dataDir}/dist' 0750 ${cfg.user} ${cfg.group} - -"
|
|
||||||
];
|
|
||||||
|
|
||||||
# Create the systemd service
|
|
||||||
systemd.services.tabby-web = {
|
|
||||||
description = "Tabby Web Terminal Application Server";
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
after = [ "network.target" ] ++ optional (hasPrefix "postgresql://" cfg.databaseUrl) "postgresql.service";
|
|
||||||
|
|
||||||
environment = environmentVars;
|
|
||||||
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "exec";
|
|
||||||
User = cfg.user;
|
|
||||||
Group = cfg.group;
|
|
||||||
WorkingDirectory = cfg.dataDir;
|
|
||||||
|
|
||||||
# Use the tabby-web package from our custom packages
|
|
||||||
ExecStart = "${pkgs.${namespace}.tabby-web}/bin/tabby-web --workers ${toString cfg.workers} --timeout ${toString cfg.timeout}";
|
|
||||||
|
|
||||||
# Run database migrations before starting the service
|
|
||||||
ExecStartPre = "${pkgs.${namespace}.tabby-web}/bin/tabby-web-manage migrate";
|
|
||||||
|
|
||||||
# Security settings
|
|
||||||
NoNewPrivileges = true;
|
|
||||||
ProtectSystem = "strict";
|
|
||||||
ProtectHome = true;
|
|
||||||
ReadWritePaths = [ cfg.dataDir ];
|
|
||||||
PrivateTmp = true;
|
|
||||||
ProtectKernelTunables = true;
|
|
||||||
ProtectKernelModules = true;
|
|
||||||
ProtectControlGroups = true;
|
|
||||||
RestrictSUIDSGID = true;
|
|
||||||
RestrictRealtime = true;
|
|
||||||
RestrictNamespaces = true;
|
|
||||||
LockPersonality = true;
|
|
||||||
MemoryDenyWriteExecute = true;
|
|
||||||
|
|
||||||
# Restart policy
|
|
||||||
Restart = "always";
|
|
||||||
RestartSec = "10s";
|
|
||||||
|
|
||||||
# Resource limits
|
|
||||||
LimitNOFILE = "65536";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Ensure the service starts after database if using PostgreSQL
|
|
||||||
requisite = mkIf (hasPrefix "postgresql://" cfg.databaseUrl) [ "postgresql.service" ];
|
|
||||||
};
|
|
||||||
|
|
||||||
# Open firewall if requested
|
|
||||||
networking.firewall = mkIf cfg.openFirewall {
|
|
||||||
allowedTCPPorts = [ cfg.port ];
|
|
||||||
};
|
|
||||||
|
|
||||||
# Add the tabby-web package to system packages
|
|
||||||
environment.systemPackages = [ pkgs.${namespace}.tabby-web ];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
# Example configuration for Tabby Web service
|
|
||||||
# Add this to your NixOS configuration to enable tabby-web
|
|
||||||
|
|
||||||
{
|
|
||||||
# Basic configuration - SQLite database, local storage
|
|
||||||
mjallen.services.tabby-web = {
|
|
||||||
enable = true;
|
|
||||||
port = 9000;
|
|
||||||
openFirewall = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
# Advanced configuration example (commented out)
|
|
||||||
/*
|
|
||||||
mjallen.services.tabby-web = {
|
|
||||||
enable = true;
|
|
||||||
port = 8080;
|
|
||||||
openFirewall = true;
|
|
||||||
|
|
||||||
# Use PostgreSQL database
|
|
||||||
databaseUrl = "postgresql://tabby:password@localhost:5432/tabby";
|
|
||||||
|
|
||||||
# Use S3 for app distribution storage
|
|
||||||
appDistStorage = "s3://my-bucket/tabby-dist";
|
|
||||||
|
|
||||||
# Configure GitHub OAuth
|
|
||||||
socialAuth.github = {
|
|
||||||
key = "your-github-oauth-key";
|
|
||||||
secret = "your-github-oauth-secret";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Performance tuning
|
|
||||||
workers = 8;
|
|
||||||
timeout = 300;
|
|
||||||
|
|
||||||
# Custom data directory
|
|
||||||
dataDir = "/srv/tabby-web";
|
|
||||||
|
|
||||||
# Additional environment variables
|
|
||||||
extraEnvironment = {
|
|
||||||
DEBUG = "0";
|
|
||||||
LOG_LEVEL = "info";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
{ lib, namespace, ... }:
|
|
||||||
with lib;
|
|
||||||
{
|
|
||||||
options.${namespace}.services.tabby-web = {
|
|
||||||
enable = mkEnableOption "Tabby Web terminal application server";
|
|
||||||
|
|
||||||
port = mkOption {
|
|
||||||
type = types.port;
|
|
||||||
default = 9000;
|
|
||||||
description = "Port for tabby-web server";
|
|
||||||
};
|
|
||||||
|
|
||||||
openFirewall = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
|
||||||
description = "Whether to open firewall for tabby-web";
|
|
||||||
};
|
|
||||||
|
|
||||||
user = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "tabby-web";
|
|
||||||
description = "User to run tabby-web as";
|
|
||||||
};
|
|
||||||
|
|
||||||
group = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "tabby-web";
|
|
||||||
description = "Group to run tabby-web as";
|
|
||||||
};
|
|
||||||
|
|
||||||
dataDir = mkOption {
|
|
||||||
type = types.path;
|
|
||||||
default = "/var/lib/tabby-web";
|
|
||||||
description = "Directory to store tabby-web data";
|
|
||||||
};
|
|
||||||
|
|
||||||
databaseUrl = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "sqlite:///var/lib/tabby-web/tabby.db";
|
|
||||||
description = "Database connection URL";
|
|
||||||
example = "postgresql://user:password@localhost:5432/tabby";
|
|
||||||
};
|
|
||||||
|
|
||||||
appDistStorage = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "file:///var/lib/tabby-web/dist";
|
|
||||||
description = "Storage URL for app distributions";
|
|
||||||
example = "s3://my-bucket/tabby-dist";
|
|
||||||
};
|
|
||||||
|
|
||||||
socialAuth = {
|
|
||||||
github = {
|
|
||||||
key = mkOption {
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
default = null;
|
|
||||||
description = "GitHub OAuth key";
|
|
||||||
};
|
|
||||||
secret = mkOption {
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
default = null;
|
|
||||||
description = "GitHub OAuth secret";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
gitlab = {
|
|
||||||
key = mkOption {
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
default = null;
|
|
||||||
description = "GitLab OAuth key";
|
|
||||||
};
|
|
||||||
secret = mkOption {
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
default = null;
|
|
||||||
description = "GitLab OAuth secret";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
microsoftGraph = {
|
|
||||||
key = mkOption {
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
default = null;
|
|
||||||
description = "Microsoft Graph OAuth key";
|
|
||||||
};
|
|
||||||
secret = mkOption {
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
default = null;
|
|
||||||
description = "Microsoft Graph OAuth secret";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
googleOauth2 = {
|
|
||||||
key = mkOption {
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
default = null;
|
|
||||||
description = "Google OAuth2 key";
|
|
||||||
};
|
|
||||||
secret = mkOption {
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
default = null;
|
|
||||||
description = "Google OAuth2 secret";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
extraEnvironment = mkOption {
|
|
||||||
type = types.attrsOf types.str;
|
|
||||||
default = { };
|
|
||||||
description = "Extra environment variables for tabby-web";
|
|
||||||
example = {
|
|
||||||
DEBUG = "1";
|
|
||||||
LOG_LEVEL = "info";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
workers = mkOption {
|
|
||||||
type = types.ints.positive;
|
|
||||||
default = 4;
|
|
||||||
description = "Number of gunicorn worker processes";
|
|
||||||
};
|
|
||||||
|
|
||||||
timeout = mkOption {
|
|
||||||
type = types.ints.positive;
|
|
||||||
default = 120;
|
|
||||||
description = "Worker timeout in seconds";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -11,7 +11,9 @@ let
|
|||||||
# Process extraServices into service configurations
|
# Process extraServices into service configurations
|
||||||
extraServiceConfigs =
|
extraServiceConfigs =
|
||||||
let
|
let
|
||||||
makeService = service: nameValuePair service.name {
|
makeService =
|
||||||
|
service:
|
||||||
|
nameValuePair service.name {
|
||||||
loadBalancer.servers = [
|
loadBalancer.servers = [
|
||||||
{
|
{
|
||||||
url = service.url;
|
url = service.url;
|
||||||
@@ -24,7 +26,9 @@ let
|
|||||||
# Process extraRouters into router configurations
|
# Process extraRouters into router configurations
|
||||||
extraRouterConfigs =
|
extraRouterConfigs =
|
||||||
let
|
let
|
||||||
makeRouter = router: nameValuePair router.subdomain {
|
makeRouter =
|
||||||
|
router:
|
||||||
|
nameValuePair router.subdomain {
|
||||||
entryPoints = router.entryPoints;
|
entryPoints = router.entryPoints;
|
||||||
rule = "Host(`${router.subdomain}.${domain}`)";
|
rule = "Host(`${router.subdomain}.${domain}`)";
|
||||||
service = router.service;
|
service = router.service;
|
||||||
@@ -348,7 +352,9 @@ in
|
|||||||
url = paperlessUrl;
|
url = paperlessUrl;
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
} // extraServiceConfigs // reverseProxyServiceConfigs;
|
}
|
||||||
|
// extraServiceConfigs
|
||||||
|
// reverseProxyServiceConfigs;
|
||||||
|
|
||||||
routers = {
|
routers = {
|
||||||
auth = {
|
auth = {
|
||||||
@@ -457,7 +463,9 @@ in
|
|||||||
];
|
];
|
||||||
tls.certResolver = "letsencrypt";
|
tls.certResolver = "letsencrypt";
|
||||||
};
|
};
|
||||||
} // extraRouterConfigs // reverseProxyRouterConfigs;
|
}
|
||||||
|
// extraRouterConfigs
|
||||||
|
// reverseProxyRouterConfigs;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,34 +1,42 @@
|
|||||||
{ lib, namespace, ... }:
|
{ lib, namespace, ... }:
|
||||||
with lib;
|
with lib;
|
||||||
let
|
let
|
||||||
inherit (lib.${namespace}) mkOpt mkBoolOpt;
|
inherit (lib.${namespace}) mkOpt;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.${namespace}.services.traefik = {
|
options.${namespace}.services.traefik = {
|
||||||
enable = mkEnableOption "enable traefik";
|
enable = mkEnableOption "enable traefik";
|
||||||
|
|
||||||
extraServices = mkOpt (types.listOf (types.submodule {
|
extraServices = mkOpt (types.listOf (
|
||||||
|
types.submodule {
|
||||||
options = {
|
options = {
|
||||||
name = mkOpt types.str "" "Name of the service";
|
name = mkOpt types.str "" "Name of the service";
|
||||||
url = mkOpt types.str "http://localhost:8080" "Url of the service";
|
url = mkOpt types.str "http://localhost:8080" "Url of the service";
|
||||||
};
|
};
|
||||||
})) [ ] "List of extra services to forward";
|
}
|
||||||
|
)) [ ] "List of extra services to forward";
|
||||||
|
|
||||||
extraRouters = mkOpt (types.listOf (types.submodule {
|
extraRouters = mkOpt (types.listOf (
|
||||||
|
types.submodule {
|
||||||
options = {
|
options = {
|
||||||
entryPoints = mkOpt (types.listOf types.str) [ "websecure" ] "Entrypoint";
|
entryPoints = mkOpt (types.listOf types.str) [ "websecure" ] "Entrypoint";
|
||||||
subdomain = mkOpt types.str "" "subdomain of the service";
|
subdomain = mkOpt types.str "" "subdomain of the service";
|
||||||
service = mkOpt types.str "" "name of the service";
|
service = mkOpt types.str "" "name of the service";
|
||||||
middlewares = mkOpt (types.listOf (types.enum [
|
middlewares = mkOpt (types.listOf (
|
||||||
|
types.enum [
|
||||||
"authentik"
|
"authentik"
|
||||||
"onlyoffice-websocket"
|
"onlyoffice-websocket"
|
||||||
"crowdsec"
|
"crowdsec"
|
||||||
"whitelist-geoblock"
|
"whitelist-geoblock"
|
||||||
"internal-ipallowlist"
|
"internal-ipallowlist"
|
||||||
])) [ ] "List of middlewares to enable";
|
]
|
||||||
};
|
)) [ ] "List of middlewares to enable";
|
||||||
})) [ ] "List of extra services to forward";
|
};
|
||||||
|
}
|
||||||
reverseProxies = mkOpt (types.listOf types.attrs) [ ] "List of reverse proxy configurations from mkReverseProxy";
|
)) [ ] "List of extra services to forward";
|
||||||
|
|
||||||
|
reverseProxies =
|
||||||
|
mkOpt (types.listOf types.attrs) [ ]
|
||||||
|
"List of reverse proxy configurations from mkReverseProxy";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,14 +23,14 @@ in
|
|||||||
uri = "tcp://0.0.0.0:10300";
|
uri = "tcp://0.0.0.0:10300";
|
||||||
};
|
};
|
||||||
|
|
||||||
piper = {
|
# piper = {
|
||||||
package = pkgs.stable.wyoming-piper;
|
# package = pkgs.stable.wyoming-piper;
|
||||||
servers.hass-piper = {
|
# servers.hass-piper = {
|
||||||
enable = true;
|
# enable = true;
|
||||||
voice = "en-us-ryan-high";
|
# voice = "en-us-ryan-high";
|
||||||
uri = "tcp://0.0.0.0:10200";
|
# uri = "tcp://0.0.0.0:10200";
|
||||||
};
|
# };
|
||||||
};
|
# };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,44 +1,45 @@
|
|||||||
{ lib
|
{
|
||||||
, stdenv
|
lib,
|
||||||
, fetchzip
|
stdenv,
|
||||||
, autoPatchelfHook
|
fetchzip,
|
||||||
, makeWrapper
|
autoPatchelfHook,
|
||||||
|
makeWrapper,
|
||||||
# Core dependencies
|
# Core dependencies
|
||||||
, alsa-lib
|
alsa-lib,
|
||||||
, at-spi2-core
|
at-spi2-core,
|
||||||
, cairo
|
cairo,
|
||||||
, cups
|
cups,
|
||||||
, dbus
|
dbus,
|
||||||
, expat
|
expat,
|
||||||
, fontconfig
|
fontconfig,
|
||||||
, freetype
|
freetype,
|
||||||
, gdk-pixbuf
|
gdk-pixbuf,
|
||||||
, glib
|
glib,
|
||||||
, gtk3
|
gtk3,
|
||||||
, libarchive
|
libarchive,
|
||||||
, libdrm
|
libdrm,
|
||||||
, libGL
|
libGL,
|
||||||
, libx11
|
libx11,
|
||||||
, libxcb
|
libxcb,
|
||||||
, libxext
|
libxext,
|
||||||
, libxkbcommon
|
libxkbcommon,
|
||||||
, mesa
|
mesa,
|
||||||
, nspr
|
nspr,
|
||||||
, nss
|
nss,
|
||||||
, pango
|
pango,
|
||||||
, systemd
|
systemd,
|
||||||
, xorg
|
xorg,
|
||||||
, zlib
|
zlib,
|
||||||
# Additional CEF/Chromium dependencies
|
# Additional CEF/Chromium dependencies
|
||||||
, libnotify
|
libnotify,
|
||||||
, libpulseaudio
|
libpulseaudio,
|
||||||
, libuuid
|
libuuid,
|
||||||
, libva
|
libva,
|
||||||
, pipewire
|
pipewire,
|
||||||
, udev
|
udev,
|
||||||
, wayland
|
wayland,
|
||||||
, jdk17 # for RuneLite/HDOS
|
jdk17 # for RuneLite/HDOS
|
||||||
, gtk2 ? null # for RS3
|
, # for RS3
|
||||||
}:
|
}:
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
@@ -90,7 +91,8 @@ stdenv.mkDerivation rec {
|
|||||||
pipewire
|
pipewire
|
||||||
udev
|
udev
|
||||||
wayland
|
wayland
|
||||||
] ++ (with xorg; [
|
]
|
||||||
|
++ (with xorg; [
|
||||||
libXcomposite
|
libXcomposite
|
||||||
libXcursor
|
libXcursor
|
||||||
libXdamage
|
libXdamage
|
||||||
@@ -168,7 +170,10 @@ stdenv.mkDerivation rec {
|
|||||||
description = "Free open-source third-party implementation of the Jagex Launcher";
|
description = "Free open-source third-party implementation of the Jagex Launcher";
|
||||||
homepage = "https://bolt.adamcake.com/";
|
homepage = "https://bolt.adamcake.com/";
|
||||||
license = licenses.agpl3Only;
|
license = licenses.agpl3Only;
|
||||||
platforms = [ "x86_64-linux" "aarch64-linux" ];
|
platforms = [
|
||||||
|
"x86_64-linux"
|
||||||
|
"aarch64-linux"
|
||||||
|
];
|
||||||
maintainers = with maintainers; [ ];
|
maintainers = with maintainers; [ ];
|
||||||
sourceProvenance = with sourceTypes; [ binaryNativeCode ];
|
sourceProvenance = with sourceTypes; [ binaryNativeCode ];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -29,7 +29,9 @@ python3Packages.buildPythonPackage rec {
|
|||||||
|
|
||||||
build-system = with python3Packages; [ poetry-core ];
|
build-system = with python3Packages; [ poetry-core ];
|
||||||
|
|
||||||
dependencies = with python3Packages; [
|
dependencies =
|
||||||
|
with python3Packages;
|
||||||
|
[
|
||||||
aiohttp
|
aiohttp
|
||||||
aiomqtt
|
aiomqtt
|
||||||
async-timeout
|
async-timeout
|
||||||
|
|||||||
@@ -100,7 +100,14 @@ stdenv.mkDerivation rec {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Create main executable wrapper
|
# Create main executable wrapper
|
||||||
makeWrapper ${python3.withPackages (ps: with ps; [ gunicorn django ])}/bin/python $out/bin/tabby-web \
|
makeWrapper ${
|
||||||
|
python3.withPackages (
|
||||||
|
ps: with ps; [
|
||||||
|
gunicorn
|
||||||
|
django
|
||||||
|
]
|
||||||
|
)
|
||||||
|
}/bin/python $out/bin/tabby-web \
|
||||||
--add-flags "-m gunicorn tabby_web.wsgi:application" \
|
--add-flags "-m gunicorn tabby_web.wsgi:application" \
|
||||||
--set PYTHONPATH "$out/lib/tabby-web" \
|
--set PYTHONPATH "$out/lib/tabby-web" \
|
||||||
--set DJANGO_SETTINGS_MODULE "tabby_web.settings" \
|
--set DJANGO_SETTINGS_MODULE "tabby_web.settings" \
|
||||||
@@ -114,7 +121,9 @@ stdenv.mkDerivation rec {
|
|||||||
--add-flags "--timeout 120"
|
--add-flags "--timeout 120"
|
||||||
|
|
||||||
# Create Django management wrapper
|
# Create Django management wrapper
|
||||||
makeWrapper ${python3.withPackages (ps: with ps; [ django ])}/bin/python $out/bin/tabby-web-manage \
|
makeWrapper ${
|
||||||
|
python3.withPackages (ps: with ps; [ django ])
|
||||||
|
}/bin/python $out/bin/tabby-web-manage \
|
||||||
--add-flags "manage.py" \
|
--add-flags "manage.py" \
|
||||||
--set PYTHONPATH "$out/lib/tabby-web" \
|
--set PYTHONPATH "$out/lib/tabby-web" \
|
||||||
--set DJANGO_SETTINGS_MODULE "tabby_web.settings" \
|
--set DJANGO_SETTINGS_MODULE "tabby_web.settings" \
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ jallen-nas:
|
|||||||
cloudflare-zone-api-token: ENC[AES256_GCM,data:N02jcaPLYVzOmo5omGvOKUw2MZg8/cVolRcw/pu+sFnV8IsrUFOjmA==,iv:NZ+OaNR5lmsXicYQ7QL9CBMhlm397VbqmIcmr6GGBWw=,tag:FOT0EzDDuJ/kKOArn8e/rA==,type:str]
|
cloudflare-zone-api-token: ENC[AES256_GCM,data:N02jcaPLYVzOmo5omGvOKUw2MZg8/cVolRcw/pu+sFnV8IsrUFOjmA==,iv:NZ+OaNR5lmsXicYQ7QL9CBMhlm397VbqmIcmr6GGBWw=,tag:FOT0EzDDuJ/kKOArn8e/rA==,type:str]
|
||||||
cloudflare-api-key: ENC[AES256_GCM,data:SWCsa1YzUpl5aQmeVBzKjfkZdAfduX8pl5RKd+EP6pgyMCCc6Q==,iv:ccIzA1OzGyRnq8gxXAg4B3HHtKcvXhXKMWVuTs/PHLI=,tag:R9KrYDrAluTAyuv7DfYVWQ==,type:str]
|
cloudflare-api-key: ENC[AES256_GCM,data:SWCsa1YzUpl5aQmeVBzKjfkZdAfduX8pl5RKd+EP6pgyMCCc6Q==,iv:ccIzA1OzGyRnq8gxXAg4B3HHtKcvXhXKMWVuTs/PHLI=,tag:R9KrYDrAluTAyuv7DfYVWQ==,type:str]
|
||||||
cloudflare-email: ENC[AES256_GCM,data:WCe6JlTQnv2PXYcySZNbZ5Lv,iv:qc+o+GEqdRm3U5qBqvH23HOah3Sa63QzqZyDXWozcqo=,tag:v8YY3jCoVC8h12wHTFjkIg==,type:str]
|
cloudflare-email: ENC[AES256_GCM,data:WCe6JlTQnv2PXYcySZNbZ5Lv,iv:qc+o+GEqdRm3U5qBqvH23HOah3Sa63QzqZyDXWozcqo=,tag:v8YY3jCoVC8h12wHTFjkIg==,type:str]
|
||||||
|
crowdsec-capi: ENC[AES256_GCM,data:9T3e6CzJZOT1KAXlpG323oPmk9xsoVVWI/WYnhdmzyymj61LgNJKvA==,iv:NywJk/tkmIGR5jIgxpvheRBCrK64QytXAkr+40nn62M=,tag:XFeafjL/84r0fLa8UpjyjQ==,type:str]
|
||||||
collabora: ENC[AES256_GCM,data:tFbbm16DFMsxT0I1ogXTRwyTgkE=,iv:yzembXvJ9+DroplBUDiMPa/jn9pjpAI7f5oHSTaZedA=,tag:yprIBtaRIjaHW6nplLYYzQ==,type:str]
|
collabora: ENC[AES256_GCM,data:tFbbm16DFMsxT0I1ogXTRwyTgkE=,iv:yzembXvJ9+DroplBUDiMPa/jn9pjpAI7f5oHSTaZedA=,tag:yprIBtaRIjaHW6nplLYYzQ==,type:str]
|
||||||
mariadb:
|
mariadb:
|
||||||
root_pass: ENC[AES256_GCM,data:AmZ3lU/GM9lMAjchF4kvjkIZlYX0KZV7ov0dxtnDmg==,iv:9JQuHWcb3/lCR3gw4PFtzMKxk85GXzFV35NguJydUkk=,tag:MEvmiYhAYa1LUGTN9wm/3w==,type:str]
|
root_pass: ENC[AES256_GCM,data:AmZ3lU/GM9lMAjchF4kvjkIZlYX0KZV7ov0dxtnDmg==,iv:9JQuHWcb3/lCR3gw4PFtzMKxk85GXzFV35NguJydUkk=,tag:MEvmiYhAYa1LUGTN9wm/3w==,type:str]
|
||||||
@@ -173,8 +174,8 @@ sops:
|
|||||||
NXZkbVZyV0VtTzArOE1uU1JwMXZZN0EKLDU1x+rIWecDD9x//huoM2BM9NRSa4g1
|
NXZkbVZyV0VtTzArOE1uU1JwMXZZN0EKLDU1x+rIWecDD9x//huoM2BM9NRSa4g1
|
||||||
L5nodU/J0XsfB9z3kr7eY5LYSwsqGkAxI1cXJYZGHF+bozJjweyXTQ==
|
L5nodU/J0XsfB9z3kr7eY5LYSwsqGkAxI1cXJYZGHF+bozJjweyXTQ==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
lastmodified: "2025-09-17T02:00:58Z"
|
lastmodified: "2025-09-30T23:04:02Z"
|
||||||
mac: ENC[AES256_GCM,data:l1J7omMlj1orONfmsgvGG+DZvdv5GmsdvQmUqPml9EfE7gF0ZoioEaGfcWDLBfutH9VU/9cWLclNbDinqL63m7/tAvv/8LGVvJ0s1T8xbAbu7d95+hXH7rMVU6C15h+maXLV4wNlFJFlNp1cFmZzmJmG3scXPZQ1aJM33ol/hV0=,iv:67MnPLlTh1WO6c15hB4LkeKc91r8epS5MZWT6LCOVRk=,tag:msZ3iBU+poU3BRDtV6G5zg==,type:str]
|
mac: ENC[AES256_GCM,data:rDWyDZSXNGs2q4epxCQBI5Mj8E5Dpen6F6cUU7NxTVlOI933Gi12bdpuFghrjEf2S1Lk0u/duOM07q2NJrsMOgVPws2f/jzcCzcpPeaUsrD1vkQUpCr2hUKNjSIEbrrtwanm2vbr0LMV0noxFluf68fpeph+/ZMe8eqJjxXWK+A=,iv:DvmxVM7m76trz5aXx/Llsrqmk53uTipo4SHaOdc2YUM=,tag:cIC5iF7+iaIjwLiYR22exg==,type:str]
|
||||||
pgp:
|
pgp:
|
||||||
- created_at: "2025-08-24T02:21:34Z"
|
- created_at: "2025-08-24T02:21:34Z"
|
||||||
enc: |-
|
enc: |-
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
# Hook home-manager to make a trampoline for each app we install
|
# Hook home-manager to make a trampoline for each app we install
|
||||||
# from: https://github.com/nix-community/home-manager/issues/1341#issuecomment-1870352014
|
# from: https://github.com/nix-community/home-manager/issues/1341#issuecomment-1870352014
|
||||||
{
|
{
|
||||||
config,
|
|
||||||
lib,
|
lib,
|
||||||
pkgs,
|
pkgs,
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{ namespace, ... }:
|
{ config, namespace, ... }:
|
||||||
{
|
{
|
||||||
${namespace} = {
|
${namespace} = {
|
||||||
services = {
|
services = {
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
enable = true;
|
enable = true;
|
||||||
port = 9898;
|
port = 9898;
|
||||||
apiAddress = "10.0.1.3";
|
apiAddress = "10.0.1.3";
|
||||||
apiKey = "1daH89qmJ41r2Lpd9hvDw4sxtOAtBzaj3aKFOFqE";
|
apiKey = config.sops.secrets."jallen-nas/crowdsec-capi".path;
|
||||||
dataDir = "/media/nas/main/nix-app-data/crowdsec";
|
dataDir = "/media/nas/main/nix-app-data/crowdsec";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -94,6 +94,15 @@ in
|
|||||||
restartUnits = [ "podman-collabora.service" ];
|
restartUnits = [ "podman-collabora.service" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# ------------------------------
|
||||||
|
# crowdsec
|
||||||
|
# ------------------------------
|
||||||
|
|
||||||
|
"jallen-nas/crowdsec-capi" = {
|
||||||
|
sopsFile = defaultSops;
|
||||||
|
restartUnits = [ "crowdsec.service" ];
|
||||||
|
};
|
||||||
|
|
||||||
# ------------------------------
|
# ------------------------------
|
||||||
# mariadb # TODO
|
# mariadb # TODO
|
||||||
# ------------------------------
|
# ------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user