Alternative ATProto PDS implementation
1{
2 description = "Alternative Bluesky PDS implementation";
3 inputs = {
4 nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
5 crane.url = "github:ipetkov/crane";
6 flake-utils.url = "github:numtide/flake-utils";
7 rust-overlay = {
8 url = "github:oxalica/rust-overlay";
9 inputs.nixpkgs.follows = "nixpkgs";
10 };
11 };
12 outputs = { self, nixpkgs, crane, flake-utils, rust-overlay, ... }:
13 flake-utils.lib.eachDefaultSystem (system:
14 let
15 pkgs = import nixpkgs {
16 inherit system;
17 overlays = [ (import rust-overlay) ];
18 };
19 craneLib = (crane.mkLib pkgs).overrideToolchain (p: p.rust-bin.selectLatestNightlyWith (toolchain: toolchain.default.override {
20 extensions = [
21 "rust-src" # for rust-analyzer
22 "rust-analyzer"
23 ];
24 }));
25
26 inherit (pkgs) lib;
27 unfilteredRoot = ./.; # The original, unfiltered source
28 src = lib.fileset.toSource {
29 root = unfilteredRoot;
30 fileset = lib.fileset.unions [
31 # Default files from crane (Rust and cargo files)
32 (craneLib.fileset.commonCargoSources unfilteredRoot)
33 # Include all the .sql migrations as well
34 ./migrations
35 ];
36 };
37 # Common arguments can be set here to avoid repeating them later
38 commonArgs = {
39 inherit src;
40 strictDeps = true;
41 nativeBuildInputs = with pkgs; [
42 pkg-config
43 gcc
44 ];
45 buildInputs = [
46 # Add additional build inputs here
47 pkgs.openssl
48 ] ++ lib.optionals pkgs.stdenv.isDarwin [
49 # Additional darwin specific inputs can be set here
50 pkgs.libiconv
51 pkgs.darwin.apple_sdk.frameworks.Security
52 ];
53
54 # Additional environment variables can be set directly
55 # MY_CUSTOM_VAR = "some value";
56 };
57
58 # Build *just* the cargo dependencies, so we can reuse
59 # all of that work (e.g. via cachix) when running in CI
60 cargoArtifacts = craneLib.buildDepsOnly commonArgs;
61
62 # Build the actual crate itself, reusing the dependency
63 # artifacts from above.
64 bluepds = craneLib.buildPackage (commonArgs // {
65 inherit cargoArtifacts;
66 nativeBuildInputs = (commonArgs.nativeBuildInputs or [ ]) ++ [
67 pkgs.sqlx-cli
68 ];
69 preBuild = ''
70 export DATABASE_URL=sqlite:./sqlite.db
71 cargo sqlx database create
72 cargo sqlx migrate run
73 '';
74 postInstall = ''
75 mkdir -p $out/var/lib/bluepds
76 cp ./default.toml $out/var/lib/bluepds/
77 cp ./sqlite.db $out/var/lib/bluepds/
78 '';
79 });
80 in
81 {
82 checks = {
83 # Build the crate as part of `nix flake check` for convenience
84 inherit bluepds;
85 };
86
87 packages = {
88 default = bluepds;
89 inherit bluepds;
90 };
91
92 devShells.default = craneLib.devShell {
93 # Inherit inputs from checks.
94 checks = self.checks.${system};
95
96 # Additional dev-shell environment variables can be set directly
97 # MY_CUSTOM_DEVELOPMENT_VAR = "something else";
98 RUST_BACKTRACE = 1;
99 NIXOS_OZONE_WL=1;
100
101 # Extra inputs can be added here; cargo and rustc are provided by default.
102 packages = with pkgs; [
103 sqlx-cli
104 bacon
105 sqlite
106 rust-analyzer
107 rustfmt
108 clippy
109 git
110 nixd
111 direnv
112 libpq
113 ];
114 };
115 })
116 // flake-utils.lib.eachDefaultSystemPassThrough (system:
117 {
118 nixosModules = {
119 default = { pkgs, lib, config, ... }: with lib; let
120 cfg = config.services.bluepds;
121 in
122 {
123 options.services.bluepds = {
124 enable = mkEnableOption "Enable bluepds";
125 host_name = mkOption {
126 type = types.str;
127 default = "pds.example.com";
128 description = "The public hostname of the PDS.";
129 };
130 listen_address = mkOption {
131 type = types.str;
132 default = "0.0.0.0:8000";
133 description = "The address to listen to for incoming requests.";
134 };
135 test = mkOption {
136 type = types.str;
137 default = "true";
138 description = "Test mode. This instructs BluePDS not to federate with the rest of the AT network.";
139 };
140 package = mkOption {
141 type = types.package;
142 default = self.packages.${pkgs.system}.default;
143 description = "The path to the bluepds package.";
144 };
145 };
146 config = mkIf cfg.enable {
147 systemd.services.bluepds = {
148 description = "ATProto PDS server";
149 wantedBy = [ "multi-user.target" ];
150 after = [ "network.target" ];
151 requires = [ "network-online.target" ];
152 environment = {
153 BLUEPDS_TEST = "${cfg.test}";
154 BLUEPDS_HOST_NAME = "${cfg.host_name}";
155 BLUEPDS_LISTEN_ADDRESS = "${cfg.listen_address}";
156 };
157 serviceConfig = {
158 ExecStart = "${cfg.package}/bin/bluepds";
159 ProtectHome = true;
160 WorkingDirectory= "/var/lib/bluepds";
161 Restart = "on-failure";
162 Type = "exec";
163 };
164 };
165 };
166 };
167 };
168 });
169}