Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Harbor: Private Container Registry

By Kokil Thapa | Last reviewed: September 2026

Your CI pipeline builds images every deploy. Pushing them to a public hub is a bad default. A Harbor: Private Container Registry gives you a self-hosted store for Docker and OCI images with RBAC, vulnerability scanning, replication, and retention policies. I've used private registries on production Linux servers where small teams need control without paying per-seat SaaS fees. This guide covers architecture, install steps, CI wiring, and the operational gotchas that bite after go-live. For broader context, see our container registry comparison across Docker Hub, GitLab, and ECR.

What is Harbor and why do teams choose a private container registry?

Harbor is an open-source registry built on the OCI Distribution Specification. It wraps the core push/pull API with a web UI, LDAP/OIDC auth, robot accounts, webhooks, and policy engines. You run it on your own VPS, on-prem rack, or private cloud.

Public hubs leak metadata. They also rate-limit pulls. For a law-firm portal or booking app on shared EC2, that friction shows up during deploys. Harbor keeps images inside your network boundary. Pulls stay fast. Tags stay private.

Harbor adds features the basic self-hosted Docker Registry lacks out of the box. You get project-level isolation, immutable tags, garbage-collection scheduling, and built-in scanning hooks. That matters when compliance asks who pushed what and when.

Harbor Private Container RegistryCI PipelineGitLab / JenkinsHarbor CoreRegistry + RBAC + UITrivy ScannerCVE reportsPostgreSQLMetadata storeRedisJob cacheRuntime ClusterDocker hosts / Kubernetes nodes pull images
Harbor private container registry architecture: CI pushes images, Harbor stores blobs and metadata, Trivy scans layers, runtimes pull on deploy.

Core Harbor components

  • Core service — API, auth, project management, replication rules.
  • Registry — OCI-compatible blob storage (local disk or S3-compatible backend).
  • Job service — Async tasks: scan, replicate, GC, webhooks.
  • Portal — Web UI for admins and developers.
  • Scanner adapter — Usually Trivy for CVE detection.

Harbor fits teams that outgrow a single-node registry but do not want full cloud lock-in. It also pairs well with containerd as the runtime on Ubuntu hosts you already manage.

How do you install Harbor on Ubuntu for a production-ready private registry?

Harbor ships as a Docker Compose bundle. You prepare TLS, run the installer, then tune harbor.yml. Plan disk early. Image layers add up fast on active CI pipelines.

Prerequisites

  1. Ubuntu 22.04 or 24.04 VM with 4 vCPU, 8 GB RAM minimum for small teams.
  2. Docker Engine and Docker Compose plugin installed.
  3. A DNS A record, e.g. registry.example.com, pointing at the server.
  4. TLS certificate — Let's Encrypt via Certbot works on port 443.
  5. Open ports 443 (Harbor UI/registry) and 80 only if you redirect HTTP.

Install steps

Download the official offline or online installer from the Harbor release page. Extract and edit config before the first run.

# Example paths on Ubuntu
cd /opt
wget https://github.com/goharbor/harbor/releases/download/v2.11.0/harbor-online-installer-v2.11.0.tgz
tar xzvf harbor-online-installer-v2.11.0.tgz
cd harbor

cp harbor.yml.tmpl harbor.yml
nano harbor.yml

Set hostname, HTTPS cert paths, and admin password in harbor.yml. Enable Trivy in the installer flags if you want scanning from day one.

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

# data volume — use a dedicated mount
data_volume: /data/harbor

Run the installer with the Trivy scanner included.

sudo ./install.sh --with-trivy

Log in at https://registry.example.com. Change the default admin password immediately. Create a project per app or per environment. Set the project to private unless you have a deliberate public mirror.

On real client infrastructure I treat Harbor like any other production service. Backups cover /data/harbor and the Postgres volume. Cert renewal goes into cron. UFW allows 443 from deploy runners and cluster nodes only. That mirrors how I harden other Linux production servers.

How does Harbor compare to Docker Registry, GitLab, and cloud ECR?

Not every team needs Harbor. A plain registry suffices for a solo developer. Cloud ECR wins when you live entirely inside AWS. Harbor shines when you want one private hub across mixed environments.

CriteriaHarborDocker DistributionGitLab Container RegistryAWS ECR
Self-hosted controlFullFullWith GitLabManaged
Built-in UI & RBACYesNo (needs add-ons)YesIAM-based
Vulnerability scanningTrivy built-inNoWith Ultimate tierECR scanning
Cross-registry replicationYesNoLimitedReplication rules
Operational overheadMediumLowLow if GitLab existsLow
Cost modelInfra + ops timeInfra onlyLicense / SaaSPer-GB + pull

