Install Harbor Docker Registry on VPS

Install Harbor Docker Registry on VPS

June 2026 · 8 min read

Harbor is an open-source container image registry that provides secure storage for Docker images with built-in HTTPS, user management, vulnerability scanning, and image replication capabilities for teams. If you need a private registry instead of relying on Docker Hub, this guide will walk you through installing Harbor on your VPS, including HTTPS setup, user management, and vulnerability scanning features to keep your container images secure and organized.

System Requirements

Before starting the Harbor installation, verify your VPS meets these minimum requirements:

This guide assumes a VPS with 4 CPU cores, 8 GB RAM, and 200 GB storage, which is suitable for a medium-sized Harbor instance serving a development team.

Install Docker and Docker Compose

Harbor depends on Docker and Docker Compose, so we'll install these tools first. If you already have Docker and Docker Compose installed, you can skip this section.

# Update package manager
sudo apt update && sudo apt upgrade -y

# Install Docker
sudo apt install -y docker.io docker-compose

# Add current user to docker group
sudo usermod -aG docker $USER
newgrp docker

# Verify Docker installation
docker --version
docker-compose --version
Note: After running newgrp docker, you may need to open a new terminal for the group changes to take effect.

Download and Prepare Harbor

Download the Harbor binary package from the GitHub releases page and prepare the installation directory.

# Create Harbor installation directory
mkdir -p ~/harbor
cd ~/harbor

# Download Harbor (verify latest version from github.com/goharbor/harbor/releases)
wget https://github.com/goharbor/harbor/releases/download/v2.8.4/harbor-offline-installer-v2.8.4.tgz

# Extract the archive
tar xzf harbor-offline-installer-v2.8.4.tgz

# Navigate to Harbor directory
cd harbor

# List contents
ls -la

You'll see the harbor.yml.tmpl configuration template file and the install.sh installation script that we'll use to deploy Harbor.

Configure Harbor Settings

Copy the configuration template and customize it for your deployment environment.

# Copy template to active configuration
cp harbor.yml.tmpl harbor.yml

# Edit configuration with your preferred editor
nano harbor.yml

Key configuration options to modify in harbor.yml:

# Harbor registry hostname
hostname: registry.example.com

# HTTP port (default 80)
http:
  port: 80

# HTTPS port (default 443) - enable HTTPS
https:
  port: 443
  certificate: /path/to/your/certificate.crt
  private_key: /path/to/your/private.key

# Harbor admin account password
harbor_admin_password: YourSecurePassword123!

# Storage location for images and database
data_volume: /data

# Enable vulnerability scanning
trivyoffline: true

# Enable image replication features
replication:
  enabled: true

# Logging level (info, debug, warning, error)
log:
  level: info
