Tutorial

Harbor Registry self-hosted en VPS: guía completa

Despliegue8 min de lectura7 pasos

Desde que CVE-2026-21589 sacudió la cadena de suministro de Atlassian, los equipos DevOps buscan recuperar el control sobre cada artefacto que fluye por su pipeline. Docker Hub impone un límite de 100 pulls/6h en cuentas gratuitas, GHCR vincula tus imágenes a la política de retención de GitHub, y ninguno firma ni escanea imágenes por defecto. Harbor, el registro open source de la CNCF, resuelve los tres problemas en un único despliegue: escaneo de vulnerabilidades Trivy integrado, firma Cosign, RBAC granular y logs de auditoría completos. Esta guía te lleva desde la instalación con Docker Compose hasta las políticas de admisión en producción, en un VPS de 4 vCPU / 8 GB de RAM.

Contenido· Por qué un registro Docker privado con Harbor1/9
  1. 01Por qué un registro Docker privado con Harbor
  2. 02Beneficios clave de Harbor
  3. 03Prerrequisitos cuantificados
  4. 04Instalación de Harbor v2.15 con Docker Compose
  5. 05Configuración: proyectos, usuarios y OIDC (ZITADEL)
  6. 06Escanear imágenes con Trivy
  7. 07Consejo de seguridad: políticas de admisión en Kubernetes
  8. 08Solución de problemas: 5 errores reales con sus causas
  9. 09Harbor vs Docker Hub vs GHCR vs Gitea Registry

Por qué un registro Docker privado con Harbor

Docker Hub y GHCR son servicios públicos convenientes, pero plantean tres problemas reales a medida que tu organización crece o debe cumplir con NIS2 (art. 21 § 2 f – seguridad de la cadena de suministro) o GDPR (datos de infraestructura alojados fuera de la UE). Harbor aborda cada punto directamente.

Beneficios clave de Harbor

  • Escaneo Trivy integrado — cada push dispara un análisis CVE; las políticas de admisión bloquean el despliegue de imágenes que superen el umbral de criticidad configurado.
  • Firma Cosign / Notary — cadena de confianza desde el build CI hasta el clúster Kubernetes; solo pasan las imágenes firmadas con tu clave.
  • RBAC multi-proyecto — aislamiento por equipo, entorno (dev/staging/prod) o cliente, con roles Guest, Developer, Maintainer y ProjectAdmin.
  • Replicación entre registros — sincroniza con un segundo VPS, AWS ECR o Docker Hub para distribución CDN.
  • Logs de auditoría inmutables — cada pull, push, eliminación e inicio de sesión queda registrado con la IP de origen; conformidad con NIS2 artículo 21 § 2 d.
  • Sin límite de pulls — tus runners CI descargan tantas imágenes como necesiten sin retrasos ni cuotas.
  • OIDC nativo — conecta Harbor a ZITADEL o cualquier proveedor OpenID Connect; cero cuentas locales que gestionar.

Prerrequisitos cuantificados

Harbor funciona cómodamente en un VPS con la siguiente configuración:

- CPU: 4 vCPU (mínimo 2 vCPU, pero Trivy consume 1–2 núcleos durante el escaneo)
- RAM: 8 GB (mínimo 4 GB; reserva 2 GB para PostgreSQL, 1 GB para Redis, 2 GB para Harbor core, 1 GB de margen)
- Disco: 100 GB SSD (las capas Docker se acumulan rápido; reserva 40 GB para el registro, 20 GB para los logs de Trivy, 20 GB para el sistema)
- SO: Debian 12 o Ubuntu 22.04 LTS
- Docker: ≥ 24.0, Docker Compose: ≥ 2.20
- DNS: un subdominio apuntando a tu VPS (registry.ejemplo.com), ya resolviendo
- TLS: certificado válido — Let's Encrypt via Certbot o Traefik ACME

