mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-09-04 01:06:57 +00:00
fixup atcr-appview readme
This commit is contained in:
+288
-71
@@ -1,104 +1,321 @@
|
||||
# ATCR AppView
|
||||
|
||||
The **AppView** is the OCI-compliant registry server for ATCR (ATProto Container Registry). It provides the Docker Registry HTTP API V2 and a web interface for browsing container images.
|
||||
> The registry frontend component of ATCR (ATProto Container Registry)
|
||||
|
||||
## What is AppView?
|
||||
## Overview
|
||||
|
||||
AppView serves as the central registry server that:
|
||||
**AppView** is the frontend server component of ATCR. It serves as the OCI-compliant registry API endpoint and web interface that Docker clients interact with when pushing and pulling container images.
|
||||
|
||||
- **Serves OCI Distribution API** - Compatible with Docker, containerd, podman, and other OCI clients
|
||||
- **Resolves ATProto identities** - Converts handles and DIDs to PDS endpoints
|
||||
- **Routes manifests** - Stores container manifests as ATProto records in users' Personal Data Servers
|
||||
- **Routes blobs** - Proxies blob operations to hold services (S3-compatible storage)
|
||||
- **Provides web UI** - Browse, search, and star repositories
|
||||
### What AppView Does
|
||||
|
||||
## Image Format
|
||||
AppView is the orchestration layer that:
|
||||
|
||||
Container images use ATProto identities:
|
||||
- **Serves the OCI Distribution API V2** - Compatible with Docker, containerd, podman, and all OCI clients
|
||||
- **Resolves ATProto identities** - Converts handles (`alice.bsky.social`) and DIDs (`did:plc:xyz123`) to PDS endpoints
|
||||
- **Routes manifests** - Stores container image manifests as ATProto records in users' Personal Data Servers
|
||||
- **Routes blobs** - Proxies blob (layer) operations to hold services for S3-compatible storage
|
||||
- **Provides web UI** - Browse repositories, search images, view tags, track pull counts, manage stars
|
||||
- **Manages authentication** - Validates OAuth tokens and issues registry JWTs to Docker clients
|
||||
|
||||
### The ATCR Ecosystem
|
||||
|
||||
AppView is the **frontend** of a multi-component architecture:
|
||||
|
||||
1. **AppView** (this component) - Registry API + web interface
|
||||
2. **[Hold Service](https://atcr.io/r/evan.jarrett.net/atcr-hold)** - Storage backend with embedded PDS for blob storage
|
||||
3. **Credential Helper** - Client-side tool for ATProto OAuth authentication
|
||||
|
||||
**Data flow:**
|
||||
```
|
||||
atcr.io/alice.bsky.social/myapp:latest
|
||||
atcr.io/did:plc:xyz123/myapp:latest
|
||||
Docker Client → AppView (resolves identity) → User's PDS (stores manifest)
|
||||
↓
|
||||
Hold Service (stores blobs in S3/Storj/etc.)
|
||||
```
|
||||
|
||||
## Using ATCR
|
||||
Manifests (small JSON metadata) live in users' ATProto PDS, while blobs (large binary layers) live in hold services. AppView orchestrates the routing between these components.
|
||||
|
||||
### Push Images
|
||||
## When to Run Your Own AppView
|
||||
|
||||
Most users can simply use **https://atcr.io** - you don't need to run your own AppView.
|
||||
|
||||
**Run your own AppView if you want to:**
|
||||
- Host a private/organizational container registry with ATProto authentication
|
||||
- Run a public registry for a specific community
|
||||
- Customize the registry UI or policies
|
||||
- Maintain full control over registry infrastructure
|
||||
|
||||
**Prerequisites:**
|
||||
- A running [Hold service](https://atcr.io/r/evan.jarrett.net/atcr-hold) (required for blob storage)
|
||||
- (Optional) Domain name with SSL/TLS certificates for production
|
||||
- (Optional) Access to ATProto Jetstream for real-time indexing
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Using Docker Compose
|
||||
|
||||
The fastest way to run AppView alongside a Hold service:
|
||||
|
||||
```bash
|
||||
# Install credential helper
|
||||
curl -fsSL https://atcr.io/install.sh | bash
|
||||
# Clone repository
|
||||
git clone https://tangled.org/@evan.jarrett.net/at-container-registry
|
||||
cd atcr
|
||||
|
||||
# Configure Docker (add to ~/.docker/config.json)
|
||||
{
|
||||
"credHelpers": {
|
||||
"atcr.io": "atcr"
|
||||
}
|
||||
}
|
||||
|
||||
# Push images (authenticates automatically)
|
||||
docker tag myapp:latest atcr.io/yourhandle/myapp:latest
|
||||
docker push atcr.io/yourhandle/myapp:latest
|
||||
```
|
||||
|
||||
### Pull Images
|
||||
|
||||
```bash
|
||||
# Public images (no auth required)
|
||||
docker pull atcr.io/alice.bsky.social/myapp:latest
|
||||
|
||||
# Private images (automatic OAuth authentication)
|
||||
docker pull atcr.io/yourhandle/private-app:latest
|
||||
```
|
||||
|
||||
## Running Your Own AppView
|
||||
|
||||
Deploy your own registry instance with Docker Compose:
|
||||
|
||||
```bash
|
||||
# Create configuration
|
||||
# Copy and configure environment
|
||||
cp .env.appview.example .env.appview
|
||||
# Edit .env.appview with your settings
|
||||
# Edit .env.appview - set ATCR_DEFAULT_HOLD_DID (see Configuration below)
|
||||
|
||||
# Start services
|
||||
docker-compose up -d
|
||||
|
||||
# Verify
|
||||
curl http://localhost:5000/v2/
|
||||
```
|
||||
|
||||
### Configuration
|
||||
### Minimal Configuration
|
||||
|
||||
Key environment variables:
|
||||
At minimum, you must set:
|
||||
|
||||
- `ATCR_HTTP_ADDR` - HTTP listen address (default: `:5000`)
|
||||
- `ATCR_BASE_URL` - Public URL for OAuth/JWT realm
|
||||
- `ATCR_DEFAULT_HOLD_DID` - Default hold service DID for blob storage (required)
|
||||
- `ATCR_UI_ENABLED` - Enable web interface (default: `true`)
|
||||
- `JETSTREAM_URL` - ATProto event stream URL for real-time updates
|
||||
```bash
|
||||
# Required: Default hold service for blob storage
|
||||
ATCR_DEFAULT_HOLD_DID=did:web:127.0.0.1:8080
|
||||
|
||||
See [deployment documentation](https://tangled.org/@evan.jarrett.net/at-container-registry/blob/main/deploy/README.md) for production setup.
|
||||
# Recommended for production
|
||||
ATCR_BASE_URL=https://registry.example.com
|
||||
ATCR_HTTP_ADDR=:5000
|
||||
```
|
||||
|
||||
## Features
|
||||
See **Configuration Reference** below for all options.
|
||||
|
||||
- ✅ **OCI-compliant** - Full Docker Registry API V2 support
|
||||
- ✅ **ATProto OAuth** - Secure authentication with DPoP
|
||||
- ✅ **Decentralized storage** - Manifests stored in users' PDS
|
||||
- ✅ **Web UI** - Browse repositories, view tags, search images
|
||||
- ✅ **Real-time updates** - Jetstream integration for live indexing
|
||||
- ✅ **Multi-arch support** - ARM64, AMD64, and other platforms
|
||||
- ✅ **BYOS** - Bring Your Own Storage via hold services
|
||||
## Configuration Reference
|
||||
|
||||
## Storage Architecture
|
||||
AppView is configured entirely via environment variables. Load them with:
|
||||
```bash
|
||||
source .env.appview
|
||||
./bin/atcr-appview serve
|
||||
```
|
||||
|
||||
**Hybrid model:**
|
||||
- **Manifests** → ATProto records in user's PDS (small JSON metadata)
|
||||
- **Blobs** → Hold services with S3-compatible backends (large binary layers)
|
||||
Or via Docker Compose (recommended).
|
||||
|
||||
This design keeps metadata portable and federated while leveraging cheap blob storage for layers.
|
||||
### Server Configuration
|
||||
|
||||
## License
|
||||
#### `ATCR_HTTP_ADDR`
|
||||
- **Default:** `:5000`
|
||||
- **Description:** HTTP listen address for the registry API and web UI
|
||||
- **Example:** `:5000`, `:8080`, `0.0.0.0:5000`
|
||||
|
||||
MIT
|
||||
#### `ATCR_BASE_URL`
|
||||
- **Default:** Auto-detected from `ATCR_HTTP_ADDR` (e.g., `http://127.0.0.1:5000`)
|
||||
- **Description:** Public URL for the AppView service. Used to generate OAuth redirect URIs and JWT realm claims.
|
||||
- **Development:** Auto-detection works fine (`http://127.0.0.1:5000`)
|
||||
- **Production:** Set to your public URL (e.g., `https://atcr.example.com`)
|
||||
- **Example:** `https://atcr.io`, `http://127.0.0.1:5000`
|
||||
|
||||
---
|
||||
#### `ATCR_SERVICE_NAME`
|
||||
- **Default:** Derived from `ATCR_BASE_URL` hostname, or `atcr.io`
|
||||
- **Description:** Service name used for JWT `service` and `issuer` fields. Controls token scope.
|
||||
- **Example:** `atcr.io`, `registry.example.com`
|
||||
|
||||
**Documentation:** https://tangled.org/@evan.jarrett.net/at-container-registry
|
||||
**Source Code:** https://tangled.org/@evan.jarrett.net/at-container-registry
|
||||
#### `ATCR_DEBUG_ADDR`
|
||||
- **Default:** `:5001`
|
||||
- **Description:** Debug listen address for pprof debugging endpoints
|
||||
- **Example:** `:5001`, `:6060`
|
||||
|
||||
### Storage Configuration
|
||||
|
||||
#### `ATCR_DEFAULT_HOLD_DID` ⚠️ REQUIRED
|
||||
- **Default:** None (required)
|
||||
- **Description:** DID of the default hold service for blob storage. Used when users don't have their own hold configured in their sailor profile. AppView routes all blob operations to this hold.
|
||||
- **Format:** `did:web:hostname[:port]`
|
||||
- **Docker Compose:** `did:web:atcr-hold:8080` (internal Docker network)
|
||||
- **Local dev:** `did:web:127.0.0.1:8080`
|
||||
- **Production:** `did:web:hold01.atcr.io`
|
||||
- **Note:** This hold must be reachable from AppView. To find a hold's DID, visit `https://hold-url/.well-known/did.json`
|
||||
|
||||
### Authentication Configuration
|
||||
|
||||
#### `ATCR_AUTH_KEY_PATH`
|
||||
- **Default:** `/var/lib/atcr/auth/private-key.pem`
|
||||
- **Description:** Path to JWT signing private key (RSA). Auto-generated if missing.
|
||||
- **Note:** Keep this secure - it signs all registry JWTs issued to Docker clients
|
||||
|
||||
#### `ATCR_AUTH_CERT_PATH`
|
||||
- **Default:** `/var/lib/atcr/auth/private-key.crt`
|
||||
- **Description:** Path to JWT signing certificate. Auto-generated if missing.
|
||||
- **Note:** Paired with `ATCR_AUTH_KEY_PATH`
|
||||
|
||||
#### `ATCR_TOKEN_EXPIRATION`
|
||||
- **Default:** `300` (5 minutes)
|
||||
- **Description:** JWT token expiration in seconds. Registry JWTs are short-lived for security.
|
||||
- **Recommendation:** Keep between 300-900 seconds (5-15 minutes)
|
||||
|
||||
### Web UI Configuration
|
||||
|
||||
#### `ATCR_UI_ENABLED`
|
||||
- **Default:** `true`
|
||||
- **Description:** Enable the web interface. Set to `false` to run registry API only (no web UI, no database).
|
||||
- **Use case:** API-only deployments where you don't need the browsing interface
|
||||
|
||||
#### `ATCR_UI_DATABASE_PATH`
|
||||
- **Default:** `/var/lib/atcr/ui.db`
|
||||
- **Description:** SQLite database path for UI data (OAuth sessions, stars, pull counts, repository metadata)
|
||||
- **Note:** For multi-instance deployments, use PostgreSQL (see production docs)
|
||||
|
||||
### Logging Configuration
|
||||
|
||||
#### `ATCR_LOG_LEVEL`
|
||||
- **Default:** `info`
|
||||
- **Options:** `debug`, `info`, `warn`, `error`
|
||||
- **Description:** Log verbosity level
|
||||
- **Development:** Use `debug` for detailed troubleshooting
|
||||
- **Production:** Use `info` or `warn`
|
||||
|
||||
#### `ATCR_LOG_FORMATTER`
|
||||
- **Default:** `text`
|
||||
- **Options:** `text`, `json`
|
||||
- **Description:** Log output format
|
||||
- **Production:** Use `json` for structured logging (easier to parse with log aggregators)
|
||||
|
||||
### Hold Health Check Configuration
|
||||
|
||||
AppView periodically checks if hold services are reachable and caches results to display health indicators in the UI.
|
||||
|
||||
#### `ATCR_HEALTH_CHECK_INTERVAL`
|
||||
- **Default:** `15m`
|
||||
- **Description:** How often to check health of hold endpoints in the background
|
||||
- **Format:** Duration string (e.g., `5m`, `15m`, `30m`, `1h`)
|
||||
- **Recommendation:** 15-30 minutes for production
|
||||
|
||||
#### `ATCR_HEALTH_CACHE_TTL`
|
||||
- **Default:** `15m`
|
||||
- **Description:** How long to cache health check results before re-checking
|
||||
- **Format:** Duration string (e.g., `15m`, `30m`, `1h`)
|
||||
- **Note:** Should be >= `ATCR_HEALTH_CHECK_INTERVAL` for efficiency
|
||||
|
||||
### Jetstream Configuration (ATProto Event Streaming)
|
||||
|
||||
Jetstream provides real-time indexing of ATProto records (manifests, tags) into the AppView database for the web UI.
|
||||
|
||||
#### `JETSTREAM_URL`
|
||||
- **Default:** `wss://jetstream2.us-west.bsky.network/subscribe`
|
||||
- **Description:** Jetstream WebSocket URL for real-time ATProto events
|
||||
- **Note:** Connects to Bluesky's public Jetstream by default
|
||||
|
||||
#### `ATCR_BACKFILL_ENABLED`
|
||||
- **Default:** `false`
|
||||
- **Description:** Enable periodic sync of historical ATProto records. Set to `true` for production to ensure database completeness.
|
||||
- **Recommendation:** Enable for production AppView instances
|
||||
|
||||
#### `ATCR_RELAY_ENDPOINT`
|
||||
- **Default:** `https://relay1.us-east.bsky.network`
|
||||
- **Description:** ATProto relay endpoint for backfill sync API
|
||||
- **Note:** Used when `ATCR_BACKFILL_ENABLED=true`
|
||||
|
||||
#### `ATCR_BACKFILL_INTERVAL`
|
||||
- **Default:** `1h`
|
||||
- **Description:** How often to run backfill sync
|
||||
- **Format:** Duration string (e.g., `30m`, `1h`, `2h`, `24h`)
|
||||
|
||||
### Legacy Configuration
|
||||
|
||||
#### `TEST_MODE`
|
||||
- **Default:** `false`
|
||||
- **Description:** Enable test mode (skips some validations). Do not use in production.
|
||||
|
||||
## Web Interface Features
|
||||
|
||||
The AppView web UI provides:
|
||||
|
||||
- **Home page** - Featured repositories and recent pushes feed
|
||||
- **Repository pages** - View tags, manifests, pull instructions, health status
|
||||
- **Search** - Find repositories by owner handle or repository name
|
||||
- **User profiles** - View a user's repositories and activity
|
||||
- **Stars** - Favorite repositories (requires OAuth login)
|
||||
- **Pull counts** - Track image pull statistics
|
||||
- **Multi-arch support** - Display platform-specific manifests (linux/amd64, linux/arm64)
|
||||
- **Health indicators** - Real-time hold service reachability status
|
||||
- **Install scripts** - Host credential helper installation scripts at `/install.sh`
|
||||
|
||||
## Deployment Scenarios
|
||||
|
||||
### Public Registry (like atcr.io)
|
||||
|
||||
Open to all ATProto users:
|
||||
|
||||
```bash
|
||||
# AppView config
|
||||
ATCR_BASE_URL=https://registry.example.com
|
||||
ATCR_DEFAULT_HOLD_DID=did:web:hold01.example.com
|
||||
ATCR_UI_ENABLED=true
|
||||
ATCR_BACKFILL_ENABLED=true
|
||||
|
||||
# Hold config (linked hold service)
|
||||
HOLD_PUBLIC=true # Allow public pulls
|
||||
HOLD_ALLOW_ALL_CREW=true # Allow all authenticated users to push
|
||||
```
|
||||
|
||||
### Private Organizational Registry
|
||||
|
||||
Restricted to crew members only:
|
||||
|
||||
```bash
|
||||
# AppView config
|
||||
ATCR_BASE_URL=https://registry.internal.example.com
|
||||
ATCR_DEFAULT_HOLD_DID=did:web:hold.internal.example.com
|
||||
ATCR_UI_ENABLED=true
|
||||
|
||||
# Hold config (linked hold service)
|
||||
HOLD_PUBLIC=false # Require auth for pulls
|
||||
HOLD_ALLOW_ALL_CREW=false # Only owner + explicit crew can push
|
||||
HOLD_OWNER=did:plc:your-org-did # Organization DID
|
||||
```
|
||||
|
||||
### Development/Testing
|
||||
|
||||
Local Docker Compose setup:
|
||||
|
||||
```bash
|
||||
# AppView config
|
||||
ATCR_HTTP_ADDR=:5000
|
||||
ATCR_DEFAULT_HOLD_DID=did:web:atcr-hold:8080
|
||||
ATCR_LOG_LEVEL=debug
|
||||
|
||||
# Hold config (linked hold service)
|
||||
STORAGE_DRIVER=filesystem
|
||||
STORAGE_ROOT_DIR=/tmp/atcr-hold
|
||||
HOLD_PUBLIC=true
|
||||
HOLD_ALLOW_ALL_CREW=true
|
||||
```
|
||||
|
||||
## Production Deployment
|
||||
|
||||
For production deployments with:
|
||||
- Multiple AppView instances (load balancing)
|
||||
- PostgreSQL database (instead of SQLite)
|
||||
- SSL/TLS certificates
|
||||
- Systemd service files
|
||||
- Log rotation
|
||||
- Monitoring
|
||||
|
||||
See **[deploy/README.md](https://tangled.org/@evan.jarrett.net/at-container-registry/blob/main/deploy/README.md)** for comprehensive production deployment guide.
|
||||
|
||||
### Quick Production Checklist
|
||||
|
||||
Before going to production:
|
||||
|
||||
- [ ] Set `ATCR_BASE_URL` to your public HTTPS URL
|
||||
- [ ] Set `ATCR_DEFAULT_HOLD_DID` to a production hold service
|
||||
- [ ] Enable Jetstream backfill (`ATCR_BACKFILL_ENABLED=true`)
|
||||
- [ ] Use `ATCR_LOG_FORMATTER=json` for structured logging
|
||||
- [ ] Secure JWT keys (`ATCR_AUTH_KEY_PATH`, `ATCR_AUTH_CERT_PATH`)
|
||||
- [ ] Configure SSL/TLS termination (nginx/Caddy/Cloudflare)
|
||||
- [ ] Set up database backups (if using SQLite, consider PostgreSQL)
|
||||
- [ ] Monitor hold health checks
|
||||
- [ ] Test OAuth flow end-to-end
|
||||
- [ ] Verify Docker push/pull works
|
||||
|
||||
## Configuration Files Reference
|
||||
|
||||
- **[.env.appview.example](https://tangled.org/@evan.jarrett.net/at-container-registry/blob/main/.env.appview.example)** - All available environment variables with documentation
|
||||
- **[deploy/.env.prod.template](https://tangled.org/@evan.jarrett.net/at-container-registry/blob/main/deploy/.env.prod.template)** - Production configuration template
|
||||
- **[deploy/README.md](https://tangled.org/@evan.jarrett.net/at-container-registry/blob/main/deploy/README.md)** - Production deployment guide
|
||||
- **[Hold Service Documentation](https://atcr.io/r/evan.jarrett.net/atcr-hold)** - Storage backend setup
|
||||
|
||||
Reference in New Issue
Block a user