#!/usr/bin/env bash # ───────────────────────────────────────────────────────────────────────────── # Nexus first-time provisioning # Run once on the server after: docker compose -f docker-compose.mirror.yml up -d # # Docker upstream: # By default → registry-1.docker.io (Docker Hub directly — works from VPS) # With Liara → docker-mirror.liara.ir (Iranian relay, faster + more reliable) # # To use Liara mirror, get credentials from https://app.liara.ir # (Account → Docker Mirror section), then run: # DOCKER_MIRROR_URL=https://docker-mirror.liara.ir \ # DOCKER_MIRROR_USER=your-liara-email \ # DOCKER_MIRROR_PASS=your-liara-token \ # ./mirrors/nexus/provision.sh # # Usage: # ./mirrors/nexus/provision.sh # Docker Hub direct # NEXUS_ADMIN_PASS=MySecret ./mirrors/nexus/provision.sh # ───────────────────────────────────────────────────────────────────────────── set -euo pipefail NEXUS_URL="http://localhost:8081" NEW_PASS="${NEXUS_ADMIN_PASS:-Mirror@2024!}" CONTAINER="meezi-mirror-nexus" # Docker upstream — override with Liara mirror once you have credentials DOCKER_UPSTREAM="${DOCKER_MIRROR_URL:-https://registry-1.docker.io}" DOCKER_USER="${DOCKER_MIRROR_USER:-}" DOCKER_PASS="${DOCKER_MIRROR_PASS:-}" # ── 1. Wait for Nexus ──────────────────────────────────────────────────────── echo "⏳ Waiting for Nexus (can take 2-3 min on first boot)..." until curl -sf "$NEXUS_URL/service/rest/v1/status" | grep -q '"edition"'; do printf "." sleep 6 done echo "" echo "✅ Nexus is up" # ── 2. Resolve admin password ──────────────────────────────────────────────── INIT_PASS_FILE=$(docker exec "$CONTAINER" sh -c 'cat /nexus-data/admin.password 2>/dev/null || true') if [ -n "$INIT_PASS_FILE" ]; then echo "🔐 First-time password found — changing to configured password..." HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \ -u "admin:$INIT_PASS_FILE" -X PUT \ "$NEXUS_URL/service/rest/v1/security/users/admin/change-password" \ -H "Content-Type: text/plain" \ -d "$NEW_PASS") if [ "$HTTP_CODE" = "204" ]; then echo "✅ Password updated" else echo "⚠️ Password change returned HTTP $HTTP_CODE — using original password" NEW_PASS="$INIT_PASS_FILE" fi ADMIN_PASS="$NEW_PASS" else echo "ℹ️ admin.password not found — using NEXUS_ADMIN_PASS (already provisioned?)" ADMIN_PASS="$NEW_PASS" fi AUTH="-u admin:$ADMIN_PASS" # ── 3. Enable anonymous read access ───────────────────────────────────────── echo "🔓 Enabling anonymous access..." curl -sf $AUTH -X PUT "$NEXUS_URL/service/rest/v1/security/anonymous" \ -H "Content-Type: application/json" \ -d '{"enabled":true,"userId":"anonymous","realmName":"NexusAuthorizingRealm"}' \ && echo "✅ Anonymous access enabled" # Enable NuGet + npm token realms curl -sf $AUTH -X PUT "$NEXUS_URL/service/rest/v1/security/realms/active" \ -H "Content-Type: application/json" \ -d '["NexusAuthenticatingRealm","NexusAuthorizingRealm","NuGetApiKey","NpmToken"]' \ && echo "✅ Realms configured (NuGet, npm)" # ── Helper: create or update repo ─────────────────────────────────────────── create_repo() { local TYPE="$1" local JSON="$2" local NAME NAME=$(echo "$JSON" | grep -o '"name":"[^"]*"' | head -1 | cut -d'"' -f4) HTTP=$(curl -s -o /dev/null -w "%{http_code}" $AUTH \ -X POST "$NEXUS_URL/service/rest/v1/repositories/$TYPE" \ -H "Content-Type: application/json" \ -d "$JSON") case "$HTTP" in 201) echo "✅ $NAME created" ;; 400) echo "⚠️ $NAME already exists (skipped — update via UI if needed)" ;; *) echo "❌ $NAME failed — HTTP $HTTP" ;; esac } # ── 4. NuGet proxy ────────────────────────────────────────────────────────── echo "" echo "📦 Creating NuGet proxy → nuget.org ..." create_repo "nuget/proxy" '{ "name": "nuget-proxy", "online": true, "storage": { "blobStoreName": "default", "strictContentTypeValidation": true }, "proxy": { "remoteUrl": "https://api.nuget.org/v3/index.json", "contentMaxAge": 1440, "metadataMaxAge": 1440 }, "negativeCache": { "enabled": true, "timeToLive": 1440 }, "httpClient": { "blocked": false, "autoBlock": true } }' # ── 5. npm proxy ───────────────────────────────────────────────────────────── echo "📦 Creating npm proxy → registry.npmjs.org ..." create_repo "npm/proxy" '{ "name": "npm-proxy", "online": true, "storage": { "blobStoreName": "default", "strictContentTypeValidation": false }, "proxy": { "remoteUrl": "https://registry.npmjs.org", "contentMaxAge": 1440, "metadataMaxAge": 1440 }, "negativeCache": { "enabled": true, "timeToLive": 1440 }, "httpClient": { "blocked": false, "autoBlock": true } }' # ── 6. Docker proxy ────────────────────────────────────────────────────────── if [ -n "$DOCKER_USER" ] && [ -n "$DOCKER_PASS" ]; then echo "🐳 Creating Docker proxy → $DOCKER_UPSTREAM (with auth) ..." DOCKER_AUTH_JSON='"authentication":{"type":"username","username":"'"$DOCKER_USER"'","password":"'"$DOCKER_PASS"'"},' DOCKER_INDEX_TYPE="REGISTRY" # Liara is a plain registry, not hub.docker.com else echo "🐳 Creating Docker proxy → $DOCKER_UPSTREAM (no auth) ..." DOCKER_AUTH_JSON="" DOCKER_INDEX_TYPE="HUB" # direct Docker Hub — use hub index fi create_repo "docker/proxy" '{ "name": "docker-hub-proxy", "online": true, "storage": { "blobStoreName": "default", "strictContentTypeValidation": true }, "proxy": { "remoteUrl": "'"$DOCKER_UPSTREAM"'", "contentMaxAge": 1440, "metadataMaxAge": 1440 }, "negativeCache": { "enabled": true, "timeToLive": 1440 }, "httpClient": { "blocked": false, "autoBlock": true, '"$DOCKER_AUTH_JSON"' "connection": { "useTrustStore": false } }, "docker": { "v1Enabled": false, "forceBasicAuth": false, "httpPort": 8083 }, "dockerProxy": { "indexType": "'"$DOCKER_INDEX_TYPE"'", "cacheForeignLayers": false } }' # ── Done ───────────────────────────────────────────────────────────────────── echo "" echo "═══════════════════════════════════════════════════════════════" echo "🎉 Nexus provisioned!" echo "═══════════════════════════════════════════════════════════════" echo "" echo " UI → https://mirror.soroushasadi.com/" echo " admin / $ADMIN_PASS" echo "" echo " NuGet → https://mirror.soroushasadi.com/repository/nuget-group/index.json" echo " npm → https://mirror.soroushasadi.com/repository/npm-group/" echo " Docker → https://mirror.soroushasadi.com ← upstream: $DOCKER_UPSTREAM" echo "" if [ -z "$DOCKER_USER" ]; then echo " 💡 To switch Docker upstream to Liara mirror (faster in Iran):" echo " Get credentials from https://app.liara.ir → Docker Mirror, then:" echo "" echo " DOCKER_MIRROR_URL=https://docker-mirror.liara.ir \\" echo " DOCKER_MIRROR_USER=your-email \\" echo " DOCKER_MIRROR_PASS=your-token \\" echo " ./mirrors/nexus/update-docker-upstream.sh" echo "" fi echo "To activate Docker Hub mirror on this server:" echo " Merge docker/daemon-registry-mirror.example.json into /etc/docker/daemon.json" echo ' { "registry-mirrors": ["https://mirror.soroushasadi.com"] }' echo " systemctl restart docker" echo ""