A container registry that uses the AT Protocol for manifest storage and S3 for blob storage. atcr.io
docker container atproto go
at loom 344 lines 9.7 kB view raw
1#!/bin/bash 2# 3# ATCR UpCloud Initialization Script for Rocky Linux 4# 5# This script sets up ATCR on a fresh Rocky Linux instance. 6# Paste this into UpCloud's "User data" field when creating a server. 7# 8# What it does: 9# - Updates system packages 10# - Creates 2GB swap file (for 1GB RAM instances) 11# - Installs Docker and Docker Compose 12# - Creates directory structure 13# - Clones ATCR repository 14# - Creates systemd service for auto-start 15# - Builds and starts containers 16# 17# Post-deployment: 18# 1. Edit /opt/atcr/.env with your configuration 19# 2. Run: systemctl restart atcr 20# 3. Check logs: docker logs atcr-hold (for OAuth URL) 21# 4. Complete hold registration via OAuth 22 23set -euo pipefail 24 25# Configuration 26ATCR_DIR="/opt/atcr" 27ATCR_REPO="https://tangled.org/@evan.jarrett.net/at-container-registry" # UPDATE THIS 28ATCR_BRANCH="main" 29 30# Simple logging without colors (for cloud-init log compatibility) 31log_info() { 32 echo "[INFO] $1" 33} 34 35log_warn() { 36 echo "[WARN] $1" 37} 38 39log_error() { 40 echo "[ERROR] $1" 41} 42 43# Function to check if command exists 44command_exists() { 45 command -v "$1" >/dev/null 2>&1 46} 47 48log_info "Starting ATCR deployment on Rocky Linux..." 49 50# Update system packages 51log_info "Updating system packages..." 52dnf update -y 53 54# Install required packages 55log_info "Installing prerequisites..." 56dnf install -y \ 57 git \ 58 wget \ 59 curl \ 60 nano \ 61 vim 62 63log_info "Required ports: HTTP (80), HTTPS (443), SSH (22)" 64 65# Create swap file for instances with limited RAM 66if [ ! -f /swapfile ]; then 67 log_info "Creating 2GB swap file (allows builds on 1GB RAM instances)..." 68 dd if=/dev/zero of=/swapfile bs=1M count=2048 status=progress 69 chmod 600 /swapfile 70 mkswap /swapfile 71 swapon /swapfile 72 73 # Make swap permanent 74 echo '/swapfile none swap sw 0 0' >> /etc/fstab 75 76 log_info "Swap file created and enabled" 77 free -h 78else 79 log_info "Swap file already exists" 80fi 81 82# Install Docker 83if ! command_exists docker; then 84 log_info "Installing Docker..." 85 86 # Add Docker repository 87 dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo 88 89 # Install Docker 90 dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin 91 92 # Start and enable Docker 93 systemctl enable --now docker 94 95 log_info "Docker installed successfully" 96else 97 log_info "Docker already installed" 98fi 99 100# Verify Docker Compose 101if ! docker compose version >/dev/null 2>&1; then 102 log_error "Docker Compose plugin not found. Please install manually." 103 exit 1 104fi 105 106log_info "Docker Compose version: $(docker compose version)" 107 108# Create ATCR directory 109log_info "Creating ATCR directory: $ATCR_DIR" 110mkdir -p "$ATCR_DIR" 111cd "$ATCR_DIR" 112 113# Clone repository or create minimal structure 114if [ -n "$ATCR_REPO" ] && [ "$ATCR_REPO" != "https://tangled.org/@evan.jarrett.net/at-container-registry" ]; then 115 log_info "Cloning ATCR repository..." 116 git clone -b "$ATCR_BRANCH" "$ATCR_REPO" . 117else 118 log_warn "ATCR_REPO not configured. You'll need to manually copy files to $ATCR_DIR" 119 log_warn "Required files:" 120 log_warn " - deploy/docker-compose.prod.yml" 121 log_warn " - deploy/.env.prod.template" 122 log_warn " - Dockerfile.appview" 123 log_warn " - Dockerfile.hold" 124fi 125 126# Create .env file from template if it doesn't exist 127if [ -f "deploy/.env.prod.template" ] && [ ! -f "$ATCR_DIR/.env" ]; then 128 log_info "Creating .env file from template..." 129 cp deploy/.env.prod.template "$ATCR_DIR/.env" 130 log_warn "IMPORTANT: Edit $ATCR_DIR/.env with your configuration!" 131fi 132 133# Create systemd services (caddy, appview, hold) 134log_info "Creating systemd services..." 135 136# Caddy service (reverse proxy for both appview and hold) 137cat > /etc/systemd/system/atcr-caddy.service <<'EOF' 138[Unit] 139Description=ATCR Caddy Reverse Proxy 140Requires=docker.service 141After=docker.service network-online.target 142Wants=network-online.target 143 144[Service] 145Type=oneshot 146RemainAfterExit=yes 147WorkingDirectory=/opt/atcr 148EnvironmentFile=/opt/atcr/.env 149 150# Start caddy container 151ExecStart=/usr/bin/docker compose -f /opt/atcr/deploy/docker-compose.prod.yml up -d caddy 152 153# Stop caddy container 154ExecStop=/usr/bin/docker compose -f /opt/atcr/deploy/docker-compose.prod.yml stop caddy 155 156# Restart caddy container 157ExecReload=/usr/bin/docker compose -f /opt/atcr/deploy/docker-compose.prod.yml restart caddy 158 159# Always restart on failure 160Restart=on-failure 161RestartSec=10 162 163[Install] 164WantedBy=multi-user.target 165EOF 166 167# AppView service (registry + web UI) 168cat > /etc/systemd/system/atcr-appview.service <<'EOF' 169[Unit] 170Description=ATCR AppView (Registry + Web UI) 171Requires=docker.service atcr-caddy.service 172After=docker.service network-online.target atcr-caddy.service 173Wants=network-online.target 174 175[Service] 176Type=oneshot 177RemainAfterExit=yes 178WorkingDirectory=/opt/atcr 179EnvironmentFile=/opt/atcr/.env 180 181# Start appview container 182ExecStart=/usr/bin/docker compose -f /opt/atcr/deploy/docker-compose.prod.yml up -d atcr-appview 183 184# Stop appview container 185ExecStop=/usr/bin/docker compose -f /opt/atcr/deploy/docker-compose.prod.yml stop atcr-appview 186 187# Restart appview container 188ExecReload=/usr/bin/docker compose -f /opt/atcr/deploy/docker-compose.prod.yml restart atcr-appview 189 190# Always restart on failure 191Restart=on-failure 192RestartSec=10 193 194[Install] 195WantedBy=multi-user.target 196EOF 197 198# Hold service (storage backend) 199cat > /etc/systemd/system/atcr-hold.service <<'EOF' 200[Unit] 201Description=ATCR Hold (Storage Service) 202Requires=docker.service atcr-caddy.service 203After=docker.service network-online.target atcr-caddy.service 204Wants=network-online.target 205 206[Service] 207Type=oneshot 208RemainAfterExit=yes 209WorkingDirectory=/opt/atcr 210EnvironmentFile=/opt/atcr/.env 211 212# Start hold container 213ExecStart=/usr/bin/docker compose -f /opt/atcr/deploy/docker-compose.prod.yml up -d atcr-hold 214 215# Stop hold container 216ExecStop=/usr/bin/docker compose -f /opt/atcr/deploy/docker-compose.prod.yml stop atcr-hold 217 218# Restart hold container 219ExecReload=/usr/bin/docker compose -f /opt/atcr/deploy/docker-compose.prod.yml restart atcr-hold 220 221# Always restart on failure 222Restart=on-failure 223RestartSec=10 224 225[Install] 226WantedBy=multi-user.target 227EOF 228 229# Reload systemd 230log_info "Reloading systemd daemon..." 231systemctl daemon-reload 232 233# Enable all services (but don't start yet - user needs to configure .env) 234systemctl enable atcr-caddy.service 235systemctl enable atcr-appview.service 236systemctl enable atcr-hold.service 237 238log_info "Systemd services created and enabled" 239 240# Create helper scripts 241log_info "Creating helper scripts..." 242 243# Script to rebuild and restart 244cat > "$ATCR_DIR/rebuild.sh" <<'EOF' 245#!/bin/bash 246set -e 247cd /opt/atcr 248docker compose -f deploy/docker-compose.prod.yml build 249docker compose -f deploy/docker-compose.prod.yml up -d 250docker compose -f deploy/docker-compose.prod.yml logs -f 251EOF 252chmod +x "$ATCR_DIR/rebuild.sh" 253 254# Script to view logs 255cat > "$ATCR_DIR/logs.sh" <<'EOF' 256#!/bin/bash 257cd /opt/atcr 258docker compose -f deploy/docker-compose.prod.yml logs -f "$@" 259EOF 260chmod +x "$ATCR_DIR/logs.sh" 261 262log_info "Helper scripts created in $ATCR_DIR" 263 264# Print completion message 265cat <<'EOF' 266 267================================================================================ 268ATCR Installation Complete! 269================================================================================ 270 271NEXT STEPS: 272 2731. Configure environment variables: 274 nano /opt/atcr/.env 275 276 Required settings: 277 - AWS_ACCESS_KEY_ID (UpCloud S3 credentials) 278 - AWS_SECRET_ACCESS_KEY 279 280 Pre-configured (verify these are correct): 281 - APPVIEW_DOMAIN=atcr.io 282 - HOLD_DOMAIN=hold01.atcr.io 283 - HOLD_OWNER=did:plc:pddp4xt5lgnv2qsegbzzs4xg 284 - S3_BUCKET=atcr 285 - S3_ENDPOINT=https://blobs.atcr.io 286 2872. Configure UpCloud Cloud Firewall (in control panel): 288 Allow: TCP 22 (SSH) 289 Allow: TCP 80 (HTTP) 290 Allow: TCP 443 (HTTPS) 291 Drop: Everything else 292 2933. Configure DNS (Cloudflare - DNS-only mode): 294EOF 295 296echo " A atcr.io → $(curl -s ifconfig.me || echo '[server-ip]') (gray cloud)" 297echo " A hold01.atcr.io → $(curl -s ifconfig.me || echo '[server-ip]') (gray cloud)" 298echo " CNAME blobs.atcr.io → atcr.us-chi1.upcloudobjects.com (gray cloud)" 299 300cat <<'EOF' 301 3024. Start ATCR services: 303 systemctl start atcr-caddy atcr-appview atcr-hold 304 3055. Check status: 306 systemctl status atcr-caddy 307 systemctl status atcr-appview 308 systemctl status atcr-hold 309 docker ps 310 /opt/atcr/logs.sh 311 312Helper Scripts: 313 /opt/atcr/rebuild.sh - Rebuild and restart containers 314 /opt/atcr/logs.sh [service] - View logs (e.g., logs.sh atcr-hold) 315 316Service Management: 317 systemctl start atcr-caddy - Start Caddy reverse proxy 318 systemctl start atcr-appview - Start AppView (registry + UI) 319 systemctl start atcr-hold - Start Hold (storage service) 320 321 systemctl stop atcr-appview - Stop AppView only 322 systemctl stop atcr-hold - Stop Hold only 323 systemctl stop atcr-caddy - Stop all (stops reverse proxy) 324 325 systemctl restart atcr-appview - Restart AppView 326 systemctl restart atcr-hold - Restart Hold 327 328 systemctl status atcr-caddy - Check Caddy status 329 systemctl status atcr-appview - Check AppView status 330 systemctl status atcr-hold - Check Hold status 331 332Documentation: 333 https://tangled.org/@evan.jarrett.net/at-container-registry 334 335IMPORTANT: 336 - Edit /opt/atcr/.env with S3 credentials before starting! 337 - Configure UpCloud cloud firewall (see step 2) 338 - DNS must be configured and propagated 339 - Cloudflare proxy must be DISABLED (gray cloud) 340 - Complete hold OAuth registration before first push 341 342EOF 343 344log_info "Installation complete. Follow the next steps above."