ATCR - ATProto Container Registry

A container registry that uses the AT Protocol (ATProto) for manifest storage and S3 for blob storage.

Overview

ATCR is an OCI-compliant container registry that integrates with the AT Protocol ecosystem. It stores container image manifests as ATProto records in Personal Data Servers (PDS) while keeping the actual image layers in S3-compatible storage.

Architecture

ATCR consists of three main components:

  1. AppView - OCI registry server + web UI

    • Serves OCI Distribution API (Docker push/pull)
    • Resolves identities (handle/DID → PDS endpoint)
    • Routes manifests to user's PDS, blobs to storage
    • Web interface for browsing and search
    • SQLite database for stars, pulls, metadata
  2. Hold Service - Optional storage service (BYOS)

    • Lightweight HTTP server for presigned URLs
    • Supports S3, Storj, Minio, filesystem, etc.
    • Authorization via ATProto records
    • Users can deploy their own hold
  3. Credential Helper - Client-side OAuth

    • ATProto OAuth with DPoP
    • Exchanges OAuth token for registry JWT
    • Seamless Docker integration

Storage Model:

  • Manifests → ATProto records in user PDSs (small JSON metadata)
  • Blobs/Layers → S3 or user's hold service (large binary data)
  • Name Resolution → Supports both handles and DIDs
    • atcr.io/alice.bsky.social/myimage:latest
    • atcr.io/did:plc:xyz123/myimage:latest

Features

Core Registry

  • OCI Distribution Spec compliant - Works with Docker, containerd, podman
  • ATProto-native manifest storage - Manifests stored as records in user PDSs
  • Hybrid storage - Small manifests in ATProto, large blobs in S3/BYOS
  • DID/handle resolution - Supports both handles and DIDs for image names
  • Decentralized ownership - Users own their manifest data via their PDS

Web Interface

  • Repository browser - Browse and search container images
  • Star repositories - Favorite images for quick access
  • Pull tracking - View popularity and usage metrics
  • OAuth authentication - Sign in with your ATProto identity
  • User profiles - Manage your default storage hold

Authentication

  • ATProto OAuth with DPoP - Cryptographic proof-of-possession tokens
  • Docker credential helper - Seamless docker push/pull workflow
  • Token exchange - OAuth tokens converted to registry JWTs

Storage

  • BYOS (Bring Your Own Storage) - Deploy your own hold service
  • Multi-backend support - S3, Storj, Minio, Azure, GCS, filesystem
  • Presigned URLs - Direct client-to-storage uploads/downloads
  • Hold discovery - Automatic routing based on user preferences

Building

# Build all binaries locally
go build -o atcr-appview ./cmd/appview
go build -o atcr-hold ./cmd/hold
go build -o docker-credential-atcr ./cmd/credential-helper

# Build Docker images
docker build -t atcr.io/appview:latest .
docker build -f Dockerfile.hold -t atcr.io/hold:latest .

Manual setup:

# 1. Create directories
sudo mkdir -p /var/lib/atcr/{blobs,hold,auth}
sudo chown -R $USER:$USER /var/lib/atcr

# 2. Build binaries
go build -o atcr-appview ./cmd/appview
go build -o atcr-hold ./cmd/hold

# 3. Configure environment
cp .env.example .env
# Edit .env - set ATPROTO_HANDLE and HOLD_PUBLIC_URL
export $(cat .env | xargs)

# 4. Start services
# Terminal 1:
./atcr-appview serve config/config.yml
# Terminal 2 (will prompt for OAuth):
./atcr-hold config/hold.yml
# Follow OAuth URL in logs to authorize

# 5. Test with Docker
docker tag alpine:latest localhost:5000/alice/alpine:test
docker push localhost:5000/alice/alpine:test
docker pull localhost:5000/alice/alpine:test

Running

Local Development

Configure environment:

# Copy and edit .env file
cp .env.example .env
# Edit .env with:
# - ATPROTO_HANDLE (your Bluesky handle)
# - HOLD_PUBLIC_URL (e.g., http://127.0.0.1:8080 or https://hold1.atcr.io)
# - HOLD_AUTO_REGISTER=true

# Load environment
export $(cat .env | xargs)

AppView:

./atcr-appview serve config/config.yml

Hold (Storage Service):

# Starts OAuth flow to register in your PDS
./atcr-hold config/hold.yml
# Follow the OAuth URL in the logs to authorize

Docker

Run with Docker Compose:

docker-compose up -d

Or run containers separately:

AppView:

