What is Harbor?
Harbor is a cloud-native container registry that secures and manages container images for your organization. Initially developed by VMware and now part of the CNCF, Harbor offers features that go well beyond a basic Docker Registry, including:
- Role-Based Access Control (RBAC)
- Vulnerability scanning with Trivy
- LDAP/OIDC authentication
- Replication between registries
- Notary (image signing)
- Garbage collection, retention policies, and quota management
- REST API, CLI, and Web UI
It’s ideal for organizations looking to self-host a secure, enterprise-grade Docker registry, whether for air-gapped environments, Kubernetes clusters, or hybrid cloud setups.
Overview
In this guide, we will install Harbor 2.13.1 on Ubuntu 24.04, using:
- TLS via HAProxy on port 443
- Free HTTPS certificates via Let’s Encrypt (DNS-01) with Cloudflare
- Harbor bound to
127.0.0.1:80
(local access only) - Systemd for startup on boot
- Auto TLS renewal with reload hooks
Prerequisites
- Ubuntu 24.04 server
- DNS:
harbor.maksonlee.com
managed by Cloudflare - Docker + Compose plugin: Install Docker on Ubuntu 24.04
- Port 443 open (port 80 is not required)
Install required packages:
sudo apt update
sudo apt install -y certbot python3-certbot-dns-cloudflare
sudo add-apt-repository ppa:vbernat/haproxy-3.2 -y
sudo apt-get install haproxy=3.2.\*
sudo systemctl enable --now haproxy
- Download and Extract Harbor
curl -LO https://github.com/goharbor/harbor/releases/download/v2.13.1/harbor-online-installer-v2.13.1.tgz
sudo mkdir -p /opt/harbor
sudo tar -xzf harbor-online-installer-v2.13.1.tgz -C /opt/harbor --strip-components=1
- Configure
harbor.yml
sudo cp /opt/harbor/harbor.yml.tmpl /opt/harbor/harbor.yml
sudo vi /opt/harbor/harbor.yml
Set:
hostname: harbor.maksonlee.com
http:
port: 80
external_url: https://harbor.maksonlee.com
- Skip
https:
- HAProxy handles TLS externally.
- Install Harbor
cd /opt/harbor
sudo ./install.sh
- Bind Harbor to
127.0.0.1:80
Edit:
sudo vi /opt/harbor/docker-compose.yml
Change:
ports:
- 127.0.0.1:80:8080
Then restart Harbor:
sudo docker compose down
sudo docker compose up -d
- Cloudflare Token & Certbot Credentials
- Generate Cloudflare Token
- Go to: Cloudflare API Tokens → Create Token
- Use the “Edit zone DNS” template:
- Permissions:
- Zone → DNS → Edit
- Zone Resources:
- Include →
maksonlee.com
- Include →
- Permissions:
- Click Create Token, copy the value.
- Create
cloudflare.ini
sudo vi /etc/letsencrypt/cloudflare.ini
dns_cloudflare_api_token = YOUR_CLOUDFLARE_API_TOKEN
Set strict permissions:
sudo chmod 600 /etc/letsencrypt/cloudflare.ini
- Issue Let’s Encrypt Cert via DNS-01
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials ~/.secrets/certbot/cloudflare.ini \
-d harbor.maksonlee.com
Create combined cert for HAProxy:
sudo mkdir -p /etc/haproxy/certs/
sudo bash -c "cat /etc/letsencrypt/live/harbor.maksonlee.com/fullchain.pem /etc/letsencrypt/live/harbor.maksonlee.com/privkey.pem > /etc/haproxy/certs/harbor.maksonlee.com.pem"
sudo chmod 600 /etc/haproxy/certs/harbor.maksonlee.com.pem
- Configure HAProxy
sudo vi /etc/haproxy/haproxy.cfg
Add:
frontend https_in
bind *:443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1
mode http
default_backend harbor
backend harbor
mode http
option http-buffer-request
option http-keep-alive
option forwardfor
http-request set-header X-Forwarded-Proto https
server harbor1 127.0.0.1:80
Verify and reload:
sudo haproxy -c -f /etc/haproxy/haproxy.cfg
sudo systemctl reload haproxy
- Auto-Renew Deploy Hook
Create a deploy hook:
sudo vi /etc/letsencrypt/renewal-hooks/deploy/reload-haproxy.sh
Paste:
#!/bin/bash
cat "$RENEWED_LINEAGE/fullchain.pem" "$RENEWED_LINEAGE/privkey.pem" > /etc/haproxy/certs/harbor.maksonlee.com.pem
systemctl reload haproxy
Make it executable:
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-haproxy.sh
- Enable Harbor on Boot
Create systemd service:
sudo vi /etc/systemd/system/harbor.service
[Unit]
Description=Harbor Registry
After=network-online.target docker.service
Requires=docker.service
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/harbor
ExecStart=/usr/bin/docker compose up -d
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0
[Install]
WantedBy=multi-user.target
Enable it:
sudo systemctl daemon-reexec
sudo systemctl daemon-reload
sudo systemctl enable --now harbor.service
- Verify Installation
- Open in Browser
Visit:
https://harbor.maksonlee.com
You should see the Harbor UI with a valid HTTPS certificate.
- Docker CLI Login
docker login harbor.maksonlee.com
- Push a Test Image
docker pull ubuntu:24.04
docker tag ubuntu:24.04 harbor.maksonlee.com/library/ubuntu:24.04
docker push harbor.maksonlee.com/library/ubuntu:24.04
Check the Harbor UI → Projects → library → Repositories.