A container registry that uses the AT Protocol for manifest storage and S3 for blob storage.
1# ATCR AppView
2
3> The registry frontend component of ATCR (ATProto Container Registry)
4
5## Overview
6
7**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.
8
9### What AppView Does
10
11AppView is the orchestration layer that:
12
13- **Serves the OCI Distribution API V2** - Compatible with Docker, containerd, podman, and all OCI clients
14- **Resolves ATProto identities** - Converts handles (`alice.bsky.social`) and DIDs (`did:plc:xyz123`) to PDS endpoints
15- **Routes manifests** - Stores container image manifests as ATProto records in users' Personal Data Servers
16- **Routes blobs** - Proxies blob (layer) operations to hold services for S3-compatible storage
17- **Provides web UI** - Browse repositories, search images, view tags, track pull counts, manage stars
18- **Manages authentication** - Validates OAuth tokens and issues registry JWTs to Docker clients
19
20### The ATCR Ecosystem
21
22AppView is the **frontend** of a multi-component architecture:
23
241. **AppView** (this component) - Registry API + web interface
252. **[Hold Service](https://atcr.io/r/evan.jarrett.net/atcr-hold)** - Storage backend with embedded PDS for blob storage
263. **Credential Helper** - Client-side tool for ATProto OAuth authentication
27
28**Data flow:**
29```
30Docker Client → AppView (resolves identity) → User's PDS (stores manifest)
31 ↓
32 Hold Service (stores blobs in S3/Storj/etc.)
33```
34
35Manifests (small JSON metadata) live in users' ATProto PDS, while blobs (large binary layers) live in hold services. AppView orchestrates the routing between these components.
36
37## When to Run Your Own AppView
38
39Most users can simply use **https://atcr.io** - you don't need to run your own AppView.
40
41**Run your own AppView if you want to:**
42- Host a private/organizational container registry with ATProto authentication
43- Run a public registry for a specific community
44- Customize the registry UI or policies
45- Maintain full control over registry infrastructure
46
47**Prerequisites:**
48- A running [Hold service](https://atcr.io/r/evan.jarrett.net/atcr-hold) (required for blob storage)
49- (Optional) Domain name with SSL/TLS certificates for production
50- (Optional) Access to ATProto Jetstream for real-time indexing
51
52## Quick Start
53
54### Using Docker Compose
55
56The fastest way to run AppView alongside a Hold service:
57
58```bash
59# Clone repository
60git clone https://tangled.org/@evan.jarrett.net/at-container-registry
61cd atcr
62
63# Copy and configure environment
64cp .env.appview.example .env.appview
65# Edit .env.appview - set ATCR_DEFAULT_HOLD_DID (see Configuration below)
66
67# Start services
68docker-compose up -d
69
70# Verify
71curl http://localhost:5000/v2/
72```
73
74### Minimal Configuration
75
76At minimum, you must set:
77
78```bash
79# Required: Default hold service for blob storage
80ATCR_DEFAULT_HOLD_DID=did:web:127.0.0.1:8080
81
82# Recommended for production
83ATCR_BASE_URL=https://registry.example.com
84ATCR_HTTP_ADDR=:5000
85```
86
87See **Configuration Reference** below for all options.
88
89## Configuration Reference
90
91AppView is configured entirely via environment variables. Load them with:
92```bash
93source .env.appview
94./bin/atcr-appview serve
95```
96
97Or via Docker Compose (recommended).
98
99### Server Configuration
100
101#### `ATCR_HTTP_ADDR`
102- **Default:** `:5000`
103- **Description:** HTTP listen address for the registry API and web UI
104- **Example:** `:5000`, `:8080`, `0.0.0.0:5000`
105
106#### `ATCR_BASE_URL`
107- **Default:** Auto-detected from `ATCR_HTTP_ADDR` (e.g., `http://127.0.0.1:5000`)
108- **Description:** Public URL for the AppView service. Used to generate OAuth redirect URIs and JWT realm claims.
109- **Development:** Auto-detection works fine (`http://127.0.0.1:5000`)
110- **Production:** Set to your public URL (e.g., `https://atcr.example.com`)
111- **Example:** `https://atcr.io`, `http://127.0.0.1:5000`
112
113#### `ATCR_SERVICE_NAME`
114- **Default:** Derived from `ATCR_BASE_URL` hostname, or `atcr.io`
115- **Description:** Service name used for JWT `service` and `issuer` fields. Controls token scope.
116- **Example:** `atcr.io`, `registry.example.com`
117
118#### `ATCR_DEBUG_ADDR`
119- **Default:** `:5001`
120- **Description:** Debug listen address for pprof debugging endpoints
121- **Example:** `:5001`, `:6060`
122
123### Storage Configuration
124
125#### `ATCR_DEFAULT_HOLD_DID` ⚠️ REQUIRED
126- **Default:** None (required)
127- **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.
128- **Format:** `did:web:hostname[:port]`
129- **Docker Compose:** `did:web:atcr-hold:8080` (internal Docker network)
130- **Local dev:** `did:web:127.0.0.1:8080`
131- **Production:** `did:web:hold01.atcr.io`
132- **Note:** This hold must be reachable from AppView. To find a hold's DID, visit `https://hold-url/.well-known/did.json`
133
134### Authentication Configuration
135
136#### `ATCR_AUTH_KEY_PATH`
137- **Default:** `/var/lib/atcr/auth/private-key.pem`
138- **Description:** Path to JWT signing private key (RSA). Auto-generated if missing.
139- **Note:** Keep this secure - it signs all registry JWTs issued to Docker clients
140
141#### `ATCR_AUTH_CERT_PATH`
142- **Default:** `/var/lib/atcr/auth/private-key.crt`
143- **Description:** Path to JWT signing certificate. Auto-generated if missing.
144- **Note:** Paired with `ATCR_AUTH_KEY_PATH`
145
146#### `ATCR_TOKEN_EXPIRATION`
147- **Default:** `300` (5 minutes)
148- **Description:** JWT token expiration in seconds. Registry JWTs are short-lived for security.
149- **Recommendation:** Keep between 300-900 seconds (5-15 minutes)
150
151### Web UI Configuration
152
153#### `ATCR_UI_ENABLED`
154- **Default:** `true`
155- **Description:** Enable the web interface. Set to `false` to run registry API only (no web UI, no database).
156- **Use case:** API-only deployments where you don't need the browsing interface
157
158#### `ATCR_UI_DATABASE_PATH`
159- **Default:** `/var/lib/atcr/ui.db`
160- **Description:** SQLite database path for UI data (OAuth sessions, stars, pull counts, repository metadata)
161- **Note:** For multi-instance deployments, use PostgreSQL (see production docs)
162
163### Logging Configuration
164
165#### `ATCR_LOG_LEVEL`
166- **Default:** `info`
167- **Options:** `debug`, `info`, `warn`, `error`
168- **Description:** Log verbosity level
169- **Development:** Use `debug` for detailed troubleshooting
170- **Production:** Use `info` or `warn`
171
172#### `ATCR_LOG_FORMATTER`
173- **Default:** `text`
174- **Options:** `text`, `json`
175- **Description:** Log output format
176- **Production:** Use `json` for structured logging (easier to parse with log aggregators)
177
178### Hold Health Check Configuration
179
180AppView periodically checks if hold services are reachable and caches results to display health indicators in the UI.
181
182#### `ATCR_HEALTH_CHECK_INTERVAL`
183- **Default:** `15m`
184- **Description:** How often to check health of hold endpoints in the background
185- **Format:** Duration string (e.g., `5m`, `15m`, `30m`, `1h`)
186- **Recommendation:** 15-30 minutes for production
187
188#### `ATCR_HEALTH_CACHE_TTL`
189- **Default:** `15m`
190- **Description:** How long to cache health check results before re-checking
191- **Format:** Duration string (e.g., `15m`, `30m`, `1h`)
192- **Note:** Should be >= `ATCR_HEALTH_CHECK_INTERVAL` for efficiency
193
194### Jetstream Configuration (ATProto Event Streaming)
195
196Jetstream provides real-time indexing of ATProto records (manifests, tags) into the AppView database for the web UI.
197
198#### `JETSTREAM_URL`
199- **Default:** `wss://jetstream2.us-west.bsky.network/subscribe`
200- **Description:** Jetstream WebSocket URL for real-time ATProto events
201- **Note:** Connects to Bluesky's public Jetstream by default
202
203#### `ATCR_BACKFILL_ENABLED`
204- **Default:** `false`
205- **Description:** Enable periodic sync of historical ATProto records. Set to `true` for production to ensure database completeness.
206- **Recommendation:** Enable for production AppView instances
207
208#### `ATCR_RELAY_ENDPOINT`
209- **Default:** `https://relay1.us-east.bsky.network`
210- **Description:** ATProto relay endpoint for backfill sync API
211- **Note:** Used when `ATCR_BACKFILL_ENABLED=true`
212
213#### `ATCR_BACKFILL_INTERVAL`
214- **Default:** `1h`
215- **Description:** How often to run backfill sync
216- **Format:** Duration string (e.g., `30m`, `1h`, `2h`, `24h`)
217
218### Legacy Configuration
219
220#### `TEST_MODE`
221- **Default:** `false`
222- **Description:** Enable test mode (skips some validations). Do not use in production.
223
224## Web Interface Features
225
226The AppView web UI provides:
227
228- **Home page** - Featured repositories and recent pushes feed
229- **Repository pages** - View tags, manifests, pull instructions, health status
230- **Search** - Find repositories by owner handle or repository name
231- **User profiles** - View a user's repositories and activity
232- **Stars** - Favorite repositories (requires OAuth login)
233- **Pull counts** - Track image pull statistics
234- **Multi-arch support** - Display platform-specific manifests (linux/amd64, linux/arm64)
235- **Health indicators** - Real-time hold service reachability status
236- **Install scripts** - Host credential helper installation scripts at `/install.sh`
237
238## Deployment Scenarios
239
240### Public Registry (like atcr.io)
241
242Open to all ATProto users:
243
244```bash
245# AppView config
246ATCR_BASE_URL=https://registry.example.com
247ATCR_DEFAULT_HOLD_DID=did:web:hold01.example.com
248ATCR_UI_ENABLED=true
249ATCR_BACKFILL_ENABLED=true
250
251# Hold config (linked hold service)
252HOLD_PUBLIC=true # Allow public pulls
253HOLD_ALLOW_ALL_CREW=true # Allow all authenticated users to push
254```
255
256### Private Organizational Registry
257
258Restricted to crew members only:
259
260```bash
261# AppView config
262ATCR_BASE_URL=https://registry.internal.example.com
263ATCR_DEFAULT_HOLD_DID=did:web:hold.internal.example.com
264ATCR_UI_ENABLED=true
265
266# Hold config (linked hold service)
267HOLD_PUBLIC=false # Require auth for pulls
268HOLD_ALLOW_ALL_CREW=false # Only owner + explicit crew can push
269HOLD_OWNER=did:plc:your-org-did # Organization DID
270```
271
272### Development/Testing
273
274Local Docker Compose setup:
275
276```bash
277# AppView config
278ATCR_HTTP_ADDR=:5000
279ATCR_DEFAULT_HOLD_DID=did:web:atcr-hold:8080
280ATCR_LOG_LEVEL=debug
281
282# Hold config (linked hold service)
283STORAGE_DRIVER=filesystem
284STORAGE_ROOT_DIR=/tmp/atcr-hold
285HOLD_PUBLIC=true
286HOLD_ALLOW_ALL_CREW=true
287```
288
289## Production Deployment
290
291For production deployments with:
292- Multiple AppView instances (load balancing)
293- PostgreSQL database (instead of SQLite)
294- SSL/TLS certificates
295- Systemd service files
296- Log rotation
297- Monitoring
298
299See **[deploy/README.md](https://tangled.org/@evan.jarrett.net/at-container-registry/blob/main/deploy/README.md)** for comprehensive production deployment guide.
300
301### Quick Production Checklist
302
303Before going to production:
304
305- [ ] Set `ATCR_BASE_URL` to your public HTTPS URL
306- [ ] Set `ATCR_DEFAULT_HOLD_DID` to a production hold service
307- [ ] Enable Jetstream backfill (`ATCR_BACKFILL_ENABLED=true`)
308- [ ] Use `ATCR_LOG_FORMATTER=json` for structured logging
309- [ ] Secure JWT keys (`ATCR_AUTH_KEY_PATH`, `ATCR_AUTH_CERT_PATH`)
310- [ ] Configure SSL/TLS termination (nginx/Caddy/Cloudflare)
311- [ ] Set up database backups (if using SQLite, consider PostgreSQL)
312- [ ] Monitor hold health checks
313- [ ] Test OAuth flow end-to-end
314- [ ] Verify Docker push/pull works
315
316## Configuration Files Reference
317
318- **[.env.appview.example](https://tangled.org/@evan.jarrett.net/at-container-registry/blob/main/.env.appview.example)** - All available environment variables with documentation
319- **[deploy/.env.prod.template](https://tangled.org/@evan.jarrett.net/at-container-registry/blob/main/deploy/.env.prod.template)** - Production configuration template
320- **[deploy/README.md](https://tangled.org/@evan.jarrett.net/at-container-registry/blob/main/deploy/README.md)** - Production deployment guide
321- **[Hold Service Documentation](https://atcr.io/r/evan.jarrett.net/atcr-hold)** - Storage backend setup