docker run -d \
  --name atcr-appview \
  -p 5000:5000 \
  -e ATPROTO_DID=did:plc:your-did \
  -e ATPROTO_ACCESS_TOKEN=your-access-token \
  -e AWS_ACCESS_KEY_ID=your-aws-key \
  -e AWS_SECRET_ACCESS_KEY=your-aws-secret \
  -v $(pwd)/config/config.yml:/etc/atcr/config.yml \
  atcr.io/appview:latest

Hold (Storage Service):

docker run -d \
  --name atcr-hold \
  -p 8080:8080 \
  -e AWS_ACCESS_KEY_ID=your-aws-key \
  -e AWS_SECRET_ACCESS_KEY=your-aws-secret \
  -v $(pwd)/config/hold.yml:/etc/atcr/hold.yml \
  atcr.io/hold:latest

Kubernetes

apiVersion: apps/v1
kind: Deployment
metadata:
  name: atcr-appview
spec:
  replicas: 3
  selector:
    matchLabels:
      app: atcr-appview
  template:
    metadata:
      labels:
        app: atcr-appview
    spec:
      containers:
      - name: appview
        image: atcr.io/appview:latest
        ports:
        - containerPort: 5000
        env:
        - name: ATPROTO_DID
          valueFrom:
            secretKeyRef:
              name: atcr-secrets
              key: did
        - name: ATPROTO_ACCESS_TOKEN
          valueFrom:
            secretKeyRef:
              name: atcr-secrets
              key: access-token
        volumeMounts:
        - name: config
          mountPath: /etc/atcr
      volumes:
      - name: config
        configMap:
          name: atcr-config

Configuration

See config/config.yml for full configuration options.

Key settings:

  • storage.s3: S3 bucket configuration for blob storage
  • middleware.repository: ATProto routing middleware
  • middleware.registry: Name resolution middleware

Usage

# Build and configure the credential helper
go build -o docker-credential-atcr ./cmd/credential-helper
./docker-credential-atcr configure
# Follow the OAuth flow in your browser

# Add to Docker config (~/.docker/config.json)
{
  "credHelpers": {
    "atcr.io": "atcr"
  }
}

Pushing an Image

# Tag your image
docker tag myapp:latest atcr.io/alice/myapp:latest

# Push to ATCR (credential helper handles auth)
docker push atcr.io/alice/myapp:latest

Pulling an Image

# Pull from ATCR
docker pull atcr.io/alice/myapp:latest

Web Interface

Visit the AppView URL (default: http://localhost:5000) to:

  • Browse repositories
  • Search for images
  • Star your favorites
  • View pull statistics
  • Manage your storage settings

Development

Project Structure

atcr.io/
├── cmd/
│   ├── appview/              # AppView entrypoint (registry + web UI)
│   ├── hold/                 # Hold service entrypoint (BYOS)
│   └── credential-helper/    # Docker credential helper
├── pkg/
│   ├── appview/              # Web UI components
│   │   ├── handlers/         # HTTP handlers (home, repo, search, auth)
│   │   ├── db/               # SQLite database layer
│   │   ├── jetstream/        # ATProto Jetstream consumer
│   │   ├── static/           # JS, CSS assets
│   │   └── templates/        # HTML templates
│   ├── atproto/              # ATProto integration
│   │   ├── client.go         # PDS client
│   │   ├── resolver.go       # DID/handle resolution
│   │   ├── manifest_store.go # OCI manifest store
│   │   ├── lexicon.go        # ATProto record schemas
│   │   └── profile.go        # Sailor profile management
│   ├── storage/              # Storage layer
│   │   ├── routing_repository.go  # Routes manifests/blobs
│   │   ├── proxy_blob_store.go    # BYOS proxy
│   │   ├── s3_blob_store.go       # S3 wrapper
│   │   └── hold_cache.go          # Hold endpoint cache
│   ├── middleware/           # Registry middleware
│   │   ├── registry.go       # Name resolution
│   │   └── repository.go     # Storage routing
│   └── auth/                 # Authentication
│       ├── oauth/            # ATProto OAuth with DPoP
│       ├── token/            # JWT issuer/validator
│       └── atproto/          # Session validation
├── config/                   # Configuration files
├── docs/                     # Documentation
└── Dockerfile

Testing

# Run tests
go test ./...

# Run with race detector
go test -race ./...

License

MIT

Contributing

Contributions welcome! Please open an issue or PR.

Description
No description provided
Readme 126 MiB
Languages
Go 88.4%
HTML 8%
Shell 1.2%
JavaScript 1.2%
CSS 0.8%
Other 0.3%