mastodon-container/mastodon-container.nix

232 lines
8.1 KiB
Nix
Raw Permalink Normal View History

2023-07-25 18:37:43 -07:00
{ config, lib, pkgs, ... }@toplevel:
with lib;
2024-01-17 12:57:19 -08:00
let cfg = config.services.mastodonContainer;
2023-07-25 18:37:43 -07:00
in {
2024-01-17 13:13:47 -08:00
options.services.mastodonContainer = with types; {
2024-01-17 12:57:19 -08:00
enable = mkEnableOption "Enable Mastodon running in an Arion container.";
2023-07-26 16:30:53 -07:00
2024-01-17 12:57:19 -08:00
domain = mkOption {
2023-07-26 16:30:53 -07:00
type = str;
2024-01-17 12:57:19 -08:00
description = "Domain name of this Mastodon instance.";
2023-07-26 16:30:53 -07:00
};
2024-01-17 12:57:19 -08:00
hostname = mkOption {
2023-07-25 18:37:43 -07:00
type = str;
2024-01-17 12:57:19 -08:00
description = "Hostname of the Mastodon server.";
default = toplevel.config.services.mastodonContainer.domain;
2023-07-25 18:37:43 -07:00
};
state-directory = mkOption {
type = str;
description = "Port at which to store server data.";
};
2023-07-26 09:25:12 -07:00
port = mkOption {
type = port;
description = "Port at which to serve Mastodon web requests.";
2024-01-17 13:08:19 -08:00
default = 55001;
2023-07-25 18:37:43 -07:00
};
2024-01-17 12:57:19 -08:00
environment-files = mkOption {
type = listOf str;
description =
"List of files with env variables to set for the Mastodon job.";
default = [ ];
2023-09-03 10:51:31 -07:00
};
2024-01-17 14:25:57 -08:00
streaming-processes = mkOption {
type = int;
description =
"Number of processes to use for Mastodon streaming. Recommended is (#cores - 1).";
default = 4;
};
2024-01-28 15:43:58 -08:00
allow-registrations = mkOption {
type = bool;
description = "Enable the creation of new accounts.";
default = true;
};
2024-01-28 12:26:11 -08:00
2023-07-26 16:30:53 -07:00
smtp = {
2024-01-17 12:57:19 -08:00
host = mkOption {
2023-07-26 16:30:53 -07:00
type = str;
description = "Outgoing SMTP server.";
};
port = mkOption {
type = port;
description = "Outgoing SMTP server port.";
default = 25;
};
2024-01-17 12:57:19 -08:00
user = mkOption {
type = str;
description = "User as which to authenticate to the SMTP server.";
2024-01-17 13:08:19 -08:00
default = "mastodon";
2023-07-25 18:37:43 -07:00
};
2024-01-17 12:57:19 -08:00
password-file = mkOption {
2024-01-17 13:08:19 -08:00
type = nullOr str;
2024-01-17 12:57:19 -08:00
description = "Path to file containing SMTP password";
2024-01-17 16:19:14 -08:00
default = null;
2023-07-26 16:30:53 -07:00
};
2024-01-17 12:57:19 -08:00
from-address = mkOption {
type = str;
description = "Address from which to send outgoing mail.";
default =
"${toplevel.config.services.mastodonContainer.smtp.user}@${toplevel.config.services.mastodonContainer.domain}";
2023-09-06 11:12:10 -07:00
};
};
2024-01-17 12:57:19 -08:00
};
2023-07-25 18:51:57 -07:00
2024-01-17 12:57:19 -08:00
config = mkIf cfg.enable {
2023-07-25 18:37:43 -07:00
virtualisation.arion.projects.mastodon.settings = let
image = { pkgs, ... }: {
project.name = "mastodon";
2024-01-17 17:11:33 -08:00
docker-compose.volumes = {
postgres-data = { };
redis-data = { };
mastodon-data = { };
};
2024-01-18 18:55:43 -08:00
networks.external_network.internal = false;
2023-07-25 18:37:43 -07:00
services = {
2024-01-17 12:57:19 -08:00
mastodon = { pkgs, ... }: {
service = {
restart = "always";
volumes = [
"postgres-data:/var/lib/postgresql"
2024-01-17 12:57:19 -08:00
"redis-data:/var/lib/redis"
"mastodon-data:/var/lib/mastodon"
2024-01-18 10:46:04 -08:00
] ++ (map (env-file: "${env-file}:${env-file}:ro,Z")
cfg.environment-files);
2024-01-17 18:15:11 -08:00
ports = [ "${toString cfg.port}:80" ];
2024-01-18 18:55:43 -08:00
networks = [ "external_network" ];
2024-01-17 12:57:19 -08:00
};
2024-01-17 14:12:39 -08:00
nixos = {
useSystemd = true;
configuration = {
boot.tmp.useTmpfs = true;
system.nssModules = mkForce [ ];
services = {
nscd.enable = false;
postgresql.enable = true;
mastodon = {
enable = true;
webPort = cfg.port;
localDomain = cfg.domain;
extraEnvFiles = cfg.environment-files;
smtp = {
inherit (cfg.smtp) host port user;
fromAddress = cfg.smtp.from-address;
authenticate = !isNull cfg.smtp.password-file;
2024-01-17 16:19:14 -08:00
passwordFile = mkIf (!isNull cfg.smtp.password-file)
cfg.smtp.password-file;
2024-01-17 14:12:39 -08:00
};
redis.createLocally = true;
database.createLocally = true;
configureNginx = true;
automaticMigrations = true;
2024-01-17 14:25:57 -08:00
streamingProcesses = cfg.streaming-processes;
2024-01-28 15:50:55 -08:00
extraConfig.registrations_open =
2024-01-28 16:07:58 -08:00
if cfg.allow-registrations then "true" else "false";
2024-01-17 12:57:19 -08:00
};
nginx = {
recommendedTlsSettings = true;
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedProxySettings = true;
commonHttpConfig = ''
log_format with_response_time '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$request_time" "$upstream_response_time"';
access_log /var/log/nginx/access.log with_response_time;
'';
virtualHosts."${cfg.hostname}" = {
forceSSL = false;
enableACME = false;
locations = let
mkCacheLine = { maxAge ? 2419200, immutable ? false }:
let
immutableString = if immutable then
"immutable"
else
"must-revalidate";
2024-01-18 14:52:06 -08:00
in {
extraConfig = ''
add_header Cache-Control "public, max-age=${
toString maxAge
}, ${immutableString}";
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";
try_files $uri =404;
'';
};
in {
"/api/v1/streaming" = {
extraConfig = ''
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_redirect off;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";
tcp_nodelay on;
'';
};
"@proxy" = {
extraConfig = ''
proxy_set_header X-Forwarded-Proto https; # NOTE: Lie and say we're on HTTPS! Otherwise Mastodon will refuse to serve.
proxy_pass_header Server;
proxy_buffering on;
proxy_redirect off;
## TODO: consider uncommentingq
2024-01-18 15:32:42 -08:00
# proxy_cache CACHE;
# proxy_cache_valid 200 7d;
# proxy_cache_valid 410 24h;
# proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
# add_header X-Cached $upstream_cache_status;
tcp_nodelay on;
'';
};
"/sw.js" = mkCacheLine { maxAge = 604800; };
"^/assets/" = mkCacheLine { };
"^/avatars/" = mkCacheLine { };
"^/emoji/" = mkCacheLine { };
"^/headers/" = mkCacheLine { };
"^/packs" = mkCacheLine { };
"^/shortcuts" = mkCacheLine { };
"^/sounds/" = mkCacheLine { };
"^/system" = mkCacheLine { immutable = true; };
};
};
};
2024-01-17 12:57:19 -08:00
};
};
};
2023-07-25 18:37:43 -07:00
};
};
};
in { imports = [ image ]; };
2024-01-17 12:57:19 -08:00
services.nginx = {
enable = true;
virtualHosts."${cfg.hostname}" = {
enableACME = true;
forceSSL = true;
2024-01-17 12:57:19 -08:00
locations."/" = {
2024-01-17 23:32:24 -08:00
proxyPass = "http://127.0.0.1:${toString cfg.port}/";
2024-01-17 12:57:19 -08:00
proxyWebsockets = true;
recommendedProxySettings = true;
2024-01-17 12:57:19 -08:00
};
};
};
2023-07-25 18:37:43 -07:00
};
}