How to install Harbor Container Registry Installation on Debian 13
This guide installs Harbor on Debian 13 using the official Harbor installer and Docker Compose.
Harbor is an open-source OCI/container registry that provides:
Private Docker / OCI registry
Projects and repositories
Role-based access control
Vulnerability scanning
Image replication
Robot accounts
OIDC / LDAP authentication
Retention policies
Image signing and verification
Web administration portal
Harbor is a CNCF Graduated project and can be used as a private registry for Docker, Podman, Kubernetes, K3s, CI/CD pipelines, and other OCI-compatible clients. (Harbor)
Architecture
A basic Harbor deployment looks like:
Developers / CI/CD
│
│ HTTPS :443
▼
registry.example.com
│
▼
┌─────────────────────┐
│ Harbor │
│ │
│ Portal │
│ Core │
│ Registry │
│ Job Service │
│ PostgreSQL │
│ Redis │
│ Trivy (optional) │
└──────────┬──────────┘
│
▼
/data
│
Container Images
Harbor 2.14 can be installed on a Docker host using Docker Compose, or deployed on Kubernetes using Helm. (Harbor)
System Requirements
Harbor's official requirements for a Docker Compose deployment are: (Harbor)
| Resource | Minimum | Recommended |
|---|---|---|
| CPU | 2 cores | 4 cores |
| Memory | 4 GB | 8 GB |
| Disk | 40 GB | 160 GB |
For a production registry, I recommend:
CPU: 4+ cores
RAM: 8 GB+
OS Disk: 40 GB+
Registry: 200 GB+ depending on images
Storage: SSD / RAID / Object Storage
Network: Gigabit Ethernet+
The registry storage requirement depends primarily on:
Number of images
Image sizes
Number of tags
Build frequency
Retention policy
Replication
Vulnerability scanning
Software Requirements
Harbor 2.14 officially requires: (Harbor)
Docker Engine > 20.10
Docker Compose > 2.3
OpenSSL Latest (optional)
Verify:
docker --version
docker compose version
openssl version
Network Requirements
Harbor normally requires:
80/TCP HTTP
443/TCP HTTPS
These ports can be changed in harbor.yml. (Harbor)
For production:
443/TCP Required
80/TCP Optional / HTTP redirect
1. Install Required Packages
sudo apt update
sudo apt install -y \
curl \
wget \
tar \
openssl
Docker Engine & Docker Compose
This application requires Docker Engine and Docker Compose v2.
Check whether Docker is already installed:
docker --version
docker compose version
If both commands return valid versions, continue with the installation.
If Docker is not installed, install it first using the Docker installation guide:
Quick Docker installation:
curl -fsSL https://get.docker.com | sudo sh
Enable and start Docker:
sudo systemctl enable --now docker
Optionally allow the current user to run Docker without sudo:
sudo usermod -aG docker $USER
Then log out and log back in, or run:
newgrp docker
Verify:
docker --version
docker compose version
docker run --rm hello-world
Note: Membership in the
dockergroup grants effectively root-level privileges. Only trusted users should be added.
2. Create Harbor Directory
sudo mkdir -p /opt/harbor
sudo chown $USER:$USER /opt/harbor
cd /opt/harbor
3. Download Harbor Installer
Harbor provides two official installer types: (Harbor)
Online Installer
Offline Installer
Online Installer
Use this when the Harbor server has Internet access.
The installer itself is small and downloads the required Harbor images during installation.
Offline Installer
Use this when:
Harbor server has no Internet access
Air-gapped environment
Pre-download of all Harbor images is required
The offline installer contains the required container images and is therefore significantly larger. (Harbor)
Download Example
Go to the official Harbor releases page and download the required release.
For example, for Harbor 2.14.x:
wget https://github.com/goharbor/harbor/releases/download/v<VERSION>/harbor-online-installer-v<VERSION>.tgz
Example structure:
harbor-online-installer-v2.14.x.tgz
or:
harbor-offline-installer-v2.14.x.tgz
Replace
<VERSION>with the exact Harbor release you intend to deploy rather than blindly using an old example version.
Harbor's official documentation recommends downloading either the online or offline installer from the Harbor releases page. (Harbor)
4. Extract Harbor
Example:
tar -xzf harbor-online-installer-v<VERSION>.tgz
Move into the directory:
cd harbor
Check:
ls
Typical contents:
harbor.yml.tmpl
install.sh
prepare
common.sh
LICENSE
The offline installer additionally contains:
harbor.v<VERSION>.tar.gz
5. Create Harbor Configuration
Copy the template:
cp harbor.yml.tmpl harbor.yml
Edit:
nano harbor.yml
Harbor requires at minimum that you configure the:
hostname:
property. (Harbor)
Basic HTTP Configuration
For an internal test environment:
hostname: harbor.example.local
http:
port: 80
harbor_admin_password: CHANGE_THIS_PASSWORD
database:
password: CHANGE_DATABASE_PASSWORD
data_volume: /data
Harbor's official documentation states that plain HTTP should only be used for air-gapped test or development environments. Production deployments should use HTTPS. (Harbor)
Recommended HTTPS Configuration
For production:
hostname: registry.example.com
http:
port: 80
https:
port: 443
certificate: /data/cert/registry.example.com.crt
private_key: /data/cert/registry.example.com.key
harbor_admin_password: CHANGE_THIS_ADMIN_PASSWORD
database:
password: CHANGE_THIS_DATABASE_PASSWORD
data_volume: /data
Generate Strong Passwords
For example:
openssl rand -base64 32
Generate one for:
harbor_admin_password
and another for:
database.password
Do not reuse them.
Important Harbor Password
The initial administrator username is:
admin
The password comes from:
harbor_admin_password:
Example:
harbor_admin_password: VeryStrongRandomPassword
After Harbor is installed, use:
Username: admin
Password: <harbor_admin_password>
Data Storage
The default persistent data location is commonly:
data_volume: /data
Create it:
sudo mkdir -p /data
Check disk space:
df -h /data
A production registry should have sufficient space for container images and database growth.
Recommended Storage Layout
/
├── opt/
│ └── harbor/
│ └── harbor/
│ ├── harbor.yml
│ ├── install.sh
│ └── docker-compose.yml
│
└── data/
├── registry/
├── database/
├── redis/
├── job_logs/
├── secret/
└── ca_download/
Keep:
/opt/harbor
for installation/configuration files and:
/data
for persistent Harbor data.
HTTPS Configuration
For production, use a certificate issued by:
Let's Encrypt
Internal Enterprise CA
DigiCert
Sectigo
GoDaddy
Other trusted CA
Harbor's documentation explicitly recommends a trusted third-party certificate for production deployments. (Harbor)
6. Create Certificate Directory
sudo mkdir -p /data/cert
For example:
/data/cert/registry.example.com.crt
/data/cert/registry.example.com.key
Set permissions:
sudo chmod 600 /data/cert/registry.example.com.key
Example with Let's Encrypt
If your certificates already exist:
/etc/letsencrypt/live/registry.example.com/fullchain.pem
/etc/letsencrypt/live/registry.example.com/privkey.pem
you can reference them directly:
https:
port: 443
certificate: /etc/letsencrypt/live/registry.example.com/fullchain.pem
private_key: /etc/letsencrypt/live/registry.example.com/privkey.pem
Or copy/manage them under:
/data/cert/
according to your certificate-renewal architecture.
Self-Signed Certificate
For an internal Harbor registry, you can use your own CA.
Harbor provides an official procedure for creating:
CA certificate
Server certificate
Server private key
using OpenSSL. (Harbor)
Example CA private key:
openssl genrsa -out ca.key 4096
Create CA:
openssl req \
-x509 \
-new \
-nodes \
-sha512 \
-days 3650 \
-key ca.key \
-out ca.crt
Create server key:
openssl genrsa \
-out registry.example.com.key \
4096
Create CSR:
openssl req \
-sha512 \
-new \
-key registry.example.com.key \
-out registry.example.com.csr
Make sure the resulting server certificate contains the registry hostname in its Subject Alternative Name (SAN).
Harbor's HTTPS documentation requires SAN-compliant certificates for modern clients. (Harbor)
Copy Certificates
sudo cp registry.example.com.crt /data/cert/
sudo cp registry.example.com.key /data/cert/
Then configure:
https:
port: 443
certificate: /data/cert/registry.example.com.crt
private_key: /data/cert/registry.example.com.key
7. Install Harbor
Harbor's official installer uses:
sudo ./install.sh
after harbor.yml has been configured. (Harbor)
Run:
sudo ./install.sh
The installer generates the Docker Compose configuration and starts Harbor.
Install Harbor with Trivy
The default installation does not include Trivy. Harbor supports installing it using the optional installer flag. (Harbor)
For a production container registry, I recommend enabling Trivy:
sudo ./install.sh --with-trivy
Trivy provides container image vulnerability scanning.
Architecture:
Image pushed
│
▼
Harbor Registry
│
▼
Trivy Scanner
│
▼
Vulnerability Report
Recommended Installation Command
For most production installations:
sudo ./install.sh --with-trivy
8. Check Harbor Containers
docker compose ps
Harbor runs as several Docker containers. (Harbor)
You should see components similar to:
harbor-core
harbor-db
harbor-jobservice
harbor-log
harbor-portal
nginx
redis
registry
registryctl
trivy-adapter
Check:
docker ps
All required services should be:
Up
Harbor's troubleshooting documentation recommends docker compose ps as the first check when services fail to start. (Harbor)
9. Open Harbor
Open:
https://registry.example.com
Login:
Username: admin
Password: <harbor_admin_password>
DNS
Create:
registry.example.com
│
▼
Harbor Server IP
For example:
Type: A
Name: registry
Value: 163.53.181.162
Internal deployments can instead resolve:
registry.example.local
through internal DNS.
Firewall
For HTTPS:
sudo ufw allow 443/tcp
Optionally allow HTTP:
sudo ufw allow 80/tcp
Check:
sudo ufw status
Production clients normally need only:
443/TCP
Harbor's documented network ports are HTTP 80 and HTTPS 443, unless overridden in harbor.yml. (Harbor)
Test Docker Login
From a Docker client:
docker login registry.example.com
Enter:
Username: admin
Password: ********
Expected:
Login Succeeded
Create Harbor Project
Open:
Projects
→ New Project
Example:
Project Name:
xeon
You then have:
registry.example.com/xeon/
for container images.
Push Docker Image
Pull an image:
docker pull nginx:alpine
Tag it:
docker tag \
nginx:alpine \
registry.example.com/xeon/nginx:alpine
Push:
docker push \
registry.example.com/xeon/nginx:alpine
Image path:
registry.example.com/xeon/nginx:alpine
Pull Image
docker pull \
registry.example.com/xeon/nginx:alpine
ASP.NET Core Image Example
Suppose your application image is:
myCompanyApp-api:latest
Tag:
docker tag \
myCompanyApp-api:latest \
registry.example.com/erp/myCompanyApp-api:latest
Push:
docker push \
registry.example.com/erp/myCompanyApp-api:latest
Kubernetes/K3s can then pull:
registry.example.com/erp/myCompanyApp-api:latest
Podman Login
Harbor also works with Podman.
podman login registry.example.com
Push:
podman push \
registry.example.com/xeon/application:latest
Kubernetes / K3s Registry Authentication
Create an image pull secret:
kubectl create secret docker-registry harbor-registry \
--docker-server=registry.example.com \
--docker-username=USERNAME \
--docker-password=PASSWORD \
[email protected]
Then:
spec:
imagePullSecrets:
- name: harbor-registry
Example:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myCompanyApp-api
spec:
template:
spec:
imagePullSecrets:
- name: harbor-registry
containers:
- name: myCompanyApp-api
image: registry.example.com/erp/myCompanyApp-api:latest
For automated systems, prefer a Harbor Robot Account rather than using the Harbor administrator account.
Robot Accounts
Harbor robot accounts are designed for:
GitHub Actions
GitLab CI
Jenkins
Kubernetes
K3s
Argo CD
Automated deployments
Build servers
Example architecture:
GitHub Actions
│
│ Robot credentials
▼
Harbor
│
▼
registry.example.com/erp
Create from:
Project
→ Robot Accounts
→ New Robot Account
Give only the permissions required by the CI/CD system.
For example:
Pull Repository
Push Repository
Avoid using:
admin
credentials in CI/CD pipelines.
GitHub Actions Example
Store:
HARBOR_USERNAME
HARBOR_PASSWORD
as repository secrets.
Then:
- name: Login to Harbor
uses: docker/login-action@v3
with:
registry: registry.example.com
username: ${{ secrets.HARBOR_USERNAME }}
password: ${{ secrets.HARBOR_PASSWORD }}
- name: Build and Push
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: registry.example.com/erp/myCompanyApp-api:latest
Prefer a Harbor robot account for these credentials.
Vulnerability Scanning with Trivy
If Harbor was installed with:
sudo ./install.sh --with-trivy
you can scan repositories for vulnerabilities.
Typical flow:
Container Image
│
▼
Harbor
│
▼
Trivy
│
├── Critical
├── High
├── Medium
└── Low
Projects can also be configured to prevent vulnerable artifacts from being pulled based on your security policy.
Image Retention
Container registries can grow quickly.
Example:
myCompanyApp-api
│
├── build-1001
├── build-1002
├── build-1003
├── build-1004
├── ...
└── build-4500
Configure:
Project
→ Policy
→ Tag Retention
Example policy:
Keep latest 20 images
or:
Keep artifacts pushed during the last 30 days
Retention policies help control storage consumption.
Garbage Collection
Deleting image tags does not necessarily immediately reclaim all registry storage.
Use Harbor's:
Administration
→ Clean Up
→ Garbage Collection
to reclaim unused artifact storage.
A typical schedule might be:
Weekly
during a low-traffic maintenance window.
Replication
Harbor supports registry replication.
Example:
Harbor Bangladesh
│
│ Replication
▼
Harbor Singapore
or:
Harbor
│
├── Docker Hub
├── Another Harbor
└── Other supported registries
Harbor supports third-party replication adapters as part of its registry ecosystem. (Harbor)
LDAP / Active Directory
Harbor can use external authentication such as:
LDAP
Active Directory
OIDC
Configure from:
Administration
→ Configuration
→ Authentication
For enterprise environments, OIDC can be used with an identity provider such as authentik.
Example:
Users
│
▼
authentik
│ OIDC
▼
Harbor
Harbor Behind Reverse Proxy
Harbor includes its own nginx component.
A standard deployment can therefore expose:
443
directly.
If another reverse proxy is placed in front:
Internet
│
▼
Nginx / HAProxy
│
▼
Harbor
ensure that:
Large request bodies are allowed
Long upload timeouts are supported
HTTPS scheme/headers are preserved
Docker Registry API paths are forwarded
Container layers can be several gigabytes, so ordinary website reverse-proxy upload limits may cause failed pushes.
Self-Signed Certificate on Docker Clients
When Harbor uses an internal CA, Docker clients must trust that CA.
Create:
sudo mkdir -p \
/etc/docker/certs.d/registry.example.com
Copy CA:
sudo cp ca.crt \
/etc/docker/certs.d/registry.example.com/ca.crt
Restart Docker:
sudo systemctl restart docker
Then:
docker login registry.example.com
Harbor's official HTTPS documentation describes installing registry trust material under /etc/docker/certs.d/<registry>/. (Harbor)
Registry with Non-Standard Port
Suppose Harbor uses:
registry.example.com:8443
The Docker certificate directory must include the port:
/etc/docker/certs.d/registry.example.com:8443/
For example:
/etc/docker/certs.d/
└── registry.example.com:8443/
└── ca.crt
Harbor's official HTTPS documentation explicitly notes this requirement for non-default ports. (Harbor)
Harbor Service Management
Go to the Harbor installer directory:
cd /opt/harbor/harbor
Check:
docker compose ps
Stop:
docker compose down
Start:
docker compose up -d
Restart:
docker compose restart
Logs:
docker compose logs
Follow:
docker compose logs -f
Reconfigure Harbor
Edit:
nano harbor.yml
Then regenerate configuration:
sudo ./prepare
Recreate:
docker compose down
docker compose up -d
The prepare utility regenerates Harbor's runtime configuration from harbor.yml. Harbor documents this workflow when reconfiguring an existing deployment. (Harbor)
Harbor Logs
Check all logs:
docker compose logs
Core:
docker compose logs harbor-core
Registry:
docker compose logs registry
Database:
docker compose logs harbor-db
Trivy:
docker compose logs trivy-adapter
Follow:
docker compose logs -f
Check Storage
sudo du -sh /data
Registry:
sudo du -sh /data/registry
Database:
sudo du -sh /data/database
Check filesystem:
df -h
Registry servers should be monitored carefully for low disk space.
Backup
Important Harbor data includes:
/data
harbor.yml
Certificates
Database
Registry artifacts
Secrets
At minimum:
sudo tar \
-czf harbor-config-backup.tar.gz \
/opt/harbor/harbor/harbor.yml \
/data/cert
For a complete backup strategy, include the database and registry storage.
Harbor's upgrade documentation explicitly instructs administrators to back up both the Harbor installation files and the database before an upgrade. (Harbor)
Upgrade Harbor
Do not simply replace the Harbor image versions in the generated Compose file.
Harbor upgrades may require:
Configuration migration
Database migration
New installer
Updated harbor.yml
The official upgrade procedure for Harbor 2.14 begins by stopping Harbor and backing up the installation and database before migration. (Harbor)
Typical high-level process:
1. Back up Harbor
2. Back up /data/database
3. Download newer Harbor installer
4. Migrate harbor.yml
5. Run prepare/migration
6. Start new Harbor version
7. Verify repositories and users
Always follow the official migration guide for the exact source and target versions.
Recommended Production Configuration
Example:
hostname: registry.example.com
http:
port: 80
https:
port: 443
certificate: /data/cert/registry.example.com.crt
private_key: /data/cert/registry.example.com.key
harbor_admin_password: CHANGE_TO_STRONG_PASSWORD
database:
password: CHANGE_TO_DIFFERENT_STRONG_PASSWORD
data_volume: /data
Install:
sudo ./install.sh --with-trivy
Recommended Production Architecture
Internet / Private WAN
│
▼
registry.example.com
│
HTTPS :443
│
▼
┌────────────────────┐
│ Harbor │
│ │
│ Portal │
│ Core │
│ Registry │
│ Job Service │
│ Trivy │
│ Redis │
│ PostgreSQL │
└─────────┬──────────┘
│
▼
/data
│
┌───────────┴───────────┐
│ │
▼ ▼
Registry Data Database
Clients:
GitHub Actions ──┐
│
Docker ──────────┤
│
Podman ──────────┼──→ Harbor
│
K3s ─────────────┤
│
Kubernetes ──────┘
Quick Installation
Install dependencies:
sudo apt update
sudo apt install -y \
wget \
curl \
tar \
openssl
Download the Harbor installer:
wget https://github.com/goharbor/harbor/releases/download/v<VERSION>/harbor-online-installer-v<VERSION>.tgz
Extract:
tar -xzf harbor-online-installer-v<VERSION>.tgz
cd harbor
Create configuration:
cp harbor.yml.tmpl harbor.yml
Edit:
nano harbor.yml
Configure:
hostname: registry.example.com
https:
port: 443
certificate: /data/cert/registry.example.com.crt
private_key: /data/cert/registry.example.com.key
harbor_admin_password: YOUR_STRONG_PASSWORD
database:
password: YOUR_DATABASE_PASSWORD
data_volume: /data
Install with Trivy:
sudo ./install.sh --with-trivy
Check:
docker compose ps
Open:
https://registry.example.com
Login:
Username: admin
Password: <harbor_admin_password>
Test Registry
Login:
docker login registry.example.com
Pull:
docker pull nginx:alpine
Tag:
docker tag \
nginx:alpine \
registry.example.com/library/nginx:alpine
Push:
docker push \
registry.example.com/library/nginx:alpine
Pull back:
docker pull \
registry.example.com/library/nginx:alpine
Recommended Security Checklist
- [ ] Use HTTPS in production.
- [ ] Use a trusted TLS certificate where possible.
- [ ] Do not use the default/example administrator password.
- [ ] Use a different strong database password.
- [ ] Protect
harbor.yml. - [ ] Keep
/dataon reliable persistent storage. - [ ] Back up the Harbor database.
- [ ] Back up registry data.
- [ ] Enable Trivy vulnerability scanning.
- [ ] Use robot accounts for CI/CD.
- [ ] Do not use the
adminaccount in GitHub Actions or Kubernetes. - [ ] Configure retention policies.
- [ ] Configure garbage collection.
- [ ] Monitor available disk space.
- [ ] Keep Harbor updated.
- [ ] Follow the official migration guide before upgrades.
- [ ] Restrict Harbor's management access where appropriate.
- [ ] Use OIDC/LDAP for centralized enterprise authentication where appropriate.
References
Harbor 2.14 officially supports Docker Compose deployments and documents minimum resources of 2 CPU, 4 GB RAM, and 40 GB disk, with 4 CPU, 8 GB RAM, and 160 GB disk recommended. It requires Docker Engine newer than 20.10 and Docker Compose newer than 2.3. (Harbor)
Harbor provides both online and offline installers. The online installer downloads Harbor container images during installation, while the offline installer packages the required images for disconnected environments. (Harbor)
The standard Harbor installation process is to download the installer, configure HTTPS, configure harbor.yml, and run install.sh; the default installation excludes Trivy, while --with-trivy installs Harbor with vulnerability scanning. (Harbor)
Harbor strongly recommends HTTPS for production environments and supports either trusted third-party certificates or self-signed certificates for internal environments. (Harbor)





