Add post on hosting masto
This commit is contained in:
parent
0154015497
commit
73201e8164
1 changed files with 206 additions and 0 deletions
206
content/posts/2023/01/mastodon-nixos.md
Normal file
206
content/posts/2023/01/mastodon-nixos.md
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
---
|
||||||
|
title: Containerised Mastodon server on NixOS
|
||||||
|
date: 2023-01-15
|
||||||
|
tags: [nix, fediverse]
|
||||||
|
---
|
||||||
|
|
||||||
|
I've been on the fediverse on and off since [friendi.ca](https://friendi.ca/) started to be a thing.
|
||||||
|
I remember hosting an instance at ponk.pink that suddenly got popular and the server melted away while I was apologising to the users.
|
||||||
|
I can see someone bought the domain to host some psychedelic My Little Pony stuff, I'm all for that.
|
||||||
|
|
||||||
|
I moved to [todon.nl](https://todon.nl/) when it got started and was quite happy there - check it out if you're looking for an instance !
|
||||||
|
The itch was there though, what if I host my own small cozy place on the fediverse myself.
|
||||||
|
I knew I didn't have as much time to do server admin, so I decided to start small, with a single user instance an use the power of NixOS to help with maintenance.
|
||||||
|
|
||||||
|
Here is my full config - hosting Mastodon under the apex domain of [peninsula.industries](https://peninsula.industries/), Mastodon is running inside a systemd container and the config is using nix-sops to store the secrets.
|
||||||
|
Few things that were unexpected/of note
|
||||||
|
- I needed to create the folder structure with correct permissions so that Mastodon starts normally.
|
||||||
|
- I'm decrypting secrets on the host and making them available read-only to the container. Not sure if this is better or worse than having sops inside of the container, but I was having some trouble using sops module from there, so left it as it is for now - something to look into in the future
|
||||||
|
- I needed to change the postgres port that is running inside of the Mastodon container because I had another postgres on this host already.
|
||||||
|
- If you're gonna be playing with this a lot, you might need to remove the container and its data and start from scratch - you can do so by doing:
|
||||||
|
- remove the container definition and `nixos-rebuild switch`
|
||||||
|
- rm -fr /var/lib/nixos-containers/mastodon/ *
|
||||||
|
- to use Mastodon CLI you need to be running it as a correct user and within the Nix-changed env:
|
||||||
|
```bash
|
||||||
|
nixos-container root-login mastodon
|
||||||
|
sudo -u mastodon bash
|
||||||
|
cd
|
||||||
|
source mastodon-env
|
||||||
|
RAILS_ENV=production tootctl
|
||||||
|
```
|
||||||
|
- The below can use some refactoring, there is some weird repetition in some places still
|
||||||
|
- You can find the newest version of this and see how it's being used in context on my [code hosting site](https://git.cyplo.dev/cyplo/dotfiles/src/branch/main/nixos/boxes/vpsfree1/mastodon.nix).
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
inputs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
domain = "peninsula.industries";
|
||||||
|
streamingPort = 55000;
|
||||||
|
webPort = 55001;
|
||||||
|
postgresPort = 5433;
|
||||||
|
path = "/var/lib/mastodon/";
|
||||||
|
mailgunSmtpSecretName = "mastodon-mailgun-smtp-password";
|
||||||
|
mailgunSmtpPasswordPath = "/run/secrets/${mailgunSmtpSecretName}";
|
||||||
|
mastodonDbSecretName = "mastodon-db";
|
||||||
|
mastodonDbSecretPath = "/run/secrets/${mastodonDbSecretName}";
|
||||||
|
uid = 2049;
|
||||||
|
gid = 3049;
|
||||||
|
systemUserName = "mastodon";
|
||||||
|
systemGroupName = "mastodon";
|
||||||
|
users = {
|
||||||
|
users."${systemUserName}" = {
|
||||||
|
inherit uid;
|
||||||
|
isSystemUser = true;
|
||||||
|
isNormalUser = false;
|
||||||
|
group = systemGroupName;
|
||||||
|
};
|
||||||
|
groups."${systemGroupName}" = {
|
||||||
|
inherit gid;
|
||||||
|
members = ["${systemUserName}" "nginx"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
secretSettings = {
|
||||||
|
owner = systemUserName;
|
||||||
|
group = systemGroupName;
|
||||||
|
};
|
||||||
|
publicPath = "${path}/public-system/";
|
||||||
|
package =
|
||||||
|
inputs.nixpkgs-nixos-unstable.legacyPackages."${pkgs.system}".mastodon;
|
||||||
|
in {
|
||||||
|
imports = [../nginx.nix];
|
||||||
|
|
||||||
|
services.nginx = {
|
||||||
|
virtualHosts = {
|
||||||
|
"${domain}" = {
|
||||||
|
forceSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
root = "${package}/public/";
|
||||||
|
|
||||||
|
locations."/" = {tryFiles = "$uri @proxy";};
|
||||||
|
locations."/system/".alias = "${publicPath}";
|
||||||
|
|
||||||
|
locations."@proxy" = {
|
||||||
|
proxyPass = "http://127.0.0.1:" + toString webPort;
|
||||||
|
proxyWebsockets = true;
|
||||||
|
};
|
||||||
|
locations."/api/v1/streaming/" = {
|
||||||
|
proxyPass = "http://127.0.0.1:" + toString streamingPort;
|
||||||
|
proxyWebsockets = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
sops.secrets."${mailgunSmtpSecretName}" =
|
||||||
|
{
|
||||||
|
sopsFile = ./mailgun.sops.yaml;
|
||||||
|
path = mailgunSmtpPasswordPath;
|
||||||
|
}
|
||||||
|
// secretSettings;
|
||||||
|
sops.secrets."${mastodonDbSecretName}" =
|
||||||
|
{
|
||||||
|
sopsFile = ./mastodon-db.sops.yaml;
|
||||||
|
path = mastodonDbSecretPath;
|
||||||
|
}
|
||||||
|
// secretSettings;
|
||||||
|
|
||||||
|
inherit users;
|
||||||
|
|
||||||
|
systemd.services.mastodon-make-path = {
|
||||||
|
script = ''
|
||||||
|
mkdir -p ${path}
|
||||||
|
chown -R ${systemUserName}:${systemGroupName} ${path}
|
||||||
|
mkdir -p ${publicPath}
|
||||||
|
chmod -R o-rwx ${publicPath}
|
||||||
|
chmod -R g-rwx ${publicPath}
|
||||||
|
chmod -R g+X ${publicPath}
|
||||||
|
chmod -R g+r ${publicPath}
|
||||||
|
chmod -R u+rwX ${publicPath}
|
||||||
|
'';
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
ProtectSystem = "strict";
|
||||||
|
ReadWritePaths = path;
|
||||||
|
};
|
||||||
|
before = ["container@mastodon.service"];
|
||||||
|
};
|
||||||
|
|
||||||
|
containers.mastodon = {
|
||||||
|
autoStart = true;
|
||||||
|
forwardPorts = [
|
||||||
|
{
|
||||||
|
containerPort = streamingPort;
|
||||||
|
hostPort = streamingPort;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
containerPort = webPort;
|
||||||
|
hostPort = webPort;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
bindMounts = {
|
||||||
|
"${path}" = {
|
||||||
|
hostPath = "${path}";
|
||||||
|
isReadOnly = false;
|
||||||
|
};
|
||||||
|
"${mailgunSmtpPasswordPath}" = {
|
||||||
|
hostPath = "${mailgunSmtpPasswordPath}";
|
||||||
|
isReadOnly = true;
|
||||||
|
};
|
||||||
|
"${mastodonDbSecretPath}" = {
|
||||||
|
hostPath = "${mastodonDbSecretPath}";
|
||||||
|
isReadOnly = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = {
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
system.stateVersion = "22.05";
|
||||||
|
services.postgresql.port = postgresPort;
|
||||||
|
users =
|
||||||
|
users
|
||||||
|
// {
|
||||||
|
mutableUsers = false;
|
||||||
|
allowNoPasswordLogin = true;
|
||||||
|
};
|
||||||
|
services.mastodon = {
|
||||||
|
enable = true;
|
||||||
|
inherit package;
|
||||||
|
localDomain = "${domain}";
|
||||||
|
user = systemUserName;
|
||||||
|
group = systemGroupName;
|
||||||
|
smtp = {
|
||||||
|
host = "smtp.eu.mailgun.org";
|
||||||
|
port = 465;
|
||||||
|
authenticate = true;
|
||||||
|
user = "postmaster@${domain}";
|
||||||
|
fromAddress = "Peninsula Industries Mastodon <mastodon@${domain}>";
|
||||||
|
createLocally = false;
|
||||||
|
passwordFile = "${mailgunSmtpPasswordPath}";
|
||||||
|
};
|
||||||
|
extraConfig = {
|
||||||
|
SMTP_TLS = "true";
|
||||||
|
SMTP_ENABLE_STARTTLS_AUTO = "true";
|
||||||
|
SINGLE_USER_MODE = "true";
|
||||||
|
RAILS_SERVE_STATIC_FILES = "true";
|
||||||
|
};
|
||||||
|
inherit streamingPort;
|
||||||
|
inherit webPort;
|
||||||
|
configureNginx = false;
|
||||||
|
enableUnixSocket = false;
|
||||||
|
database = {
|
||||||
|
port = postgresPort;
|
||||||
|
passwordFile = mastodonDbSecretPath;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
Loading…
Reference in a new issue