coze部署参考链接:coze部署
找到coze的git仓库,直接下载coze-studio-main源码即可:官方coze仓库
1. coze离线部署运行docker-compose --profile ‘*’ up -d时报错
Error response form daemon:Get "https://registry-1.docker.io/v2/ ": context deadline exceeded(Client.Timeout exceeded while awaiting headers
原因:未联网,需要在外网下载镜像后导入docker中,因为外网Windows机没有装docker,使用python代码的方式进行下载(需要科学上网):
import os
import io
import json
import tarfile
import requests
from time import sleep
REGISTRY = "registry-1.docker.io"
def get_token(repo, scope="pull"):
url = f"https://auth.docker.io/token?service=registry.docker.io&scope=repository:{repo}:{scope}"
r = requests.get(url, timeout=30)
r.raise_for_status()
return r.json()["token"]
def get_manifest(repo, reference, token):
headers = {
"Authorization": f"Bearer {token}",
"Accept": (
"application/vnd.docker.distribution.manifest.v2+json,"
"application/vnd.docker.distribution.manifest.list.v2+json,"
"application/vnd.oci.image.index.v1+json,"
"application/vnd.oci.image.manifest.v1+json"
)
}
url = f"https://{REGISTRY}/v2/{repo}/manifests/{reference}"
r = requests.get(url, headers=headers, timeout=60)
r.raise_for_status()
return r.json(), r.headers.get("Content-Type")
def download_blob(repo, digest, token, outdir, max_retries=5):
"""下载镜像层,支持断点续传 + 自动刷新 token"""
path = os.path.join(outdir, digest.replace(":", "_"))
url = f"https://{REGISTRY}/v2/{repo}/blobs/{digest}"
for attempt in range(max_retries):
try:
mode = "ab" if os.path.exists(path) else "wb"
existing_size = os.path.getsize(path) if os.path.exists(path) else 0
headers = {"Authorization": f"Bearer {token}"}
if existing_size > 0:
headers["Range"] = f"bytes={existing_size}-"
with requests.get(url, headers=headers, stream=True, timeout=120) as r:
if r.status_code == 401: # token 失效,重新获取
print(f"🔑 Token expired, refreshing for {digest}")
token = get_token(repo, "pull")
continue
r.raise_for_status()
with open(path, mode) as f:
for chunk in r.iter_content(1024 * 1024): # 1MB buffer
if chunk:
f.write(chunk)
return path # 成功就返回
except Exception as e:
print(f"⚠️ Error downloading {digest} (attempt {attempt+1}/{max_retries}): {e}")
sleep(3)
raise RuntimeError(f"❌ Failed to download {digest} after {max_retries} attempts")
def save_tar(repo, tag, config_file, layer_files, outname):
with tarfile.open(outname, "w") as tar:
# manifest.json
manifest_json = [{
"Config": os.path.basename(config_file),
"RepoTags": [f"{repo}:{tag}"],
"Layers": [os.path.basename(x) for x in layer_files]
}]
data = json.dumps(manifest_json, indent=2).encode("utf-8")
info = tarfile.TarInfo("manifest.json")
info.size = len(data)
tar.addfile(info, io.BytesIO(data))
# repositories
repositories = {repo: {tag: manifest_json[0]["Layers"][0]}}
data = json.dumps(repositories, indent=2).encode("utf-8")
info = tarfile.TarInfo("repositories")
info.size = len(data)
tar.addfile(info, io.BytesIO(data))
# config.json (真实的 config)
tar.add(config_file, arcname=os.path.basename(config_file))
# layers
for lf in layer_files:
tar.add(lf, arcname=os.path.basename(lf))
def pull_image(image, outdir="images"):
if ":" in image:
repo, tag = image.split(":", 1)
else:
repo, tag = image, "latest"
if "/" not in repo:
repo = f"library/{repo}" # 补全前缀
token = get_token(repo)
manifest, ctype = get_manifest(repo, tag, token)
# 选择 amd64/linux 架构
if "list.v2" in ctype or "image.index" in ctype:
amd64 = next(
m for m in manifest["manifests"]
if m["platform"]["architecture"] == "amd64" and m["platform"]["os"] == "linux"
)
manifest, ctype = get_manifest(repo, amd64["digest"], token)
config_digest = manifest["config"]["digest"]
layers = [l["digest"] for l in manifest["layers"]]
os.makedirs(outdir, exist_ok=True)
# 下载 config.json (非常关键,确保 entrypoint/cmd 等信息保留)
config_file = download_blob(repo, config_digest, token, outdir)
layer_files = [download_blob(repo, d, token, outdir) for d in layers]
outname = os.path.join(outdir, f"{repo.replace('/', '_')}_{tag}.tar")
save_tar(repo, tag, config_file, layer_files, outname)
print(f"✅ Saved {image} -> {outname}")
if __name__ == "__main__":
images = [
"golang:1.24-alpine",
"alpine:3.20",
"alpine:3.22.0",
"mysql:8.4.5",
"bitnami/redis:8.0",
"bitnami/elasticsearch:8.18.0",
"minio/minio:RELEASE.2025-06-13T11-33-47Z-cpuv1",
"bitnami/etcd:3.5",
"milvusdb/milvus:v2.5.10",
"nsqio/nsq:v1.2.1",
"opencoze/opencoze:latest",
"cozedev/coze-studio-server:latest",
"cozedev/coze-studio-web:latest"
]
for img in images:
pull_image(img)
下载完成后如下所示:

将其导入到内网机中,然后docker进行load安装:
docker load -i /path/XXX.tar
完成之后,执行以下命令进行coze配置:

此时遇到问题:

输入命令:
docker-compose run coze-server /bin/sh
ls -l /app
可以看到没有bootstrap.sh文件:

因此需要自己将其导入,在文件路径coze-studio/backend/script路径下能够找到bootstrap.sh

所以修改docker目录下的docker-compose.yml文件,在第342行添加以下内容:
- …/backend/script/bootstrap.sh:app/bootstrap.sh
保存之后再次运行:
docker-compose run coze-server /bin/sh
ls -l /app

注意文件权限,如果权限不全,则运行:
chmod 777 bootstrap.sh
然后再次运行
docker–compose --profile ‘*’ up -d
结果如下:

在浏览器输入:localhost:8888,注册使用即可

2. Coze发布的Agent在其他服务器上远程访问
在docker文件夹下输入:
vim .env
找到WEB_LISTEN_ADDR,将127.0.0.1:8888改为0.0.0.0:8888即可;

Coze离线部署与远程访问解决方案

3745





