Harbor
Overview
This image runs Harbor as a single-node deployment. Harbor is the CNCF graduated open source registry that secures container artefacts with policies and role-based access control, scans images for vulnerabilities with the integrated Trivy scanner, and supports replication across registries. The image delivers Harbor fully installed and configured, so a private container registry is running within minutes of launch.
What you get:
- Harbor running as a Docker Compose stack: nginx as the front proxy on port 80, the Harbor core, the portal web user interface, the registry, registryctl, the jobservice, a local PostgreSQL metadata database, Redis and the Trivy vulnerability scanner
- A single
harbor.servicesystemd unit that brings the whole stack up and down at boot - Docker Engine and the Docker Compose plugin, installed from the official Docker package repository
- An administrator password generated on the first boot of every deployed instance, so two instances launched from the same Amazon Machine Image never share a password
- The initial administrator password written to
/root/harbor-credentials.txtwith mode 0600, so that only the root user can read it - The Harbor data directory at
/dataon a separate, independently resizable EBS volume, which holds the registry image blobs, the PostgreSQL metadata database, the Redis state and the Trivy scan cache, so none of them use the operating system disk
Prerequisites
Before you deploy this image, you need:
- An Amazon Web Services account where you can launch EC2 instances
- IAM permissions to launch instances, create security groups and subscribe to AWS Marketplace products
- An EC2 key pair in the target Region for SSH access to the instance
- A VPC and subnet in the target Region, with a security group that allows inbound port 22 from your management network and inbound ports 80 and 443 from the network you will reach the Harbor web interface from
- The AWS CLI (version 2) installed locally, if you plan to deploy from the command line
- A Docker client on your workstation to push and pull images
Launch the instance from the AWS Marketplace
Sign in to the AWS Management Console, open the EC2 service, and select Launch instance. Under Application and OS Images, choose AWS Marketplace AMIs and search for Harbor. Select the SecureAnyCloud listing, choose Select, then choose Continue on the subscription summary.
Pick an instance type of m5.large or larger. Harbor runs ten containers in its Compose stack, including a PostgreSQL database, Redis and the Trivy vulnerability scanner, so it runs best with at least two vCPUs and 8 GiB of memory. Choose your EC2 key pair under Key pair (login).
Under Network settings, select your VPC and subnet. Create or select a security group that allows inbound port 22 from your management network, and inbound ports 80 and 443 from the network you will reach the web interface and the registry from. Leave the root volume at the default size or larger. The image also attaches a separate 50 GiB gp3 data volume to /data for registry storage.
Select Launch instance. First-boot initialisation takes about two to three minutes after the instance state becomes Running and the status checks pass. During this time Harbor brings up its full Compose stack, initialises the metadata database and rotates the administrator password.
Launch the instance from the AWS CLI
The following command launches an instance from the SecureAnyCloud Harbor Marketplace AMI into an existing subnet and security group. Replace <ami-id> with the AMI ID shown on the Marketplace listing and <key-name> with your EC2 key pair name. Replace <subnet-id> with your subnet ID and <security-group-id> with a security group that opens ports 22, 80 and 443 as described above.
aws ec2 run-instances \
--image-id <ami-id> \
--instance-type m5.large \
--key-name <key-name> \
--subnet-id <subnet-id> \
--security-group-ids <security-group-id> \
--block-device-mappings '[{"DeviceName":"/dev/sda1","Ebs":{"VolumeSize":30,"VolumeType":"gp3"}}]' \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=harbor-01}]'On success, the command prints a JSON document. Note the instance ID, then retrieve the public address once the instance is running withaws ec2 describe-instances --instance-ids <instance-id> --query "Reservations[].Instances[].PublicIpAddress" --output text.
Connect and retrieve the initial credentials
Connect over SSH with the key pair you selected and the public IP address from Step 2. On Harbor on Ubuntu 24.04, the SSH login user is ubuntu.
The first-boot service rotates the password through the Harbor REST API before it writes the credentials file, so the file is always in place when you first log in. Display it with:
sudo cat /root/harbor-credentials.txtThe plain-text file contains the Harbor URL, the administrator username (admin) and the administrator password. Copy these values somewhere secure, such as a password manager or encrypted vault. Do not commit them to source control.
From the same SSH session, confirm that the deployment is healthy. The Harbor health endpoint needs no authentication and reports every component of the Compose stack:
curl -fsS http://127.0.0.1/api/v2.0/healthA JSON document that reports the core, database, jobservice, portal, redis, registry, registryctl and trivy components confirms that the full stack is up.
You can also inspect the Compose stack directly:
sudo docker compose -f /opt/harbor/harbor/docker-compose.yml psOnce the stack has warmed up, every container reports Up (healthy).
Sign in to the Harbor web interface
Open a web browser and go to http://<public-ip>/. Harbor shows the sign-in form to visitors who do not yet have a session.
Enter the administrator username admin and the administrator password from /root/harbor-credentials.txt, then select LOG IN. After you sign in, Harbor shows the navigation rail down the left side of every page.
Review the Projects page
After you sign in, Harbor opens the Projects page. The image registers one default public project, library, ready to receive container images. Harbor uses projects to group container repositories and to apply access control, replication, scanning and retention policies.
The summary cards along the top show the number of private and public projects, the number of repositories, and the total quota used by the registry. The table lists each project with its access level, your role, the project type, the repository count and the creation time. To create another project, select + NEW PROJECT above the table.
Open the library project
Select library in the projects table to open the project detail view. The view has tabs for Summary, Repositories, Members, Labels, Scanner, P2P Preheat, Policy, Robot Accounts, Webhooks, Logs and Configuration.
The Repositories tab is selected by default. On a new instance the project is empty, and Harbor reports "We couldn't find any repositories!" with a 0 item count. The PUSH COMMAND drop-down on the right shows the exact docker push command for pushing your first image into the project.
Push and pull your first image
From a workstation with Docker installed, sign in to the Harbor registry, tag an existing image with the registry hostname, and push it.
docker login <instance-public-ip>
# Username: admin
# Password: paste the admin password from /root/harbor-credentials.txt
docker pull nginx:stable
docker tag nginx:stable <instance-public-ip>/library/nginx:stable
docker push <instance-public-ip>/library/nginx:stableAfter the push completes, refresh the project's Repositories tab in the web interface. library/nginx appears with one artefact. You can pull the same image from any other Docker client that can reach the registry:
docker pull <instance-public-ip>/library/nginx:stableScan for vulnerabilities
The image enables Trivy as the default vulnerability scanner. Open a repository in the web interface, select an artefact, then select SCAN. Trivy pulls the image layers, scans them against its CVE database, and reports the result on the artefact row with a breakdown of critical, high, medium and low findings.
To scan every artefact in a project on a schedule, use the project's Configuration tab.
To trigger a scan from the command line, use the REST API. Replace nginx and stable with the repository and tag you want to scan:
PASS=$(sudo grep '^harbor.admin.pass=' /root/harbor-credentials.txt | cut -d= -f2-)
curl -fsS -u admin:"$PASS" -X POST \
http://127.0.0.1/api/v2.0/projects/library/repositories/nginx/artifacts/stable/scanThe first scan downloads the Trivy CVE database and can take a couple of minutes. Later scans are quick.
Administer the system
The Administration group in the navigation rail collects every system-wide setting: Users, Robot Accounts, Registries (for replication source and target endpoints), Replications, Distributions, Labels, Project Quotas, Interrogation Services (the scanner configuration), Clean Up (the garbage collector) and the global Configuration.
The Users page lists every named user with the administrator flag, the email address and the registration time. Use + NEW USER to add a named account for each team member, so that they do not sign in as admin. The SET AS ADMIN action promotes the selected user to administrator.
From a project's Members tab, add each user to one or more projects as a Project Admin, Master, Developer, Guest or Limited Guest.
Server components
The image contains the following components:
- Harbor 2.x: container registry, vulnerability scanning and role-based access control
- Docker Engine: the container runtime that hosts the Harbor Compose stack
- Docker Compose plugin: brings the Harbor stack up and down as a single Compose project
- harbor.service systemd unit: wraps docker compose up -d and down in the install directory
- harbor-firstboot.service systemd unit: a one-shot service that rotates the admin password on first boot
The Compose stack runs the following containers:
- nginx: front proxy on port 80, which routes traffic to the portal, core, registry and registryctl
- harbor-core: the Harbor application server, business logic and REST API
- harbor-portal: the Angular single-page web user interface
- registry: the OCI distribution registry that stores image blobs
- registryctl: the registry management daemon, used by the Harbor core
- harbor-jobservice: the background job runner for replication, scanning and garbage collection
- harbor-db: the PostgreSQL metadata database for Harbor
- redis: cache for the Harbor core, the jobservice and the registry
- harbor-log: centralised log collector for every Harbor container
- trivy-adapter: the Trivy vulnerability scanner adapter for Harbor
Filesystem layout
The image uses the following paths:
- /opt/harbor/harbor/: the Harbor installation directory, containing install.sh, prepare, docker-compose.yml and harbor.yml
- /opt/harbor/harbor/harbor.yml: the Harbor configuration (hostname, ports, secret key, data root)
- /opt/harbor/harbor/docker-compose.yml: the Compose definition, rendered from harbor.yml by the prepare script
- /data/: the Harbor data root, on a dedicated EBS volume
- /data/registry/: OCI distribution registry image blobs
- /data/database/: the PostgreSQL metadata database for Harbor
- /data/redis/: Redis persistence files
- /data/job_logs/: background job logs
- /data/secret/: Harbor signing keys
- /data/trivy-adapter/: the Trivy CVE database cache
- /root/harbor-credentials.txt: the per-instance administrator password, generated on first boot and readable by root only
The data volume is mounted by UUID in /etc/fstab with the nofail option, so the instance still boots if the volume is detached.
Manage the services
systemd starts the Harbor Compose stack at boot through the harbor.service unit. To check its status, run:
sudo systemctl status harbor.serviceTo restart the whole stack:
sudo systemctl restart harbor.serviceTo inspect individual containers, use docker compose from the install directory:
cd /opt/harbor/harbor && sudo docker compose ps --format 'table {{.Name}}\t{{.Status}}'To read or follow container logs, run:
sudo docker compose -f /opt/harbor/harbor/docker-compose.yml logs --tail 100 harbor-core
sudo docker compose -f /opt/harbor/harbor/docker-compose.yml logs -f nginxTo follow the systemd unit log:
sudo journalctl -u harbor.service -n 50 --no-pagerUse the REST API
The Harbor REST API is served on port 80, the same port as the web interface, under the /api/v2.0/ prefix. Authenticate with HTTP basic auth and the administrator credentials. The following commands list every project on the registry:
PASS=$(sudo grep '^harbor.admin.pass=' /root/harbor-credentials.txt | cut -d= -f2-)
curl -fsS -u admin:"$PASS" http://127.0.0.1/api/v2.0/projectsThe full REST API reference is published as an OpenAPI document at http://<public-ip>/devcenter-api-2.0 and in the Harbor documentation at https://goharbor.io/docs/latest/install-config/configure-https/.
Change the administrator password
For a production deployment, rotate the administrator password that was generated on first boot. Use the REST API with the current password:
OLD=$(sudo grep '^harbor.admin.pass=' /root/harbor-credentials.txt | cut -d= -f2-)
curl -fsS -u admin:"$OLD" -X PUT \
-H 'Content-Type: application/json' \
-d '{"old_password":"'"$OLD"'","new_password":"<NEW_PASSWORD>"}' \
http://127.0.0.1/api/v2.0/users/1/passwordAlso create named users and assign them roles such as Project Admin, Master, Developer, Guest or Limited Guest from a project's Members tab, so that team members do not share the administrator account. For CI pipelines that push or pull images, use the accounts under Robot Accounts.
Enable HTTPS
The Compose stack listens on plain HTTP on port 80. For any deployment beyond a trusted management network, enable HTTPS so that credentials and image layers cannot be intercepted.
Harbor supports HTTPS natively. Edit /opt/harbor/harbor/harbor.yml, uncomment the https: block and set port: 443. Point certificate: and private_key: at your TLS certificate and private key files, then re-run prepare followed by docker compose up -d:
sudo vi /opt/harbor/harbor/harbor.yml
# Uncomment the https: block, set port: 443, certificate, private_key cd /opt/harbor/harbor
sudo ./prepare
sudo docker compose down
sudo docker compose up -dTo use a custom hostname, set hostname: in harbor.yml to your hostname before you run prepare. Then restrict the instance security group so that port 80 is used only for the HTTP-to-HTTPS redirect and port 443 carries the traffic.
For a free, automatically renewed certificate, run certbot --standalone to obtain a Let's Encrypt certificate and point Harbor at the issued files. Add a renewal hook that copies the renewed files into place and runs prepare and docker compose up -d.
Back up and maintain the instance
Back up Harbor's two data sources together. The PostgreSQL metadata database in /data/database holds projects, users, role bindings, scan results and replication state. The OCI registry blobs in /data/registry hold the image layers themselves. The following commands stop the stack and archive the data root:
sudo systemctl stop harbor.service
sudo tar -czf /var/backups/harbor-data-$(date +%F).tgz -C /data .
sudo systemctl start harbor.serviceCopy the archive to an Amazon S3 bucket or another object store. Because the data root is on its own EBS volume, you can also take EBS snapshots of that volume for point-in-time recovery without taking the service offline. The snapshots are crash-consistent.
Ubuntu's unattended-upgrades is enabled by default, so security patches for the kernel and packages apply automatically.
To upgrade Harbor itself, download the new offline installer tarball from https://github.com/goharbor/harbor/releases. Follow the Harbor upgrade documentation at https://goharbor.io/docs/latest/administration/upgrade/, and re-run the prepare and install.sh scripts.
Scale beyond a single instance
For larger deployments, move Harbor off the single-instance pattern:
- Move the metadata database to Amazon RDS for PostgreSQL by setting the external database section in
harbor.ymland re-runningprepare - Move the Redis cache to Amazon ElastiCache for Redis in the same way
- Move the registry blob storage to Amazon S3 with the registry's S3 storage driver in
harbor.yml - Or run Harbor on Amazon EKS with the official Harbor Helm chart from
https://github.com/goharbor/harbor-helm, and front it with the AWS Load Balancer Controller for managed TLS termination
Screenshots
The Harbor web sign-in page, served on first boot with no manual setup.
The Harbor Projects page listing the container repositories available on the instance.
The Harbor system administration page showing users, projects, replication and labels.
Support and Resources
- SecureAnyCloud support: 24/7 by email and chat for deployment, upgrades, TLS configuration, replication and vulnerability scanning
- Harbor documentation:
https://goharbor.io/docs/ - Harbor releases:
https://github.com/goharbor/harbor/releases - Harbor REST API reference, available on every instance:
http://<public-ip>/devcenter-api-2.0
Deploy on AWS
Launch Harbor on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com