All checks were successful
Reindex Knowledge Base / reindex (push) Successful in 3s
Adds title, description, type, domain, and tags frontmatter to every doc for improved KB semantic search. The description field is prepended to every search chunk, and domain/type/tags enable filtered queries. Type values: context, guide, runbook, reference, troubleshooting Domain values match directory structure (networking, docker, etc.) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
386 lines
7.9 KiB
Markdown
386 lines
7.9 KiB
Markdown
---
|
|
title: "Harbor Registry Setup Guide"
|
|
description: "Step-by-step guide to deploying Harbor as a self-hosted Docker registry on a Proxmox LXC. Covers installation, NPM reverse proxy config, Gitea Actions integration, vulnerability scanning, backup strategy, and troubleshooting."
|
|
type: guide
|
|
domain: server-configs
|
|
tags: [harbor, docker-registry, proxmox, lxc, gitea-actions, vulnerability-scanning, docker]
|
|
---
|
|
|
|
# Harbor Docker Registry Setup Guide
|
|
|
|
Complete guide to setting up Harbor on a Proxmox LXC for self-hosted Docker registry.
|
|
|
|
## Prerequisites
|
|
|
|
- Proxmox LXC with Ubuntu 22.04
|
|
- 2 CPU cores, 4GB RAM, 50GB disk
|
|
- Docker and docker-compose installed
|
|
- Domain name (e.g., registry.manticorum.com)
|
|
|
|
## Quick Setup
|
|
|
|
### 1. Create LXC Container
|
|
|
|
```bash
|
|
# On Proxmox host
|
|
pct create 227 local:vztmpl/ubuntu-22.04-standard_22.04-1_amd64.tar.zst \
|
|
--hostname harbor \
|
|
--cores 2 \
|
|
--memory 4096 \
|
|
--swap 512 \
|
|
--net0 name=eth0,bridge=vmbr0,ip=10.10.0.227/24,gw=10.10.0.1 \
|
|
--rootfs local-lvm:50 \
|
|
--unprivileged 1 \
|
|
--features nesting=1 \
|
|
--onboot 1 \
|
|
--start 1
|
|
```
|
|
|
|
### 2. Install Docker
|
|
|
|
```bash
|
|
ssh root@10.10.0.227
|
|
|
|
apt update && apt install -y curl
|
|
curl -fsSL https://get.docker.com | sh
|
|
systemctl enable docker
|
|
```
|
|
|
|
### 3. Download Harbor
|
|
|
|
```bash
|
|
cd /opt
|
|
wget https://github.com/goharbor/harbor/releases/download/v2.10.0/harbor-offline-installer-v2.10.0.tgz
|
|
tar xzvf harbor-offline-installer-v2.10.0.tgz
|
|
cd harbor
|
|
```
|
|
|
|
### 4. Configure Harbor
|
|
|
|
```bash
|
|
cp harbor.yml.tmpl harbor.yml
|
|
|
|
# Edit harbor.yml
|
|
nano harbor.yml
|
|
```
|
|
|
|
**Key settings to change:**
|
|
```yaml
|
|
hostname: registry.manticorum.com # Your domain
|
|
|
|
# HTTPS (configure after NPM setup, start with HTTP for now)
|
|
# https:
|
|
# port: 443
|
|
# certificate: /path/to/cert
|
|
# private_key: /path/to/key
|
|
|
|
# Or disable HTTPS initially
|
|
# Comment out entire https section
|
|
|
|
harbor_admin_password: YourSecurePassword123
|
|
|
|
database:
|
|
password: YourDBPassword123
|
|
|
|
data_volume: /mnt/harbor-data
|
|
```
|
|
|
|
### 5. Install Harbor
|
|
|
|
```bash
|
|
./install.sh
|
|
```
|
|
|
|
### 6. Access Harbor
|
|
|
|
Open: `http://10.10.0.227` (or `http://registry.manticorum.com` if DNS configured)
|
|
|
|
**Default login:**
|
|
- Username: `admin`
|
|
- Password: `YourSecurePassword123` (what you set)
|
|
|
|
### 7. Configure NPM Reverse Proxy
|
|
|
|
In Nginx Proxy Manager (10.10.0.16):
|
|
|
|
**Proxy Host:**
|
|
- Domain: `registry.manticorum.com`
|
|
- Scheme: `http`
|
|
- Forward Hostname: `10.10.0.227`
|
|
- Forward Port: `80`
|
|
- Websockets: ✅ Enabled
|
|
- Block Common Exploits: ✅ Enabled
|
|
- SSL: Let's Encrypt
|
|
|
|
**Custom Nginx Configuration:**
|
|
```nginx
|
|
# Increase timeouts for large image uploads
|
|
proxy_read_timeout 900;
|
|
proxy_send_timeout 900;
|
|
client_max_body_size 0; # No upload limit
|
|
|
|
# Required for Docker registry
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
```
|
|
|
|
## Using Your Registry
|
|
|
|
### 1. Login from Dev Machine
|
|
|
|
```bash
|
|
docker login registry.manticorum.com
|
|
# Username: admin
|
|
# Password: YourSecurePassword123
|
|
```
|
|
|
|
### 2. Tag and Push Image
|
|
|
|
```bash
|
|
# Tag existing image
|
|
docker tag manticorum67/paper-dynasty:latest registry.manticorum.com/paper-dynasty/bot:latest
|
|
|
|
# Push to your registry
|
|
docker push registry.manticorum.com/paper-dynasty/bot:latest
|
|
```
|
|
|
|
### 3. Pull from Production
|
|
|
|
```bash
|
|
# On sba-bots
|
|
docker login registry.manticorum.com
|
|
docker pull registry.manticorum.com/paper-dynasty/bot:latest
|
|
```
|
|
|
|
### 4. Update docker-compose
|
|
|
|
```yaml
|
|
services:
|
|
paper-dynasty:
|
|
# Old: image: manticorum67/paper-dynasty:latest
|
|
# New:
|
|
image: registry.manticorum.com/paper-dynasty/bot:latest
|
|
```
|
|
|
|
## Integrating with Gitea Actions
|
|
|
|
Update your workflow to push to both registries:
|
|
|
|
```yaml
|
|
- name: Login to Docker Hub
|
|
uses: docker/login-action@v3
|
|
with:
|
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
|
|
- name: Login to Harbor
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: registry.manticorum.com
|
|
username: ${{ secrets.HARBOR_USERNAME }}
|
|
password: ${{ secrets.HARBOR_PASSWORD }}
|
|
|
|
- name: Build and push
|
|
uses: docker/build-push-action@v5
|
|
with:
|
|
context: .
|
|
push: ${{ github.ref == 'refs/heads/main' }}
|
|
tags: |
|
|
manticorum67/paper-dynasty:latest
|
|
manticorum67/paper-dynasty:v${{ steps.meta.outputs.version }}
|
|
registry.manticorum.com/paper-dynasty/bot:latest
|
|
registry.manticorum.com/paper-dynasty/bot:v${{ steps.meta.outputs.version }}
|
|
```
|
|
|
|
## Harbor Features
|
|
|
|
### Create Projects
|
|
|
|
1. Login to Harbor UI
|
|
2. Click **New Project**
|
|
3. Name: `paper-dynasty`
|
|
4. Access Level: Private or Public
|
|
|
|
### Enable Vulnerability Scanning
|
|
|
|
1. Go to **Administration** → **Interrogation Services**
|
|
2. Enable **Trivy** scanner
|
|
3. Set scan on push: ✅ Enabled
|
|
|
|
Now images are auto-scanned for CVEs!
|
|
|
|
### Set Up Replication
|
|
|
|
Replicate between Harbor and Docker Hub:
|
|
|
|
1. **Administration** → **Replications**
|
|
2. **New Replication Rule**
|
|
- Name: `sync-to-dockerhub`
|
|
- Source: Local
|
|
- Destination: Docker Hub (add endpoint first)
|
|
- Trigger: Event Based
|
|
|
|
### Garbage Collection
|
|
|
|
Free up disk space from deleted images:
|
|
|
|
1. **Administration** → **Garbage Collection**
|
|
2. Schedule: Daily at 2 AM
|
|
3. Dry run first to see what would be deleted
|
|
|
|
## Backup Strategy
|
|
|
|
### What to Backup
|
|
|
|
1. **Harbor database** (PostgreSQL)
|
|
2. **Image storage** (`/mnt/harbor-data`)
|
|
3. **Configuration** (`/opt/harbor/harbor.yml`)
|
|
|
|
### Backup Script
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
BACKUP_DIR="/mnt/backups/harbor"
|
|
DATE=$(date +%Y%m%d)
|
|
|
|
# Stop Harbor
|
|
cd /opt/harbor
|
|
docker-compose down
|
|
|
|
# Backup database
|
|
docker exec harbor-db pg_dumpall -U postgres > $BACKUP_DIR/harbor-db-$DATE.sql
|
|
|
|
# Backup data (incremental)
|
|
rsync -av /mnt/harbor-data/ $BACKUP_DIR/harbor-data/
|
|
|
|
# Backup config
|
|
cp /opt/harbor/harbor.yml $BACKUP_DIR/harbor-config-$DATE.yml
|
|
|
|
# Start Harbor
|
|
docker-compose up -d
|
|
|
|
# Keep last 7 days
|
|
find $BACKUP_DIR -name "harbor-db-*.sql" -mtime +7 -delete
|
|
```
|
|
|
|
## Monitoring
|
|
|
|
### Check Harbor Status
|
|
|
|
```bash
|
|
cd /opt/harbor
|
|
docker-compose ps
|
|
|
|
# View logs
|
|
docker-compose logs -f
|
|
```
|
|
|
|
### Disk Usage
|
|
|
|
```bash
|
|
du -sh /mnt/harbor-data
|
|
|
|
# By project
|
|
du -sh /mnt/harbor-data/docker/registry/v2/repositories/*
|
|
```
|
|
|
|
### API Health Check
|
|
|
|
```bash
|
|
curl -k https://registry.manticorum.com/api/v2.0/health
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### "401 Unauthorized" on push
|
|
|
|
**Problem:** Docker login not working
|
|
|
|
**Solution:**
|
|
```bash
|
|
# Clear old credentials
|
|
rm ~/.docker/config.json
|
|
|
|
# Login again
|
|
docker login registry.manticorum.com
|
|
```
|
|
|
|
### "413 Request Entity Too Large"
|
|
|
|
**Problem:** Nginx upload limit
|
|
|
|
**Solution:** Add to NPM custom config:
|
|
```nginx
|
|
client_max_body_size 0;
|
|
```
|
|
|
|
### Disk space full
|
|
|
|
**Problem:** Old images filling disk
|
|
|
|
**Solution:**
|
|
```bash
|
|
# Run garbage collection
|
|
cd /opt/harbor
|
|
docker-compose exec core /harbor/garbage-collection.sh
|
|
|
|
# Or via UI: Administration → Garbage Collection → Run Now
|
|
```
|
|
|
|
### Can't pull from registry
|
|
|
|
**Problem:** Firewall or network issue
|
|
|
|
**Solution:**
|
|
```bash
|
|
# Test connection
|
|
telnet 10.10.0.227 80
|
|
|
|
# Check Harbor logs
|
|
docker-compose logs registry
|
|
```
|
|
|
|
## Advanced: High Availability
|
|
|
|
For production-critical registries, set up HA:
|
|
|
|
1. Multiple Harbor instances
|
|
2. Shared storage (NFS, S3, Minio)
|
|
3. Load balancer in front
|
|
4. Database replication
|
|
|
|
## Cost Analysis
|
|
|
|
**LXC Resources:**
|
|
- CPU: 2 cores = $0 (spare capacity)
|
|
- RAM: 4GB = $0 (spare capacity)
|
|
- Disk: 50GB = $0 (local storage)
|
|
- Bandwidth: Internal = $0
|
|
|
|
**Total ongoing cost: $0/month**
|
|
|
|
**Docker Hub Pro alternative: $5/month**
|
|
|
|
**Time investment:**
|
|
- Setup: 2-3 hours
|
|
- Maintenance: 30 min/month
|
|
- Break-even: 3 months of learning value
|
|
|
|
## Next Steps
|
|
|
|
1. ✅ Set up Harbor on LXC 227
|
|
2. ✅ Configure NPM reverse proxy
|
|
3. ✅ Test push/pull from dev machine
|
|
4. ✅ Update one project to use Harbor
|
|
5. ✅ Set up Gitea Actions to push to both registries
|
|
6. ✅ Configure vulnerability scanning
|
|
7. ✅ Set up automated backups
|
|
|
|
---
|
|
|
|
**Created:** 2026-02-04
|
|
**For:** Manticorum Home Lab
|
|
**Reference:** Paper Dynasty as first use case
|