For a side-by-side of public and managed options, our Docker Hub vs GitLab vs ECR guide fills in pricing and pull-limit details Harbor does not address.

Verdict: choose Harbor when you need enterprise-style registry features on your own metal or VPS. Skip it if GitLab already hosts your repos and images. Skip it if you are all-in on one cloud registry and never replicate elsewhere.

When to Pick HarborNeed private images?Single app, low riskPlain Docker RegistryScan + RBAC neededChoose HarborAlready on GitLab CI?Use GitLab registry firstMulti-cloud or air-gapHarbor wins
Decision tree for Harbor private container registry: scanning, RBAC, and multi-environment replication tilt the choice toward Harbor.

How do you push and pull images to Harbor from CI/CD pipelines?

Harbor speaks the standard Docker Registry HTTP API V2. Any tool that supports docker push works. Use robot accounts for CI. Never embed personal user passwords in pipeline variables.

Create a robot account

  1. In Harbor UI, open your project → Robot Accounts.
  2. Create a robot with push and pull permissions scoped to that project.
  3. Copy the generated token once. Harbor will not show it again.

GitLab CI example

variables:
  HARBOR_REGISTRY: registry.example.com
  HARBOR_PROJECT: myapp
  IMAGE_NAME: $HARBOR_REGISTRY/$HARBOR_PROJECT/api

build-and-push:
  stage: deploy
  image: docker:27-cli
  services:
    - docker:27-dind
  before_script:
    - echo "$HARBOR_ROBOT_TOKEN" | docker login $HARBOR_REGISTRY -u "$HARBOR_ROBOT_NAME" --password-stdin
  script:
    - docker build -t $IMAGE_NAME:$CI_COMMIT_SHA .
    - docker push $IMAGE_NAME:$CI_COMMIT_SHA
    - docker tag $IMAGE_NAME:$CI_COMMIT_SHA $IMAGE_NAME:latest
    - docker push $IMAGE_NAME:latest

Store HARBOR_ROBOT_TOKEN and HARBOR_ROBOT_NAME as masked CI variables. Tag images with the Git commit SHA. Mutable latest tags are fine for dev. Use immutable tags or digest pins in production.

On Kubernetes, create an image pull secret from the same robot credentials. Reference it in the pod spec or service account. For Docker hosts, run docker login once on the deploy user. Better yet, use a credential helper.

This pattern matches how I wire automated container builds elsewhere. Only the registry endpoint changes. The build stage stays the same.

Pull by digest for reproducible deploys

# After push, read digest from Harbor UI or API
docker pull registry.example.com/myapp/api@sha256:abc123...

# In Kubernetes deployment manifest
image: registry.example.com/myapp/api@sha256:abc123...

Digest pins stop silent overwrites when someone retags latest. Pair them with Harbor's immutable tag project setting for release branches.

How do you enable vulnerability scanning and security policies in Harbor?

Harbor integrates Trivy for layer scanning. Enable scan-on-push at the project level. Block deployments when critical CVEs appear. That closes the gap between "we built an image" and "we ship safe code."

Our dedicated guides on container image scanning with Trivy and Trivy for containers and IaC explain scanner flags in depth. Harbor wraps Trivy so developers see results in the UI without running CLI scans locally.

Scan-on-push configuration

  • Project → Configuration →勾选 Automatically scan images on push.
  • Set a CVE allowlist for base images you cannot patch yet.
  • Configure webhooks to notify Slack or your ticket system on scan failure.

Add a deployment policy: reject pulls or warn when severity ≥ High. Harbor 2.x supports vulnerability severity thresholds per project. Test the threshold against real images first. Alpine and distroless bases report different noise levels.

For supply-chain hardening, combine scanning with Cosign image signing. Harbor supports Notary in older setups. Cosign is the modern path for keyless or keyed signatures in 2026 pipelines.

Push → Scan → Deploy Gatedocker pushHarbor storeTrivy scanPolicypass / failFail: block pullNotify team via webhookPass: deployK8s / Docker pullProduction runtimeOnly scanned, signed images
Harbor private container registry scan gate: every push triggers Trivy; policy blocks bad images before they reach production.

How do you operate Harbor reliably in production?

Installation is one afternoon. Operations are ongoing. Disk fills up. Certificates expire. Replication jobs stall. Treat Harbor as production infrastructure, not a sidecar experiment.

Storage and garbage collection

Harbor deduplicates layers, but orphaned uploads still happen after failed pushes. Schedule GC during low-traffic windows. The UI under Administration → Garbage Collection triggers a run. Automate it weekly via the Harbor API if your version supports cron-style jobs.

