separate vm.nix files for vm-specific configuration

This commit is contained in:
Taeer Bar-Yam 2024-08-28 08:35:48 -04:00
parent 366a67e112
commit 353c0a7ffa
12 changed files with 324 additions and 313 deletions

View file

@ -1,67 +0,0 @@
{ pkgs, ... }: {
# customize nixos-rebuild build-vm to be a bit more convenient
virtualisation.vmVariant = {
# let us log in
users.mutableUsers = false;
users.users.root.hashedPassword = "";
services.openssh = {
enable = true;
settings = {
PermitRootLogin = "yes";
PermitEmptyPasswords = "yes";
UsePAM = "no";
};
};
# automatically log in
services.getty.autologinUser = "root";
services.getty.helpLine = ''
Type `C-a c` to access the qemu console
Type `C-a x` to quit
'';
# access to convenient things
environment.systemPackages = with pkgs; [
w3m
python3
xterm # for `resize`
];
environment.loginShellInit = ''
eval "$(resize)"
'';
nix.extraOptions = ''
extra-experimental-features = nix-command flakes
'';
# no graphics. see nixos-shell
virtualisation = {
graphics = false;
qemu.consoles = [ "tty0" "hvc0" ];
qemu.options = [
"-serial null"
"-device virtio-serial"
"-chardev stdio,mux=on,id=char0,signal=off"
"-mon chardev=char0,mode=readline"
"-device virtconsole,chardev=char0,nr=0"
];
};
# we can't forward port 80 or 443, so let's run nginx on a different port
networking.firewall.allowedTCPPorts = [ 8443 8080 ];
services.nginx.defaultSSLListenPort = 8443;
services.nginx.defaultHTTPListenPort = 8080;
virtualisation.forwardPorts = [
{
from = "host";
host.port = 8080;
guest.port = 8080;
}
{
from = "host";
host.port = 8443;
guest.port = 8443;
}
];
};
}

View file

@ -2,18 +2,14 @@
"nodes": { "nodes": {
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1708475490, "lastModified": 1724846166,
"narHash": "sha256-g1v0TsWBQPX97ziznfJdWhgMyMGtoBFs102xSYO4syU=", "narHash": "sha256-Um1Ahz09XHepSA1QQmdQk8nbsJEwHe54gP3naWp6D94=",
"owner": "nixos", "path": "/home/qolen/nixpkgs",
"repo": "nixpkgs", "type": "path"
"rev": "0e74ca98a74bc7270d28838369593635a5db3260",
"type": "github"
}, },
"original": { "original": {
"owner": "nixos", "path": "/home/qolen/nixpkgs",
"ref": "nixos-unstable", "type": "path"
"repo": "nixpkgs",
"type": "github"
} }
}, },
"root": { "root": {

View file

@ -2,7 +2,8 @@
description = "Testing mastodon configurations"; description = "Testing mastodon configurations";
inputs = { inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; # nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
nixpkgs.url = "path:/home/qolen/nixpkgs";
}; };
outputs = { self, nixpkgs }: outputs = { self, nixpkgs }:
@ -12,31 +13,41 @@
in { in {
nixosModules = { nixosModules = {
interactive-vm = import ./interactive-vm.nix;
mastodon = import ./mastodon.nix; mastodon = import ./mastodon.nix;
mastodon-vm = import ./mastodon-vm.nix;
peertube = import ./peertube.nix; peertube = import ./peertube.nix;
peertube-vm = import ./peertube-vm.nix;
pixelfed = import ./pixelfed.nix; pixelfed = import ./pixelfed.nix;
pixelfed-vm = import ./pixelfed-vm.nix;
garage = import ./garage.nix; garage = import ./garage.nix;
}; };
nixosConfigurations = { nixosConfigurations = {
mastodon = nixpkgs.lib.nixosSystem { mastodon = nixpkgs.lib.nixosSystem {
inherit system; inherit system;
modules = [ ./common.nix ./mastodon.nix ./garage.nix ]; modules = with self.nixosModules; [ interactive-vm mastodon mastodon-vm garage ];
}; };
peertube = nixpkgs.lib.nixosSystem { peertube = nixpkgs.lib.nixosSystem {
inherit system; inherit system;
modules = [ ./common.nix ./peertube.nix ./garage.nix ]; modules = with self.nixosModules; [ interactive-vm peertube peertube-vm garage ];
}; };
pixelfed = nixpkgs.lib.nixosSystem { pixelfed = nixpkgs.lib.nixosSystem {
inherit system; inherit system;
modules = [ ./common.nix ./pixelfed.nix ./garage.nix ]; modules = with self.nixosModules; [ interactive-vm pixelfed pixelfed-vm garage ];
}; };
all = nixpkgs.lib.nixosSystem { all = nixpkgs.lib.nixosSystem {
inherit system; inherit system;
modules = [ ./common.nix ./mastodon.nix ./peertube.nix ./pixelfed.nix ./garage.nix ]; modules = with self.nixosModules; [
interactive-vm
peertube peertube-vm
pixelfed pixelfed-vm
mastodon mastodon-vm
garage
];
}; };
}; };

64
interactive-vm.nix Normal file
View file

@ -0,0 +1,64 @@
# customize nixos-rebuild build-vm to be a bit more convenient
{ pkgs, ... }: {
# let us log in
users.mutableUsers = false;
users.users.root.hashedPassword = "";
services.openssh = {
enable = true;
settings = {
PermitRootLogin = "yes";
PermitEmptyPasswords = "yes";
UsePAM = false;
};
};
# automatically log in
services.getty.autologinUser = "root";
services.getty.helpLine = ''
Type `C-a c` to access the qemu console
Type `C-a x` to quit
'';
# access to convenient things
environment.systemPackages = with pkgs; [
w3m
python3
xterm # for `resize`
];
environment.loginShellInit = ''
eval "$(resize)"
'';
nix.extraOptions = ''
extra-experimental-features = nix-command flakes
'';
# no graphics. see nixos-shell
virtualisation = {
graphics = false;
qemu.consoles = [ "tty0" "hvc0" ];
qemu.options = [
"-serial null"
"-device virtio-serial"
"-chardev stdio,mux=on,id=char0,signal=off"
"-mon chardev=char0,mode=readline"
"-device virtconsole,chardev=char0,nr=0"
];
};
# we can't forward port 80 or 443, so let's run nginx on a different port
networking.firewall.allowedTCPPorts = [ 8443 8080 ];
services.nginx.defaultSSLListenPort = 8443;
services.nginx.defaultHTTPListenPort = 8080;
virtualisation.forwardPorts = [
{
from = "host";
host.port = 8080;
guest.port = 8080;
}
{
from = "host";
host.port = 8443;
guest.port = 8443;
}
];
}

118
mastodon-vm.nix Normal file
View file

@ -0,0 +1,118 @@
{ modulesPath, lib, config, ... }: {
imports = [ (modulesPath + "/virtualisation/qemu-vm.nix") ];
config = lib.mkMerge [
{
services.mastodon = {
# redirects to localhost, but allows it to have a proper domain name
localDomain = "mastodon.localhost";
smtp = {
fromAddress = "mastodon@mastodon.localhost";
createLocally = false;
};
extraConfig = {
EMAIL_DOMAIN_ALLOWLIST = "example.com";
};
# from the documentation: recommended is the amount of your CPU cores
# minus one. but it also must be a positive integer
streamingProcesses = lib.max 1 (config.virtualisation.cores - 1);
};
security.acme = {
defaults = {
# invalid server; the systemd service will fail, and we won't get
# properly signed certificates. but let's not spam the letsencrypt
# servers (and we don't own this domain anyways)
server = "https://127.0.0.1";
email = "none";
};
};
virtualisation.memorySize = 2048;
virtualisation.forwardPorts = [
{
from = "host";
host.port = 44443;
guest.port = 443;
}
];
}
#### run mastodon as development environment
{
networking.firewall.allowedTCPPorts = [ 55001 ];
services.mastodon = {
# needed so we can directly access mastodon at port 55001
# otherwise, mastodon has to be accessed *from* port 443, which we can't do via port forwarding
enableUnixSocket = false;
extraConfig = {
RAILS_ENV = "development";
# to be accessible from outside the VM
BIND = "0.0.0.0";
# for letter_opener (still doesn't work though)
REMOTE_DEV = "true";
LOCAL_DOMAIN = "mastodon.localhost:8443";
};
};
services.postgresql = {
enable = true;
ensureUsers = [
{
name = config.services.mastodon.database.user;
ensureClauses.createdb = true;
# ensurePermissions doesn't work anymore
# ensurePermissions = {
# "mastodon_development.*" = "ALL PRIVILEGES";
# "mastodon_test.*" = "ALL PRIVILEGES";
# }
}
];
# ensureDatabases = [ "mastodon_development_test" "mastodon_test" ];
};
# Currently, nixos seems to be able to create a single database per
# postgres user. This works for the production version of mastodon, which
# is what's packaged in nixpkgs. For development, we need two databases,
# mastodon_development and mastodon_test. This used to be possible with
# ensurePermissions, but that's broken and has been removed. Here I copy
# the mastodon-init-db script from upstream nixpkgs, but add the single
# line `rails db:setup`, which asks mastodon to create the postgres
# databases for us.
# FIXME: the commented out lines were breaking things, but presumably they're necessary for something.
# TODO: see if we can fix the upstream ensurePermissions stuff. See commented out lines in services.postgresql above for what that config would look like.
systemd.services.mastodon-init-db.script = lib.mkForce ''
result="$(psql -t --csv -c \
"select count(*) from pg_class c \
join pg_namespace s on s.oid = c.relnamespace \
where s.nspname not in ('pg_catalog', 'pg_toast', 'information_schema') \
and s.nspname not like 'pg_temp%';")" || error_code=$?
if [ "''${error_code:-0}" -ne 0 ]; then
echo "Failure checking if database is seeded. psql gave exit code $error_code"
exit "$error_code"
fi
if [ "$result" -eq 0 ]; then
echo "Seeding database"
rails db:setup
# SAFETY_ASSURED=1 rails db:schema:load
rails db:seed
# else
# echo "Migrating database (this might be a noop)"
# rails db:migrate
fi
'';
virtualisation.forwardPorts = [
{
from = "host";
host.port = 55001;
guest.port = 55001;
}
];
}
];
}

View file

@ -4,188 +4,78 @@ let
secret = "7d37d093435a41f2aab8f13c19ba067d9776c90215f56614adad6ece597dbb34"; secret = "7d37d093435a41f2aab8f13c19ba067d9776c90215f56614adad6ece597dbb34";
}; };
in in
{ config, lib, pkgs, ... }: lib.mkMerge [ { config, lib, pkgs, ... }: {
{ # garage setup #### garage setup
services.garage = { services.garage = {
ensureBuckets = { ensureBuckets = {
mastodon = { mastodon = {
website = true; website = true;
corsRules = { corsRules = {
enable = true; enable = true;
allowedHeaders = [ "*" ]; allowedHeaders = [ "*" ];
allowedMethods = [ "GET" ]; allowedMethods = [ "GET" ];
allowedOrigins = [ "*" ]; allowedOrigins = [ "*" ];
};
}; };
}; };
ensureKeys = { };
mastodon = { ensureKeys = {
inherit (snakeoil_key) id secret; mastodon = {
ensureAccess = { inherit (snakeoil_key) id secret;
mastodon = { ensureAccess = {
read = true; mastodon = {
write = true; read = true;
owner = true; write = true;
}; owner = true;
}; };
}; };
}; };
}; };
services.mastodon = { };
extraConfig = rec { services.mastodon = {
S3_ENABLED = "true"; extraConfig = rec {
S3_ENDPOINT = "http://s3.garage.localhost:3900"; S3_ENABLED = "true";
S3_REGION = "garage"; # TODO: this shouldn't be hard-coded, it should come from the garage configuration
S3_BUCKET = "mastodon"; S3_ENDPOINT = "http://s3.garage.localhost:3900";
# use <S3_BUCKET>.<S3_ENDPOINT> S3_REGION = "garage";
S3_OVERRIDE_PATH_STLE = "true"; S3_BUCKET = "mastodon";
AWS_ACCESS_KEY_ID = snakeoil_key.id; # use <S3_BUCKET>.<S3_ENDPOINT>
AWS_SECRET_ACCESS_KEY = snakeoil_key.secret; S3_OVERRIDE_PATH_STLE = "true";
S3_PROTOCOL = "http"; AWS_ACCESS_KEY_ID = snakeoil_key.id;
S3_HOSTNAME = "web.garage.localhost:3902"; AWS_SECRET_ACCESS_KEY = snakeoil_key.secret;
# by default it tries to use "<S3_HOSTNAME>/<S3_BUCKET>" S3_PROTOCOL = "http";
S3_ALIAS_HOST = "${S3_BUCKET}.${S3_HOSTNAME}"; S3_HOSTNAME = "web.garage.localhost:3902";
# SEE: the last section in https://docs.joinmastodon.org/admin/optional/object-storage/ # by default it tries to use "<S3_HOSTNAME>/<S3_BUCKET>"
# TODO: can we set up ACLs with garage? S3_ALIAS_HOST = "${S3_BUCKET}.${S3_HOSTNAME}";
S3_PERMISSION = ""; # SEE: the last section in https://docs.joinmastodon.org/admin/optional/object-storage/
}; # TODO: can we set up ACLs with garage?
S3_PERMISSION = "";
}; };
} };
# mastodon setup
{
# open up access to the mastodon web interface
networking.firewall.allowedTCPPorts = [ 443 ];
services.mastodon = { #### mastodon setup
enable = true;
# TODO: set up a domain name, and a DNS service so that this can run not in a vm # open up access to the mastodon web interface
# localDomain = "domain.social"; networking.firewall.allowedTCPPorts = [ 443 ];
configureNginx = true;
# TODO: configure a mailserver so this works services.mastodon = {
# smtp.fromAddress = "mastodon@mastodon.localhost"; enable = true;
# TODO: this is hardware-dependent. let's figure it out when we have hardware # TODO: set up a domain name, and a DNS service so that this can run not in a vm
# streamingProcesses = 1; # localDomain = "domain.social";
}; configureNginx = true;
security.acme = { # TODO: configure a mailserver so this works
acceptTerms = true; # smtp.fromAddress = "mastodon@domain.social";
preliminarySelfsigned = true;
# TODO: configure a mailserver so we can set up acme
# defaults.email = "test@example.com";
};
}
# VM setup # TODO: this is hardware-dependent. let's figure it out when we have hardware
{ # streamingProcesses = 1;
services.mastodon = { };
# redirects to localhost, but allows it to have a proper domain name
localDomain = "mastodon.localhost";
smtp = { security.acme = {
fromAddress = "mastodon@mastodon.localhost"; acceptTerms = true;
createLocally = false; preliminarySelfsigned = true;
}; # TODO: configure a mailserver so we can set up acme
# defaults.email = "test@example.com";
};
}
extraConfig = {
EMAIL_DOMAIN_ALLOWLIST = "example.com";
};
# from the documentation: recommended is the amount of your CPU cores minus one.
# but it also must be a positive integer
streamingProcesses = lib.max 1 (config.virtualisation.cores - 1);
};
security.acme = {
defaults = {
# invalid server; the systemd service will fail, and we won't get properly signed certificates
# but let's not spam the letsencrypt servers (and we don't own this domain anyways)
server = "https://127.0.0.1";
email = "none";
};
};
virtualisation.memorySize = 2048;
virtualisation.forwardPorts = [
{
from = "host";
host.port = 44443;
guest.port = 443;
}
];
}
# run mastodon as development environment
{
networking.firewall.allowedTCPPorts = [ 55001 ];
services.mastodon = {
# needed so we can directly access mastodon at port 55001
# otherwise, mastodon has to be accessed *from* port 443, which we can't do via port forwarding
enableUnixSocket = false;
extraConfig = {
RAILS_ENV = "development";
# to be accessible from outside the VM
BIND = "0.0.0.0";
# for letter_opener (still doesn't work though)
REMOTE_DEV = "true";
LOCAL_DOMAIN = "mastodon.localhost:8443";
};
};
services.postgresql = {
enable = true;
ensureUsers = [
{
name = config.services.mastodon.database.user;
ensureClauses.createdb = true;
# ensurePermissions doesn't work anymore
# ensurePermissions = {
# "mastodon_development.*" = "ALL PRIVILEGES";
# "mastodon_test.*" = "ALL PRIVILEGES";
# }
}
];
# ensureDatabases = [ "mastodon_development_test" "mastodon_test" ];
};
# Currently, nixos seems to be able to create a single database per
# postgres user. This works for the production version of mastodon, which
# is what's packaged in nixpkgs. For development, we need two databases,
# mastodon_development and mastodon_test. This used to be possible with
# ensurePermissions, but that's broken and has been removed. Here I copy
# the mastodon-init-db script from upstream nixpkgs, but add the single
# line `rails db:setup`, which asks mastodon to create the postgres
# databases for us.
# FIXME: the commented out lines were breaking things, but presumably they're necessary for something.
# TODO: see if we can fix the upstream ensurePermissions stuff. See above for what that config would look like.
systemd.services.mastodon-init-db.script = lib.mkForce ''
result="$(psql -t --csv -c \
"select count(*) from pg_class c \
join pg_namespace s on s.oid = c.relnamespace \
where s.nspname not in ('pg_catalog', 'pg_toast', 'information_schema') \
and s.nspname not like 'pg_temp%';")" || error_code=$?
if [ "''${error_code:-0}" -ne 0 ]; then
echo "Failure checking if database is seeded. psql gave exit code $error_code"
exit "$error_code"
fi
if [ "$result" -eq 0 ]; then
echo "Seeding database"
rails db:setup
# SAFETY_ASSURED=1 rails db:schema:load
rails db:seed
# else
# echo "Migrating database (this might be a noop)"
# rails db:migrate
fi
'';
virtualisation.forwardPorts = [
{
from = "host";
host.port = 55001;
guest.port = 55001;
}
];
}
]

30
peertube-vm.nix Normal file
View file

@ -0,0 +1,30 @@
{ pkgs, modulesPath, ... }: {
imports = [ (modulesPath + "/virtualisation/qemu-vm.nix") ];
services.peertube = {
enable = true;
# redirects to localhost, but allows it to have a proper domain name
localDomain = "peertube.localhost";
enableWebHttps = false;
settings = {
listen.hostname = "0.0.0.0";
instance.name = "PeerTube Test VM";
};
# TODO: use agenix
secrets.secretsFile = pkgs.writeText "secret" ''
574e093907d1157ac0f8e760a6deb1035402003af5763135bae9cbd6abe32b24
'';
# TODO: in most of nixpkgs, these are true by default. upstream that unless there's a good reason not to.
redis.createLocally = true;
database.createLocally = true;
configureNginx = true;
};
virtualisation.forwardPorts = [
{
from = "host";
host.port = 9000;
guest.port = 9000;
}
];
}

View file

@ -83,34 +83,4 @@ in
AWS_ACCESS_KEY_ID=${snakeoil_key.id} AWS_ACCESS_KEY_ID=${snakeoil_key.id}
AWS_SECRET_ACCESS_KEY=${snakeoil_key.secret} AWS_SECRET_ACCESS_KEY=${snakeoil_key.secret}
''; '';
virtualisation.vmVariant = { config, ... }: {
services.peertube = {
enable = true;
# redirects to localhost, but allows it to have a proper domain name
localDomain = "peertube.localhost";
enableWebHttps = false;
settings = {
listen.hostname = "0.0.0.0";
instance.name = "PeerTube Test VM";
};
# TODO: use agenix
secrets.secretsFile = pkgs.writeText "secret" ''
574e093907d1157ac0f8e760a6deb1035402003af5763135bae9cbd6abe32b24
'';
# TODO: in most of nixpkgs, these are true by default. upstream that unless there's a good reason not to.
redis.createLocally = true;
database.createLocally = true;
configureNginx = true;
};
virtualisation.forwardPorts = [
{
from = "host";
host.port = 9000;
guest.port = 9000;
}
];
};
} }

27
pixelfed-vm.nix Normal file
View file

@ -0,0 +1,27 @@
{ pkgs, modulesPath, ... }: {
imports = [ (modulesPath + "/virtualisation/qemu-vm.nix") ];
networking.firewall.allowedTCPPorts = [ 80 ];
services.pixelfed = {
enable = true;
domain = "pixelfed.localhost";
# TODO: secrets management!
secretFile = pkgs.writeText "secrets.env" ''
APP_KEY=adKK9EcY8Hcj3PLU7rzG9rJ6KKTOtYfA
'';
settings = {
OPEN_REGISTRATION = true;
FORCE_HTTPS_URLS = false;
};
# I feel like this should have an `enable` option and be configured via `services.nginx` rather than mirroring those options in services.pixelfed.nginx
# TODO: If that indeed makes sense, upstream it.
nginx = {};
};
virtualisation.memorySize = 2048;
virtualisation.forwardPorts = [
{
from = "host";
host.port = 8000;
guest.port = 80;
}
];
}

View file

@ -5,7 +5,6 @@ let
}; };
in in
{ config, lib, pkgs, ... }: { { config, lib, pkgs, ... }: {
services.garage = { services.garage = {
ensureBuckets = { ensureBuckets = {
pixelfed = { pixelfed = {
@ -45,31 +44,4 @@ in
AWS_ENDPOINT = "http://s3.garage.localhost:3900"; AWS_ENDPOINT = "http://s3.garage.localhost:3900";
AWS_USE_PATH_STYLE_ENDPOINT = false; AWS_USE_PATH_STYLE_ENDPOINT = false;
}; };
virtualisation.vmVariant = {
networking.firewall.allowedTCPPorts = [ 80 ];
services.pixelfed = {
enable = true;
domain = "pixelfed.localhost";
# TODO: secrets management!
secretFile = pkgs.writeText "secrets.env" ''
APP_KEY=adKK9EcY8Hcj3PLU7rzG9rJ6KKTOtYfA
'';
settings = {
OPEN_REGISTRATION = true;
FORCE_HTTPS_URLS = false;
};
# I feel like this should have an `enable` option and be configured via `services.nginx` rather than mirroring those options here
# TODO: If that indeed makes sense, upstream it.
nginx = {};
};
virtualisation.memorySize = 2048;
virtualisation.forwardPorts = [
{
from = "host";
host.port = 8000;
guest.port = 80;
}
];
};
} }

View file

@ -37,9 +37,9 @@ rebuildableTest {
name = "test-mastodon-garage"; name = "test-mastodon-garage";
nodes = { nodes = {
server = {config, ...}: { server = { config, ... }: {
virtualisation.memorySize = lib.mkVMOverride 4096; virtualisation.memorySize = lib.mkVMOverride 4096;
imports = [ self.nixosModules.garage self.nixosModules.mastodon ]; imports = with self.nixosModules; [ garage mastodon mastodon-vm ];
# TODO: pair down # TODO: pair down
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [
python3 python3

View file

@ -15,7 +15,7 @@ let
settings = { settings = {
PermitRootLogin = "yes"; PermitRootLogin = "yes";
PermitEmptyPasswords = "yes"; PermitEmptyPasswords = "yes";
UsePAM = "no"; UsePAM = false;
}; };
}; };