Files
at-container-registry/deploy/init-upcloud.sh
2025-10-29 12:06:47 -05:00

345 lines
9.5 KiB
Bash

#!/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 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 Proxy
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 caddy container
ExecStart=/usr/bin/docker compose -f /opt/atcr/deploy/docker-compose.prod.yml up -d caddy
# Stop caddy container
ExecStop=/usr/bin/docker compose -f /opt/atcr/deploy/docker-compose.prod.yml stop caddy
# Restart caddy container
ExecReload=/usr/bin/docker compose -f /opt/atcr/deploy/docker-compose.prod.yml restart caddy
# Always restart on failure
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
# 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.service
After=docker.service network-online.target atcr-caddy.service
Wants=network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/atcr
EnvironmentFile=/opt/atcr/.env
# Start appview container
ExecStart=/usr/bin/docker compose -f /opt/atcr/deploy/docker-compose.prod.yml up -d atcr-appview
# Stop appview container
ExecStop=/usr/bin/docker compose -f /opt/atcr/deploy/docker-compose.prod.yml stop atcr-appview
# Restart appview container
ExecReload=/usr/bin/docker compose -f /opt/atcr/deploy/docker-compose.prod.yml restart atcr-appview
# Always restart on failure
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
# Hold service (storage backend)
cat > /etc/systemd/system/atcr-hold.service <<'EOF'
[Unit]
Description=ATCR Hold (Storage Service)
Requires=docker.service atcr-caddy.service
After=docker.service network-online.target atcr-caddy.service
Wants=network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/atcr
EnvironmentFile=/opt/atcr/.env
# Start hold container
ExecStart=/usr/bin/docker compose -f /opt/atcr/deploy/docker-compose.prod.yml up -d atcr-hold
# Stop hold container
ExecStop=/usr/bin/docker compose -f /opt/atcr/deploy/docker-compose.prod.yml stop atcr-hold
# Restart hold container
ExecReload=/usr/bin/docker compose -f /opt/atcr/deploy/docker-compose.prod.yml restart atcr-hold
# 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 all services (but don't start yet - user needs to configure .env)
systemctl enable atcr-caddy.service
systemctl enable atcr-appview.service
systemctl enable atcr-hold.service
log_info "Systemd services 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"
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 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."