171 lines
7.1 KiB
Bash
171 lines
7.1 KiB
Bash
|
|
#!/usr/bin/env bash
|
|||
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|||
|
|
# Nexus first-time provisioning
|
|||
|
|
# Run once on the server after: docker compose -f docker-compose.mirror.yml up -d
|
|||
|
|
#
|
|||
|
|
# What this does:
|
|||
|
|
# 1. Waits for Nexus to finish starting up
|
|||
|
|
# 2. Reads the one-time admin password, changes it to NEXUS_ADMIN_PASS
|
|||
|
|
# 3. Enables anonymous (unauthenticated) read access — needed for CI
|
|||
|
|
# 4. Creates proxy repos: nuget-proxy, npm-proxy, docker-hub-proxy
|
|||
|
|
#
|
|||
|
|
# Usage:
|
|||
|
|
# ./mirrors/nexus/provision.sh
|
|||
|
|
# NEXUS_ADMIN_PASS=MySecret ./mirrors/nexus/provision.sh
|
|||
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|||
|
|
set -euo pipefail
|
|||
|
|
|
|||
|
|
NEXUS_URL="http://localhost:8081"
|
|||
|
|
NEW_PASS="${NEXUS_ADMIN_PASS:-Mirror@2024!}" # change this or set env var
|
|||
|
|
CONTAINER="meezi-mirror-nexus"
|
|||
|
|
|
|||
|
|
# ── 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 — continuing with original password"
|
|||
|
|
NEW_PASS="$INIT_PASS_FILE"
|
|||
|
|
fi
|
|||
|
|
ADMIN_PASS="$NEW_PASS"
|
|||
|
|
else
|
|||
|
|
echo "ℹ️ admin.password not present — 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 repo (skip if already exists) ────────────────────────────
|
|||
|
|
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)" ;;
|
|||
|
|
*) 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 Hub proxy (port 8083) ─────────────────────────────────────────
|
|||
|
|
echo "🐳 Creating Docker Hub proxy → registry-1.docker.io (port 8083) ..."
|
|||
|
|
create_repo "docker/proxy" '{
|
|||
|
|
"name": "docker-hub-proxy",
|
|||
|
|
"online": true,
|
|||
|
|
"storage": {
|
|||
|
|
"blobStoreName": "default",
|
|||
|
|
"strictContentTypeValidation": true
|
|||
|
|
},
|
|||
|
|
"proxy": {
|
|||
|
|
"remoteUrl": "https://registry-1.docker.io",
|
|||
|
|
"contentMaxAge": 1440,
|
|||
|
|
"metadataMaxAge": 1440
|
|||
|
|
},
|
|||
|
|
"negativeCache": { "enabled": true, "timeToLive": 1440 },
|
|||
|
|
"httpClient": { "blocked": false, "autoBlock": true },
|
|||
|
|
"docker": {
|
|||
|
|
"v1Enabled": false,
|
|||
|
|
"forceBasicAuth": false,
|
|||
|
|
"httpPort": 8083
|
|||
|
|
},
|
|||
|
|
"dockerProxy": {
|
|||
|
|
"indexType": "HUB",
|
|||
|
|
"cacheForeignLayers": false
|
|||
|
|
}
|
|||
|
|
}'
|
|||
|
|
|
|||
|
|
# ── Done ─────────────────────────────────────────────────────────────────────
|
|||
|
|
echo ""
|
|||
|
|
echo "═══════════════════════════════════════════════════════"
|
|||
|
|
echo "🎉 Nexus provisioned successfully!"
|
|||
|
|
echo "═══════════════════════════════════════════════════════"
|
|||
|
|
echo ""
|
|||
|
|
echo " UI → http://SERVER_IP:8081"
|
|||
|
|
echo " admin / $ADMIN_PASS"
|
|||
|
|
echo ""
|
|||
|
|
echo " NuGet → http://SERVER_IP:8081/repository/nuget-proxy/index.json"
|
|||
|
|
echo " npm → http://SERVER_IP:8081/repository/npm-proxy/"
|
|||
|
|
echo " Docker → http://SERVER_IP:8083"
|
|||
|
|
echo ""
|
|||
|
|
echo "To activate Docker Hub mirror — edit /etc/docker/daemon.json:"
|
|||
|
|
cat << 'EOF'
|
|||
|
|
{
|
|||
|
|
"insecure-registries": ["SERVER_IP:8083"],
|
|||
|
|
"registry-mirrors": ["http://SERVER_IP:8083"]
|
|||
|
|
}
|
|||
|
|
EOF
|
|||
|
|
echo " then: systemctl restart docker"
|
|||
|
|
echo ""
|