Hosting a static site on our PDS domain

@fei.chicory.blue

A writeup about our edits to the included Caddy config.

Quick tips

You're probably here to check what PDS paths to reverse proxy, so here they are:

/xrpc/*
/.well-known/atproto-did
/.well-known/oauth-protected-resource
/.well-known/oauth-authorization-server
/oauth/*
/@atproto/*
/gate

Subdomains only need /.well-known/atproto-did.

If you're here because you thought the PDS needed to be on your base domain to assign user handles from it, the environment variable PDS_SERVICE_HANDLE_DOMAINS (in /pds/pds.env) is your friend!

Some guides you might find useful

*(Please note you'll still need the new OAuth paths if you want to use OAuth.)

If you need to configure a PDS to work around existing services you're running, check out these:

If you want to confirm that OAuth works on your PDS, here are some great ATmosphere sites you can log into to check:

Where we put website files

Our files are in /srv. Another common location is /var/www. You can use other locations, but you may have to configure permissions if you do so.

Our folder structure is like this:

srv
- default
- subdomains
-- <username>

Allowing Caddy to access the files

The default PDS installation uses Docker. This means PDS-related things are in a container and can't mess with anything outside of it unless you let it know it's okay to do that.

You can do that by adding to /pds/compose.yml. Under services: caddy: volumes:, there are a bunch of paths and what path they'll be called in the container. We added /srv there:

      - type: bind
        source: /srv
        target: /srv

Caddy also restarts when you sudo systemctl restart pds.

Our Caddyfile

The Caddyfile for the PDS is /pds/caddy/etc/caddy/Caddyfile.

About the PDS paths:

  • Most requests go to /xrpc/.
  • Handles are verified using /.well-known/atproto-did.
  • Logging in with OAuth uses /oauth/ plus information in /.well-known/oauth-protected-resource and /.well-known/oauth-authorization-server. (See AT Protocol OAuth spec.)
  • I have no idea the specifics but OAuth also uses /@atproto/ in some browsers.
  • hCaptcha uses /gate/.

About our blob paths (this is irrelevant to normal PDS use):

  • If you look up a blob by DID+CID (user + hash), you'll always get the same blob, so they can be cached for outside use like linking atfile files.
  • We are rewriting a convenient path (/blob/<did>/<cid>) and using defer to replace the PDS's Cache-Control header so browsers will cache the files when using this path.

About our subdomains:

  • We have separate websites for each handle on our PDS, and if someone doesn't have a website, it redirects to our base URL. Check out the many error handling options in the Caddy documentation.
  • Nonexistent handles do error, since we don't have a wildcard certificate.

Our Caddyfile:

{
	email our@email.here
	on_demand_tls {
		ask http://localhost:3000/tls-check
	}
}

chicory.blue {
	root * /srv/default
	@pds {
		path /xrpc/*
		path /.well-known/atproto-did
		path /.well-known/oauth-protected-resource
		path /.well-known/oauth-authorization-server
		path /oauth/*
		path /@atproto/*
		path /gate/*
	}
	@blobs {
		path_regexp ^/blob/(.*)/(.*)$
	}
	header @blobs Cache-Control "public, max-age=15552000" {
		defer
	}
	rewrite @blobs /xrpc/com.atproto.sync.getBlob?did={re.1}&cid={re.2}
	reverse_proxy @pds http://localhost:3000
	file_server
}

*.chicory.blue {
	root * /srv/subdomains/{labels.2}
	tls {
		on_demand
	}
	@pds {
		path /.well-known/atproto-did
	}
	handle_errors {
		redir https://chicory.blue
	}
	reverse_proxy @pds http://localhost:3000
	file_server
}

Credits

Thanks to fry69 (🦋) for helping me understand Docker!

Thanks to ducky.ws (🦋) and benharri.org (🦋) for explaining how to create the blob path and sharing the regex!

Thanks to mov.eax on Discord for suggesting edits to the confusing section about blob paths!

Thanks to iame.li (🦋) for adding /gate to the routes!

@fei.chicory.blue

did:plc:xz3euvkhf44iadavovbsmqoo

Post reaction in Bluesky

*To be shown as a reaction, include article link in the post or add link card

Reactions from everyone (0)