#!/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 # Configuration ATCR_DIR="/opt/atcr" ATCR_REPO="https://tangled.org/@evan.jarrett.net/at-container-registry" # UPDATE THIS ATCR_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 exists command_exists() { command -v "$1" >/dev/null 2>&1 } log_info "Starting ATCR deployment on Rocky Linux..." # Update system packages log_info "Updating system packages..." dnf update -y # Install required packages log_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 RAM if [ ! -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 -h else log_info "Swap file already exists" fi # Install Docker if ! 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 Compose if ! docker compose version >/dev/null 2>&1; then log_error "Docker Compose plugin not found. Please install manually." exit 1 fi log_info "Docker Compose version: $(docker compose version)" # Create ATCR directory log_info "Creating ATCR directory: $ATCR_DIR" mkdir -p "$ATCR_DIR" cd "$ATCR_DIR" # Clone repository or create minimal structure if [ -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 exist if [ -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 service log_info "Creating systemd service..." cat > /etc/systemd/system/atcr.service <<'EOF' [Unit] Description=ATCR Container Registry Requires=docker.service After=docker.service network-online.target Wants=network-online.target [Service] Type=oneshot RemainAfterExit=yes WorkingDirectory=/opt/atcr EnvironmentFile=/opt/atcr/.env # Start containers ExecStart=/usr/bin/docker compose -f /opt/atcr/deploy/docker-compose.prod.yml up -d # Stop containers ExecStop=/usr/bin/docker compose -f /opt/atcr/deploy/docker-compose.prod.yml down # Restart containers ExecReload=/usr/bin/docker compose -f /opt/atcr/deploy/docker-compose.prod.yml restart # Always restart on failure Restart=on-failure RestartSec=10 [Install] WantedBy=multi-user.target EOF # Reload systemd log_info "Reloading systemd daemon..." systemctl daemon-reload # Enable service (but don't start yet - user needs to configure .env) systemctl enable atcr.service log_info "Systemd service created and enabled" # Create helper scripts log_info "Creating helper scripts..." # Script to rebuild and restart cat > "$ATCR_DIR/rebuild.sh" <<'EOF' #!/bin/bash set -e cd /opt/atcr docker compose -f deploy/docker-compose.prod.yml build docker compose -f deploy/docker-compose.prod.yml up -d docker compose -f deploy/docker-compose.prod.yml logs -f EOF chmod +x "$ATCR_DIR/rebuild.sh" # Script to view logs cat > "$ATCR_DIR/logs.sh" <<'EOF' #!/bin/bash cd /opt/atcr docker compose -f deploy/docker-compose.prod.yml logs -f "$@" EOF chmod +x "$ATCR_DIR/logs.sh" # Script to get hold OAuth URL cat > "$ATCR_DIR/get-hold-oauth.sh" <<'EOF' #!/bin/bash echo "Checking atcr-hold logs for OAuth registration URL..." docker logs atcr-hold 2>&1 | grep -i "oauth\|authorization\|visit\|http" | tail -20 EOF chmod +x "$ATCR_DIR/get-hold-oauth.sh" log_info "Helper scripts created in $ATCR_DIR" # Print completion message cat <<'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: systemctl start atcr 5. Complete Hold OAuth registration: /opt/atcr/get-hold-oauth.sh Visit the OAuth URL in your browser to authorize the hold service. 6. Check status: systemctl status atcr 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) /opt/atcr/get-hold-oauth.sh - Get hold OAuth URL Service Management: systemctl start atcr - Start ATCR systemctl stop atcr - Stop ATCR systemctl restart atcr - Restart ATCR systemctl status atcr - Check 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."