Setting Up Harbor with Let's Encrypt and Cloudflare Tunnel on Ubuntu

Naimul IslamNaimul Islam
3 min read

Harbor is an enterprise-class private container registry with advanced features like RBAC, replication, vulnerability scanning, and more. In this guide, we'll set up Harbor on a Ubuntu machine, secure it with Let's Encrypt certificates, and use Cloudflare Tunnel for the HTTP-01 challenge.


1. System Prerequisites

Make sure you meet the following requirements:

  • Ubuntu 24.04

  • Publicly resolvable domain (e.g., harbor.kcnaiamh.com)

  • Access to your Cloudflare account

  • Root privileges or sudo access

  • Docker engine version 27.5.1

  • Docker compose version 1.29.2

Install Required Tools

sudo apt update && sudo apt install -y curl git unzip apt-transport-https ca-certificates gnupg lsb-release jq docker.io docker-compose openssl tar certbot

2. Install Harbor via Online Installer

Download Harbor Installer

cd ~
curl -s https://api.github.com/repos/goharbor/harbor/releases/latest | grep browser_download_url | cut -d '"' -f 4 | grep '\.tgz$' | tail -1 | wget -i -
tar xf harbor-online-installer-v*.tgz
cd harbor

Prepare the harbor.yml Configuration

cp harbor.yml.tmpl harbor.yml

Edit the following fields in harbor.yml:

hostname: harbor.kcnaiamh.com
https:
  port: 443
  certificate: /etc/letsencrypt/live/harbor.kcnaiamh.com/fullchain.pem
  private_key: /etc/letsencrypt/live/harbor.kcnaiamh.com/privkey.pem

You need to specify your own subdomain here.

You can run the following command to change the required filed without opening the file. Also, don't forget to change harbor.kcnaiamh.com to your own subdomain.

sed -i 's/^hostname: .*/hostname: harbor.kcnaiamh.com/g' harbor.yml
sed -i 's/^http:/# http:/g' harbor.yml
sed -i 's/^  port: 80/  # port: 80/g' harbor.yml
sed -i 's|^  certificate: .*|  certificate: /etc/letsencrypt/live/harbor.kcnaiamh.com/fullchain.pem|g' harbor.yml
sed -i 's|^  private_key: .*|  private_key: /etc/letsencrypt/live/harbor.kcnaiamh.com/privkey.pem|g' harbor.yml

⚠️ Don’t run install.sh yet — we need the certs first.


3. Setup Cloudflare Tunnel (For Let's Encrypt HTTP-01 Challenge)

If you have dedicated public IP address from your ISP then you don't need this step.

Create a Cloudflare Tunnel

  1. Install cloudflared:

    If you don’t have cloudflared installed on your machine, run the following:

# Add cloudflare gpg key
sudo mkdir -p --mode=0755 /usr/share/keyrings
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null

# Add this repo to your apt repositories
echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared any main' | sudo tee /etc/apt/sources.list.d/cloudflared.list

# install cloudflared
sudo apt-get update && sudo apt-get install cloudflared
  1. Setup cloudflared service:

    After you have installed cloudflared on your machine, you can install a service to automatically run your tunnel whenever your machine starts:

sudo cloudflared service install eyJhIjoiNGM1MTIxNmFhNGU2MTU0NWM4OGUxMjExMDk3YTNjNWYiLCJ0IjoiODIyZjU0ZjYtMmRlNi00NjNiLWEzZDYtYzdkOWUxMDAxZTkzIiwicyI6Ik16aGhOMlpsWmpNdE5UUXpNeTAwWW1ZMUxXSmxPRE10TW1Rd1lqVTRZamxsWVdSaSJ9

You will get the token when doing the tunnel setup.

  1. Now setup appropriate subdomain and domain in the cloudflare route tunnel.


4. Get Let's Encrypt Certificate via Certbot

Since HTTP is tunneled through Cloudflare, Certbot's default HTTP challenge will work.

Temporarily Serve HTTP for Challenge

sudo certbot certonly --standalone --preferred-challenges http -d "harbor.kcnaiamh.com" --agree-tos -n -m "naim@gmail.com" --keep-until-expiring

Change subdomain and email address according to yours.

Certs will be saved under:

/etc/letsencrypt/live/harbor.kcnaiamh.com/

5. Start Harbor

🔧 Install Harbor

sudo ./install.sh --with-trivy

Harbor should now be accessible via:

https://harbor.kcnaiamh.com

Default credentials:

  • Username: admin

  • Password: set in harbor.yml (Default pass: Harbor12345)


Optional: Setup Cert Renewal with Systemd Timer

Create /etc/systemd/system/renew-harbor-cert.service:

[Unit]
Description=Renew Let's Encrypt certs and restart Harbor
[Service]
Type=oneshot
ExecStart=/usr/bin/certbot renew --quiet
ExecStartPost=/opt/harbor/prepare
ExecStartPost=/opt/harbor/install.sh

Create the timer /etc/systemd/system/renew-harbor-cert.timer:

[Unit]
Description=Timer for cert renewal

[Timer]
OnCalendar=weekly
Persistent=true

[Install]
WantedBy=timers.target

Enable it:

sudo systemctl daemon-reexec
sudo systemctl enable --now renew-harbor-cert.timer

Clean Up

To delete the certificate, run the following command:

sudo certbot delete --cert-name harbor.kcnaiamh.com

Final Thoughts

Using Cloudflare Tunnel with Let's Encrypt offers a neat workaround for systems behind NAT or without public IPs. Combined with Harbor, this makes a secure and professional-grade private registry feasible on even home labs.

If you're using Harbor in production, consider:

  • Enabling RBAC & LDAP

  • Enabling replication for DR

0
Subscribe to my newsletter

Read articles from Naimul Islam directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Naimul Islam
Naimul Islam