Something went wrong. Try again.
Monorepo for Tangled tangled.org
Something went wrong. Try again.
Nix
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257{ config, pkgs, lib, ...}: let cfg = config.services.tangled.knotmirror;in with lib; { options.services.tangled.knotmirror = { enable = mkOption { type = types.bool; default = false; description = "Enable a tangled knotmirror"; };
package = mkOption { type = types.package; description = "Package to use for the knotmirror"; };
v2 = { package = mkOption { type = types.package; description = "Package to use for the knotmirror/v2"; };
listenAddr = mkOption { type = types.str; default = "127.0.0.1:9001"; description = "Address to listen on"; };
logging = { endpoint = mkOption { type = types.str; default = ""; description = "Full OTLP/HTTP logs endpoint, e.g. http://prometheus:3100/otlp/v1/logs (empty disables export)"; };
serviceName = mkOption { type = types.str; default = "gitmirror"; description = "OpenTelemetry log service name"; }; }; };
tap-package = mkOption { type = types.package; description = "tap package to use for the knotmirror"; };
listenAddr = mkOption { type = types.str; default = "0.0.0.0:7000"; description = "Address to listen on"; };
adminListenAddr = mkOption { type = types.str; default = "127.0.0.1:7200"; description = "Address to listen on"; };
metricsListenAddr = mkOption { type = types.str; default = "0.0.0.0:7100"; description = "Listen address for the Prometheus metrics endpoint"; };
hostname = mkOption { type = types.str; example = "my.knotmirror.com"; description = "Hostname for the server (required)"; };
dbUrl = mkOption { type = types.str; example = "postgresql://..."; description = "Database URL. postgresql expected (required)"; };
deliberiUrl = mkOption { type = types.str; default = ""; description = "base URL for Deliberi XRPC calls"; };
deliberiDid = mkOption { type = types.str; default = ""; description = "Deliberi service DID used as the service-auth audience"; };
environmentFile = mkOption { type = types.nullOr types.path; default = null; description = "file with secret env vars such as MIRROR_SERVICE_PRIVATE_KEY"; };
atpPlcUrl = mkOption { type = types.str; default = "https://plc.directory"; description = "atproto PLC directory"; };
atpRelayUrl = mkOption { type = types.str; default = "https://relay1.us-east.bsky.network"; description = "atproto relay"; };
fullNetwork = mkOption { type = types.bool; default = false; description = "Whether to automatically mirror from entire network"; };
knotUseSSL = mkOption { type = types.bool; default = true; description = "Use SSL for knot connection"; };
knotSSRF = mkOption { type = types.bool; default = true; description = "enable SSRF protection for knots"; };
zoektUrl = mkOption { type = types.str; default = ""; example = "https://zoekt.tngl.boltless.dev/indexserver"; description = "zoekt-tnglserver url"; };
tap = { port = mkOption { type = types.port; default = 7480; description = "Internal port to run the knotmirror tap"; };
dbUrl = mkOption { type = types.str; default = "sqlite:///var/lib/knotmirror-tap/tap.db"; description = "database connection string (sqlite://path or postgres://...)"; }; }; }; config = mkIf cfg.enable { assertions = [ { assertion = (cfg.deliberiUrl == "") == (cfg.deliberiDid == ""); message = "services.tangled.knotmirror deliberiUrl and deliberiDid must be set together"; } { assertion = cfg.deliberiUrl == "" || cfg.environmentFile != null; message = "services.tangled.knotmirror environmentFile is required when Deliberi is configured"; } ];
environment.systemPackages = [ pkgs.git cfg.package ];
services.redis.servers.knotmirror = { enable = true; port = 6377; };
systemd.services.tap-knotmirror = { description = "knotmirror tap service"; after = ["network.target"]; wantedBy = ["multi-user.target"]; serviceConfig = { LogsDirectory = "knotmirror-tap"; StateDirectory = "knotmirror-tap"; Environment = [ "TAP_BIND=:${toString cfg.tap.port}" "TAP_PLC_URL=${cfg.atpPlcUrl}" "TAP_RELAY_URL=${cfg.atpRelayUrl}" "TAP_RESYNC_PARALLELISM=10" "TAP_DATABASE_URL=${cfg.tap.dbUrl}" "TAP_RETRY_TIMEOUT=60s" "TAP_COLLECTION_FILTERS=sh.tangled.repo" ( if cfg.fullNetwork then "TAP_SIGNAL_COLLECTION=sh.tangled.repo" else "TAP_FULL_NETWORK=false" ) ]; ExecStart = "${getExe cfg.tap-package} run"; }; };
systemd.services.knotmirror = { description = "knotmirror service"; after = ["network.target" "tap-knotmirror.service"]; wantedBy = ["multi-user.target"]; path = [ pkgs.git pkgs.util-linux ]; serviceConfig = { LogsDirectory = "knotmirror"; StateDirectory = "knotmirror"; EnvironmentFile = mkIf (cfg.environmentFile != null) cfg.environmentFile; Environment = [ # TODO: add environment variables "MIRROR_LISTEN=${cfg.listenAddr}" "MIRROR_HOSTNAME=${cfg.hostname}" "MIRROR_TAP_URL=http://localhost:${toString cfg.tap.port}" "MIRROR_DB_URL=${cfg.dbUrl}" "MIRROR_REDIS_ADDR=localhost:6377" "MIRROR_GIT_BASEPATH=/var/lib/knotmirror/repos" "MIRROR_KNOT_USE_SSL=${boolToString cfg.knotUseSSL}" "MIRROR_KNOT_SSRF=${boolToString cfg.knotSSRF}" "MIRROR_RESYNC_PARALLELISM=12" "MIRROR_METRICS_LISTEN=${cfg.metricsListenAddr}" "MIRROR_ADMIN_LISTEN=${cfg.adminListenAddr}" "MIRROR_SLURPER_CONCURRENCY=4" "MIRROR_SEARCH_ZOEKT_URL=${cfg.zoektUrl}" "MIRROR_V2_HOST=http://${cfg.v2.listenAddr}" "MIRROR_DELIBERI_URL=${cfg.deliberiUrl}" "MIRROR_DELIBERI_DID=${cfg.deliberiDid}" ]; ExecStart = "${getExe cfg.package} serve"; Restart = "always"; }; };
systemd.services.gitmirror = { description = "gitmirror service"; after = ["network.target" "knotmirror.service"]; wantedBy = ["multi-user.target"]; serviceConfig = { LogsDirectory = "gitmirror"; StateDirectory = "gitmirror"; Environment = [ "GITMIRROR_BIND=${cfg.v2.listenAddr}" "GITMIRROR_SCAN_PATH=/var/lib/knotmirror/repos" "GITMIRROR_PLC_URL=${cfg.atpPlcUrl}" "GITMIRROR_SERVICE_DID=did:web:${cfg.hostname}" "GITMIRROR_LOG_ENDPOINT=${cfg.v2.logging.endpoint}" "GITMIRROR_LOG_SERVICE_NAME=${cfg.v2.logging.serviceName}" ]; ExecStart = "${getExe cfg.v2.package} serve"; Restart = "always"; }; }; }; }