2025-11-11 01:01:05 -06:00
|
|
|
{
|
|
|
|
|
flake,
|
|
|
|
|
config,
|
|
|
|
|
pkgs,
|
|
|
|
|
lib,
|
|
|
|
|
...
|
|
|
|
|
}:
|
|
|
|
|
let
|
|
|
|
|
inherit (flake.config.people) user0;
|
|
|
|
|
inherit (flake.config.services) instances;
|
|
|
|
|
serviceCfg = flake.config.services.instances.mastodon;
|
|
|
|
|
smtpCfg = flake.config.services.instances.smtp;
|
|
|
|
|
hostCfg = flake.config.services.instances.web;
|
|
|
|
|
host = serviceCfg.domains.url0;
|
|
|
|
|
dns0 = instances.web.dns.provider0;
|
|
|
|
|
dns0Path = "dns/${dns0}";
|
2025-11-21 18:29:53 -06:00
|
|
|
|
|
|
|
|
fedifetcherConfig = pkgs.writeText "fedifetcher-config.json" (
|
|
|
|
|
builtins.toJSON {
|
|
|
|
|
server = "https://${host}";
|
|
|
|
|
home-timeline-length = 200;
|
|
|
|
|
max-followings = 80;
|
|
|
|
|
from-notifications = 1;
|
|
|
|
|
max-bookmarks = 80;
|
|
|
|
|
max-favourites = 40;
|
|
|
|
|
backfill-with-context = 1;
|
|
|
|
|
backfill-mentioned-users = 1;
|
|
|
|
|
remember-users-for-hours = 168;
|
|
|
|
|
remember-hosts-for-days = 30;
|
|
|
|
|
http-timeout = 5;
|
|
|
|
|
lock-hours = 24;
|
|
|
|
|
log-level = "INFO";
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
fedifetcherPython = pkgs.python3.withPackages (
|
|
|
|
|
ps: with ps; [
|
|
|
|
|
requests
|
|
|
|
|
pytz
|
|
|
|
|
beautifulsoup4
|
2025-12-02 03:47:29 -06:00
|
|
|
certifi
|
|
|
|
|
charset-normalizer
|
|
|
|
|
defusedxml
|
|
|
|
|
docutils
|
|
|
|
|
idna
|
|
|
|
|
iniconfig
|
|
|
|
|
packaging
|
|
|
|
|
pluggy
|
|
|
|
|
pytest
|
|
|
|
|
python-dateutil
|
|
|
|
|
requests
|
|
|
|
|
six
|
|
|
|
|
smmap
|
|
|
|
|
urllib3
|
|
|
|
|
xxhash
|
2025-11-21 18:29:53 -06:00
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
fedifetcherSrc = pkgs.fetchFromGitHub {
|
|
|
|
|
owner = "nanos";
|
|
|
|
|
repo = "FediFetcher";
|
|
|
|
|
rev = "main";
|
|
|
|
|
hash = "sha256-/J7psV/mA7okuuO7/aXVVWS9p63eMncG2CEEGN38ip0=";
|
|
|
|
|
};
|
2025-11-11 01:01:05 -06:00
|
|
|
in
|
|
|
|
|
{
|
|
|
|
|
# If you need to start fresh for some reason, run these to create the new Admin account:
|
|
|
|
|
# sudo -u mastodon mastodon-tootctl accounts create nick --email=nick@localhost --confirmed --role=Owner
|
|
|
|
|
# sudo -u mastodon mastodon-tootctl accounts approve nick
|
|
|
|
|
# If you fuck up and lose the password, use this:
|
|
|
|
|
# sudo mastodon-tootctl accounts modify --reset-password nick
|
|
|
|
|
# If you really fuck up and name yourself wrong, use this shit
|
|
|
|
|
# sudo mastodon-tootctl accounts modify username --remove-role
|
2025-11-21 06:02:56 -06:00
|
|
|
|
2025-11-21 21:55:56 -06:00
|
|
|
nixpkgs.overlays = [
|
|
|
|
|
(final: prev: {
|
|
|
|
|
mastodon = prev.mastodon.overrideAttrs (oldAttrs: {
|
|
|
|
|
patches = (oldAttrs.patches or [ ]) ++ [
|
|
|
|
|
./config/chars.patch
|
|
|
|
|
];
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
];
|
|
|
|
|
|
2025-11-11 01:01:05 -06:00
|
|
|
microvm.vms = {
|
|
|
|
|
${serviceCfg.name} = {
|
|
|
|
|
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;
|
2025-11-21 18:29:53 -06:00
|
|
|
|
2025-11-11 01:01:05 -06:00
|
|
|
services = {
|
|
|
|
|
${serviceCfg.name} = {
|
|
|
|
|
enable = true;
|
|
|
|
|
localDomain = host;
|
2025-11-17 02:26:07 -06:00
|
|
|
secretKeyBaseFile = "/etc/mastodon-secrets/pass";
|
2025-11-11 01:01:05 -06:00
|
|
|
streamingProcesses = 7;
|
2025-11-17 02:26:07 -06:00
|
|
|
trustedProxy = hostCfg.localhost.address0;
|
2025-11-11 01:01:05 -06:00
|
|
|
automaticMigrations = true;
|
|
|
|
|
database = {
|
|
|
|
|
createLocally = true;
|
|
|
|
|
name = serviceCfg.name;
|
|
|
|
|
host = "/run/postgresql";
|
|
|
|
|
user = serviceCfg.name;
|
2025-11-17 02:26:07 -06:00
|
|
|
passwordFile = "/etc/mastodon-secrets/database";
|
2025-11-11 01:01:05 -06:00
|
|
|
};
|
|
|
|
|
extraConfig = {
|
2025-11-21 19:14:02 -06:00
|
|
|
SINGLE_USER_MODE = "false";
|
2025-11-11 01:01:05 -06:00
|
|
|
SMTP_AUTH_METHOD = "plain";
|
|
|
|
|
SMTP_DELIVERY_METHOD = "smtp";
|
|
|
|
|
SMTP_ENABLE_STARTTLS_AUTO = "true";
|
|
|
|
|
SMTP_SSL = "false";
|
|
|
|
|
};
|
2025-11-21 21:55:56 -06:00
|
|
|
|
|
|
|
|
# if you're starting from scratch, you gotta cd into /var/lib/mastodon and run:
|
|
|
|
|
# sudo -u mastodon mastodon-tootctl search deploy
|
|
|
|
|
|
|
|
|
|
elasticsearch = {
|
|
|
|
|
preset = "single_node_cluster";
|
|
|
|
|
host = hostCfg.localhost.address0;
|
|
|
|
|
port = 9200;
|
|
|
|
|
};
|
2025-11-11 01:01:05 -06:00
|
|
|
mediaAutoRemove = {
|
|
|
|
|
enable = true;
|
|
|
|
|
olderThanDays = 14;
|
|
|
|
|
};
|
|
|
|
|
redis = {
|
|
|
|
|
createLocally = true;
|
|
|
|
|
enableUnixSocket = true;
|
|
|
|
|
};
|
|
|
|
|
sidekiqThreads = 25;
|
|
|
|
|
sidekiqProcesses = {
|
|
|
|
|
all = {
|
2025-11-21 18:29:53 -06:00
|
|
|
jobClasses = [ ];
|
2025-11-11 01:01:05 -06:00
|
|
|
threads = null;
|
|
|
|
|
};
|
|
|
|
|
default = {
|
2025-11-21 18:29:53 -06:00
|
|
|
jobClasses = [ "default" ];
|
2025-11-11 01:01:05 -06:00
|
|
|
threads = 5;
|
|
|
|
|
};
|
|
|
|
|
ingress = {
|
2025-11-21 18:29:53 -06:00
|
|
|
jobClasses = [ "ingress" ];
|
2025-11-11 01:01:05 -06:00
|
|
|
threads = 5;
|
|
|
|
|
};
|
|
|
|
|
push-pull = {
|
|
|
|
|
jobClasses = [
|
|
|
|
|
"push"
|
|
|
|
|
"pull"
|
|
|
|
|
];
|
|
|
|
|
threads = 5;
|
|
|
|
|
};
|
|
|
|
|
mailers = {
|
2025-11-21 18:29:53 -06:00
|
|
|
jobClasses = [ "mailers" ];
|
2025-11-11 01:01:05 -06:00
|
|
|
threads = 5;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
smtp = {
|
|
|
|
|
authenticate = true;
|
|
|
|
|
createLocally = false;
|
|
|
|
|
fromAddress = "upRootNutrition <${smtpCfg.email.address1}>";
|
|
|
|
|
host = smtpCfg.hostname;
|
2025-11-17 02:26:07 -06:00
|
|
|
passwordFile = "/etc/mastodon-secrets/smtp";
|
2025-11-11 01:01:05 -06:00
|
|
|
port = smtpCfg.ports.port1;
|
|
|
|
|
user = smtpCfg.email.address1;
|
|
|
|
|
};
|
|
|
|
|
};
|
2025-11-21 21:55:56 -06:00
|
|
|
opensearch.enable = true;
|
2025-11-11 01:01:05 -06:00
|
|
|
caddy = {
|
2025-11-11 05:00:52 -06:00
|
|
|
enable = true;
|
2025-11-11 01:01:05 -06:00
|
|
|
virtualHosts = {
|
2025-11-12 04:43:11 -06:00
|
|
|
":80" = {
|
2025-11-11 01:01:05 -06:00
|
|
|
extraConfig = ''
|
|
|
|
|
handle_path /system/* {
|
|
|
|
|
file_server * {
|
|
|
|
|
root /var/lib/mastodon/public-system
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-11-21 06:02:56 -06:00
|
|
|
|
2025-11-11 01:01:05 -06:00
|
|
|
handle /api/v1/streaming/* {
|
2025-11-17 02:26:07 -06:00
|
|
|
reverse_proxy unix//run/mastodon-streaming/streaming.socket {
|
|
|
|
|
header_up X-Forwarded-Proto {http.request.header.X-Forwarded-Proto}
|
|
|
|
|
header_up X-Forwarded-Host {http.request.header.X-Forwarded-Host}
|
|
|
|
|
}
|
2025-11-11 01:01:05 -06:00
|
|
|
}
|
2025-11-21 06:02:56 -06:00
|
|
|
|
2025-11-11 01:01:05 -06:00
|
|
|
route * {
|
|
|
|
|
file_server * {
|
|
|
|
|
root ${pkgs.mastodon}/public
|
|
|
|
|
pass_thru
|
|
|
|
|
}
|
2025-11-17 02:26:07 -06:00
|
|
|
reverse_proxy * unix//run/mastodon-web/web.socket {
|
|
|
|
|
header_up X-Forwarded-Proto {http.request.header.X-Forwarded-Proto}
|
|
|
|
|
header_up X-Forwarded-Host {http.request.header.X-Forwarded-Host}
|
|
|
|
|
}
|
2025-11-11 01:01:05 -06:00
|
|
|
}
|
2025-11-21 06:02:56 -06:00
|
|
|
|
2025-11-11 01:01:05 -06:00
|
|
|
handle_errors {
|
|
|
|
|
root * ${pkgs.mastodon}/public
|
|
|
|
|
rewrite 500.html
|
|
|
|
|
file_server
|
|
|
|
|
}
|
2025-11-21 06:02:56 -06:00
|
|
|
|
2025-11-11 01:01:05 -06:00
|
|
|
encode gzip
|
2025-11-21 06:02:56 -06:00
|
|
|
|
2025-11-11 01:01:05 -06:00
|
|
|
header /* {
|
|
|
|
|
Strict-Transport-Security "max-age=31536000;"
|
|
|
|
|
}
|
2025-11-21 06:02:56 -06:00
|
|
|
|
2025-11-11 01:01:05 -06:00
|
|
|
header /emoji/* Cache-Control "public, max-age=31536000, immutable"
|
|
|
|
|
header /packs/* Cache-Control "public, max-age=31536000, immutable"
|
|
|
|
|
header /system/accounts/avatars/* Cache-Control "public, max-age=31536000, immutable"
|
|
|
|
|
header /system/media_attachments/files/* Cache-Control "public, max-age=31536000, immutable"
|
|
|
|
|
'';
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
};
|
2025-11-21 06:02:56 -06:00
|
|
|
|
2025-11-11 01:01:05 -06:00
|
|
|
postgresql = {
|
|
|
|
|
enable = true;
|
|
|
|
|
};
|
2025-11-21 06:02:56 -06:00
|
|
|
|
2025-11-11 01:01:05 -06:00
|
|
|
openssh = {
|
|
|
|
|
enable = true;
|
|
|
|
|
settings = {
|
|
|
|
|
PasswordAuthentication = false;
|
|
|
|
|
PermitRootLogin = "prohibit-password";
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
};
|
2025-11-21 06:02:56 -06:00
|
|
|
|
2025-11-21 18:29:53 -06:00
|
|
|
users.users = {
|
|
|
|
|
${serviceCfg.name}.extraGroups = [ "postgres" ];
|
|
|
|
|
caddy.extraGroups = [ serviceCfg.name ];
|
|
|
|
|
fedifetcher = {
|
|
|
|
|
isSystemUser = true;
|
|
|
|
|
group = "fedifetcher";
|
|
|
|
|
home = "/var/lib/fedifetcher";
|
|
|
|
|
createHome = true;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
users.groups.fedifetcher = { };
|
2025-11-21 06:02:56 -06:00
|
|
|
|
2025-11-11 01:01:05 -06:00
|
|
|
networking.firewall.allowedTCPPorts = [
|
|
|
|
|
22 # SSH
|
|
|
|
|
80 # Caddy
|
|
|
|
|
25 # SMTP
|
|
|
|
|
139 # SMTP
|
|
|
|
|
587 # SMTP
|
|
|
|
|
2525 # SMTP
|
|
|
|
|
5432 # Postgres
|
|
|
|
|
];
|
2025-11-21 06:02:56 -06:00
|
|
|
|
2025-11-11 01:01:05 -06:00
|
|
|
systemd = {
|
|
|
|
|
services = {
|
2025-11-21 18:29:53 -06:00
|
|
|
mastodon-init-dirs.serviceConfig.PrivateMounts = lib.mkForce false;
|
|
|
|
|
mastodon-web.serviceConfig.PrivateMounts = lib.mkForce false;
|
|
|
|
|
mastodon-streaming-1.serviceConfig.PrivateMounts = lib.mkForce false;
|
2025-11-17 02:26:07 -06:00
|
|
|
mastodon-streaming-2.serviceConfig.PrivateMounts = lib.mkForce false;
|
|
|
|
|
mastodon-streaming-3.serviceConfig.PrivateMounts = lib.mkForce false;
|
|
|
|
|
mastodon-streaming-4.serviceConfig.PrivateMounts = lib.mkForce false;
|
|
|
|
|
mastodon-streaming-5.serviceConfig.PrivateMounts = lib.mkForce false;
|
|
|
|
|
mastodon-streaming-6.serviceConfig.PrivateMounts = lib.mkForce false;
|
|
|
|
|
mastodon-streaming-7.serviceConfig.PrivateMounts = lib.mkForce false;
|
|
|
|
|
mastodon-sidekiq-all.serviceConfig.PrivateMounts = lib.mkForce false;
|
|
|
|
|
mastodon-sidekiq-default.serviceConfig.PrivateMounts = lib.mkForce false;
|
|
|
|
|
mastodon-sidekiq-ingress.serviceConfig.PrivateMounts = lib.mkForce false;
|
|
|
|
|
mastodon-sidekiq-mailers.serviceConfig.PrivateMounts = lib.mkForce false;
|
|
|
|
|
mastodon-sidekiq-push-pull.serviceConfig.PrivateMounts = lib.mkForce false;
|
2025-11-21 18:29:53 -06:00
|
|
|
|
2025-11-17 02:26:07 -06:00
|
|
|
mastodon-copy-secrets = {
|
|
|
|
|
description = "Copy secrets from virtiofs to local filesystem";
|
2025-11-11 05:00:52 -06:00
|
|
|
before = [ "mastodon-init-dirs.service" ];
|
2025-11-17 02:26:07 -06:00
|
|
|
requiredBy = [ "mastodon-init-dirs.service" ];
|
2025-11-21 06:02:56 -06:00
|
|
|
|
2025-11-11 05:00:52 -06:00
|
|
|
serviceConfig = {
|
|
|
|
|
Type = "oneshot";
|
|
|
|
|
RemainAfterExit = true;
|
|
|
|
|
};
|
2025-11-21 06:02:56 -06:00
|
|
|
|
2025-11-11 05:00:52 -06:00
|
|
|
script = ''
|
2025-11-17 02:26:07 -06:00
|
|
|
mkdir -p /etc/mastodon-secrets
|
|
|
|
|
cp /run/secrets/pass /etc/mastodon-secrets/pass
|
|
|
|
|
cp /run/secrets/database /etc/mastodon-secrets/database
|
|
|
|
|
cp /run/secrets/redis /etc/mastodon-secrets/redis
|
|
|
|
|
cp /run/secrets/smtp /etc/mastodon-secrets/smtp
|
2025-11-21 18:29:53 -06:00
|
|
|
cp /run/secrets/fedifetcher-token /etc/mastodon-secrets/fedifetcher-token
|
2025-11-17 02:26:07 -06:00
|
|
|
chmod 755 /etc/mastodon-secrets
|
|
|
|
|
chmod 644 /etc/mastodon-secrets/*
|
2025-11-11 05:00:52 -06:00
|
|
|
'';
|
|
|
|
|
};
|
2025-11-21 18:29:53 -06:00
|
|
|
|
|
|
|
|
fedifetcher = {
|
|
|
|
|
description = "FediFetcher - Fetch missing posts for Mastodon";
|
|
|
|
|
after = [
|
|
|
|
|
"network-online.target"
|
|
|
|
|
"mastodon-web.service"
|
|
|
|
|
];
|
|
|
|
|
wants = [ "network-online.target" ];
|
|
|
|
|
|
|
|
|
|
serviceConfig = {
|
|
|
|
|
Type = "oneshot";
|
|
|
|
|
User = "fedifetcher";
|
|
|
|
|
Group = "fedifetcher";
|
|
|
|
|
WorkingDirectory = "/var/lib/fedifetcher";
|
|
|
|
|
TimeoutStartSec = "300";
|
|
|
|
|
PrivateTmp = true;
|
|
|
|
|
NoNewPrivileges = true;
|
|
|
|
|
ProtectSystem = "strict";
|
|
|
|
|
ProtectHome = true;
|
|
|
|
|
ReadWritePaths = "/var/lib/fedifetcher";
|
|
|
|
|
ExecStart =
|
|
|
|
|
let
|
|
|
|
|
script = pkgs.writeShellScript "fedifetcher-run" ''
|
|
|
|
|
set -e
|
|
|
|
|
|
|
|
|
|
# Wait for Mastodon to be fully ready
|
|
|
|
|
for i in {1..30}; do
|
|
|
|
|
if ${pkgs.curl}/bin/curl -sf http://localhost:80/health >/dev/null 2>&1; then
|
|
|
|
|
echo "Mastodon is ready"
|
|
|
|
|
break
|
|
|
|
|
fi
|
|
|
|
|
echo "Waiting for Mastodon to be ready... ($i/30)"
|
|
|
|
|
sleep 2
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
export ACCESS_TOKEN=$(cat /etc/mastodon-secrets/fedifetcher-token)
|
|
|
|
|
${fedifetcherPython}/bin/python ${fedifetcherSrc}/find_posts.py \
|
|
|
|
|
-c=${fedifetcherConfig} \
|
|
|
|
|
--access-token="$ACCESS_TOKEN"
|
|
|
|
|
'';
|
|
|
|
|
in
|
|
|
|
|
"${script}";
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
mastodon-init-db.serviceConfig.EnvironmentFile = "/var/lib/mastodon/.secrets_env";
|
2025-11-22 00:38:45 -06:00
|
|
|
|
2025-11-21 18:29:53 -06:00
|
|
|
systemd-tmpfiles-setup.after = [ "var-lib-mastodon.mount" ];
|
|
|
|
|
|
2025-11-22 00:38:45 -06:00
|
|
|
opensearch-install-plugins = {
|
|
|
|
|
description = "Install OpenSearch plugins";
|
|
|
|
|
before = [ "opensearch.service" ];
|
|
|
|
|
requiredBy = [ "opensearch.service" ];
|
|
|
|
|
serviceConfig = {
|
|
|
|
|
Type = "oneshot";
|
|
|
|
|
RemainAfterExit = true;
|
|
|
|
|
};
|
|
|
|
|
script = ''
|
|
|
|
|
PLUGIN_DIR="/var/lib/opensearch/plugins/analysis-icu"
|
|
|
|
|
if [ ! -d "$PLUGIN_DIR" ]; then
|
|
|
|
|
# Create the plugins directory if it doesn't exist
|
|
|
|
|
mkdir -p /var/lib/opensearch/plugins
|
|
|
|
|
|
|
|
|
|
# Install using the proper OpenSearch plugin command
|
|
|
|
|
export OPENSEARCH_JAVA_HOME="${pkgs.jdk17}/lib/openjdk"
|
|
|
|
|
${pkgs.opensearch}/bin/opensearch-plugin install --batch analysis-icu || {
|
|
|
|
|
echo "Plugin installation failed, but continuing anyway"
|
|
|
|
|
exit 0
|
|
|
|
|
}
|
|
|
|
|
fi
|
|
|
|
|
'';
|
|
|
|
|
};
|
|
|
|
|
};
|
2025-11-21 18:29:53 -06:00
|
|
|
timers.fedifetcher = {
|
|
|
|
|
description = "Timer for FediFetcher";
|
|
|
|
|
wantedBy = [ "timers.target" ];
|
|
|
|
|
|
|
|
|
|
timerConfig = {
|
|
|
|
|
OnBootSec = "10min";
|
|
|
|
|
OnUnitActiveSec = "15min";
|
|
|
|
|
Unit = "fedifetcher.service";
|
|
|
|
|
Persistent = true;
|
|
|
|
|
AccuracySec = "1min";
|
|
|
|
|
};
|
2025-11-11 01:01:05 -06:00
|
|
|
};
|
2025-11-21 18:29:53 -06:00
|
|
|
|
2025-11-11 01:01:05 -06:00
|
|
|
network = {
|
|
|
|
|
enable = true;
|
|
|
|
|
networks."20-lan" = {
|
2025-11-11 05:00:52 -06:00
|
|
|
matchConfig.Name = "enp0s6";
|
2025-11-11 01:01:05 -06:00
|
|
|
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"
|
|
|
|
|
];
|
|
|
|
|
};
|
|
|
|
|
};
|
2025-11-21 18:29:53 -06:00
|
|
|
|
2025-11-11 01:01:05 -06:00
|
|
|
tmpfiles.rules = [
|
2025-11-17 02:26:07 -06:00
|
|
|
"d /var/lib/mastodon 0755 mastodon mastodon -"
|
|
|
|
|
"Z /var/lib/mastodon 0755 mastodon mastodon -"
|
2025-11-11 05:00:52 -06:00
|
|
|
"Z /var/lib/postgresql 0755 postgres postgres -"
|
2025-11-17 02:26:07 -06:00
|
|
|
"d /var/cache/mastodon/precompile 0755 mastodon mastodon -"
|
2025-11-17 05:46:55 -06:00
|
|
|
"d /var/lib/mastodon/public-system 0755 mastodon mastodon -"
|
|
|
|
|
"d /var/lib/mastodon/public-system/accounts 0755 mastodon mastodon -"
|
|
|
|
|
"d /var/lib/mastodon/public-system/media_attachments 0755 mastodon mastodon -"
|
|
|
|
|
"d /var/lib/mastodon/public-system/media_attachments/files 0755 mastodon mastodon -"
|
|
|
|
|
"d /var/lib/mastodon/public-system/site_uploads 0755 mastodon mastodon -"
|
2025-11-21 18:29:53 -06:00
|
|
|
"d /var/lib/fedifetcher 0755 fedifetcher fedifetcher -"
|
2025-11-11 01:01:05 -06:00
|
|
|
];
|
|
|
|
|
};
|
|
|
|
|
|
2025-11-27 05:12:15 -06:00
|
|
|
environment.systemPackages = builtins.attrValues {
|
|
|
|
|
inherit
|
|
|
|
|
fedifetcherPython
|
|
|
|
|
;
|
|
|
|
|
inherit (pkgs)
|
|
|
|
|
bottom
|
|
|
|
|
;
|
|
|
|
|
};
|
2025-11-21 18:29:53 -06:00
|
|
|
|
2025-11-11 01:01:05 -06:00
|
|
|
microvm = {
|
2025-11-27 05:12:15 -06:00
|
|
|
vcpu = 2;
|
2025-11-24 19:28:55 -06:00
|
|
|
mem = 1024 * 6;
|
2025-11-11 01:01:05 -06:00
|
|
|
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 = "/var/lib/${serviceCfg.name}";
|
|
|
|
|
proto = "virtiofs";
|
2025-11-11 05:00:52 -06:00
|
|
|
source = "${serviceCfg.mntPaths.path0}/data";
|
2025-11-11 01:01:05 -06:00
|
|
|
tag = "${serviceCfg.name}_data";
|
|
|
|
|
}
|
2025-11-11 05:00:52 -06:00
|
|
|
{
|
|
|
|
|
mountPoint = "/var/lib/postgresql";
|
|
|
|
|
proto = "virtiofs";
|
|
|
|
|
source = "${serviceCfg.mntPaths.path0}/database";
|
|
|
|
|
tag = "${serviceCfg.name}_database";
|
|
|
|
|
}
|
2025-11-11 01:01:05 -06:00
|
|
|
{
|
|
|
|
|
mountPoint = "/run/secrets";
|
|
|
|
|
proto = "virtiofs";
|
|
|
|
|
source = "/run/secrets/${serviceCfg.name}";
|
|
|
|
|
tag = "host_secrets";
|
|
|
|
|
}
|
|
|
|
|
];
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
};
|
2025-11-21 06:02:56 -06:00
|
|
|
|
2025-11-11 01:01:05 -06:00
|
|
|
sops = {
|
|
|
|
|
secrets = builtins.listToAttrs (
|
|
|
|
|
map
|
|
|
|
|
(secret: {
|
|
|
|
|
name = "${serviceCfg.name}/${secret}";
|
|
|
|
|
value = {
|
|
|
|
|
owner = "root";
|
2025-11-17 02:26:07 -06:00
|
|
|
group = "root";
|
|
|
|
|
mode = "0644";
|
2025-11-11 01:01:05 -06:00
|
|
|
};
|
|
|
|
|
})
|
|
|
|
|
[
|
|
|
|
|
"smtp"
|
|
|
|
|
"database"
|
|
|
|
|
"redis"
|
|
|
|
|
"pass"
|
2025-11-21 18:29:53 -06:00
|
|
|
"fedifetcher-token"
|
2025-11-11 01:01:05 -06:00
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
systemd.tmpfiles.rules = [
|
|
|
|
|
"d ${serviceCfg.mntPaths.path0} 0751 microvm wheel - -"
|
2025-11-11 05:00:52 -06:00
|
|
|
"d ${serviceCfg.mntPaths.path0}/data 0751 microvm wheel - -"
|
|
|
|
|
"d ${serviceCfg.mntPaths.path0}/database 0751 microvm wheel - -"
|
2025-11-11 01:01:05 -06:00
|
|
|
];
|
|
|
|
|
|
|
|
|
|
services.caddy.virtualHosts."${host}" = {
|
|
|
|
|
extraConfig = ''
|
2025-11-17 02:26:07 -06:00
|
|
|
reverse_proxy http://${serviceCfg.interface.ip}:80 {
|
|
|
|
|
header_up X-Forwarded-Proto {scheme}
|
|
|
|
|
header_up X-Real-IP {remote_host}
|
|
|
|
|
header_up X-Forwarded-For {remote_host}
|
|
|
|
|
}
|
2025-11-21 06:02:56 -06:00
|
|
|
|
2025-11-11 01:01:05 -06:00
|
|
|
tls ${serviceCfg.ssl.cert} ${serviceCfg.ssl.key}
|
2025-11-21 06:02:56 -06:00
|
|
|
|
2025-11-11 01:01:05 -06:00
|
|
|
encode zstd gzip
|
|
|
|
|
'';
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
users.users.caddy.extraGroups = [ "acme" ];
|
|
|
|
|
|
|
|
|
|
security.acme.certs."${host}" = {
|
|
|
|
|
dnsProvider = dns0;
|
|
|
|
|
environmentFile = config.sops.secrets.${dns0Path}.path;
|
|
|
|
|
group = "caddy";
|
|
|
|
|
};
|
|
|
|
|
}
|