TagSpaces 6.13.9 Docker Compose 部署指南
TagSpaces 6.13.9 自托管 Web 形态(静态 Web 应用+MinIO S3 后端)Docker Compose 部署指南:栈编排、SigV4 读写闭环与 CORS 实测、extconfig.js 预置位置、数据持久化与运维命令、六条排障实录(含 network 资源占用处置),全流程实测回显。
TagSpaces 6.13.9 Docker Compose 部署指南
目标:本篇在 Linux 服务器上以 Docker Compose 从零部署 TagSpaces 6.13.9 的自托管 Web 形态——「静态 Web 应用 + S3 兼容对象存储(MinIO)」双组件栈,覆盖编排文件、部署拉起、存储桶创建与读写闭环验证、外置配置预置位置、数据持久化与常见问题,全流程已在真实环境实测通过。
一、环境信息
- 操作系统:Linux x86_64(Ubuntu 系发行版实测)
- Docker:29.x(build a82e528)
- Docker Compose:v2 语法兼容
- TagSpaces:6.13.9(官方镜像
tagspaces/tagspaces-lite-web:6.13.9,压缩体积约 451MB,digestsha256:05c4eabbf5049004e7e456ceb261bb7d3f2617a21efe8edfdc93493329671f2e,构建日期 2026-07-01) - 对象存储:MinIO(镜像
pgsty/minio:RELEASE.2026-08-04T00-00-00Z,S3 兼容 API) - 服务端口:宿主机 8148 → Web 应用 80;宿主机 8149 → MinIO S3 API 9000;宿主机 8150 → MinIO 控制台 9001(均为本机空闲端口,部署前需按实际情况自检)
- 专用网络:
tagspaces-6.13.9-net(显式子网10.89.60.0/24) - 数据目录:
/opt/data/quzuo/tmp/tagspaces/compose/data(宿主机)→/data(对象存储服务内) - 外置配置:
/opt/data/quzuo/tmp/tagspaces/compose/extconfig.js→ Web 应用根目录extconfig.js - 演示凭据:对象存储访问密钥
admin/q1w2e3r4(本文演示账号,生产环境请替换为强密钥) - 版本说明:官方当前最新稳定版为 v6.14.3(shields.io 实查,查询日期 2026-11-01);本文以 6.13.9 实测,升级路径见第十一章
二、镜像选型说明
TagSpaces 官方在 Docker Hub 发布 Web 形态镜像 tagspaces/tagspaces-lite-web(官方文档站 Docker 教程原文:镜像基于 Alpine Linux、使用 nginx 作为 Web 服务器,容器内监听 80 端口)。Web 版的本质是纯静态单页应用 + nginx 伺服——服务端没有任何业务进程,文件操作由浏览器直接对 S3 兼容对象存储发起,因此本栈必须再配一个 S3 后端。
- tag 选型:固定具体版本 tag(
6.13.9)而非latest,便于回滚与审计;官方镜像 tag 与官网发行版本号一致、不带v前缀。 - 对象存储选型:任何 S3 兼容服务都可用(官方教程点名 AWS S3、Wasabi、Cloudflare R2、MinIO、S3Proxy 桥接 NAS)。本文选自托管 MinIO:数据完全落在本机磁盘,闭环可验证。
pgsty/minio为 Pigsty 社区维护的 MinIO 发行镜像,行为与上游 MinIO 一致。 - 升级路径:更新 Web 应用 tag 后
docker compose up -d重建即可;文件数据全部在对象存储的挂载目录中,重建不丢。⚠️ 官方特别提示:升级镜像前先确认extconfig.js已开启ExtSaveLocationsInBrowser,否则浏览器里保存的位置数据会丢(官方文档原文警告,见第十一章)。
三、前置条件
- 已安装 Docker 与 Docker Compose v2+,且当前用户在 docker 用户组(或具备等效权限);
- 宿主机 8148/8149/8150 端口空闲(自检命令:
ss -ltn | grep -E ':(8148|8149|8150)\b',无输出即空闲); - 若使用专用网络,选定一个未被占用的子网槽位(本文取
10.89.60.0/24,可用docker network inspect逐一核对已占网段); - 浏览器与服务器之间需能访问 8148(Web 应用)与 8149(S3 API)两个端口——Web 版由浏览器直连对象存储,只开放 8148 不开 8149 时应用无法读写文件,这是本架构与传统 B/S 应用最大的差异。
端口与网段占用自检:
ss -ltn | grep -E ':(8148|8149|8150)\b'
docker network ls -q | xargs -r docker network inspect --format '{{.Name}} {{range .IPAM.Config}}{{.Subnet}}{{end}}' | grep 10.89.60
两条命令均无输出,说明端口与子网均可用。
四、部署步骤
4.1 编排文件
在工作目录创建 docker-compose.yml(本文落盘于 /opt/data/quzuo/tmp/tagspaces/compose/),必须显式声明项目名 name: tagspaces-6.13.9-stack,避免多套部署共存时项目同名互相覆盖:
name: tagspaces-6.13.9-stack
services:
tagspaces:
image: tagspaces/tagspaces-lite-web:6.13.9
container_name: tagspaces-6.13.9-web
ports:
- "8148:80"
volumes:
- ./extconfig.js:/usr/share/nginx/html/extconfig.js:ro
depends_on:
- minio
networks: [tsnet]
restart: unless-stopped
minio:
image: pgsty/minio:RELEASE.2026-08-04T00-00-00Z
container_name: tagspaces-6.13.9-minio
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: admin
MINIO_ROOT_PASSWORD: q1w2e3r4
ports:
- "8149:9000"
- "8150:9001"
volumes:
- ./data:/data
networks: [tsnet]
restart: unless-stopped
networks:
tsnet:
name: tagspaces-6.13.9-net
driver: bridge
ipam:
config:
- subnet: 10.89.60.0/24
配置要点:
container_name:按<产品>-<版本>-<用途>规范命名;ports:Web 应用容器内固定监听 80(nginx),映射宿主机 8148;MinIO 的 9000 是 S3 API、9001 是 Web 控制台,分别映射 8149/8150;environment:MINIO_ROOT_USER/MINIO_ROOT_PASSWORD即对象存储的 root 访问密钥,后续 TagSpaces 位置配置里要原样填入;volumes:./data:/data把对象存储全部数据(桶、对象、元数据)落在宿主机目录实现持久化;extconfig.js只读挂载进 Web 应用根目录,用于预置位置与标签库(见第六章);networks:显式命名网络并固定子网,防止与其他服务的动态网段冲突。
4.2 拉起服务
docker compose up -d
实测回显(逐行照抄;其中 Network/Container 各出现两次为 compose v2 的分步输出,原样保留):
Network tagspaces-6.13.9-net Creating
Network tagspaces-6.13.9-net Created
Container tagspaces-6.13.9-minio Creating
Container tagspaces-6.13.9-minio Created
Container tagspaces-6.13.9-web Creating
Container tagspaces-6.13.9-web Created
Container tagspaces-6.13.9-minio Starting
Container tagspaces-6.13.9-minio Started
Container tagspaces-6.13.9-web Starting
Container tagspaces-6.13.9-web Started
4.3 状态确认
docker compose ps
实测回显:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
tagspaces-6.13.9-minio pgsty/minio:RELEASE.2026-08-04T00-00-00Z "/usr/bin/docker-ent…" minio Less than a second ago Up Less than a second 0.0.0.0:8149->9000/tcp, [::]:8149->9000/tcp, 0.0.0.0:8150->9001/tcp, [::]:8150->9001/tcp
tagspaces-6.13.9-web tagspaces/tagspaces-lite-web:6.13.9 "/docker-entrypoint.…" tagspaces Less than a second ago Up Less than a second 0.0.0.0:8148->80/tcp, [::]:8148->80/tcp
两个服务均已启动并完成端口映射。再确认双端口的 HTTP 服务真实就绪:
curl -sI http://127.0.0.1:8148/ | head -4
curl -s -o /dev/null -w 'minio health/live HTTP %{http_code}\n' http://127.0.0.1:8149/minio/health/live
实测回显:
HTTP/1.1 200 OK
Server: nginx/1.31.2
Date: Sun, 01 Nov 2026 06:51:17 GMT
Content-Type: text/html
minio health/live HTTP 200
Web 应用返回 200(nginx 1.31.2 伺服),对象存储健康检查通过。拉取首页确认应用版本:
curl -s http://127.0.0.1:8148/ | grep -oE '<title>[^<]*</title>'
实测回显:
<title>TagSpaces Web</title>
应用内部的自检(可选):Service Worker 配置文件中的缓存名直接携带版本号:
docker exec tagspaces-6.13.9-web head -1 /usr/share/nginx/html/sw-config.js
实测回显:
const CACHE_NAME = "TS-6.13.9-1782838041514";
版本号 6.13.9 与所选镜像 tag 一致,部署无误。
五、存储后端初始化与读写闭环
TagSpaces Web 不经过服务端写文件,所有读写都是浏览器对 S3 API 的直接调用。部署后的第一件事是建桶,并用 S3 API 做一次完整的写读闭环验证——这一步等价于在 Web 界面里将要发生的所有底层动作。
5.1 建桶
S3 API 请求需要 AWS SigV4 签名,手工用 curl 构造不现实。准备一个零依赖的 Python 签名客户端(stdlib 实现 SigV4,兼容 Python 3.8+),保存为 s3cli.py:
#!/usr/bin/env python3
"""Minimal S3 SigV4 client (stdlib only) for TagSpaces experiment."""
import sys, hashlib, hmac, datetime, urllib.request, urllib.error, urllib.parse
ENDPOINT = "http://localhost:8149" # MinIO S3 API
REGION = "us-east-1"
AK, SK = "admin", "q1w2e3r4"
def sign(key, msg): return hmac.new(key, msg.encode(), hashlib.sha256).digest()
def get_key(datestamp, region, service):
k = sign(("AWS4" + SK).encode(), datestamp)
for part in (region, service, "aws4_request"):
k = sign(k, part)
return k
def s3req(method, path, body=b"", query=""):
path = urllib.parse.quote(path, safe="/")
t = datetime.datetime.now(datetime.timezone.utc)
amzdate = t.strftime("%Y%m%dT%H%M%SZ")
datestamp = t.strftime("%Y%m%d")
host = ENDPOINT.split("//")[1]
payload_hash = hashlib.sha256(body).hexdigest()
canonical_headers = f"host:{host}\nx-amz-content-sha256:{payload_hash}\nx-amz-date:{amzdate}\n"
signed_headers = "host;x-amz-content-sha256;x-amz-date"
canonical_request = f"{method}\n{path}\n{query}\n{canonical_headers}\n{signed_headers}\n{payload_hash}"
scope = f"{datestamp}/{REGION}/s3/aws4_request"
string_to_sign = f"AWS4-HMAC-SHA256\n{amzdate}\n{scope}\n{hashlib.sha256(canonical_request.encode()).hexdigest()}"
signature = hmac.new(get_key(datestamp, REGION, "s3"), string_to_sign.encode(), hashlib.sha256).hexdigest()
auth = f"AWS4-HMAC-SHA256 Credential={AK}/{scope}, SignedHeaders={signed_headers}, Signature={signature}"
req = urllib.request.Request(ENDPOINT + path, data=body if body else None, method=method)
req.add_header("Authorization", auth)
req.add_header("x-amz-content-sha256", payload_hash)
req.add_header("x-amz-date", amzdate)
try:
with urllib.request.urlopen(req, timeout=15) as r:
data = r.read()
print(f"HTTP {r.status} {method} {path}")
if data: print(data.decode("utf-8", "replace"))
except urllib.error.HTTPError as e:
print(f"HTTP {e.code} {method} {path}")
print(e.read().decode("utf-8", "replace"))
if __name__ == "__main__":
cmd = sys.argv[1]
if cmd == "mb": s3req("PUT", "/" + sys.argv[2] + "/") # 建桶
elif cmd == "put": s3req("PUT", "/" + sys.argv[2], open(sys.argv[3], "rb").read()) # 上传
elif cmd == "get": s3req("GET", "/" + sys.argv[2]) # 下载
elif cmd == "ls": s3req("GET", "/" + sys.argv[2].strip("/") + "/", query="list-type=2") # 列举
创建对象存储桶:
python3 s3cli.py mb ts-demo
实测回显(全新桶首次创建):
HTTP 200 PUT /ts-fresh/
⚠️ 注意:桶名全局唯一且重复创建会报 409。实测对已存在的
ts-demo再次执行建桶的回显:HTTP 409 PUT /ts-demo/ <?xml version="1.0" encoding="UTF-8"?> <Error><Code>BucketAlreadyOwnedByYou</Code><Message>Your previous request to create the named bucket succeeded and you already own it.</Message><BucketName>ts-demo</BucketName><Resource>/ts-demo/</Resource><RequestId>18E3D9CC54B857C9</RequestId><HostId>dd9025bab4ad464b049177c95eb6ebf374d3b3fd1af9251148b658df7ac2e3e8</HostId></Error>看到 409 不代表部署失败,只说明桶已存在,直接进入下一步即可。
5.2 上传与下载闭环验证
printf 'TagSpaces 部署验证文件:S3 闭环写读测试。\n' > verify.md
python3 s3cli.py put ts-demo/verify.md verify.md
python3 s3cli.py get ts-demo/verify.md
python3 s3cli.py ls 'ts-demo/'
实测回显(逐行照抄):
HTTP 200 PUT /ts-demo/verify.md
HTTP 200 GET /ts-demo/verify.md
TagSpaces 部署验证文件:S3 闭环写读测试。
<KeyCount>2</KeyCount>
<Key>note.md</Key>
<Key>verify.md</Key>
上传 200、下载回读内容与写入一致、列举可见对象——对象存储读写链路完整可用,且密钥 admin/q1w2e3r4 有效。ls 输出中的 note.md 为此前通过 Web 界面上传的对象,与 verify.md 同桶共存。
5.3 跨域(CORS)确认
TagSpaces Web 的页面源是 http://<服务器IP>:8148,而 S3 请求发往 http://<服务器IP>:8149——跨端口即跨域。MinIO 对 S3 API 默认回显宽松的 CORS 头,验证方式:
curl -s -o /dev/null -D- -H 'Origin: http://localhost:8148' http://127.0.0.1:8149/ts-demo/ | grep -iE 'HTTP/|access-control-allow-origin'
实测回显:
HTTP/1.1 403 Forbidden
Access-Control-Allow-Origin: http://localhost:8148
💡 说明:这里的 403 是未签名请求访问私有桶的正常拒绝(浏览器会带 SigV4 签名访问,不会 403);关键在第二行——
Access-Control-Allow-Origin已按请求源回显,跨域放行成立。若部署到公网域名后浏览器控制台报 CORS 错误,请核对浏览器实际访问的 S3 端口与第 4.1 节映射是否一致。
六、Web 界面接入对象存储
6.1 外置配置预置位置
手工方式:浏览器打开 http://<服务器IP>:8148,在位置管理里新建对象存储位置,填入端点 http://<服务器IP>:8149、桶名 ts-demo、密钥 admin/q1w2e3r4、区域 us-east-1。
声明式方式(推荐,可随编排一起交付):在 compose 同目录准备 extconfig.js(即第 4.1 节只读挂载进应用根目录的文件):
// TagSpaces Web 外置配置(实验用)
window.ExtSaveLocationsInBrowser = true;
window.ExtTagLibrary = [
{
title: "项目标签",
color: "#8bc34a",
textcolor: "#ffffff",
expanded: true,
children: [
{ title: "财务", color: "#f44336", textcolor: "#ffffff" },
{ title: "合同", color: "#2196f3", textcolor: "#ffffff" },
{ title: "已审阅", color: "#4caf50", textcolor: "#ffffff" }
]
}
];
window.ExtLocations = [
{
uuid: "b3f2a1c8-6d4e-4f2a-9b7c-1a2b3c4d5e6f",
type: "1",
name: "MinIO ts-demo",
path: "",
accessKeyId: "admin",
secretAccessKey: "q1w2e3r4",
bucketName: "ts-demo",
region: "us-east-1",
endpointURL: "http://localhost:8149",
isDefault: true,
isReadOnly: false,
isNotEditable: false,
disableIndexing: false,
disableThumbnailGeneration: false,
fullTextIndex: true,
watchForChanges: false,
maxIndexAge: 600000,
persistTagsInSidecarFile: true
}
];
逐项说明(全量参数见本专栏《TagSpaces 6.13.9 配置参数详解》):
type: "1":对象存储位置;"0"是本地文件夹(桌面版专用,Web 版不可用);endpointURL:浏览器访问的 S3 地址,不是服务器本机地址——部署在云服务器上时应写http://<服务器公网IP>:8149;isDefault: true:应用启动自动加载该位置;ExtSaveLocationsInBrowser: true:允许位置数据(含密钥)持久化到浏览器 localStorage;Web 版默认关闭,关闭时每次打开都要手工重建位置。⚠️ 公用电脑务必保持默认关闭,离开前清空站点数据(官方文档明确警告);persistTagsInSidecarFile: true:S3 对象无法改名,标签必须走.ts/旁车 JSON;ExtTagLibrary:预置标签库(本文预置「项目标签」组:财务/合同/已审阅),定义后界面标签库转为只读;maxIndexAge: 600000:索引有效期 10 分钟(毫秒),过期后浏览器重建索引。
验证配置文件已被应用伺服:
curl -sI http://127.0.0.1:8148/extconfig.js | grep -iE 'HTTP|Content-Type|Content-Length'
curl -s http://127.0.0.1:8148/extconfig.js | head -2
实测回显:
HTTP/1.1 200 OK
Content-Type: application/javascript
Content-Length: 986
// TagSpaces Web 外置配置(实验用)
window.ExtSaveLocationsInBrowser = true;
extconfig.js 以 200 返回、Content-Length 与宿主文件字节数一致、首行注释与首条参数可见,说明 nginx 已正确伺服该文件。浏览器打开 http://<服务器IP>:8148 后,左侧位置列表即出现预置的「MinIO ts-demo」位置,点击进入即可浏览桶内对象(官方文档:外置配置的位置自动只读,不能在界面里改属性)。
6.2 界面操作与底层对象对照
在 Web 界面中打开位置后,界面上看到的每个文件都对应桶里的一个 S3 对象;对文件打标签、写描述(旁车模式)时,应用会在桶内同前缀下创建 .ts/ 目录与 JSON 对象。用第 5.1 节的客户端复核真实落盘:
python3 s3cli.py ls 'ts-demo/'
实测回显(节选,仅键名):
<KeyCount>2</KeyCount>
<Key>note.md</Key>
<Key>verify.md</Key>
继续在界面上传文件后再次列举,<Key> 列表会逐个增加——界面操作与 S3 对象一一对应,这正是第五章读写闭环验证的意义:闭环通了,界面一定通;界面不通时,先回到命令行复测闭环。
七、数据持久化说明
全部业务数据只有一份,位于宿主机目录 /opt/data/quzuo/tmp/tagspaces/compose/data(对应编排里的 ./data:/data):
- 桶与对象:
data/<桶名>/<对象键>(如data/ts-demo/note.md); - 旁车元数据:
data/<桶名>/<前缀>/.ts/*.json; - 存储自身元数据:
data/.minio.sys/(勿手工改动)。
docker compose down 再 up -d 后数据完整保留,实测:重建后健康检查 200、原对象仍在(列举回显 <KeyCount>1</KeyCount>、<Key>note.md</Key>)。备份策略:停写后直接打包 data/ 目录即可;在线备份建议用 mc mirror(MinIO 官方客户端)同步到异地 S3。
Web 应用本体(nginx + 静态页面)无状态,重建即恢复;唯一的"状态"在浏览器 localStorage(开启 ExtSaveLocationsInBrowser 后的位置与密钥),不随服务端迁移,换浏览器需重新加载位置(预置配置的存在让这一步零成本)。
八、环境变量表
本栈只有对象存储服务消费环境变量(TagSpaces Web 为纯静态应用,无环境变量可配,其配置入口是 extconfig.js):
| 变量 | 示例值 | 说明 |
|---|---|---|
MINIO_ROOT_USER | admin | root 访问密钥(Access Key),同时是 TagSpaces 位置配置里的 accessKeyId |
MINIO_ROOT_PASSWORD | q1w2e3r4 | root 私有密钥(Secret Key),对应 secretAccessKey;生产环境必须换强密钥 |
MINIO_BROWSER_REDIRECT_URL | 未设置 | 控制台重定向地址;经反向代理暴露控制台时需设置 |
补充两点:
- TagSpaces Web 侧的等价「环境变量」是
extconfig.js中的window.Ext*参数(完整清单与默认值见本专栏《TagSpaces 6.13.9 配置参数详解》); - 演示环境使用
admin/q1w2e3r4弱口令仅因对象存储端口未对公网开放;生产部署请改强密钥,或为每个使用者创建最小权限子账号(只授权其工作桶)。
九、配置文件挂载说明
| 文件 | 挂载 | 作用 | 改后生效方式 |
|---|---|---|---|
extconfig.js | ./extconfig.js:/usr/share/nginx/html/extconfig.js:ro | 预置位置、标签库、界面开关 | 浏览器刷新页面(应用启动时加载一次);文件本身为静态直出,服务端无需重启 |
data/ | ./data:/data | 对象存储全部数据 | 持久化目录,勿手工增删 |
/etc/nginx/conf.d/default.conf | 需自定义镜像或 docker cp 覆盖 | nginx 配置(加 basic auth、TLS 时改这里) | docker compose restart tagspaces |
实测容器内 nginx 配置为官方镜像默认值(监听 80、站点根 /usr/share/nginx/html),未做任何额外配置即可工作。官方文档建议的加固路径:用 htpasswd 生成密码文件后 docker cp 进容器,在 default.conf 的 server 段加 auth_basic 两行并重启——这一步同时保护了 extconfig.js(官方警告:该文件含 S3 密钥时必须限制访问)。
十、等价 docker run 命令
不使用 Compose 时,两条 docker run 与第 4.1 节编排等价(注意先建网络、MinIO 先于 Web 启动):
docker network create --subnet 10.89.60.0/24 tagspaces-6.13.9-net
docker run -d --name tagspaces-6.13.9-minio \
--network tagspaces-6.13.9-net \
-p 8149:9000 -p 8150:9001 \
-v /opt/data/quzuo/tmp/tagspaces/compose/data:/data \
-e MINIO_ROOT_USER=admin -e MINIO_ROOT_PASSWORD=q1w2e3r4 \
--restart unless-stopped \
pgsty/minio:RELEASE.2026-08-04T00-00-00Z \
server /data --console-address ":9001"
docker run -d --name tagspaces-6.13.9-web \
--network tagspaces-6.13.9-net \
-p 8148:80 \
-v /opt/data/quzuo/tmp/tagspaces/compose/extconfig.js:/usr/share/nginx/html/extconfig.js:ro \
--restart unless-stopped \
tagspaces/tagspaces-lite-web:6.13.9
与 Compose 版的一致性由端口、挂载、网络三要素保证;日常运维仍建议统一走 Compose。
十一、常用运维命令
docker compose ps # 栈内服务状态与端口映射
docker compose logs -f tagspaces # Web 应用(nginx)日志
docker compose logs -f minio # 对象存储日志
docker compose restart # 整栈重启
docker compose down # 停止并移除容器与网络(数据目录保留)
docker compose up -d # 重新拉起
docker compose pull && docker compose up -d # 升级到编排文件中的新 tag
docker compose ps 实测回显见第 4.3 节;重启后健康与数据验证:
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8148/
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8149/minio/health/live
python3 s3cli.py ls 'ts-demo/'
实测回显(down/up 循环后):
200
200
<KeyCount>2</KeyCount>
<Key>note.md</Key>
<Key>verify.md</Key>
升级注意(官方文档原文归纳):换新版本镜像前先确认 ExtSaveLocationsInBrowser 已开启,再在浏览器加载新版页面,否则浏览器保存的位置数据会丢失;升级后可用第 4.3 节的 sw-config.js 缓存名核对新版本号。
十二、常见问题
Q1:docker compose down 卡在 Network tagspaces-6.13.9-net Resource is still in use,怎么办?
本栈网络被编排之外的运行实例占用时就会这样。实测实录(一个 CLI 辅助运行实例也接在同一网络上时):
Container tagspaces-6.13.9-web Stopping
Container tagspaces-6.13.9-web Stopped
Container tagspaces-6.13.9-web Removing
Container tagspaces-6.13.9-web Removed
Container tagspaces-6.13.9-minio Stopping
Container tagspaces-6.13.9-minio Stopped
Container tagspaces-6.13.9-minio Removing
Container tagspaces-6.13.9-minio Removed
Network tagspaces-6.13.9-net Removing
Network tagspaces-6.13.9-net Resource is still in use
定位方法与处置:
docker network inspect tagspaces-6.13.9-net --format '{{range .Containers}}{{.Name}} {{end}}'
把列出的编排外实例逐个断开网络后重新 down:
docker network disconnect tagspaces-6.13.9-net <占用实例名>
docker compose down
实测断开后的干净回显:
Network tagspaces-6.13.9-net Removing
Network tagspaces-6.13.9-net Removed
Q2:浏览器打不开文件、控制台一片 CORS/网络错误?
Web 版的文件操作由浏览器直连 S3 API。依次核对:① 8149(S3 API)端口对浏览器网络可达(公网部署必须开放,不能只开 8148);② extconfig.js 里 endpointURL 写的是浏览器侧可达地址;③ 服务端防火墙/安全组放行 8149。命令行侧用第 5.2 节闭环复测:闭环通而界面不通,问题一定在浏览器到 8149 的网络路径上。
Q3:签名/鉴权类 403(SignatureDoesNotMatch、InvalidAccessKeyId)?
多为密钥或区域不匹配:核对 extconfig.js 的 accessKeyId/secretAccessKey 与第 4.1 节 MINIO_ROOT_USER/MINIO_ROOT_PASSWORD 完全一致、region 为 us-east-1(MinIO 默认区域)。用第 5.2 节客户端验证同一组密钥——命令行能读写而界面报 403 时,重点检查位置配置是否复制走样(首尾空格、全角引号)。
Q4:每次刷新页面位置都不见了,要重新配置?
这是 ExtSaveLocationsInBrowser 未开启的默认安全行为(官方设计:避免在浏览器留下 S3 密钥)。在 extconfig.js 加 window.ExtSaveLocationsInBrowser = true; 并刷新页面即可持久化。代价与官方警告:密钥会落进浏览器 localStorage,公用/共享电脑不要开启,离开前清空站点数据。
Q5:升级 TagSpaces 后浏览器位置数据丢了?
官方文档明确:升级镜像后先确认 ExtSaveLocationsInBrowser 开启,再加载新版页面。补救:因为有 extconfig.js 预置位置,刷新后位置会自动回来(这正是第六章推荐声明式配置的原因——位置定义在服务端文件里,不依赖浏览器状态)。
Q6:想给部署加访问密码?
TagSpaces Web 本身无账号体系。按官方教程在 nginx 层加 basic auth:htpasswd -c .htpasswd user1 生成密码文件,docker cp 到容器 /etc/nginx/.htpasswd,在 /etc/nginx/conf.d/default.conf 的 server 段加 auth_basic "TagSpaces Web"; 与 auth_basic_user_file /etc/nginx/.htpasswd;,重启服务生效。官方同时警告:extconfig.js 含 S3 密钥,必须与页面一起纳入访问控制。
十三、参考链接
- 官方 Docker 部署教程:https://docs.tagspaces.org/tutorials/tagspaces-web-docker/
- 外置配置参考(ExtLocations 等):https://docs.tagspaces.org/dev/external-config/
- 官方 MinIO 接入教程:https://docs.tagspaces.org/tutorials/setup-minio-bucket-nas/
- Docker Hub 镜像:https://hub.docker.com/r/tagspaces/tagspaces-lite-web
- AWS SigV4 签名规范(s3cli.py 实现依据):https://docs.aws.amazon.com/general/latest/gr/sigv4-signing.html
- 本专栏系列:《TagSpaces 介绍与选型指南》、《TagSpaces 6.13.9 配置参数详解》、《TagSpaces 6.13.9 常用 CLI 命令与工具详解》