Fetch, resize, reformat, and cache Atmosphere avatar images atp.pics
atproto
Go 99.0%
Dockerfile 1.0%
12 2 0

Clone this repository

https://tangled.org/graham.systems/atp.pics https://tangled.org/did:plc:57od6g2ic3e3b3kauctjmo3k/atp.pics
git@tangled.org:graham.systems/atp.pics git@tangled.org:did:plc:57od6g2ic3e3b3kauctjmo3k/atp.pics

For self-hosted knots, clone URLs may differ based on your setup.

Download tar.gz
README.md

atp.pics#

HTTP service that resolves AT Protocol user identifiers to avatar images, caches them in S3, and redirects clients to the cached image.

Usage#

GET /{identifier}

identifier may be an AT Protocol handle (e.g. alice.bsky.social) or a DID (e.g. did:plc:abc123).

Query parameters#

Parameter Type Default Description
w integer Output width in pixels
h integer Output height in pixels
q integer (1–100) 85 Encode quality (WebP and JPEG only)
f webp | jpg | png webp Output format

When both w and h are provided the image is cover-cropped to exact dimensions. When only one dimension is provided the image is scaled proportionally.

Response#

A 302 Found redirect to the public S3 URL of the cached image. The redirect itself carries no Cache-Control header so browsers always re-check for avatar changes. The S3 objects are served with Cache-Control: public, max-age=31536000, immutable.

Running#

docker build -t atp-pics .
docker run -p 8080:8080 \
  -e BUCKET_NAME=my-bucket \
  -e AWS_REGION=us-east-1 \
  -e AWS_ACCESS_KEY_ID=... \
  -e AWS_SECRET_ACCESS_KEY=... \
  atp-pics

Local development#

Requires a C compiler and libwebp development headers for CGO.

On macOS: brew install webp On Debian/Ubuntu: apt install libwebp-dev On Alpine: apk add libwebp-dev

CGO_ENABLED=1 go build ./cmd/server

Environment variables#

Variable Required Default Description
BUCKET_NAME yes Storage bucket name
AWS_REGION yes AWS/Tigris region (use auto for Tigris)
AWS_ACCESS_KEY_ID no* AWS access key
AWS_SECRET_ACCESS_KEY no* AWS secret key
AWS_ENDPOINT_URL_S3 no Custom S3 endpoint (e.g. https://fly.storage.tigris.dev for Tigris)
BUCKET_PUBLIC_HOST no Custom hostname for public object URLs (e.g. cdn.example.com); overrides the computed bucket URL
LISTEN_ADDR no :8080 Server listen address

* AWS credentials may be provided via environment variables, credentials file, IAM role, or any other mechanism supported by the AWS SDK default credential chain.

On Fly.io with Tigris, BUCKET_NAME, AWS_ENDPOINT_URL_S3, AWS_ACCESS_KEY_ID, and AWS_SECRET_ACCESS_KEY are injected automatically by flyctl storage create. Set AWS_REGION=auto manually as a Fly.io secret after provisioning.

Bucket setup#

The bucket must allow public read access so clients can follow redirects directly to object URLs. On Fly.io this is achieved by provisioning with flyctl storage create --public (Tigris). Objects are stored under:

avatars/{did}/original/{cid}          — raw blob from PDS
avatars/{did}/{cid}/default.webp      — no-param WebP output
avatars/{did}/{cid}/w200-h200-q85.webp
avatars/{did}/{cid}/w200-h200-q85.jpg
avatars/{did}/{cid}/w200-h200.png