Harbor is deployed as several Docker containers. You can therefore deploy it on any Linux distribution that supports Docker. The target host requires Docker, and Docker Compose to be installed.
Prerequisites
Hardware
The following table lists the minimum and recommended hardware configurations for deploying Harbor.
Resource | Minimum | Recommended |
---|---|---|
CPU | 2 CPU | 4 CPU |
Memory | 4 GB | 8 GB |
Disk | 40 GB | 160 GB |
Software
The following table lists the software versions that must be installed on the target host.
Software | Version | Description |
---|---|---|
Docker engine | Version 17.06.0-ce+ or higher | For installation instructions, see Docker Engine documentation |
Docker Compose | Version 1.18.0 or higher | For installation instructions, see Docker Compose documentation |
Openssl | Latest is preferred | Used to generate certificate and keys for Harbor |
Network Ports
Harbor requires that the following ports be open on the target host.
Port | Protocol | Description |
---|---|---|
443 | HTTPS | Harbor portal and core API accept HTTPS requests on this port. You can change this port in the configuration file. |
80 | HTTP | Harbor portal and core API accept HTTP requests on this port. You can change this port in the configuration file. |
Launch an EC2 Instance
- AWS Account and Login
- If you don’t have an AWS account, sign up at AWS Sign Up.
- Log in to the AWS Management Console.
- Navigate to EC2 Dashboard
- Choose an Amazon Machine Image (AMI)
- Click "Launch Instance."
- In the AMI selection screen, search for "Ubuntu 24.04".
- Choose an Instance Type
- Select the
t3.medium
instance type. - Click "Next: Configure Instance Details."
- Select/Create a Key Pair
- Select "Create a new key pair."
- Name the key pair.
- Download the key pair file (.pem) and store it securely.
- Network Settings
- Use the default settings.
- Ensure you have selected the correct VPC and subnet.
- Configure Security Group
- Create a new security group.
- Set the security group name and description.
- Add a rule to allow SSH, HTTP, & HTTPS Traffic:
- SSH
- Type: ssh
- Protocol: TCP
- Port Range : 22
- Source: Anywhere
- HTTP
- Type: HTTP
- Protocol: TCP
- Port Range : 80
- Source: Anywhere
- HTTPS
- Type: HTTPS
- Protocol: TCP
- Port Range : 443
- Source: Anywhere
- SSH
- Add Storage
- Modify the root volume size to 40 GB.
- Add Second volume with the size 40 GB.
- Review Instance Launch
- Review all configurations.
- Click "Launch."
Install Docker
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo usermod -aG docker $USER
Setup Second Disk
- Create Partition
lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
loop0 7:0 0 25.2M 1 loop /snap/amazon-ssm-agent/7993
loop1 7:1 0 55.7M 1 loop /snap/core18/2829
loop2 7:2 0 38.8M 1 loop /snap/snapd/21759
nvme0n1 259:0 0 40G 0 disk
├─nvme0n1p1 259:2 0 39G 0 part /
├─nvme0n1p14 259:3 0 4M 0 part
├─nvme0n1p15 259:4 0 106M 0 part /boot/efi
└─nvme0n1p16 259:5 0 913M 0 part /boot
nvme1n1 259:1 0 40G 0 disk
Command (m for help): n
Partition type
p primary (0 primary, 0 extended, 4 free)
e extended (container for logical partitions)
Select (default p): p
Partition number (1-4, default 1):
First sector (2048-83886079, default 2048):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-83886079, default 83886079):
Created a new partition 1 of type 'Linux' and of size 40 GiB.
Command (m for help): t
Selected partition 1
Hex code or alias (type L to list all): 8e
Changed type of partition 'Linux' to 'Linux LVM'.
Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
loop0 7:0 0 25.2M 1 loop /snap/amazon-ssm-agent/7993
loop1 7:1 0 55.7M 1 loop /snap/core18/2829
loop2 7:2 0 38.8M 1 loop /snap/snapd/21759
nvme0n1 259:0 0 40G 0 disk
├─nvme0n1p1 259:2 0 39G 0 part /
├─nvme0n1p14 259:3 0 4M 0 part
├─nvme0n1p15 259:4 0 106M 0 part /boot/efi
└─nvme0n1p16 259:5 0 913M 0 part /boot
nvme1n1 259:1 0 40G 0 disk
└─nvme1n1p1 259:6 0 40G 0 part
- Create LVM
# Create PV
pvcreate /dev/nvme1n1p1
# Create VG
vgcreate harbor_vg /dev/nvme1n1p1
# Create LV
lvcreate -n harbor_lv -l 100%FREE harbor_vg
# Format LVM to XFS
mkfs.xfs /dev/mapper/harbor_vg-harbor_lv
- Create & Mount Directory
mkdir /data
mount -t xfs /dev/mapper/harbor_vg-harbor_lv /data/
nano /etc/fstab
---
/dev/mapper/harbor_vg-harbor_lv /data xfs defaults 0 0
---
systemctl daemon-reload
mount -a
df -hT
lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
loop0 7:0 0 25.2M 1 loop /snap/amazon-ssm-agent/7993
loop1 7:1 0 55.7M 1 loop /snap/core18/2829
loop2 7:2 0 38.8M 1 loop /snap/snapd/21759
nvme0n1 259:0 0 40G 0 disk
├─nvme0n1p1 259:2 0 39G 0 part /
├─nvme0n1p14 259:3 0 4M 0 part
├─nvme0n1p15 259:4 0 106M 0 part /boot/efi
└─nvme0n1p16 259:5 0 913M 0 part /boot
nvme1n1 259:1 0 40G 0 disk
└─nvme1n1p1 259:6 0 40G 0 part
└─harbor_vg-harbor_lv 252:0 0 40G 0 lvm /data
Deploy Harbor
# Download Harbor Installer
wget https://github.com/goharbor/harbor/releases/download/v2.11.0/harbor-online-installer-v2.11.0.tgz
tar xvfz harbor-online-installer-v2.11.0.tgz
cd harbor/
# Edit harbor.yml
cp harbor.yml.tmpl harbor.yml
nano harbor.yml
---
hostname: registry.yourdomain.com
http:
port: 80
https:
port: 443
certificate: /your/certificate/path
private_key: /your/private/key/path
harbor_admin_password: StR0N9p@S5WORD!
database:
password: StR0N9p@S5WORD!
data_volume: /data
# Run harbor prepare with trivy
./prepare --with-trivy
# Start harbor service with docker compose
docker compose up -d
Operasional Test Pull and Push Image
docker login registry.yourdomain.com
docker pull nginx:alpine
docker tag nginx:alpine registry.yourdomain.com/library/nginx:alpine
docker push registry.yourdomain.com/library/nginx:alpine
Trust Private SSL Certificate?
Here's an example workaround if you are using a private SSL certificate for Harbor where you need to manually trust the certificate.
- Linux
cat /your/ca-certificate/path >> /etc/ssl/certs/ca-certificates.crt
curl https://registry.yourdomain.com
- Docker
mkdir -p /etc/docker/certs.d/registry.yourdomain.com/
cp ca.crt /etc/docker/certs.d/registry.yourdomain.com/
systemctl restart docker
docker login registry.yourdomain.com
- Containerd
cp ca.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates
sudo systemctl restart containerd
- Cri-o
nano /etc/crio/crio.conf
---
[crio.image]
insecure_registries = [ "registry.yourdomain.com"
]
---
nano /etc/crio/crio.conf.d/registries.conf
---
# insecure_registries is used to skip TLS verification when pulling images.
insecure_registries = [
"https://registry.yourdomain.com"
]
# registries is used to specify a comma separated list of registries to be used
# when pulling an unqualified image (e.g. fedora:rawhide).
registries = [
"docker.io",
"https://registry.yourdomain.com"
]
---
crictl pull --creds "admin:StR0N9p@S5WORD!" registry.yourdomain.com/library/nginx:alpine
- RKE2
nano /etc/rancher/rke2/registries.yaml
---
mirrors:
registry.yourdomain.com:
endpoint:
- "https://registry.yourdomain.com"
configs:
"registry.yourdomain.com":
tls:
cert_file: "/etc/ssl/private/registry.yourdomain.com/registry.yourdomain.com.crt"
key_file: "/etc/ssl/private/registry.yourdomain.com/registry.yourdomain.com.key"
ca_file: "/etc/ssl/private/registry.yourdomain.com/ca.crt"
insecure_skip_verify: true
---
# For master nodes
systemctl restart rke2-server
# For worker and ingress nodes
systemctl restart rke2-agent
cat << EOF > test-pull.yaml
apiVersion: v1
kind: Pod
metadata:
name: test-harbor
spec:
containers:
- name: test-harbor-nginx
image: registry.yourdomain.com/nginx:alpine
EOF
kubectl apply -f test-pull.yaml
Renew Certificate
- Get your new certificate
- Stop Harbor:
sudo docker-compose down
- Edit harbor.yml, replace your old certificate w new certificate
- Re-run prepare command and redeploy harbor:
./prepare --with-trivy
- Redeploy Harbor:
docker-compose up -d