Something went wrong. Try again.
A container registry that uses the AT Protocol for manifest storage and S3 for blob storage.
Something went wrong. Try again.
9.7 kB · 344 lines
Shell
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345#!/bin/bash## ATCR UpCloud Initialization Script for Rocky Linux## This script sets up ATCR on a fresh Rocky Linux instance.# Paste this into UpCloud's "User data" field when creating a server.## What it does:# - Updates system packages# - Creates 2GB swap file (for 1GB RAM instances)# - Installs Docker and Docker Compose# - Creates directory structure# - Clones ATCR repository# - Creates systemd service for auto-start# - Builds and starts containers## Post-deployment:# 1. Edit /opt/atcr/.env with your configuration# 2. Run: systemctl restart atcr# 3. Check logs: docker logs atcr-hold (for OAuth URL)# 4. Complete hold registration via OAuth
set -euo pipefail
# ConfigurationATCR_DIR="/opt/atcr"ATCR_REPO="https://tangled.org/@evan.jarrett.net/at-container-registry" # UPDATE THISATCR_BRANCH="main"
# Simple logging without colors (for cloud-init log compatibility)log_info() { echo "[INFO] $1"}
log_warn() { echo "[WARN] $1"}
log_error() { echo "[ERROR] $1"}
# Function to check if command existscommand_exists() { command -v "$1" >/dev/null 2>&1}
log_info "Starting ATCR deployment on Rocky Linux..."
# Update system packageslog_info "Updating system packages..."dnf update -y
# Install required packageslog_info "Installing prerequisites..."dnf install -y \ git \ wget \ curl \ nano \ vim
log_info "Required ports: HTTP (80), HTTPS (443), SSH (22)"
# Create swap file for instances with limited RAMif [ ! -f /swapfile ]; then log_info "Creating 2GB swap file (allows builds on 1GB RAM instances)..." dd if=/dev/zero of=/swapfile bs=1M count=2048 status=progress chmod 600 /swapfile mkswap /swapfile swapon /swapfile
# Make swap permanent echo '/swapfile none swap sw 0 0' >> /etc/fstab
log_info "Swap file created and enabled" free -helse log_info "Swap file already exists"fi
# Install Dockerif ! command_exists docker; then log_info "Installing Docker..."
# Add Docker repository dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# Install Docker dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# Start and enable Docker systemctl enable --now docker
log_info "Docker installed successfully"else log_info "Docker already installed"fi
# Verify Docker Composeif ! docker compose version >/dev/null 2>&1; then log_error "Docker Compose plugin not found. Please install manually." exit 1fi
log_info "Docker Compose version: $(docker compose version)"
# Create ATCR directorylog_info "Creating ATCR directory: $ATCR_DIR"mkdir -p "$ATCR_DIR"cd "$ATCR_DIR"
# Clone repository or create minimal structureif [ -n "$ATCR_REPO" ] && [ "$ATCR_REPO" != "https://tangled.org/@evan.jarrett.net/at-container-registry" ]; then log_info "Cloning ATCR repository..." git clone -b "$ATCR_BRANCH" "$ATCR_REPO" .else log_warn "ATCR_REPO not configured. You'll need to manually copy files to $ATCR_DIR" log_warn "Required files:" log_warn " - deploy/docker-compose.prod.yml" log_warn " - deploy/.env.prod.template" log_warn " - Dockerfile.appview" log_warn " - Dockerfile.hold"fi
# Create .env file from template if it doesn't existif [ -f "deploy/.env.prod.template" ] && [ ! -f "$ATCR_DIR/.env" ]; then log_info "Creating .env file from template..." cp deploy/.env.prod.template "$ATCR_DIR/.env" log_warn "IMPORTANT: Edit $ATCR_DIR/.env with your configuration!"fi
# Create systemd services (caddy, appview, hold)log_info "Creating systemd services..."
# Caddy service (reverse proxy for both appview and hold)cat > /etc/systemd/system/atcr-caddy.service <<'EOF'[Unit]Description=ATCR Caddy Reverse ProxyRequires=docker.serviceAfter=docker.service network-online.targetWants=network-online.target
[Service]Type=oneshotRemainAfterExit=yesWorkingDirectory=/opt/atcrEnvironmentFile=/opt/atcr/.env
# Start caddy containerExecStart=/usr/bin/docker compose -f /opt/atcr/deploy/docker-compose.prod.yml up -d caddy
# Stop caddy containerExecStop=/usr/bin/docker compose -f /opt/atcr/deploy/docker-compose.prod.yml stop caddy
# Restart caddy containerExecReload=/usr/bin/docker compose -f /opt/atcr/deploy/docker-compose.prod.yml restart caddy
# Always restart on failureRestart=on-failureRestartSec=10
[Install]WantedBy=multi-user.targetEOF
# AppView service (registry + web UI)cat > /etc/systemd/system/atcr-appview.service <<'EOF'[Unit]Description=ATCR AppView (Registry + Web UI)Requires=docker.service atcr-caddy.serviceAfter=docker.service network-online.target atcr-caddy.serviceWants=network-online.target
[Service]Type=oneshotRemainAfterExit=yesWorkingDirectory=/opt/atcrEnvironmentFile=/opt/atcr/.env
# Start appview containerExecStart=/usr/bin/docker compose -f /opt/atcr/deploy/docker-compose.prod.yml up -d atcr-appview
# Stop appview containerExecStop=/usr/bin/docker compose -f /opt/atcr/deploy/docker-compose.prod.yml stop atcr-appview
# Restart appview containerExecReload=/usr/bin/docker compose -f /opt/atcr/deploy/docker-compose.prod.yml restart atcr-appview
# Always restart on failureRestart=on-failureRestartSec=10
[Install]WantedBy=multi-user.targetEOF
# Hold service (storage backend)cat > /etc/systemd/system/atcr-hold.service <<'EOF'[Unit]Description=ATCR Hold (Storage Service)Requires=docker.service atcr-caddy.serviceAfter=docker.service network-online.target atcr-caddy.serviceWants=network-online.target
[Service]Type=oneshotRemainAfterExit=yesWorkingDirectory=/opt/atcrEnvironmentFile=/opt/atcr/.env
# Start hold containerExecStart=/usr/bin/docker compose -f /opt/atcr/deploy/docker-compose.prod.yml up -d atcr-hold
# Stop hold containerExecStop=/usr/bin/docker compose -f /opt/atcr/deploy/docker-compose.prod.yml stop atcr-hold
# Restart hold containerExecReload=/usr/bin/docker compose -f /opt/atcr/deploy/docker-compose.prod.yml restart atcr-hold
# Always restart on failureRestart=on-failureRestartSec=10
[Install]WantedBy=multi-user.targetEOF
# Reload systemdlog_info "Reloading systemd daemon..."systemctl daemon-reload
# Enable all services (but don't start yet - user needs to configure .env)systemctl enable atcr-caddy.servicesystemctl enable atcr-appview.servicesystemctl enable atcr-hold.service
log_info "Systemd services created and enabled"
# Create helper scriptslog_info "Creating helper scripts..."
# Script to rebuild and restartcat > "$ATCR_DIR/rebuild.sh" <<'EOF'#!/bin/bashset -ecd /opt/atcrdocker compose -f deploy/docker-compose.prod.yml builddocker compose -f deploy/docker-compose.prod.yml up -ddocker compose -f deploy/docker-compose.prod.yml logs -fEOFchmod +x "$ATCR_DIR/rebuild.sh"
# Script to view logscat > "$ATCR_DIR/logs.sh" <<'EOF'#!/bin/bashcd /opt/atcrdocker compose -f deploy/docker-compose.prod.yml logs -f "$@"EOFchmod +x "$ATCR_DIR/logs.sh"
log_info "Helper scripts created in $ATCR_DIR"
# Print completion messagecat <<'EOF'
================================================================================ATCR Installation Complete!================================================================================
NEXT STEPS:
1. Configure environment variables: nano /opt/atcr/.env
Required settings: - AWS_ACCESS_KEY_ID (UpCloud S3 credentials) - AWS_SECRET_ACCESS_KEY
Pre-configured (verify these are correct): - APPVIEW_DOMAIN=atcr.io - HOLD_DOMAIN=hold01.atcr.io - HOLD_OWNER=did:plc:pddp4xt5lgnv2qsegbzzs4xg - S3_BUCKET=atcr - S3_ENDPOINT=https://blobs.atcr.io
2. Configure UpCloud Cloud Firewall (in control panel): Allow: TCP 22 (SSH) Allow: TCP 80 (HTTP) Allow: TCP 443 (HTTPS) Drop: Everything else
3. Configure DNS (Cloudflare - DNS-only mode):EOF
echo " A atcr.io → $(curl -s ifconfig.me || echo '[server-ip]') (gray cloud)"echo " A hold01.atcr.io → $(curl -s ifconfig.me || echo '[server-ip]') (gray cloud)"echo " CNAME blobs.atcr.io → atcr.us-chi1.upcloudobjects.com (gray cloud)"
cat <<'EOF'
4. Start ATCR services: systemctl start atcr-caddy atcr-appview atcr-hold
5. Check status: systemctl status atcr-caddy systemctl status atcr-appview systemctl status atcr-hold docker ps /opt/atcr/logs.sh
Helper Scripts: /opt/atcr/rebuild.sh - Rebuild and restart containers /opt/atcr/logs.sh [service] - View logs (e.g., logs.sh atcr-hold)
Service Management: systemctl start atcr-caddy - Start Caddy reverse proxy systemctl start atcr-appview - Start AppView (registry + UI) systemctl start atcr-hold - Start Hold (storage service)
systemctl stop atcr-appview - Stop AppView only systemctl stop atcr-hold - Stop Hold only systemctl stop atcr-caddy - Stop all (stops reverse proxy)
systemctl restart atcr-appview - Restart AppView systemctl restart atcr-hold - Restart Hold
systemctl status atcr-caddy - Check Caddy status systemctl status atcr-appview - Check AppView status systemctl status atcr-hold - Check Hold status
Documentation: https://tangled.org/@evan.jarrett.net/at-container-registry
IMPORTANT: - Edit /opt/atcr/.env with S3 credentials before starting! - Configure UpCloud cloud firewall (see step 2) - DNS must be configured and propagated - Cloudflare proxy must be DISABLED (gray cloud) - Complete hold OAuth registration before first push
EOF
log_info "Installation complete. Follow the next steps above."