{
"$type": "site.standard.document",
"canonicalUrl": "https://isabelroses.com/blog/nix-pds-guide",
"coverImage": {
"$type": "blob",
"ref": {
"$link": "bafkreib54ej5hy5ojpjbzitv2h636vpabxph6dzfqz4qwtsqxgmojeiape"
},
"mimeType": "image/png",
"size": 12082
},
"description": "How to host your own personal data server using NixOS",
"path": "/blog/nix-pds-guide",
"publishedAt": "2025-11-04T00:00:00.000Z",
"site": "at://did:plc:qxichs7jsycphrsmbujwqbfb/site.standard.publication/3mn5hmwkcmb22",
"tags": [
"guide",
"nix",
"nixos"
],
"textContent": "Introduction\n\nOver the last number of days leading up to writing this guide I have been\nsharing my dotfiles left and right as a way to help people setting up their own\npersonal data server, which I shall start to refer to as PDS going forwards.\n\nUnderstanding my assumptions\n\nBefore we go any further I think it's best you understand some of the assumptions\nI have made when writing this guide.\n\n1. I am going to make a logical leap to assume you already are using NixOS as\n the host for your server. If you are not, I would highly recommend reading\n the NixOS manual on installing\n NixOS.\n\n2. I will be keeping all nix code agnostic from flakes and classic nix.\n\n3. We will only be dealing with the reference implementation of the PDS and not\n alternative implementations such as cocoon even if they are packaged in\n nixpkgs.\n\n4. I will be targeting my article towards unstable and the next upcoming stable\n release. If you are using the 25.05 release of NixOS, you will have to change\n any references of bluesky-pds to pds as the package was renamed on\n unstable and later releases.\n\nUnderstanding your requirements\n\nBefore even starting to set up your PDS we should first consider how many\npeople we are going to host on the PDS. The bluesky PDS\ndocumentation\nsuggests that for 1-20 users 1GB of ram, 1 vCPU and 20GB of storage is\nsufficient. However, if you plan to host more users you should consider\nincreasing these resources accordingly. I also personally consider a single\nuser PDS to be a different entire world from a multi user PDS, so keep that in\nmind.\n\nSetting up the PDS\n\nAs with any NixOS service the first step will be to set the enable option for\nthe service we have chosen to true. This will look like such\n\nConfiguring the PDS\n\noverwhelming configuration\n\nAt first the list of environment\nvariables\ncan appear overwhelming. However, we are only going to need a few of them. Those being:\n\n- PDS_PORT\n- PDS_HOSTNAME\n- PDS_ADMIN_EMAIL\n- PDS_JWT_SECRET\n- PDS_ADMIN_PASSWORD\n- PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX\n\nIf you are going to be dealing with more than one user on your PDS you should\nalso be aware of the following optional environment variables.\n\n- PDS_EMAIL_SMTP_URL\n- PDS_EMAIL_FROM_ADDRESS\n\nSo lets get started with the easier ones! I personally run the PDS on the port\n3000 since I have it free, so that's what I'll use that in our example. Now\nwe will need to get a domain name for our PDS for the sake of this example I\nwill be using example.com. It is also 2025 so I'll assume that everyone has\nan email address that they can use for the admin of the PDS. So now let's put\nthat all into practice by adding the settings to our nix configuration.\n\nSecrets\n\nWe are now faced with the time old question, \"how do we deal with secrets in\nnix?\". First off you should not put your secrets into plain nix code as this\nwill place your secrets into the nix store, which everyone can see. So I would\nrecommend either agenix or\nsops-nix. I shall not cover setting up\neither of these but I will explain how to generate the secrets and how to use\nboth agenix and sops-nix here\n\nTo generate the PDS_JWT_SECRET and PDS_ADMIN_PASSWORD, you should open your\npreferred terminal and run\n\nYou must run this once for each secret.\n\nAnd to generate the PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX secret you\nshould run\n\nYou should now place your newly generated secrets into your secrets manager.\nThis should look something similar to\n\nWith Agenix this may look something like\n\nAnd sops-nix this will look like\n\nThe mailer\n\nIf you're on a single user PDS you can skip this step, as long as you're willing\nto search for the email_token in /var/lib/pds/accounts.sqlite, when you\nfirst move your account, whenever you're trying to reset your password and so on.\n\nI have set up both SMTP and resend in my time hosting my\nPDS. Resend is by far the easier option if want your PDS to just work, or this\nis your first time dealing with the horrors of SMTP and emails.\n\nIn the case of resend append the following to your secrets, having replaced the\nplaceholder details.\n\nIn the case that you are daring enough to use SMTP and your own mail server. You\nshould append the following to your secrets file, having replaced the placeholder data.\nPlease note that you must percent encode your username and password.\n\nAdditional fun variables\n\nThere are still some more optional variables that you may want to consider\nusing!\n\nIf you have multiple domains that would be good for using as handles you can\nuse PDS_SERVICE_HANDLE_DOMAINS to do this. An example of this is\nPDS_SERVICE_HANDLE_DOMAINS=.example.com,.catsky.social.\n\nAnother useful option is PDS_CRAWLERS. I have shamelessly sourced my example\nof crawlers from compare hoses. So here is how it\nmay look in nix code.\n\nThe web server\n\nFor this part I shall be be providing both nginx and\ncaddy examples. We will need to proxy the port we\nselected, in my case that is 3000 but we can do this in a smart way by\naccessing the port through the config attr. This will look like\nconfig.services.bluesky-pds.settings.PDS_PORT, from there we can apply this\nsame premise to the domain. We must also proxy both our domain and all\nsubdomains of our PDS's domain since subdomains are used for the handles of the\nPDS accounts.\n\nIn nginx this will look like\n\nand in caddy it will look like\n\nAge assurance\n\nWe cannot be done just there; some of us are unfortunate enough to live in the\nUK under the online safety act. However, a lovely gist on bluesky\nosa has\nbeen provided to us by the lovely\nmary. So let us apply this to our nix code.\n\nIn nginx this will look like such\n\nAnd with caddy\n\nCreate a test account & migration\n\nIt is important that you now access the server and create a test repo. To do\nthis you can use pdsadmin which is installed by default by the NixOS module.\nWe really want to do this because there are possible issue that may arise when using a\nnewly setup PDS, see setting up a pds by\nlyna.\n\nThe below example will create an account for you with the email address and\nhandle as follows, make sure you replace the placeholder with your own data.\n\nWhen you have confirmed that everything is running well you can use\npdsmoover by the lovely Bailey\nTownsend. But to do\nso you will need an invite code from your PDS which you can generate with the\nfollowing command\n\nNow you can move your account over for which there are many guides.\n\nAdd PDS gatekeeper (optional)\n\nPDS gatekeeper is a\nservice, once again created by Bailey Townsend, that adds 2FA email and\nendpoint spam prevention, which is why I choose to employ it. In the future I\nintend to upstream my code packaging and modularizing to nixpkgs, but until\nthen you will have to consume tgirlpkgs.\nPlease follow the setup guide documented in their readme!\n\nFrom there it is as simple as adding the following to your previous configuration.\n\nConclusion\n\nYou should now be all set! You have got your PDS running!\n\nYou should also consider giving me money on\nko-fi or github\nsponsors for writing this because I\nsuck at writing and I spent a few hours on this.",
"title": "A NixOS PDS Hosting Guide",
"updatedAt": "2025-12-09T00:00:00.000Z"
}