mirror of
https://gitlab.com/upRootNutrition/dotfiles.git
synced 2025-12-07 05:27:13 -06:00
test: jellyfin microVM
This commit is contained in:
parent
b553e92ad1
commit
e25c1a2e06
13 changed files with 271 additions and 358 deletions
|
|
@ -287,6 +287,7 @@ in
|
||||||
sslPath = "${var}/acme";
|
sslPath = "${var}/acme";
|
||||||
sopsPath = "${var}/secrets";
|
sopsPath = "${var}/secrets";
|
||||||
secretPath = "${var}/secrets";
|
secretPath = "${var}/secrets";
|
||||||
|
cachePath = "/var/cache";
|
||||||
dummy = "";
|
dummy = "";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ let
|
||||||
sslPath
|
sslPath
|
||||||
varPath
|
varPath
|
||||||
mntPath
|
mntPath
|
||||||
|
cachePath
|
||||||
secretPath
|
secretPath
|
||||||
;
|
;
|
||||||
label = "Jellyfin";
|
label = "Jellyfin";
|
||||||
|
|
@ -53,6 +54,7 @@ in
|
||||||
};
|
};
|
||||||
varPaths = {
|
varPaths = {
|
||||||
path0 = "${varPath}/${name}";
|
path0 = "${varPath}/${name}";
|
||||||
|
path1 = "${cachePath}/${name}";
|
||||||
};
|
};
|
||||||
mntPaths = {
|
mntPaths = {
|
||||||
path0 = "${mntPath}/${name}";
|
path0 = "${mntPath}/${name}";
|
||||||
|
|
|
||||||
|
|
@ -1,40 +1,40 @@
|
||||||
{
|
{
|
||||||
pkgs,
|
pkgs,
|
||||||
lib,
|
# lib,
|
||||||
flake,
|
# flake,
|
||||||
osConfig,
|
# osConfig,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
# let
|
||||||
inherit (flake.config.machines.devices) mars deimos;
|
# inherit (flake.config.machines.devices) mars deimos;
|
||||||
hostname = osConfig.networking.hostName;
|
# hostname = osConfig.networking.hostName;
|
||||||
|
|
||||||
sharedPaths = ''
|
# sharedPaths = ''
|
||||||
${pkgs.zoxide}/bin/zoxide add ~/projects/dotfiles
|
# ${pkgs.zoxide}/bin/zoxide add ~/projects/dotfiles
|
||||||
${pkgs.zoxide}/bin/zoxide add ~/downloads
|
# ${pkgs.zoxide}/bin/zoxide add ~/downloads
|
||||||
${pkgs.zoxide}/bin/zoxide add ~/projects
|
# ${pkgs.zoxide}/bin/zoxide add ~/projects
|
||||||
${pkgs.zoxide}/bin/zoxide add /mnt/media/ceres/jellyfin
|
# ${pkgs.zoxide}/bin/zoxide add /mnt/media/ceres/jellyfin
|
||||||
${pkgs.zoxide}/bin/zoxide add /mnt/media/ceres/comfyui
|
# ${pkgs.zoxide}/bin/zoxide add /mnt/media/ceres/comfyui
|
||||||
'';
|
# '';
|
||||||
|
|
||||||
desktopPaths = ''
|
# desktopPaths = ''
|
||||||
${pkgs.zoxide}/bin/zoxide add ~/projects/website
|
# ${pkgs.zoxide}/bin/zoxide add ~/projects/website
|
||||||
${pkgs.zoxide}/bin/zoxide add ~/projects/workflowbuilder
|
# ${pkgs.zoxide}/bin/zoxide add ~/projects/workflowbuilder
|
||||||
${pkgs.zoxide}/bin/zoxide add /mnt/media/storage
|
# ${pkgs.zoxide}/bin/zoxide add /mnt/media/storage
|
||||||
'';
|
# '';
|
||||||
|
|
||||||
zoxidePaths = {
|
# zoxidePaths = {
|
||||||
home.activation.initZoxidePaths = lib.hm.dag.entryAfter [ "writeBoundary" ] (
|
# home.activation.initZoxidePaths = lib.hm.dag.entryAfter [ "writeBoundary" ] (
|
||||||
if hostname == mars.name then
|
# if hostname == mars.name then
|
||||||
(sharedPaths + desktopPaths)
|
# (sharedPaths + desktopPaths)
|
||||||
else if hostname == deimos.name then
|
# else if hostname == deimos.name then
|
||||||
sharedPaths
|
# sharedPaths
|
||||||
else
|
# else
|
||||||
""
|
# ""
|
||||||
);
|
# );
|
||||||
};
|
# };
|
||||||
|
|
||||||
in
|
# in
|
||||||
{
|
{
|
||||||
programs.zoxide = {
|
programs.zoxide = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
@ -44,4 +44,4 @@ in
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// zoxidePaths
|
# // zoxidePaths
|
||||||
|
|
|
||||||
|
|
@ -44,15 +44,15 @@ in
|
||||||
ceres = {
|
ceres = {
|
||||||
imports = builtins.attrValues {
|
imports = builtins.attrValues {
|
||||||
inherit (modules)
|
inherit (modules)
|
||||||
acmeCeres
|
acme
|
||||||
# audiobookshelf
|
# audiobookshelf
|
||||||
caddyCeres
|
caddy
|
||||||
# comfyui
|
# comfyui
|
||||||
# filesorter
|
# filesorter
|
||||||
# firefly-iii
|
# firefly-iii
|
||||||
# forgejo
|
# forgejo
|
||||||
# glance
|
# glance
|
||||||
# jellyfin
|
jellyfin
|
||||||
# logrotate
|
# logrotate
|
||||||
# mastodon
|
# mastodon
|
||||||
microvm
|
microvm
|
||||||
|
|
|
||||||
|
|
@ -1,87 +0,0 @@
|
||||||
{
|
|
||||||
config,
|
|
||||||
flake,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
inherit (flake.config.people) user0;
|
|
||||||
inherit (flake.config.people.users.${user0}) email;
|
|
||||||
inherit (flake.config.services) instances;
|
|
||||||
domain0 = instances.web.domains.url0;
|
|
||||||
domain1 = instances.web.domains.url1;
|
|
||||||
domain4 = flake.inputs.linkpage.secrets.domains.projectsite;
|
|
||||||
service = instances.acme;
|
|
||||||
dns0 = instances.web.dns.provider0;
|
|
||||||
dns1 = instances.web.dns.provider1;
|
|
||||||
dns0Path = "dns/${dns0}";
|
|
||||||
dns1Path = "dns/${dns1}";
|
|
||||||
in
|
|
||||||
{
|
|
||||||
security.acme = {
|
|
||||||
acceptTerms = true;
|
|
||||||
defaults = {
|
|
||||||
email = email.address0;
|
|
||||||
server = "https://acme-v02.api.letsencrypt.org/directory";
|
|
||||||
};
|
|
||||||
certs =
|
|
||||||
let
|
|
||||||
dnsConfig = provider: dns: {
|
|
||||||
dnsProvider = dns;
|
|
||||||
environmentFile = config.sops.secrets.${provider}.path;
|
|
||||||
};
|
|
||||||
in
|
|
||||||
{
|
|
||||||
# "${instances.audiobookshelf.domains.url0}" = dnsConfig dns0Path dns0;
|
|
||||||
# "${instances.glance.domains.url0}" = dnsConfig dns0Path dns0;
|
|
||||||
# "${instances.jellyfin.domains.url0}" = dnsConfig dns0Path dns0;
|
|
||||||
# "${instances.ollama.domains.url0}" = dnsConfig dns0Path dns0;
|
|
||||||
# "${instances.searx.domains.url0}" = dnsConfig dns0Path dns0;
|
|
||||||
# "${instances.syncthing.domains.url0}" = dnsConfig dns0Path dns0;
|
|
||||||
# "${instances.vaultwarden.domains.url0}" = dnsConfig dns0Path dns0; # Moved to vaultwarden service module
|
|
||||||
# "${instances.prompter.domains.url0}" = dnsConfig dns0Path dns0;
|
|
||||||
# "${instances.comfyui.domains.url0}" = dnsConfig dns0Path dns0;
|
|
||||||
# "${instances.firefly-iii.domains.url0}" = dnsConfig dns0Path dns0;
|
|
||||||
# "${instances.opencloud.domains.url0}" = dnsConfig dns0Path dns0;
|
|
||||||
"${instances.forgejo.domains.url0}" = dnsConfig dns0Path dns0;
|
|
||||||
# "${instances.mastodon.domains.url0}" = dnsConfig dns0Path dns0;
|
|
||||||
# "${domain0}" = dnsConfig dns0Path dns0;
|
|
||||||
# "${domain1}" = dnsConfig dns0Path dns0;
|
|
||||||
# "${domain4}" = dnsConfig dns1Path dns1;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
sops =
|
|
||||||
let
|
|
||||||
dnsList = [
|
|
||||||
dns0
|
|
||||||
dns1
|
|
||||||
];
|
|
||||||
secretList = [
|
|
||||||
"pass"
|
|
||||||
];
|
|
||||||
sopsPath = secret: dns: {
|
|
||||||
path = "/var/lib/secrets/${instances.acme.name}/${dns}-${secret}";
|
|
||||||
owner = "root";
|
|
||||||
mode = "600";
|
|
||||||
};
|
|
||||||
in
|
|
||||||
{
|
|
||||||
secrets = builtins.listToAttrs (
|
|
||||||
builtins.concatLists (
|
|
||||||
map (
|
|
||||||
dns:
|
|
||||||
map (secret: {
|
|
||||||
name = "dns/${dns}";
|
|
||||||
value = sopsPath secret dns;
|
|
||||||
}) secretList
|
|
||||||
) dnsList
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd = {
|
|
||||||
tmpfiles.rules = [
|
|
||||||
"Z ${service.sops.path0} 755 ${service.name} ${service.name} -"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -1,75 +0,0 @@
|
||||||
{
|
|
||||||
config,
|
|
||||||
flake,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
inherit (flake.config.people) user0;
|
|
||||||
inherit (flake.config.people.users.${user0}) email;
|
|
||||||
inherit (flake.config.services) instances;
|
|
||||||
service = instances.acme;
|
|
||||||
domain0 = instances.web.domains.url0;
|
|
||||||
dns0 = instances.web.dns.provider0;
|
|
||||||
dns0Path = "dns/${dns0}";
|
|
||||||
instanceName = service: (instances.${service}.subdomain);
|
|
||||||
|
|
||||||
dnsConfig = provider: dns: {
|
|
||||||
dnsProvider = dns;
|
|
||||||
directory = instances.acme.paths.path0;
|
|
||||||
environmentFile = config.sops.secrets.${provider}.path;
|
|
||||||
};
|
|
||||||
in
|
|
||||||
{
|
|
||||||
security.acme = {
|
|
||||||
acceptTerms = true;
|
|
||||||
defaults = {
|
|
||||||
email = email.address0;
|
|
||||||
server = "https://acme-v02.api.letsencrypt.org/directory";
|
|
||||||
};
|
|
||||||
certs = builtins.listToAttrs (
|
|
||||||
(map
|
|
||||||
(service: {
|
|
||||||
name = "${instanceName service}.${domain0}";
|
|
||||||
value = dnsConfig dns0Path dns0;
|
|
||||||
})
|
|
||||||
[
|
|
||||||
# instances.opencloud.name
|
|
||||||
]
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
sops =
|
|
||||||
let
|
|
||||||
dnsList = [
|
|
||||||
dns0
|
|
||||||
];
|
|
||||||
secretList = [
|
|
||||||
"pass"
|
|
||||||
];
|
|
||||||
sopsPath = secret: dns: {
|
|
||||||
path = "/var/lib/secrets/${instances.acme.name}/${dns}-${secret}";
|
|
||||||
owner = "root";
|
|
||||||
mode = "600";
|
|
||||||
};
|
|
||||||
in
|
|
||||||
{
|
|
||||||
secrets = builtins.listToAttrs (
|
|
||||||
builtins.concatLists (
|
|
||||||
map (
|
|
||||||
dns:
|
|
||||||
map (secret: {
|
|
||||||
name = "dns/${dns}";
|
|
||||||
value = sopsPath secret dns;
|
|
||||||
}) secretList
|
|
||||||
) dnsList
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd = {
|
|
||||||
tmpfiles.rules = [
|
|
||||||
"Z ${service.sops.path0} 755 ${service.name} ${service.name} -"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +1,56 @@
|
||||||
|
{
|
||||||
|
flake,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
importList =
|
inherit (flake.config.people) user0;
|
||||||
let
|
inherit (flake.config.people.users.${user0}) email;
|
||||||
content = builtins.readDir ./.;
|
inherit (flake.config.services) instances;
|
||||||
dirContent = builtins.filter (n: content.${n} == "directory") (builtins.attrNames content);
|
service = instances.acme;
|
||||||
in
|
dns0 = instances.web.dns.provider0;
|
||||||
map (name: ./. + "/${name}") dirContent;
|
dns1 = instances.web.dns.provider1;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = importList;
|
security.acme = {
|
||||||
|
acceptTerms = true;
|
||||||
|
defaults = {
|
||||||
|
email = email.address0;
|
||||||
|
server = "https://acme-v02.api.letsencrypt.org/directory";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
sops =
|
||||||
|
let
|
||||||
|
dnsList = [
|
||||||
|
dns0
|
||||||
|
dns1
|
||||||
|
];
|
||||||
|
secretList = [
|
||||||
|
"pass"
|
||||||
|
];
|
||||||
|
sopsPath = secret: dns: {
|
||||||
|
path = "/var/lib/secrets/${instances.acme.name}/${dns}-${secret}";
|
||||||
|
owner = "root";
|
||||||
|
mode = "600";
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
secrets = builtins.listToAttrs (
|
||||||
|
builtins.concatLists (
|
||||||
|
map (
|
||||||
|
dns:
|
||||||
|
map (secret: {
|
||||||
|
name = "dns/${dns}";
|
||||||
|
value = sopsPath secret dns;
|
||||||
|
}) secretList
|
||||||
|
) dnsList
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd = {
|
||||||
|
tmpfiles.rules = [
|
||||||
|
"Z ${service.sops.path0} 755 ${service.name} ${service.name} -"
|
||||||
|
];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
{ flake, ... }:
|
|
||||||
let
|
|
||||||
inherit (flake.config.services) instances;
|
|
||||||
|
|
||||||
service = instances.caddy;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
services.caddy = {
|
|
||||||
enable = true;
|
|
||||||
};
|
|
||||||
users.users.${service.name}.extraGroups = [
|
|
||||||
"acme"
|
|
||||||
"mastodon"
|
|
||||||
"firefly-iii"
|
|
||||||
];
|
|
||||||
|
|
||||||
networking = {
|
|
||||||
firewall = {
|
|
||||||
allowedTCPPorts = [
|
|
||||||
service.ports.port0
|
|
||||||
service.ports.port1
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
{ flake, ... }:
|
|
||||||
let
|
|
||||||
inherit (flake.config.services.instances) caddy;
|
|
||||||
|
|
||||||
service = caddy;
|
|
||||||
|
|
||||||
in
|
|
||||||
{
|
|
||||||
services.caddy = {
|
|
||||||
enable = true;
|
|
||||||
};
|
|
||||||
users.users.${service.name}.extraGroups = [
|
|
||||||
"acme"
|
|
||||||
];
|
|
||||||
|
|
||||||
networking = {
|
|
||||||
firewall = {
|
|
||||||
allowedTCPPorts = [
|
|
||||||
service.ports.port0
|
|
||||||
service.ports.port1
|
|
||||||
service.ports.port2
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +1,20 @@
|
||||||
|
{ flake, ... }:
|
||||||
let
|
let
|
||||||
importList =
|
inherit (flake.config.services) instances;
|
||||||
let
|
|
||||||
content = builtins.readDir ./.;
|
service = instances.caddy;
|
||||||
dirContent = builtins.filter (n: content.${n} == "directory") (builtins.attrNames content);
|
|
||||||
in
|
|
||||||
map (name: ./. + "/${name}") dirContent;
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = importList;
|
services.caddy = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
networking = {
|
||||||
|
firewall = {
|
||||||
|
allowedTCPPorts = [
|
||||||
|
service.ports.port0
|
||||||
|
service.ports.port1
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,133 @@
|
||||||
{ flake, ... }:
|
{
|
||||||
|
config,
|
||||||
|
flake,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
inherit (flake.config.people) user0;
|
inherit (flake.config.people) user0;
|
||||||
inherit (flake.config.machines.devices) ceres;
|
inherit (flake.config.services) instances;
|
||||||
inherit (flake.config.services.instances) jellyfin web;
|
serviceCfg = flake.config.services.instances.jellyfin;
|
||||||
service = jellyfin;
|
hostCfg = flake.config.services.instances.web;
|
||||||
localhost = web.localhost.address0;
|
host = serviceCfg.domains.url0;
|
||||||
host = service.domains.url0;
|
dns0 = instances.web.dns.provider0;
|
||||||
|
dns0Path = "dns/${dns0}";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
users.users.caddy.extraGroups = [ "acme" ];
|
||||||
|
|
||||||
|
security.acme.certs."${host}" = {
|
||||||
|
dnsProvider = dns0;
|
||||||
|
environmentFile = config.sops.secrets.${dns0Path}.path;
|
||||||
|
group = "caddy";
|
||||||
|
};
|
||||||
|
|
||||||
|
microvm.vms.jellyin = {
|
||||||
|
autostart = true;
|
||||||
|
|
||||||
|
restartIfChanged = true;
|
||||||
|
config = {
|
||||||
|
system.stateVersion = "24.05";
|
||||||
|
time.timeZone = "America/Winnipeg";
|
||||||
|
users.users.root.openssh.authorizedKeys.keys = flake.config.people.users.${user0}.sshKeys;
|
||||||
|
services = {
|
||||||
|
jellyfin = {
|
||||||
|
enable = true;
|
||||||
|
openFirewall = true;
|
||||||
|
user = user0;
|
||||||
|
};
|
||||||
|
jellyseerr = {
|
||||||
|
openFirewall = true;
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
openssh = {
|
||||||
|
enable = true;
|
||||||
|
settings = {
|
||||||
|
PasswordAuthentication = false;
|
||||||
|
PermitRootLogin = "prohibit-password";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.firewall.allowedTCPPorts = [
|
||||||
|
serviceCfg.ports.port0
|
||||||
|
serviceCfg.ports.port1
|
||||||
|
serviceCfg.ports.port2
|
||||||
|
];
|
||||||
|
systemd.network = {
|
||||||
|
enable = true;
|
||||||
|
networks."20-lan" = {
|
||||||
|
matchConfig.Name = "enp0s5";
|
||||||
|
addresses = [
|
||||||
|
{ Address = "${serviceCfg.interface.ip}/24"; }
|
||||||
|
];
|
||||||
|
routes = [
|
||||||
|
{
|
||||||
|
Destination = "${hostCfg.localhost.address1}/0";
|
||||||
|
Gateway = serviceCfg.interface.gate;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
dns = [
|
||||||
|
"1.1.1.1"
|
||||||
|
"8.8.8.8"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.systemd-networkd.wantedBy = [ "multi-user.target" ];
|
||||||
|
microvm = {
|
||||||
|
vcpu = 4;
|
||||||
|
mem = 4096;
|
||||||
|
hypervisor = "qemu";
|
||||||
|
interfaces = [
|
||||||
|
{
|
||||||
|
type = "tap";
|
||||||
|
id = serviceCfg.interface.id;
|
||||||
|
mac = serviceCfg.interface.mac;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
type = "user";
|
||||||
|
id = serviceCfg.interface.idUser;
|
||||||
|
mac = serviceCfg.interface.macUser;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
forwardPorts = [
|
||||||
|
{
|
||||||
|
from = "host";
|
||||||
|
host.port = serviceCfg.interface.ssh;
|
||||||
|
guest.port = 22;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
shares = [
|
||||||
|
{
|
||||||
|
mountPoint = "/nix/.ro-store";
|
||||||
|
proto = "virtiofs";
|
||||||
|
source = "/nix/store";
|
||||||
|
tag = "read_only_nix_store";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
mountPoint = serviceCfg.varPaths.path0;
|
||||||
|
proto = "virtiofs";
|
||||||
|
source = serviceCfg.mntPaths.path0;
|
||||||
|
tag = "service_data";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
mountPoint = serviceCfg.varPaths.path1;
|
||||||
|
proto = "virtiofs";
|
||||||
|
source = "${serviceCfg.mntPaths.path0}/cache";
|
||||||
|
tag = "service_cache";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"d ${serviceCfg.mntPaths.path0} 0755 root root -"
|
||||||
|
];
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
jellyfin = {
|
|
||||||
enable = true;
|
|
||||||
openFirewall = true;
|
|
||||||
user = user0;
|
|
||||||
};
|
|
||||||
jellyseerr = {
|
|
||||||
openFirewall = true;
|
|
||||||
enable = true;
|
|
||||||
};
|
|
||||||
caddy = {
|
caddy = {
|
||||||
virtualHosts = {
|
virtualHosts = {
|
||||||
"${host}" = {
|
"${host}" = {
|
||||||
|
|
@ -25,50 +135,12 @@ in
|
||||||
redir /.well-known/carddav /remote.php/dav/ 301
|
redir /.well-known/carddav /remote.php/dav/ 301
|
||||||
redir /.well-known/caldav /remote.php/dav/ 301
|
redir /.well-known/caldav /remote.php/dav/ 301
|
||||||
|
|
||||||
reverse_proxy ${localhost}:${toString service.ports.port0}
|
reverse_proxy ${serviceCfg.interface.ip}:${toString serviceCfg.ports.port0}
|
||||||
|
|
||||||
tls ${service.ssl.cert} ${service.ssl.key}
|
tls ${serviceCfg.ssl.cert} ${serviceCfg.ssl.key}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
fileSystems =
|
|
||||||
let
|
|
||||||
settings = {
|
|
||||||
fsType = "none";
|
|
||||||
options = [
|
|
||||||
"bind"
|
|
||||||
];
|
|
||||||
depends = [
|
|
||||||
ceres.storage0.mount
|
|
||||||
];
|
|
||||||
};
|
|
||||||
in
|
|
||||||
{
|
|
||||||
"/var/lib/${service.name}" = {
|
|
||||||
device = service.paths.path0;
|
|
||||||
}
|
|
||||||
// settings;
|
|
||||||
"/var/cache/${service.name}" = {
|
|
||||||
device = "${service.paths.path1}";
|
|
||||||
}
|
|
||||||
// settings;
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.tmpfiles.rules = [
|
|
||||||
"Z ${service.paths.path0} 0755 ${user0} ${service.name} -"
|
|
||||||
"Z ${service.paths.path0} 0755 ${user0} ${service.name} -"
|
|
||||||
];
|
|
||||||
|
|
||||||
networking = {
|
|
||||||
firewall = {
|
|
||||||
allowedTCPPorts = [
|
|
||||||
service.ports.port0
|
|
||||||
service.ports.port1
|
|
||||||
service.ports.port2
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,21 +4,15 @@
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
vaultwardenCfg = flake.config.services.instances.vaultwarden;
|
|
||||||
smtpCfg = flake.config.services.instances.smtp;
|
|
||||||
inherit (flake.config.people) user0;
|
inherit (flake.config.people) user0;
|
||||||
inherit (flake.config.services) instances;
|
inherit (flake.config.services) instances;
|
||||||
|
serviceCfg = flake.config.services.instances.vaultwarden;
|
||||||
|
smtpCfg = flake.config.services.instances.smtp;
|
||||||
|
host = serviceCfg.domains.url0;
|
||||||
dns0 = instances.web.dns.provider0;
|
dns0 = instances.web.dns.provider0;
|
||||||
dns0Path = "dns/${dns0}";
|
dns0Path = "dns/${dns0}";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
users.users.caddy.extraGroups = [ "acme" ];
|
|
||||||
security.acme.certs."${vaultwardenCfg.domains.url0}" = {
|
|
||||||
dnsProvider = dns0;
|
|
||||||
environmentFile = config.sops.secrets.${dns0Path}.path;
|
|
||||||
group = "caddy";
|
|
||||||
};
|
|
||||||
|
|
||||||
microvm.vms.vaultwarden = {
|
microvm.vms.vaultwarden = {
|
||||||
autostart = true;
|
autostart = true;
|
||||||
|
|
@ -32,13 +26,13 @@ in
|
||||||
dbBackend = "sqlite";
|
dbBackend = "sqlite";
|
||||||
config = {
|
config = {
|
||||||
# Domain Configuration
|
# Domain Configuration
|
||||||
DOMAIN = "https://${vaultwardenCfg.domains.url0}";
|
DOMAIN = "https://${host}";
|
||||||
|
|
||||||
# Email Configuration
|
# Email Configuration
|
||||||
SMTP_AUTH_MECHANISM = "Plain";
|
SMTP_AUTH_MECHANISM = "Plain";
|
||||||
SMTP_EMBED_IMAGES = true;
|
SMTP_EMBED_IMAGES = true;
|
||||||
SMTP_FROM = vaultwardenCfg.email.address0;
|
SMTP_FROM = serviceCfg.email.address0;
|
||||||
SMTP_FROM_NAME = vaultwardenCfg.label;
|
SMTP_FROM_NAME = serviceCfg.label;
|
||||||
SMTP_HOST = smtpCfg.hostname;
|
SMTP_HOST = smtpCfg.hostname;
|
||||||
SMTP_PORT = smtpCfg.ports.port1;
|
SMTP_PORT = smtpCfg.ports.port1;
|
||||||
SMTP_SECURITY = smtpCfg.records.record1;
|
SMTP_SECURITY = smtpCfg.records.record1;
|
||||||
|
|
@ -57,11 +51,11 @@ in
|
||||||
|
|
||||||
# Rocket (Web Server) Settings
|
# Rocket (Web Server) Settings
|
||||||
ROCKET_ADDRESS = "0.0.0.0";
|
ROCKET_ADDRESS = "0.0.0.0";
|
||||||
ROCKET_PORT = vaultwardenCfg.ports.port0;
|
ROCKET_PORT = serviceCfg.ports.port0;
|
||||||
};
|
};
|
||||||
|
|
||||||
# Environment file with secrets (mounted from host)
|
# Environment file with secrets (mounted from host)
|
||||||
environmentFile = "/run/secrets/vaultwarden/env";
|
environmentFile = "/run/secrets/${serviceCfg.name}/env";
|
||||||
};
|
};
|
||||||
|
|
||||||
services.openssh = {
|
services.openssh = {
|
||||||
|
|
@ -78,18 +72,18 @@ in
|
||||||
139 # SMTP
|
139 # SMTP
|
||||||
587 # SMTP
|
587 # SMTP
|
||||||
2525 # SMTP
|
2525 # SMTP
|
||||||
vaultwardenCfg.ports.port0
|
serviceCfg.ports.port0
|
||||||
];
|
];
|
||||||
|
|
||||||
systemd.network = {
|
systemd.network = {
|
||||||
enable = true;
|
enable = true;
|
||||||
networks."20-lan" = {
|
networks."20-lan" = {
|
||||||
matchConfig.Name = "enp0s5";
|
matchConfig.Name = "enp0s5";
|
||||||
addresses = [ { Address = "${vaultwardenCfg.interface.ip}/24"; } ];
|
addresses = [ { Address = "${serviceCfg.interface.ip}/24"; } ];
|
||||||
routes = [
|
routes = [
|
||||||
{
|
{
|
||||||
Destination = "0.0.0.0/0";
|
Destination = "0.0.0.0/0";
|
||||||
Gateway = vaultwardenCfg.interface.gate;
|
Gateway = serviceCfg.interface.gate;
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
dns = [
|
dns = [
|
||||||
|
|
@ -108,19 +102,19 @@ in
|
||||||
interfaces = [
|
interfaces = [
|
||||||
{
|
{
|
||||||
type = "tap";
|
type = "tap";
|
||||||
id = vaultwardenCfg.interface.id;
|
id = serviceCfg.interface.id;
|
||||||
mac = vaultwardenCfg.interface.mac;
|
mac = serviceCfg.interface.mac;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
type = "user";
|
type = "user";
|
||||||
id = vaultwardenCfg.interface.idUser;
|
id = serviceCfg.interface.idUser;
|
||||||
mac = vaultwardenCfg.interface.macUser;
|
mac = serviceCfg.interface.macUser;
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
forwardPorts = [
|
forwardPorts = [
|
||||||
{
|
{
|
||||||
from = "host";
|
from = "host";
|
||||||
host.port = vaultwardenCfg.interface.ssh;
|
host.port = serviceCfg.interface.ssh;
|
||||||
guest.port = 22;
|
guest.port = 22;
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
@ -134,7 +128,7 @@ in
|
||||||
{
|
{
|
||||||
mountPoint = "/var/lib/bitwarden_rs";
|
mountPoint = "/var/lib/bitwarden_rs";
|
||||||
proto = "virtiofs";
|
proto = "virtiofs";
|
||||||
source = vaultwardenCfg.mntPaths.path0;
|
source = serviceCfg.mntPaths.path0;
|
||||||
tag = "vaultwarden_data";
|
tag = "vaultwarden_data";
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
|
@ -148,22 +142,32 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.tmpfiles.rules = [
|
security.acme.certs."${host}" = {
|
||||||
"d ${vaultwardenCfg.mntPaths.path0} 0755 root root -"
|
dnsProvider = dns0;
|
||||||
];
|
environmentFile = config.sops.secrets.${dns0Path}.path;
|
||||||
|
group = "caddy";
|
||||||
services.caddy.virtualHosts."${vaultwardenCfg.domains.url0}" = {
|
|
||||||
extraConfig = ''
|
|
||||||
reverse_proxy ${vaultwardenCfg.interface.ip}:${toString vaultwardenCfg.ports.port0} {
|
|
||||||
header_up X-Real-IP {remote_host}
|
|
||||||
}
|
|
||||||
tls ${vaultwardenCfg.ssl.cert} ${vaultwardenCfg.ssl.key}
|
|
||||||
encode zstd gzip
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
services.caddy.virtualHosts = {
|
||||||
|
"${host}" = {
|
||||||
|
extraConfig = ''
|
||||||
|
reverse_proxy ${serviceCfg.interface.ip}:${toString serviceCfg.ports.port0} {
|
||||||
|
header_up X-Real-IP {remote_host}
|
||||||
|
}
|
||||||
|
tls ${serviceCfg.ssl.cert} ${serviceCfg.ssl.key}
|
||||||
|
encode zstd gzip
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
users.users.caddy.extraGroups = [ "acme" ];
|
||||||
|
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"d ${serviceCfg.mntPaths.path0} 0755 root root -"
|
||||||
|
];
|
||||||
|
|
||||||
sops.secrets = {
|
sops.secrets = {
|
||||||
"vaultwarden/env" = {
|
"${serviceCfg.name}/env" = {
|
||||||
owner = "root";
|
owner = "root";
|
||||||
mode = "0600";
|
mode = "0600";
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,10 @@ let
|
||||||
wireguardService = instances.wireGuard;
|
wireguardService = instances.wireGuard;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
# Enable microVM host
|
|
||||||
microvm.host.enable = true;
|
microvm.host.enable = true;
|
||||||
|
|
||||||
# systemd-networkd for bridge management (required for TAP interfaces)
|
|
||||||
systemd.network.enable = true;
|
systemd.network.enable = true;
|
||||||
|
|
||||||
# Bridge configuration for microVMs
|
|
||||||
systemd.network.netdevs."10-br-vms" = {
|
systemd.network.netdevs."10-br-vms" = {
|
||||||
netdevConfig = {
|
netdevConfig = {
|
||||||
Name = "br-vms";
|
Name = "br-vms";
|
||||||
|
|
@ -23,7 +20,6 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# Attach physical interface and tap interfaces to bridge
|
|
||||||
systemd.network.networks."20-lan" = {
|
systemd.network.networks."20-lan" = {
|
||||||
matchConfig.Name = [
|
matchConfig.Name = [
|
||||||
"enp10s0"
|
"enp10s0"
|
||||||
|
|
@ -34,7 +30,6 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# Bridge gets the host IP
|
|
||||||
systemd.network.networks."30-br-vms" = {
|
systemd.network.networks."30-br-vms" = {
|
||||||
matchConfig.Name = "br-vms";
|
matchConfig.Name = "br-vms";
|
||||||
networkConfig = {
|
networkConfig = {
|
||||||
|
|
@ -47,12 +42,9 @@ in
|
||||||
|
|
||||||
networking = {
|
networking = {
|
||||||
hostName = ceres.name;
|
hostName = ceres.name;
|
||||||
# NetworkManager disabled - using declarative networking
|
|
||||||
networkmanager.enable = false;
|
networkmanager.enable = false;
|
||||||
nftables.enable = true;
|
nftables.enable = true;
|
||||||
useDHCP = false;
|
useDHCP = false;
|
||||||
# Network configuration handled by systemd-networkd bridge
|
|
||||||
|
|
||||||
firewall = {
|
firewall = {
|
||||||
enable = true;
|
enable = true;
|
||||||
allowedTCPPorts = [
|
allowedTCPPorts = [
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue