ops/nixos/bsky-pds: init
This commit is contained in:
parent
d5996ca89a
commit
0c4a432cf2
4 changed files with 294 additions and 1 deletions
249
ops/nixos/lib/bsky-pds.nix
Normal file
249
ops/nixos/lib/bsky-pds.nix
Normal file
|
@ -0,0 +1,249 @@
|
|||
{ depot, config, pkgs, lib, ... }:
|
||||
|
||||
let
|
||||
cfg = config.my.services.bsky-pds;
|
||||
|
||||
marshalValue = key: value: if builtins.isString value then value
|
||||
else if builtins.isInt value then toString value
|
||||
else if builtins.isBool value then (if value then "true" else "false")
|
||||
else throw "unknown value type for key ${key}";
|
||||
cfgFile = pkgs.writeTextFile {
|
||||
name = "bsky-pds.env";
|
||||
text = lib.concatStringsSep "\n" (lib.mapAttrsToList (attrName: attrVal: lib.optionalString (attrVal != null) ''
|
||||
${lib.toUpper attrName}=${marshalValue attrName attrVal}
|
||||
'') cfg.settings);
|
||||
};
|
||||
|
||||
inSecretsDir = v: builtins.isString v && (builtins.match "/var/lib/bsky-pds/secrets/.*" (toString v)) != null;
|
||||
|
||||
testAndGenerate = how: path: ''
|
||||
test -f "${path}" || {
|
||||
${how} >> "${path}"
|
||||
}
|
||||
'';
|
||||
testAndGenerateHex = testAndGenerate "${pkgs.openssl}/bin/openssl rand --hex 16";
|
||||
testAndGenerateK256 = testAndGenerate "${pkgs.openssl}/bin/openssl ecparam --name secp256k1 --genkey --noout --outform DER";
|
||||
in
|
||||
{
|
||||
options.my.services.bsky-pds = {
|
||||
enable = lib.mkEnableOption "Bluesky Personal Data Server";
|
||||
|
||||
package = lib.mkOption {
|
||||
type = lib.types.package;
|
||||
default = depot.nix.pkgs.bsky-pds;
|
||||
description = ''
|
||||
Package containing the PDS code.
|
||||
'';
|
||||
};
|
||||
|
||||
configureCaddy = (lib.mkEnableOption "configure Caddy to serve the PDS") // {
|
||||
default = true;
|
||||
};
|
||||
|
||||
settings = lib.mkOption {
|
||||
type = with lib.types; submodule {
|
||||
freeformType = attrsOf (nullOr (oneOf [
|
||||
str
|
||||
bool
|
||||
int
|
||||
]));
|
||||
|
||||
options.log_enabled = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether or not to output any log messages.
|
||||
'';
|
||||
};
|
||||
options.port = lib.mkOption {
|
||||
type = lib.types.port;
|
||||
default = 3000;
|
||||
description = ''
|
||||
Port number that the PDS will listen on.
|
||||
'';
|
||||
};
|
||||
options.pds_hostname = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = ''
|
||||
Hostname under which the PDS will run.
|
||||
'';
|
||||
};
|
||||
options.pds_admin_email = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = ''
|
||||
Email address of the PDS operator.
|
||||
'';
|
||||
};
|
||||
options.pds_data_directory = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
default = "/var/lib/bsky-pds/data";
|
||||
description = ''
|
||||
Path to data directory.
|
||||
'';
|
||||
};
|
||||
options.pds_blobstore_disk_location = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.path;
|
||||
default = "/var/lib/bsky-pds/blobs";
|
||||
description = ''
|
||||
Path to location for blobstore storage, if using on-disk storage.
|
||||
'';
|
||||
};
|
||||
options.pds_blob_upload_limit = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = 52428800;
|
||||
description = ''
|
||||
Maximum allowable blob size for upload.
|
||||
'';
|
||||
};
|
||||
options.pds_did_plc_url = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "https://plc.directory";
|
||||
description = ''
|
||||
URL of the PLC directory.
|
||||
'';
|
||||
};
|
||||
|
||||
options.pds_bsky_app_view_url = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "https://api.bsky.app";
|
||||
description = ''
|
||||
URL of the Bluesky AppView.
|
||||
'';
|
||||
};
|
||||
options.pds_bsky_app_view_did = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "did:web:api.bsky.app";
|
||||
description = ''
|
||||
DID of the Bluesky AppView.
|
||||
'';
|
||||
};
|
||||
options.pds_report_service_url = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "https://mod.bsky.app";
|
||||
description = ''
|
||||
URL of the Bluesky moderation service.
|
||||
'';
|
||||
};
|
||||
options.pds_report_service_did = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "did:plc:ar7c4by46qjdydhdevvrndac";
|
||||
description = ''
|
||||
DID of the Bluesky moderation service.
|
||||
'';
|
||||
};
|
||||
options.crawlers = lib.mkOption {
|
||||
type = lib.types.commas;
|
||||
default = "https://bsky.network";
|
||||
description = ''
|
||||
URLs of hosts to notify of new data.
|
||||
'';
|
||||
};
|
||||
};
|
||||
default = {};
|
||||
description = ''
|
||||
Configuration for Bluesky PDS.
|
||||
'';
|
||||
};
|
||||
|
||||
generateSecrets = lib.mkEnableOption "automatically generate required PDS secrets";
|
||||
|
||||
secrets = lib.mkOption {
|
||||
type = with lib.types; submodule {
|
||||
freeformType = attrsOf (nullOr path);
|
||||
|
||||
options.pds_jwt_secret = lib.mkOption {
|
||||
type = nullOr path;
|
||||
default = null;
|
||||
description = ''
|
||||
Path to a file containing a 16 character hex secret used for JWT secrets.
|
||||
'';
|
||||
};
|
||||
options.pds_admin_password = lib.mkOption {
|
||||
type = nullOr path;
|
||||
default = null;
|
||||
description = ''
|
||||
Path to a file containing the PDS admin password.
|
||||
'';
|
||||
};
|
||||
options.pds_plc_rotation_key_k256_private_key = lib.mkOption {
|
||||
type = nullOr path;
|
||||
default = null;
|
||||
description = ''
|
||||
Path to a file containing a secp256k1 private key in DER format.
|
||||
'';
|
||||
};
|
||||
};
|
||||
default = {};
|
||||
description = ''
|
||||
Path to files containing secrets for Bluesky PDS.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkMerge [(lib.mkIf cfg.generateSecrets {
|
||||
my.services.bsky-pds.secrets = {
|
||||
pds_jwt_secret = lib.mkDefault "/var/lib/bsky-pds/secrets/pds_jwt_secret";
|
||||
pds_admin_password = lib.mkDefault "/var/lib/bsky-pds/secrets/pds_admin_password";
|
||||
pds_plc_rotation_key_k256_private_key = lib.mkDefault "/var/lib/bsky-pds/secrets/pds_plc_rotation_key_k256_private_key";
|
||||
};
|
||||
}) (lib.mkIf cfg.enable {
|
||||
systemd.services.bsky-pds = {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
unitConfig = {
|
||||
Description = "Bluesky PDS Service";
|
||||
Documentation = "https://github.com/bluesky-social/pds";
|
||||
};
|
||||
script = ''
|
||||
mkdir -p /var/lib/bsky-pds "$PDS_DATA_DIRECTORY"
|
||||
if [[ ! -z "$PDS_BLOBSTORE_DISK_LOCATION" ]]; then
|
||||
mkdir -p "$PDS_BLOBSTORE_DISK_LOCATION"
|
||||
fi
|
||||
|
||||
old_umask=$(umask)
|
||||
umask 077
|
||||
mkdir -p /var/lib/bsky-pds/secrets
|
||||
${lib.optionalString (inSecretsDir cfg.secrets.pds_jwt_secret) (testAndGenerateHex cfg.secrets.pds_jwt_secret)}
|
||||
${lib.optionalString (inSecretsDir cfg.secrets.pds_admin_password) (testAndGenerateHex cfg.secrets.pds_admin_password)}
|
||||
${lib.optionalString (inSecretsDir cfg.secrets.pds_plc_rotation_key_k256_private_key) (testAndGenerateK256 cfg.secrets.pds_plc_rotation_key_k256_private_key)}
|
||||
umask "$old_umask"
|
||||
|
||||
${lib.concatStringsSep "\n" (lib.mapAttrsToList (k: v: lib.optionalString (v != null) ''
|
||||
export ${lib.toUpper k}="$(cat "${v}")"
|
||||
'') cfg.secrets)}
|
||||
|
||||
${lib.optionalString (cfg.secrets.pds_plc_rotation_key_k256_private_key != null) ''
|
||||
if [[ -z "$PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX ]]; then
|
||||
export PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX="$(cat "${cfg.secrets.pds_plc_rotation_key_k256_private_key}" | ${pkgs.coreutils}/bin/tail --bytes=+8 | ${pkgs.coreutils}/bin/head --bytes=32 | ${pkgs.xxd}/bin/xxd --plain --cols 32)"
|
||||
fi
|
||||
''}
|
||||
|
||||
exec ${cfg.package}/bin/bsky-pds
|
||||
'';
|
||||
serviceConfig = {
|
||||
User = "bsky-pds";
|
||||
DynamicUser = true;
|
||||
StateDirectory = "bsky-pds";
|
||||
EnvironmentFile = cfgFile;
|
||||
};
|
||||
};
|
||||
}) (lib.mkIf (cfg.enable && cfg.configureCaddy) {
|
||||
services.caddy = {
|
||||
enable = lib.mkDefault true;
|
||||
globalConfig = ''
|
||||
email ${cfg.settings.pds_admin_email}
|
||||
on_demand_tls {
|
||||
ask http://localhost:${toString cfg.settings.port}/tls-check
|
||||
}
|
||||
'';
|
||||
virtualHosts."${cfg.settings.pds_hostname}" = {
|
||||
serverAliases = [ "*.${cfg.settings.pds_hostname}" ];
|
||||
extraConfig = ''
|
||||
tls {
|
||||
on_demand
|
||||
}
|
||||
reverse_proxy http://localhost:${toString cfg.settings.port}
|
||||
'';
|
||||
};
|
||||
};
|
||||
})];
|
||||
}
|
42
ops/nixos/rexxar/bsky-pds.nix
Normal file
42
ops/nixos/rexxar/bsky-pds.nix
Normal file
|
@ -0,0 +1,42 @@
|
|||
{ config, lib, ... }:
|
||||
|
||||
let
|
||||
bskySecretsFromVault = [
|
||||
"PDS_ADMIN_PASSWORD"
|
||||
"PDS_BLOBSTORE_S3_ACCESS_KEY_ID"
|
||||
"PDS_BLOBSTORE_S3_SECRET_ACCESS_KEY"
|
||||
"PDS_JWT_SECRET"
|
||||
"PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX"
|
||||
];
|
||||
in {
|
||||
imports = [ ../lib/bsky-pds.nix ];
|
||||
|
||||
my.services.bsky-pds = {
|
||||
enable = true;
|
||||
settings = {
|
||||
pds_hostname = "pds.lukegb.com";
|
||||
pds_admin_email = "bskypds@lukegb.com";
|
||||
pds_blobstore_disk_location = null;
|
||||
pds_blobstore_s3_bucket = "bsky-pds";
|
||||
pds_blobstore_s3_region = "anywhere";
|
||||
pds_blobstore_s3_endpoint = "https://objdump.zxcvbnm.ninja";
|
||||
pds_blobstore_s3_force_path_style = false;
|
||||
pds_blobstore_s3_upload_timeout_ms = 10000;
|
||||
};
|
||||
generateSecrets = false;
|
||||
secrets = lib.listToAttrs (map (k: lib.nameValuePair (lib.toLower k) config.my.vault.secrets."bsky_${lib.toLower k}".path) bskySecretsFromVault);
|
||||
};
|
||||
|
||||
my.vault.secrets = let
|
||||
bskySecret = key: {
|
||||
group = "bsky-pds";
|
||||
template = ''
|
||||
{{- with secret "kv/apps/bsky-pds" -}}
|
||||
{{- .Data.data.${key} -}}
|
||||
{{- end -}}
|
||||
'';
|
||||
};
|
||||
in lib.listToAttrs (map (k: lib.nameValuePair "bsky_${lib.toLower k}" (bskySecret k)) bskySecretsFromVault);
|
||||
users.groups.bsky-pds = {};
|
||||
users.users.bsky-pds = { isSystemUser = true; group = "bsky-pds"; };
|
||||
}
|
|
@ -14,6 +14,7 @@
|
|||
../lib/emfminiserv.nix
|
||||
../lib/seaweedfs.nix
|
||||
../lib/fup.nix
|
||||
./bsky-pds.nix
|
||||
];
|
||||
|
||||
# Otherwise _this_ machine won't enumerate things properly.
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
my.apps.hacky-vouchproxy = {};
|
||||
my.apps.hackyplayer = {};
|
||||
my.apps.emfminiserv = {};
|
||||
my.apps.bsky-pds = {};
|
||||
|
||||
my.servers.etheroute-lon01.apps = [ "pomerium" ];
|
||||
my.servers.howl.apps = [ "nixbuild" ];
|
||||
|
@ -90,5 +91,5 @@
|
|||
my.servers.bvm-heptapod.apps = [ "gitlab-runner" ];
|
||||
my.servers.bvm-nixosmgmt.apps = [ "plex-pass" ];
|
||||
my.servers.bvm-netbox.apps = [ "netbox" ];
|
||||
my.servers.rexxar.apps = [ "deluge" "gitlab-runner" "nixbuild" "hacky-vouchproxy" "hackyplayer" "emfminiserv" "fup" ];
|
||||
my.servers.rexxar.apps = [ "deluge" "gitlab-runner" "nixbuild" "hacky-vouchproxy" "hackyplayer" "emfminiserv" "fup" "bsky-pds" ];
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue