# 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 (recommended) ```sh 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` ```sh 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 ```