Files
meezi/mirrors/nexus/provision.sh
T
soroush.asadi 7321c59e43 fix(mirror): Nexus Docker proxy with optional Liara upstream + credential support
provision.sh: Docker proxy defaults to registry-1.docker.io (works directly
  from VPS). Set DOCKER_MIRROR_URL/USER/PASS env vars to route through
  docker-mirror.liara.ir once Liara credentials are obtained.

update-docker-upstream.sh: swap Docker proxy upstream at any time without
  re-running the full provision (useful after getting Liara credentials).

indexType auto-selects: HUB for docker.io direct, REGISTRY for Liara/Harbor.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 15:56:22 +03:30

201 lines
8.7 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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 → http://$(hostname -I | awk '{print $1}'):8081"
echo " admin / $ADMIN_PASS"
echo ""
echo " NuGet → http://$(hostname -I | awk '{print $1}'):8081/repository/nuget-proxy/index.json"
echo " npm → http://$(hostname -I | awk '{print $1}'):8081/repository/npm-proxy/"
echo " Docker → http://$(hostname -I | awk '{print $1}'):8083 ← 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 " Edit /etc/docker/daemon.json:"
echo ' { "insecure-registries": ["'"$(hostname -I | awk '{print $1}'):8083"'"], "registry-mirrors": ["http://'"$(hostname -I | awk '{print $1}'):8083"'"] }'
echo " systemctl restart docker"
echo ""