Important: For production deployments, use a valid SSL certificate (e.g., from Let's Encrypt) and set a strong admin password with uppercase, lowercase, numbers, and special characters.

Set Up HTTPS with Let's Encrypt

To ensure Harbor is properly secured, configure HTTPS using a free SSL certificate from Let's Encrypt via Certbot.

# Install Certbot for SSL certificate management
sudo apt install -y certbot python3-certbot-nginx

# Generate SSL certificate from Let's Encrypt
# (ensure your domain DNS already points to this VPS)
sudo certbot certonly --standalone -d registry.example.com

# Certbot stores certificates at:
# /etc/letsencrypt/live/registry.example.com/fullchain.pem (certificate)
# /etc/letsencrypt/live/registry.example.com/privkey.pem (private key)

Update your harbor.yml to reference the Let's Encrypt certificates:

https:
  port: 443
  certificate: /etc/letsencrypt/live/registry.example.com/fullchain.pem
  private_key: /etc/letsencrypt/live/registry.example.com/privkey.pem

Install Harbor

Once configuration and HTTPS setup are complete, run the Harbor installation script.

# Navigate to Harbor directory
cd ~/harbor/harbor

# Run the installation script
sudo ./install.sh

# The script will display progress:
# [Step 0]: checking if docker command is available ...
# [Step 1]: checking docker version ...
# [Step 2]: checking docker-compose version ...
# [Step 3]: Preparing environment ...
# [Step 4]: Building docker images ...
# [Step 5]: Prepare notary files ...
# [Step 6]: Prepare core files ...
# [Step 7]: docker-compose up -d ...

# When complete, you'll see:
# ✔ ----Harbor has been installed and started successfully.----

The installation typically takes 5-15 minutes depending on your network speed and VPS performance. After completion, Harbor services will start automatically in the background.

Add Users and Configure Projects

After installation, access the Harbor web interface at https://registry.example.com using username admin and the password you set in harbor.yml.

To add new users:

  1. Log in to Harbor with your admin account
  2. Navigate to Administration > Users
  3. Click "New User" and enter username, email, and password
  4. Select user role (Project Admin, Developer, Guest)
  5. Click "OK" to create the user

To create a new project for storing images:

  1. Go to Projects > New Project
  2. Enter a project name (e.g., "myapp")
  3. Choose access level (Public or Private)
  4. Configure repository access permissions
  5. Enable image scanning (recommended for security)

Verify Harbor is Working

After installation completes, verify that all Harbor services are running correctly with these checks:

# Check Harbor container status
docker-compose ps

# Should display all services running:
# NAME                COMMAND                  STATUS
# harbor-core         "/harbor/start.sh"       Up (healthy)
# harbor-portal       "nginx -g daemon off"    Up (healthy)
# harbor-db           "docker-entrypoint..."   Up (healthy)
# harbor-jobservice   "/harbor/start.sh"       Up (healthy)
# registry            "/entrypoint.sh /etc..."  Up (healthy)
# redis               "redis-server redis..."   Up (healthy)

# Check Harbor API health endpoint
curl -k https://registry.example.com/api/v2.0/systeminfo

# Should return JSON with system configuration

# View Harbor core service logs
docker-compose logs harbor-core

# Access the Harbor web interface
# https://registry.example.com
# Login with admin account
Tip: Use the -k flag with curl to skip SSL certificate verification if using self-signed certificates during testing.

Push and Pull Docker Images

With Harbor running, you can now push Docker images to your private registry and pull them from other locations.

# Authenticate to Harbor registry
docker login -u admin -p YourPassword https://registry.example.com

# Tag your Docker image to point to Harbor registry
docker tag myapp:latest registry.example.com/myapp/myapp:latest

# Push image to Harbor
docker push registry.example.com/myapp/myapp:latest

# Expected output:
# The push refers to repository [registry.example.com/myapp/myapp]
# sha256:abc123... Pushed
# 1.2 MB

# Pull image from Harbor
docker pull registry.example.com/myapp/myapp:latest

After pushing images, view them in the Harbor web interface under Projects > myapp > Repositories.

Troubleshooting Common Issues

Connection refused - 111

This error occurs when trying to login or push images but Harbor services aren't ready or ports are blocked.

Solution:

# Verify Harbor containers are running
docker-compose ps

# If containers aren't running, start them
cd ~/harbor/harbor
docker-compose up -d

# Check firewall rules for ports 80 and 443
sudo ufw status
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw reload

# Verify ports are listening
netstat -tlnp | grep -E ':80|:443'

SSL certificate verify failed

This error means the SSL certificate is invalid, expired, or not properly configured.

Solution:

# Check SSL certificate expiration date
openssl x509 -in /etc/letsencrypt/live/registry.example.com/fullchain.pem -noout -enddate

# Renew certificate if expired
sudo certbot renew

# For self-signed certificates, add to Docker certificate store
sudo mkdir -p /etc/docker/certs.d/registry.example.com
sudo cp /etc/letsencrypt/live/registry.example.com/fullchain.pem \
  /etc/docker/certs.d/registry.example.com/ca.crt

# Restart Docker daemon
sudo systemctl restart docker

unauthorized: authentication required

This error indicates you haven't authenticated or credentials are incorrect.

Solution:

# Check current authentication status
cat ~/.docker/config.json

# Logout and login again
docker logout registry.example.com
docker login -u admin -p YourPassword registry.example.com

# Verify login success with API call
curl -u admin:YourPassword https://registry.example.com/api/v2.0/systeminfo -k

insufficient_scope - project/repo/artifact scope

User doesn't have permission to push images to the target project.

Solution:

# In Harbor web UI, access Projects > myapp > Members
# Add the user with appropriate role
# Assign "Maintainer" or "Developer" role for push access

# User must logout and login again for role changes to take effect
docker logout registry.example.com
docker login -u username -p password registry.example.com

Frequently Asked Questions

How many Docker images can Harbor store?

Harbor's capacity depends primarily on available storage space. The number of images you can store is determined by storage size and individual image dimensions. For reference, an Ubuntu base image is approximately 77 MB while a Node.js image is around 900 MB. With 200 GB storage, you can typically store 200-300 images depending on their sizes. To increase capacity, expand your VPS storage volume and update the Harbor data directory path in the configuration.

Can Harbor work with Kubernetes?

Yes, Harbor integrates seamlessly with Kubernetes. After pushing images to Harbor, configure Kubernetes to pull images by creating an imagePullSecret with your Harbor credentials. Here's the basic setup:

# Create docker-registry secret for Harbor credentials
kubectl create secret docker-registry harbor-secret \
  --docker-server=registry.example.com \
  --docker-username=admin \
  --docker-password=YourPassword \
  [email protected]

# Reference the secret in your Deployment manifest
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  template:
    spec:
      imagePullSecrets:
      - name: harbor-secret
      containers:
      - name: myapp
        image: registry.example.com/myapp/myapp:latest

How do I backup my Harbor registry?

To backup Harbor, you need to preserve the database and image volumes. Here's the backup procedure:

# Stop Harbor services
cd ~/harbor/harbor
docker-compose stop

# Create backup archive
sudo tar czf ~/harbor-backup-$(date +%Y%m%d).tar.gz \
  -C /data registry/ database/

# Restart Harbor services
docker-compose start

# To restore from backup, stop Harbor and extract files
docker-compose stop
sudo rm -rf /data/{registry,database}
sudo tar xzf ~/harbor-backup-20240627.tar.gz -C /data
docker-compose start