345 lines
9.5 KiB
Bash
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."
|