For larger fleets, point blob storage to S3-compatible object storage. Local SSD works up to a few hundred GB. Beyond that, object storage scales cheaper. Monitor free space with your existing host alerts.

Replication and DR

Harbor can replicate projects to a second Harbor instance or to cloud registries. That gives you a warm standby without rebuilding images during an outage. Test failover pulls quarterly. An untested replica is wishful thinking.

If you also run containers on ECS with Fargate, replicate select projects to ECR as a hybrid pattern. Harbor stays canonical. ECR serves the AWS region.

Backups

Back up:

  • Harbor data directory (registry blobs and internal configs).
  • PostgreSQL database (project metadata, users, policies).
  • TLS certificates and harbor.yml.

Restore drills matter. A registry you cannot rebuild blocks every deploy. Store backups off-server. Encrypt them at rest.

Resource limits and hardening

Run Harbor components with memory caps like any other stack. Our guide on limiting Docker container resources applies to the Compose services Harbor ships.

Enable rootless container practices on surrounding hosts where feasible. Harbor itself expects Docker with sufficient privileges on the install node. Isolate that node on a management VLAN. Restrict admin UI access by IP or VPN.

Rotate robot account tokens on the same schedule as database passwords. Use separate robots per pipeline. One leaked token should not grant push access to every project.

Harbor Ops ChecklistDaily monitoringDisk, API errors, scan queue depthWeekly GCReclaim unreferenced blobsMonthly cert checkLet's Encrypt auto-renewQuarterly DR testPull from replica registryNightly backup: Postgres + /data/harborOff-site encrypted storage required
Production checklist for Harbor private container registry: monitor daily, garbage-collect weekly, verify backups and replication regularly.

For multi-service apps, Harbor often sits beside app containers defined in Docker Compose multi-container stacks. Keep registry data on fast disk separate from app logs. Noisy neighbours slow pushes when IO is shared.

Common production mistakes

Teams skip TLS on internal registries. Man-in-the-middle risk is real even on private VLANs. Always terminate HTTPS. Trust corporate CAs on build agents.

Another mistake is one shared admin account for humans and CI. Robot accounts exist for a reason. Audit logs become useless when every push shows "admin."

Finally, never run Harbor on the same disk as your only database backup target. A full registry can starve IO and stall backups. Budget Rs 3,000–8,000/month (~USD 22–60) for a dedicated 200 GB SSD VPS in Nepal hosting if you are cost-sensitive but still need private images.

Key Takeaways

  • Harbor is the right private registry when you need RBAC, scanning, replication, and a UI—not just blob storage.
  • Install with the official Compose bundle, TLS on day one, and Trivy via ./install.sh --with-trivy.
  • Use robot accounts in CI; pin production deploys to image digests or immutable tags.
  • Enable scan-on-push and severity policies before your first production workload lands.
  • Schedule garbage collection, monitor disk, back up Postgres and /data/harbor, and test replication failover quarterly.
  • Compare Harbor against GitLab Registry and cloud ECR honestly—do not self-host if managed options already fit your stack.

People Also Ask

Is Harbor free to use?

Yes. Harbor is open source under the Apache 2.0 license. You pay for compute, storage, bandwidth, and the time to operate it. There is no per-user license fee like some commercial registries.

Can Harbor replace Docker Hub entirely?

For private images, yes. Public base pulls still often come from Docker Hub or mirror registries. Many teams configure Harbor as a pull-through cache or proxy for upstream hubs to avoid rate limits.

Does Harbor work with Kubernetes?

Harbor is Kubernetes-friendly. Create image pull secrets from Harbor credentials. Install the Harbor Helm chart if you want Harbor itself on Kubernetes instead of the default Compose installer on a VM.

How is Harbor different from GitLab Container Registry?

GitLab's registry is convenient when repos and pipelines already live in GitLab. Harbor is registry-first: stronger cross-registry replication, standalone RBAC, and scanning without tying you to a Git vendor. Some orgs run both—GitLab for dev, Harbor as the canonical production hub.

Ship a Harbor private container registry your team can trust

A well-run Harbor: Private Container Registry turns image storage from an afterthought into part of your security posture. You control access, scan every push, and replicate for resilience without shipping code to a public hub. Start small: one project, one pipeline, scan-on-push enabled. Expand replication and signing once the basics work.

If you want help sizing a VPS, hardening TLS, or wiring Harbor into GitLab CI on Ubuntu, I offer hands-on enterprise application and DevOps support and ongoing production maintenance. See how similar infrastructure work shows up in projects like Adventure Third Pole Trek. Validate webhook payloads with our JSON formatter before they hit your alert channels. Read more on admission controllers and webhooks if you enforce policies at the cluster edge. Visit kokil.com.np or contact us to plan your registry rollout.

Frequently Asked Questions

Harbor is a CNCF-graduated, self-hosted registry for Docker and OCI images. It adds RBAC, project quotas, Trivy scanning, replication, and retention on top of the standard push/pull API. Teams choose it when public hubs leak metadata, rate-limit pulls, and lack audit trails you need for compliance.

Yes. Harbor is open source under Apache 2.0. You pay only for compute, storage, bandwidth, and ops time—no per-user license fee.

Budget roughly Rs 3,000–8,000/month (~USD 22–60) for a dedicated 200 GB SSD VPS if you need private images without SaaS per-seat fees. That covers infra only; your time for TLS, backups, and GC is extra.

Plan for Ubuntu 22.04 or 24.04 with at least 4 vCPU and 8 GB RAM for small teams. Install Docker Engine and the Docker Compose plugin. Point a DNS A record such as registry.example.com at the host, terminate TLS on port 443, and mount a dedicated data volume because CI image layers fill disk fast.

Download the official Harbor v2.11.0 online or offline installer, extract it under /opt, copy harbor.yml.tmpl to harbor.yml, and set hostname, HTTPS certificate paths, admin password, and data_volume such as /data/harbor. Run sudo ./install.sh --with-trivy so Trivy is included from day one. Log in over HTTPS, change the default admin password immediately, and create private projects per app or environment.

Plain Docker Distribution is lighter but lacks built-in UI, RBAC, and scanning without add-ons. GitLab Registry fits teams already on GitLab; Harbor is registry-first with stronger cross-registry replication and standalone RBAC. AWS ECR wins when you are all-in on AWS with low ops overhead. Harbor fits when you want enterprise-style features on your own VPS or rack without cloud lock-in.

Choose Harbor when you need scanning, RBAC, and multi-environment replication on infrastructure you control. Skip it if GitLab already hosts your repos and images and that workflow is enough. Skip it if one cloud registry such as ECR covers every environment and you never replicate elsewhere. A solo developer may only need a basic self-hosted registry.

Harbor speaks Docker Registry HTTP API V2. Create a robot account scoped to one project with push and pull permissions, store HARBOR_ROBOT_TOKEN and HARBOR_ROBOT_NAME as masked CI variables, and log in with docker login before build. Tag images with the Git commit SHA, push both SHA and latest for dev, and pin production deploys to digests or immutable tags so silent overwrites cannot happen.

Robot accounts are scoped tokens meant for automation. Embedding personal passwords in pipeline variables is a security mistake and makes audit logs useless when every push appears as admin. Create separate robots per pipeline so one leaked token cannot push to every project, and rotate them on the same schedule as database passwords.

Enable Trivy during install with --with-trivy, then turn on Automatically scan images on push at the project level. Set a CVE allowlist for base images you cannot patch yet, configure webhooks to Slack or tickets on failures, and add deployment policies that reject or warn when severity is High or above. Test thresholds against real Alpine and distroless images because noise levels differ. Combine scanning with Cosign signing for supply-chain hardening.

Treat Harbor as production infrastructure, not a side experiment. Monitor disk daily, schedule garbage collection weekly during low traffic, and for larger fleets point blob storage to S3-compatible object storage instead of local SSD beyond a few hundred GB. Cap memory on Compose services, restrict admin UI access by IP or VPN, and keep registry data on fast disk separate from noisy app logs.

Back up the Harbor data directory at /data/harbor for registry blobs and internal configs, the PostgreSQL database holding project metadata and policies, TLS certificates, and harbor.yml. Store backups off-server encrypted at rest and run restore drills—a registry you cannot rebuild blocks every deploy. Harbor replication to a second instance or cloud registry gives warm standby; test failover pulls quarterly.

Yes. Create image pull secrets from Harbor robot credentials and reference them in pod specs or service accounts. You can pull by digest for reproducible deploys. If you prefer Harbor on Kubernetes instead of the default Compose installer on a VM, use the official Harbor Helm chart.

For private application images, yes—Harbor keeps tags inside your network boundary with fast pulls and private metadata. Public base image pulls still often come from Docker Hub or mirrors. Many teams configure Harbor as a pull-through cache or proxy for upstream hubs to avoid rate limits while keeping production images private.

Skipping TLS on internal registries exposes man-in-the-middle risk even on private VLANs—always terminate HTTPS and trust corporate CAs on build agents. Using one shared admin account for humans and CI destroys audit value; use robot accounts. Never run Harbor on the same disk as your only database backup target because a full registry can starve IO and stall backups. Change default passwords immediately after first login.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: