1. 方案 1:临时跳过 TLS 验证(测试环境适用,快速生效)

    适合临时测试,无需修改 Harbor 服务端证书,仅在客户端配置「信任该 Harbor 为不安全仓库」:

    客户端操作步骤(以 Ubuntu/Debian 为例,CentOS 操作一致):

    1. 编辑客户端 Docker 配置文件
      打开 / 新建 Docker 守护进程配置文件 daemon.json

      bash

      sudo vim /etc/docker/daemon.json
      

      写入以下内容(192.168.31.19 替换为你的 Harbor IP):

      json

      {
        "insecure-registries": ["192.168.31.19"]  // 允许客户端跳过该IP的TLS验证
      }
      

    2. 重启客户端 Docker 服务
      使配置生效:

      bash

      sudo systemctl daemon-reload
      sudo systemctl restart docker
      

    3. 客户端重新登录 Harbor
      此时 Docker 会忽略 TLS 证书格式问题,直接连接:

      bash

      sudo docker login 192.168.31.19
      # 输入Harbor管理员账号(admin)和密码,提示“Login Succeeded”即成功
  2. 停止 Harbor 服务

    bash

    cd ~/harbor  # 进入Harbor安装目录
    sudo docker compose down -v
    

  3. 生成带 SANs 的证书

    • 创建证书目录:sudo mkdir -p /etc/harbor/ssl && cd /etc/harbor/ssl

    • 新建 SANs 配置文件 san.cnf

      bash

      sudo vim san.cnf
      


      写入内容(替换 IP.1=192.168.31.19 为你的 Harbor IP):

      ini

      [req]
      default_bits = 2048
      prompt = no
      default_md = sha256
      distinguished_name = dn
      x509_extensions = req_ext
      
      [dn]
      C=CN
      ST=YourProvince
      L=YourCity
      O=YourCompany
      OU=YourDepartment
      CN=192.168.31.19  # 旧版CN(保留兼容)
      
      [req_ext]
      subjectAltName = @alt_names
      
      [alt_names]
      IP.1=192.168.31.19  # 关键:用SANs绑定Harbor IP(现代TLS要求)
      

    • 生成私钥和证书:

      bash

      sudo openssl genrsa -out harbor.key 2048
      sudo openssl req -new -x509 -key harbor.key -out harbor.crt -days 3650 -config san.cnf
      

  4. 服务端更新 Harbor 配置并重启

    • 编辑 harbor.yml 指向新证书:

      bash

      cd ~/harbor
      sudo vim harbor.yml
      


      修改 https 配置:

      yaml

      https:
        port: 443
        certificate: /etc/harbor/ssl/harbor.crt  # 新证书路径
        private_key: /etc/harbor/ssl/harbor.key   # 新私钥路径
      

    • 重新部署 Harbor:

      bash

      sudo ./prepare
      sudo docker compose up -d
      

第二步:客户端信任新证书(客户端机器上)

  1. 在客户端创建证书信任目录
    目录名必须是「Harbor IP」(与服务端 IP 一致):

    bash

    sudo mkdir -p /etc/docker/certs.d/192.168.31.19
    

  2. 从 Harbor 服务端复制新证书到客户端
    用 scp 把服务端的 harbor.crt 复制到客户端(替换 shitou 为服务端用户名):

    bash

    sudo scp shitou@192.168.31.19:/etc/harbor/ssl/harbor.crt /etc/docker/certs.d/192.168.31.19/ca.crt
    

    • 注意:客户端证书必须命名为 ca.crt(Docker 默认读取该文件名)。

  3. 重启客户端 Docker 服务

    bash

    sudo systemctl daemon-reload
    sudo systemctl restart docker
    

  4. 客户端重新登录 Harbor
    此时 Docker 会验证通过新证书,无 TLS 报错:

    bash

    sudo docker login 192.168.31.19
 shitou@shitou:sudo docker compose down -v
[sudo] password for shitou:
[+] Running 10/10
 ✔ Container harbor-jobservice  Removed                                                             1.1s
 ✔ Container nginx              Removed                                                             1.3s
 ✔ Container registryctl        Removed                                                             1.2s
 ✔ Container harbor-portal      Removed                                                             0.8s
 ✔ Container harbor-core        Removed                                                             0.7s
 ✔ Container registry           Removed                                                             1.1s
 ✔ Container harbor-db          Removed                                                             1.1s
 ✔ Container redis              Removed                                                             1.1s
 ✔ Container harbor-log         Removed                                                            11.0s
 ✔ Network harbor_harbor        Removed                                                             0.2s
shitou@shitou:~/harbor$ sudo mkdir -p /etc/harbor/ssl && cd /etc/harbor/ssl
shitou@shitou:/etc/harbor/ssl$ sudo vim san.cnf
shitou@shitou:/etc/harbor/ssl$ sudo openssl genrsa -out harbor.key 2048
shitou@shitou:/etc/harbor/ssl$ sudo openssl req -new -x509 -key harbor.key -out harbor.crt -days 3650 -config san.cnf
shitou@shitou:/etc/harbor/ssl$ cd ~/harbor
shitou@shitou:~/harbor$ sudo vim harbor.yml
shitou@shitou:~/harbor$ sudo ./prepare
prepare base dir is set to /home/shitou/harbor
Clearing the configuration file: /config/registry/passwd
Clearing the configuration file: /config/registry/config.yml
Clearing the configuration file: /config/registry/root.crt
Clearing the configuration file: /config/jobservice/env
Clearing the configuration file: /config/jobservice/config.yml
Clearing the configuration file: /config/portal/nginx.conf
Clearing the configuration file: /config/nginx/nginx.conf
Clearing the configuration file: /config/core/app.conf
Clearing the configuration file: /config/core/env
Clearing the configuration file: /config/log/logrotate.conf
Clearing the configuration file: /config/log/rsyslog_docker.conf
Clearing the configuration file: /config/registryctl/env
Clearing the configuration file: /config/registryctl/config.yml
Clearing the configuration file: /config/db/env
Generated configuration file: /config/portal/nginx.conf
Generated configuration file: /config/log/logrotate.conf
Generated configuration file: /config/log/rsyslog_docker.conf
Generated configuration file: /config/nginx/nginx.conf
Generated configuration file: /config/core/env
Generated configuration file: /config/core/app.conf
Generated configuration file: /config/registry/config.yml
Generated configuration file: /config/registryctl/env
Generated configuration file: /config/registryctl/config.yml
Generated configuration file: /config/db/env
Generated configuration file: /config/jobservice/env
Generated configuration file: /config/jobservice/config.yml
copy /data/secret/tls/harbor_internal_ca.crt to shared trust ca dir as name harbor_internal_ca.crt ...
ca file /hostfs/data/secret/tls/harbor_internal_ca.crt is not exist
copy  to shared trust ca dir as name storage_ca_bundle.crt ...
copy None to shared trust ca dir as name redis_tls_ca.crt ...
loaded secret from file: /data/secret/keys/secretkey
Generated configuration file: /compose_location/docker-compose.yml
Clean up the input dir
shitou@shitou:~/harbor$ sudo docker compose up -d
[+] Running 10/10
 ✔ Network harbor_harbor        Created                                                             0.3s
 ✔ Container harbor-log         Started                                                             2.7s
 ✔ Container registryctl        Started                                                             3.9s
 ✔ Container harbor-db          Started                                                             4.6s
 ✔ Container registry           Started                                                             4.5s
 ✔ Container redis              Started                                                             4.4s
 ✔ Container harbor-portal      Started                                                             3.8s
 ✔ Container harbor-core        Started                                                             4.6s
 ✔ Container nginx              Started                                                             6.1s
 ✔ Container harbor-jobservice  Started                                                             5.5s
shitou@shitou:~/harbor$

sudo docker pull nginx:1.29.1
1.29.1: Pulling from library/nginx
Digest: sha256:33e0bbc7ca9ecf108140af6288c7c9d1ecc77548cbfd3952fd8466a75edefe57
Status: Image is up to date for nginx:1.29.1
docker.io/library/nginx:1.29.1
shitou@aishitou:~$ sudo docker tag nginx:1.29.1 192.168.31.19/library/nginx:v1
shitou@aishitou:~$ sudo docker push 192.168.31.19/library/nginx:v1
The push refers to repository [192.168.31.19/library/nginx]
45c2d10807fb: Pushed
129b375526fc: Pushed
a0e5983a25a5: Pushed
2988603ca264: Pushed
39bc11fab520: Pushed
dab69e9f41e9: Pushed
eb5f13bce993: Pushed
v1: digest: sha256:6ef3c77a4ebfbf8f2cada3442839f0c49f7e5f643b5179ec4ed0f100ada8c9ae size: 1778
shitou@aishitou:~$ sudo docker pull tomcat:11.0.10
11.0.10: Pulling from library/tomcat
Digest: sha256:6df06d415fc022d911f43a6668167a6f74436b867d6b24e99492a386a0cd8339
Status: Image is up to date for tomcat:11.0.10
docker.io/library/tomcat:11.0.10
shitou@aishitou:~$ sudo docker tag tomcat:11.0.10 192.168.31.19/library/tomcat:11.0.10
shitou@aishitou:~$ sudo docker push 192.168.31.19/library/tomcat:11.0.10
The push refers to repository [192.168.31.19/library/tomcat]
5f70bf18a086: Pushed
b3e39a1a1009: Pushed
342586930e8a: Pushed
886ae98b49c1: Pushed
b975e904aaaf: Pushed
74b13d8a4515: Pushed
7ad9404c656d: Pushed
cd9664b1462e: Pushed
11.0.10: digest: sha256:e3fcbf18bc3d349134671c39bca6cf432ff008a90e90ce108f073ce2bf6ac48e size: 2201
shitou@aishitou:~$ sudo docker tag nginx:1.29.1 192.168.31.19/library/nginx:1.29.1
shitou@aishitou:~$ sudo docker tag nginx:1.29.1 192.168.31.19/library/nginx:1.29.1
shitou@aishitou:~$ sudo docker push 192.168.31.19/library/nginx:1.29.1
The push refers to repository [192.168.31.19/library/nginx]
45c2d10807fb: Layer already exists
129b375526fc: Layer already exists
a0e5983a25a5: Layer already exists
2988603ca264: Layer already exists
39bc11fab520: Layer already exists
dab69e9f41e9: Layer already exists
eb5f13bce993: Layer already exists
1.29.1: digest: sha256:6ef3c77a4ebfbf8f2cada3442839f0c49f7e5f643b5179ec4ed0f100ada8c9ae size: 1778
shitou@aishitou:~$