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 ];
113 };
114 })
115 // flake-utils.lib.eachDefaultSystemPassThrough (system:
116 {
117 nixosModules = {
118 default = { pkgs, lib, config, ... }: with lib; let
119 cfg = config.services.bluepds;
120 in
121 {
122 options.services.bluepds = {
123 enable = mkEnableOption "Enable bluepds";
124 host_name = mkOption {
125 type = types.str;
126 default = "pds.example.com";
127 description = "The public hostname of the PDS.";
128 };
129 listen_address = mkOption {
130 type = types.str;
131 default = "0.0.0.0:8000";
132 description = "The address to listen to for incoming requests.";
133 };
134 test = mkOption {
135 type = types.str;
136 default = "true";
137 description = "Test mode. This instructs BluePDS not to federate with the rest of the AT network.";
138 };
139 package = mkOption {
140 type = types.package;
141 default = self.packages.${pkgs.system}.default;
142 description = "The path to the bluepds package.";
143 };
144 };
145 config = mkIf cfg.enable {
146 systemd.services.bluepds = {
147 description = "ATProto PDS server";
148 wantedBy = [ "multi-user.target" ];
149 after = [ "network.target" ];
150 requires = [ "network-online.target" ];
151 environment = {
152 BLUEPDS_TEST = "${cfg.test}";
153 BLUEPDS_HOST_NAME = "${cfg.host_name}";
154 BLUEPDS_LISTEN_ADDRESS = "${cfg.listen_address}";
155 };
156 serviceConfig = {
157 ExecStart = "${cfg.package}/bin/bluepds";
158 ProtectHome = true;
159 WorkingDirectory= "/var/lib/bluepds";
160 Restart = "on-failure";
161 Type = "exec";
162 };
163 };
164 };
165 };
166 };
167 });
168}