Instalación de Harbor v2.15 con Docker Compose

  1. Descargar el instalador offline

    Conéctate por SSH a tu VPS. Descarga el paquete offline Harbor v2.15.4 (el más estable a 2026-10-13) desde GitHub:

    export HARBOR_VERSION=v2.15.4
    wget https://github.com/goharbor/harbor/releases/download/${HARBOR_VERSION}/harbor-offline-installer-${HARBOR_VERSION}.tgz
    wget https://github.com/goharbor/harbor/releases/download/${HARBOR_VERSION}/harbor-offline-installer-${HARBOR_VERSION}.tgz.asc
    # Verificar la firma GPG
    gpg --keyserver keyserver.ubuntu.com --recv-keys 7722D168DAEC457894C2988818B80B4B2D318C8A
    gpg --verify harbor-offline-installer-${HARBOR_VERSION}.tgz.asc
    tar xvf harbor-offline-installer-${HARBOR_VERSION}.tgz
    cd harbor
  2. Preparar los certificados TLS

    Harbor requiere TLS. Con Certbot:

    apt install -y certbot
    certbot certonly --standalone -d registry.ejemplo.com
    # Los certificados están en /etc/letsencrypt/live/registry.ejemplo.com/
    mkdir -p /data/cert
    cp /etc/letsencrypt/live/registry.ejemplo.com/fullchain.pem /data/cert/registry.ejemplo.com.crt
    cp /etc/letsencrypt/live/registry.ejemplo.com/privkey.pem  /data/cert/registry.ejemplo.com.key

    Si usas Traefik como reverse proxy (ver el artículo de Traefik v3), delega la terminación TLS a Traefik y configura Harbor en HTTP interno en el puerto 8080.

  3. Configurar ‎harbor.yml

    Copia la plantilla y ajusta los valores esenciales:

    cp harbor.yml.tmpl harbor.yml

    Edita harbor.yml:

    hostname: registry.ejemplo.com
    
    https:
      port: 443
      certificate: /data/cert/registry.ejemplo.com.crt
      private_key: /data/cert/registry.ejemplo.com.key
    
    harbor_admin_password: CambiaEstaContrasena!
    
    database:
      password: CambiaEstasTambien!
    
    data_volume: /data
    
    trivy:
      ignore_unfixed: false
      skip_update: false
      offline_scan: false
      security_check: vuln
      insecure: false
  4. Ejecutar el instalador

    Harbor ofrece componentes opcionales. Activa Trivy (escáner) y Notary (firmas):

    ./install.sh --with-trivy --with-notary

    El instalador genera un docker-compose.yml y arranca todos los contenedores. Verifica que todos estén healthy:

    docker compose ps
    # STATUS esperado para cada servicio: healthy
  5. Primer inicio de sesión y cambio de contraseña

    Abre https://registry.ejemplo.com en tu navegador. Inicia sesión con admin / la contraseña de harbor.yml. Ve a Administration → Users → admin y cambia la contraseña inmediatamente.

    Desde tu estación de trabajo o runner CI:

    docker login registry.ejemplo.com
    # Introduce tus credenciales de admin o una cuenta de servicio
  6. Crear un proyecto y hacer push de la primera imagen

    En la interfaz de Harbor, crea un proyecto mi-proyecto (privado). Luego desde tu máquina de build:

    docker pull nginx:alpine
    docker tag nginx:alpine registry.ejemplo.com/mi-proyecto/nginx:1.27-alpine
    docker push registry.ejemplo.com/mi-proyecto/nginx:1.27-alpine
    # En Harbor → mi-proyecto → Repositories: la imagen aparece con su estado Trivy
  7. Habilitar la renovación automática de TLS

    Crea un hook post-renovación de Certbot para recargar Harbor:

    cat > /etc/letsencrypt/renewal-hooks/post/harbor-reload.sh << 'EOF'
    #!/bin/bash
    cp /etc/letsencrypt/live/registry.ejemplo.com/fullchain.pem /data/cert/registry.ejemplo.com.crt
    cp /etc/letsencrypt/live/registry.ejemplo.com/privkey.pem  /data/cert/registry.ejemplo.com.key
    cd /opt/harbor && docker compose restart proxy
    EOF
    chmod +x /etc/letsencrypt/renewal-hooks/post/harbor-reload.sh

Configuración: proyectos, usuarios y OIDC (ZITADEL)

Proyectos y RBAC

Harbor organiza las imágenes por proyectos. Cada proyecto puede ser público o privado, con una política de retención independiente. Crea un proyecto por equipo o entorno: frontend, backend, infra. Asigna miembros con roles granulares:

- Guest: solo pull
- Developer: push + pull
- Maintainer: gestión de tags, webhooks y políticas de retención
- ProjectAdmin: gestión de miembros

Integración OIDC con ZITADEL

Si ya has desplegado ZITADEL (ver el artículo dedicado), conectar Harbor es cuestión de unos pocos clics. En ZITADEL, crea una aplicación harbor de tipo *Web*, anota el Client ID y el Client Secret. En Harbor → Administration → Configuration → Authentication:

- Auth Mode: OIDC
- OIDC Provider Name: ZITADEL
- OIDC Endpoint: https://sso.ejemplo.com
- OIDC Client ID / Secret: los de ZITADEL
- OIDC Scope: openid profile email groups
- Marca Verify Certificate

En el primer inicio de sesión OIDC, Harbor crea automáticamente la cuenta de usuario. Luego desactiva la creación de cuentas locales (Administration → Configuration → Allow Self-Registration → Off).

Escanear imágenes con Trivy

Harbor embebe Trivy directamente en el pipeline de push. En cuanto se hace push de una imagen, Harbor lanza un escaneo asíncrono que consulta la base CVE de Trivy (actualizada diariamente). El resultado aparece en la interfaz: número de vulnerabilidades por gravedad (CRITICAL, HIGH, MEDIUM, LOW, UNKNOWN).

Activar el escaneo automático en push: en Harbor → Administration → Configuration → Vulnerability → marca *Automatically scan images on push*.

Consultar un informe: abre un repositorio, haz clic en un tag → pestaña *Vulnerabilities*. Cada CVE lista el paquete afectado, la versión corregida y un enlace a la NVD.

Versión de Trivy en Harbor v2.15: Harbor v2.15.4 incluye trivy-adapter alineado con Trivy v0.55.x, con soporte para bases OS (Alpine, Debian, RHEL, Ubuntu), gestores de paquetes de aplicación (npm, pip, cargo, ‎go.mod) y archivos de lock.

Políticas de conformidad por proyecto: en Harbor → *Tu proyecto* → Policy → *Deployment Security* → elige el nivel de gravedad que bloquea el pull. Por ejemplo, bloquear cualquier pull de una imagen con al menos una CVE CRITICAL no corregida.

Consejo de seguridad: políticas de admisión en Kubernetes

Combina Harbor con el controlador de admisión Cosign (vía Kyverno o Connaisseur) para que ninguna imagen sin firmar o con una CVE CRITICAL pueda entrar en tu clúster. En tu pipeline CI:

# Firmar la imagen con Cosign después del build
cosign sign --key cosign.key registry.ejemplo.com/mi-proyecto/nginx:1.27-alpine
# Verificar en CI antes del despliegue
cosign verify --key cosign.pub registry.ejemplo.com/mi-proyecto/nginx:1.27-alpine

Configura una política Kyverno que exija la firma de Harbor: cualquier pod cuya imagen no esté firmada por tu clave es rechazado en la admisión. Esto cierra la brecha más explotada en los ataques a la cadena de suministro tras CVE-2026-21589.

Solución de problemas: 5 errores reales con sus causas

1. Error response from daemon: Get https://registry.ejemplo.com/v2/: x509: certificate signed by unknown authority
Causa: el certificado Let's Encrypt no se ha propagado aún o estás usando un certificado auto-firmado.
Solución: en cada nodo Docker cliente, copia fullchain.pem a /etc/docker/certs.d/registry.ejemplo.com/ca.crt y luego systemctl restart docker.

2. harbor-core reiniciando en bucle con Error 1045 (28000): Access denied for user 'root'@'localhost'
Causa: el volumen PostgreSQL contiene datos de una instalación anterior con una contraseña diferente.
Solución: docker compose down -v (⚠️ borra los datos), modifica la contraseña en harbor.yml, vuelve a ejecutar ./prepare && docker compose up -d.

3. Escaneo Trivy bloqueado en Fetching vulnerability DB durante más de 10 minutos
Causa: el VPS no puede acceder a ghcr.io (firewall de salida restrictivo) para descargar la base de Trivy.
Solución: permite la salida HTTPS hacia ghcr.io y pkg.dev, o activa offline_scan: true tras precargar la base con trivy image --download-db-only.

4. unauthorized: unauthorized to access repository en CI pese a un docker login exitoso
Causa: la cuenta de servicio no tiene el rol Developer en el proyecto destino.
Solución: en Harbor → *Tu proyecto* → Members → añade la cuenta robot o usuario con el rol Developer o superior.

5. Interfaz de Harbor inaccesible tras la renovación del certificado Let's Encrypt
Causa: el contenedor proxy (nginx) sigue sirviendo el antiguo certificado cargado en memoria.
Solución: docker compose restart proxy desde la carpeta de instalación de Harbor. Lo ideal es automatizarlo mediante el hook post-renovación descrito en el paso 7.

Harbor vs Docker Hub vs GHCR vs Gitea Registry

Desplace la tabla

CriterioHarbor self-hostedDocker HubGHCRGitea Registry
AlojamientoTu VPS (datos en la UE)Servidores Docker Inc. (EE.UU.)Servidores GitHub/Microsoft (EE.UU./UE opt.)Tu VPS
Escaneo de vulnerabilidadesTrivy integrado, auto en pushDocker Scout (de pago)Ninguno nativoNinguno nativo
Firma de imágenesCosign + Notary v2DCT (obsoleto)Cosign externoNinguno nativo
RBAC granular5 roles por proyectoRoles de organización limitadosRoles GitHub (gruesos)Roles básicos de Gitea
Límite de pullsNinguno100/6h (gratis), 5000/día (Pro)Vinculado a límites de GitHubNinguno
OIDC/SSO nativoSí (LDAP, OIDC, SAML)No (SSO empresarial de pago)Solo SSO de GitHubOIDC parcial
Logs de auditoría completosSí (IP, usuario, acción, tag)LimitadoParcial vía auditoría GitHubLimitado
Conformidad NIS2/GDPRTotal (datos on-premise)Solo contractualDPA Microsoft disponibleTotal (on-premise)
CosteVPS (~15–30 €/mes)Gratis / Pro ~5$/mesIncluido en GitHub Free/ProVPS compartido con Gitea

Despliega tu registro Harbor en un VPS ServOrbit

Un VPS de 4 vCPU / 8 GB RAM es suficiente para ejecutar Harbor en producción para un equipo de 10 desarrolladores. ServOrbit entrega la VM en menos de 90 segundos, con acceso root SSH y snapshots automáticos incluidos.

¿Necesita ayuda?

Consulte nuestro centro de ayuda y nuestra FAQ, o contacte con nuestro equipo: llamada, WhatsApp o correo electrónico. Soporte en francés, inglés y árabe.

Escribir por WhatsAppse abre en una pestaña nueva