Solara 2.1.6 配置参数详解
Solara 2.1.6 配置参数逐项详解:PASSWORD/API_BASE_URL/language 三个可用环境变量的生效与失效边界、PORT/HOST/DATA_DIR 被入口脚本固定的实测结论、五类缓存参数、前端内置常量,附三种场景的生产配置模板与故障注入回显。
Solara 2.1.6 配置参数详解
目标:把 Solara 2.1.6 的全部可配置项讲透——哪些环境变量真正生效、哪些被入口脚本固定、缓存与前端常量如何影响行为,并给出可照抄的生产配置模板。文中每个「生效/不生效」结论都配有 2026-10-25 在 Ubuntu 22.04 + Docker Engine 29.9.2 上的实测回显。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS(x86_64)
- Docker Engine:29.9.2,Docker Compose 插件 v5.6.1
- Solara 版本:2.1.6(镜像
ghcr.io/akudamatata/solara:2.1.6,linux/amd64,765020763 字节) - 部署形态:Docker Compose 单实例,宿主端口 8136 → 容器 8787
- 实测基线:空载 CPU 0.88% / 内存 195.4 MiB / 71 PIDs
- 演示访问口令:
q1w2e3r4 - 配置形态:无外部配置文件,全部配置项来自环境变量;容器内
/app/.dev.vars由入口脚本在每次启动时生成
二、前置条件
- 已按部署篇完成一次可运行的部署,容器状态为
Up。验证:
docker compose ps
实测输出:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
solara-v2.1.6-app ghcr.io/akudamatata/solara:2.1.6 "/app/docker-entrypo…" solara 14 minutes ago Up 14 minutes 0.0.0.0:8136->8787/tcp, [::]:8136->8787/tcp
- 已取得有效登录 Cookie(后续受保护接口都要带它):
cd /opt/solara
curl -s -c cookies.txt -X POST http://127.0.0.1:8136/api/login \
-H 'Content-Type: application/json' -d '{"password":"q1w2e3r4"}'
实测输出:
{"success":true}
三、参数查看与修改方式
Solara 的参数分三层,查看与修改方式各不相同:
| 层 | 内容 | 查看方式 | 修改方式 |
|---|---|---|---|
| 编排层(用户可改) | PASSWORD、API_BASE_URL、language | docker inspect 看容器实际环境变量 | 改 docker-compose.yml 的 environment → docker compose up -d --force-recreate |
| 入口脚本层(固定) | PORT=8787、HOST=0.0.0.0、DATA_DIR=/data、WRANGLER_API_URL=http://127.0.0.1:8788 | docker exec 读启动日志 | 改不动,需改宿主端口映射或重建镜像 |
| 源码内置层(前端常量) | 音源列表、音质档位、雷达榜单、缓存 TTL | 浏览器调试控制台 / 源码 | 需改源码重新构建镜像 |
3.1 查看容器实际生效的环境变量
docker inspect solara-v2.1.6-app \
--format '{{range .Config.Env}}{{println .}}{{end}}' | grep -E 'PASSWORD|API_BASE_URL|language'
实测输出:
PASSWORD=q1w2e3r4
API_BASE_URL=https://music-api.gdstudio.xyz/api.php
language=ENG
💡 说明:这里看到的是编排层注入的原始值。Wrangler 进程读取的是入口脚本生成的
/app/.dev.vars,内容与这三个变量一一对应(见 5.3 节回显)。
3.2 修改参数的正确姿势
# 1. 编辑编排文件(示例:改口令)
vi /opt/solara/docker-compose.yml
# 2. 重建容器让新环境变量生效
cd /opt/solara && docker compose up -d --force-recreate
实测输出:
Container solara-v2.1.6-app Creating
Container solara-v2.1.6-app Created
Container solara-v2.1.6-app Starting
Container solara-v2.1.6-app Started
⚠️ 注意:
docker compose restart不会重读编排文件。restart只是重启同一份容器配置,环境变量仍是旧值。验证方式:改口令后仅执行restart,用新口令登录仍返回{"success":false};执行up -d --force-recreate后新口令才生效。
四、参数总览
4.1 环境变量
| 变量 | 默认值 | 生效性 | 作用面 | 详见 |
|---|---|---|---|---|
PASSWORD | 空(开放访问) | ✅ 生效 | Express 认证中间件 + Wrangler 中间件 | 5.1 |
API_BASE_URL | https://music-api.gdstudio.xyz/api.php | ✅ 生效 | /proxy 上游地址 | 5.2 |
language(或 LANGUAGE) | 空(中文) | ⚠️ Docker 形态仅写入不生效 | Wrangler HTML 注入 | 5.3 |
PORT | 8787 | ❌ 被入口脚本覆盖 | Express 监听端口 | 5.4 |
HOST | 0.0.0.0 | ❌ 被入口脚本覆盖 | Express 监听地址 | 5.4 |
DATA_DIR | /data | ❌ 被入口脚本覆盖 | SQLite 数据目录 | 5.5 |
WRANGLER_API_URL | http://127.0.0.1:8788 | 入口脚本注入 | Express→Wrangler 内部转发 | 5.4 |
关键解读:只有 3 个变量是用户真正能调的。PORT/HOST/DATA_DIR 虽在 Express 源码里支持读取,但 docker-entrypoint.sh 在启动 Node 前无条件 export 了固定值,所以环境变量被覆盖。
4.2 服务端内置常量
| 常量 | 取值 | 位置 | 说明 |
|---|---|---|---|
| 容器内监听端口 | 8787 | docker-entrypoint.sh | 固定 export PORT=8787 |
| Wrangler 监听 | 127.0.0.1:8788 | docker-entrypoint.sh | 仅回环,不对外暴露 |
| 数据库路径 | /data/solara.db | server/db.js | SQLite 主库,WAL 模式 |
| 认证 Cookie 名 | auth | server/routes/login.js | 值 = Base64(口令) |
| Cookie 有效期 | 48 小时(Max-Age=172800) | server/routes/login.js | 实测响应头一致 |
/proxy 缓存 TTL | 300 秒 | server/routes/proxy.js | 空结果/错误不缓存 |
/palette 缓存 TTL | 3600 秒 | server/routes/palette.js | 封面取色结果 |
| 上传体上限 | 10 MB | server/index.js | express.json({limit:'10mb'}) |
| 酷我音频代理白名单 | *.kuwo.cn | server/routes/proxy.js | 仅该域可作流代理目标 |
4.3 前端内置常量(源码级)
| 常量 | 取值 | 影响 |
|---|---|---|
SOURCE_OPTIONS | netease / kuwo / joox / bilibili | 搜索源下拉的四项,实测仅 netease 可用 |
QUALITY_OPTIONS | 128 / 192 / 320 / 999 | 音质档位,默认 320 |
RADAR_PLAYLISTS | 热歌榜 3778678、飙升榜 19723756、新歌榜 3779629、潮流风向榜 13372522766、原创榜 2884035、全球说唱榜 14028249541、Billboard 60198 | 音乐雷达可勾选榜单 |
STORAGE_KEYS_TO_SYNC | 15 个键(playlistSongs、favoriteSongs、playbackQuality…) | 哪些前端状态同步到服务端 |
PALETTE_STORAGE_KEY | paletteCache.v3 | 前端封面取色缓存键 |
五、核心参数分类详解
5.1 访问控制:PASSWORD
作用:全站单一共享口令。未配置时完全开放;配置后所有非公开路径都要校验 Cookie auth。
生效行为(三种场景均已实测):
场景 A:配置口令(本文基线配置)
curl -s -o /dev/null -w "GET / -> %{http_code} redirect=%{redirect_url}\n" http://127.0.0.1:8136/
curl -s -X POST http://127.0.0.1:8136/api/login -H 'Content-Type: application/json' \
-d '{"password":"wrong-pass-2026"}' -w "\nHTTP %{http_code}\n"
实测输出:
GET / -> 302 redirect=http://127.0.0.1:8136/login
{"success":false}
HTTP 401
正确口令则下发 Cookie:
Set-Cookie: auth=cTF3MmUzcjQ=; Max-Age=172800; Path=/; SameSite=Lax; HttpOnly
场景 B:口令留空(删除 PASSWORD 行后重建;本文为不打断基线服务,用独立实例 solara-nopw、宿主端口 8142 验证)
docker logs solara-nopw | grep Password
curl -s -o /dev/null -w "GET / -> %{http_code}\n" http://127.0.0.1:8142/
实测输出:
Password : not set (open access)
Password: ✗ not set (open access)
GET / -> 200
⚠️ 注意:留空即任何能访问端口的人都能直接进入播放器,且
/api/storage也开始接受匿名读写。仅在完全可信的内网、或前面已有反向代理做统一认证时才可留空。
场景 C:口令变更。改 PASSWORD 并重建容器后,旧 Cookie 立即失效(auth 是口令的 Base64,口令变了值就变了),所有已登录用户需重新登录。
💡 技术拓展:访问控制模型不止「共享口令」一种——
模型 代表实现 特点 适用规模 共享口令 Solara(本文) 零账号体系,一个口令全站通行 个人/家庭 1-3 人 多用户账号 Navidrome、Jellyfin 每人独立账号、权限、歌单 团队/多人 前置统一认证 Nginx basic auth、Authelia、OAuth2 Proxy 认证交给反代,应用本身不设防 已有 SSO 的组织 Solara 自身只提供第一种;需要多用户时只能靠反向代理层叠加第三种。
安全提示(实测缺陷):口令会以明文形式出现在容器启动日志(Password : configuredq1w2e3r4),因为入口脚本把 configured 与口令值做了字符串拼接。处理建议见《Solara 日常运维手册》。
5.2 上游音源:API_BASE_URL
作用:决定搜索、歌词、封面、播放直链全部转发到哪个聚合 API。Express 的 /proxy 会把它转发给内部 Wrangler,由 Wrangler 用 BoringSSL 指纹请求上游。
默认值实测:
curl -s -b cookies.txt --max-time 60 \
"http://127.0.0.1:8136/proxy?types=search&source=netease&name=%E5%91%A8%E6%9D%B0%E4%BC%A6&count=5&pages=1" \
-o /dev/null -w "HTTP %{http_code} bytes=%{size_download} time=%{time_total}s\n"
实测输出:
HTTP 200 bytes=1188 time=6.454419s
故障注入实测:把 API_BASE_URL 指向不可达地址(http://127.0.0.1:9/api.php)后重建容器,搜索接口返回:
HTTP 500
响应体为 Wrangler 侧抛出的上游连接错误(节选):
Error: Network connection lost.
at async proxyApiRequest (file:///app/functions/proxy.ts:130:20)
at async i18nMiddleware (file:///app/functions/_middleware.ts:86:20)
⚠️ 注意:上游不可达时前端表现为「搜索无结果」并可能弹出错误提示,服务端日志是判定位数的第一手依据。恢复正确地址后重建容器即恢复 200。
音源支持现状(实测):API_BASE_URL 只是地址,能搜到哪些源由上游决定。实测 source=kuwo 返回:
{"detail":"Value of `source` is not supported."}
HTTP 400
README 宣称的「网易云/QQ/酷狗」在当前上游已收缩为仅 netease 可用。前端下拉仍显示四项,属于前端常量与上游能力的错位。
高码率参数(br)实测边界:
| 取值 | 实测结果 |
|---|---|
| 128 | HTTP 200,2.9 秒解析成功(mp3,3820077 字节) |
| 320 | 115 秒超时(HTTP 000) |
| 999(FLAC) | 115 秒超时(HTTP 000) |
💡 说明:
br不是 Solara 的配置项,而是每次请求/proxy?types=url&br=时携带的参数,由前端音质偏好决定。生产默认建议 128/192。
5.3 界面语言:language / LANGUAGE
作用:Wrangler 中间件检测到 ENG 时,向 HTML <head> 注入 <script>window.SITE_LANGUAGE = "ENG";</script>,前端 i18n 模块据此切换文案。
实测结论:Docker 形态下写入成功、界面不切换。 证据链三步:
第一步,变量确实写进了 Wrangler 读取的文件:
docker exec solara-v2.1.6-app cat /app/.dev.vars
实测输出:
PASSWORD="q1w2e3r4"
API_BASE_URL="https://music-api.gdstudio.xyz/api.php"
language="ENG"
第二步,经 8787(Express 对外端口)取回的页面里没有注入:
curl -s http://127.0.0.1:8136/login | grep -c 'SITE_LANGUAGE'
实测输出:
0
第三步,直连容器内 8788(Wrangler)取回的页面里有注入:
docker exec solara-v2.1.6-app node -e "fetch('http://127.0.0.1:8788/login').then(r=>r.text()).then(t=>console.log('count='+(t.match(/SITE_LANGUAGE/g)||[]).length))"
实测输出:
count=1
原因定位(源码核实):Docker 形态下 GET / 与 GET /login 由 Express 的 res.sendFile() 直接返回静态文件,请求根本不经过 Wrangler 的 i18nMiddleware;只有 /proxy 会转发给 Wrangler。因此注入逻辑在 Docker 形态下永远碰不到页面。
⚠️ 注意:官方 README 称 Docker 下
language=ENG可切英文,与实测不符。该参数仅在 Cloudflare Pages 部署形态生效。Docker 部署可保留该行(无副作用),但不要指望界面变化。
5.4 端口与监听:PORT / HOST
实测结论:不可通过环境变量修改。
入口脚本在启动 Node 前硬编码:
export PORT=8787
export HOST=0.0.0.0
export DATA_DIR=/data
export WRANGLER_API_URL=http://127.0.0.1:8788
因为 export 发生在读取环境变量之后、node server/index.js 之前,编排文件里传的 PORT/HOST 会被覆盖。
正确改法:改宿主映射,容器内始终 8787:
ports:
- "9090:8787" # 宿主 9090 → 容器 8787
WRANGLER_API_URL 同理固定为 http://127.0.0.1:8788:Wrangler 与 Express 在同一容器内,走回环最省事,也让 8788 天然不暴露到宿主机。
5.5 数据目录:DATA_DIR / volumes
实测结论:数据目录固定为 /data,只能通过 volumes 把宿主目录挂上去。
volumes:
- ./data:/data
目录内容与职责:
| 文件/目录 | 作用 | 是否必须备份 |
|---|---|---|
solara.db | SQLite 主库:playback_store(播放状态/队列)、favorites_store(收藏) | ✅ 必须 |
solara.db-wal | WAL 日志,含尚未 checkpoint 的最新写入 | ✅ 必须(与主库一起) |
solara.db-shm | WAL 共享内存索引 | ✅ 建议一起 |
v3/ | Wrangler/miniflare 持久化(cache/、d1/、workflows/) | 可选,可重建 |
存储接口验证(确认数据库真的在读写):
curl -s -b cookies.txt "http://127.0.0.1:8136/api/storage?status=1"
curl -s -b cookies.txt -X POST http://127.0.0.1:8136/api/storage \
-H 'Content-Type: application/json' -d '{"data":{"doc-check-2026-10-25":"solara-2.1.6-ok"}}'
curl -s -b cookies.txt "http://127.0.0.1:8136/api/storage?keys=doc-check-2026-10-25"
实测输出:
{"d1Available":true}
{"d1Available":true,"updated":1}
{"d1Available":true,"data":{"doc-check-2026-10-25":"solara-2.1.6-ok"}}
💡 说明:
d1Available是历史命名(Solara 原先用 Cloudflare D1),Docker 形态下由本地 SQLite 顶替,返回值保持true表示存储可用。
5.6 缓存参数
Solara 有两级内存缓存,没有可配置的环境变量,但理解它们的行为对排障与容量规划很重要。
/proxy 响应缓存(TTL 300 秒):
- 缓存键 = 去掉随机签名
s与nocache后的完整 URL,因此重试同一请求会命中同一条缓存 - 只有
HTTP 200且响应体不含"error"/"status":0才写缓存 - 搜索结果为空(
[])不写缓存——避免把一次「API 繁忙」的空结果钉住 5 分钟 - 请求带
nocache=true时强制回源且不回写
命中判定实测(连续两次相同请求,看响应头):
curl -s -b cookies.txt -D h1.txt -o /dev/null \
"http://127.0.0.1:8136/proxy?types=search&source=netease&name=%E5%91%A8%E6%9D%B0%E4%BC%A6&count=5&pages=1"
curl -s -b cookies.txt -D h2.txt -o /dev/null \
"http://127.0.0.1:8136/proxy?types=search&source=netease&name=%E5%91%A8%E6%9D%B0%E4%BC%A6&count=5&pages=1"
grep -i 'x-cache-status' h1.txt h2.txt
实测输出:
h1.txt:X-Cache-Status: MISS
h2.txt:X-Cache-Status: HIT
/palette 封面取色缓存(TTL 3600 秒):
curl -s -b cookies.txt --max-time 30 -o palette.json \
-w "HTTP %{http_code} bytes=%{size_download} time=%{time_total}s\n" \
"http://127.0.0.1:8136/palette?image=https%3A%2F%2Fp2.music.126.net%2FyD9vbpuILH-tqNRIaP640g%3D%3D%2F109951163038292176.jpg%3Fparam%3D300y300"
实测输出(第二次调用,命中缓存):
HTTP 200 bytes=601 time=0.002076s
返回结构(键清单 + 关键色值):
keys: ['source', 'baseColor', 'averageColor', 'accentColor', 'contrastColor', 'gradients', 'tokens']
baseColor: #ba7f5d accentColor: #ba7f5d
palette 返回的 baseColor/accentColor/gradients/tokens 就是前端「流体极光」背景的取色结果;命中缓存时 2 毫秒返回,未命中需下载并解码封面(数百毫秒级)。
💡 技术拓展:缓存淘汰策略不止本文所用的「固定 TTL」——
策略 特点 适用场景 TTL(本文) 到期即失效,实现简单、内存可控 搜索结果这类「短时有效」数据 LRU 淘汰最久未使用,容量恒定 命中分布均匀的大对象缓存 LFU 淘汰访问频次最低 有明显热点长尾的数据 FIFO 先进先出,不看访问 顺序写入的流式队列 Solara 选用 TTL 300s/3600s:搜索与直链本就有时效(直链 URL 带时间戳、过期即失效),用 TTL 比 LRU 更贴合语义;进程内
Map每 5 分钟清理一次过期项,避免泄漏。
5.7 前端内置常量(改需重建镜像)
这些常量写死在前端源码里,运行期无法通过环境变量覆盖:
| 常量 | 位置 | 当前值 | 改法 |
|---|---|---|---|
| 音源列表 | js/constants.js SOURCE_OPTIONS | netease / kuwo / joox / bilibili | 改源码 → 自建镜像 |
| 音质档位 | js/constants.js QUALITY_OPTIONS | 128 / 192 / 320 / 999,默认 320 | 同上 |
| 雷达榜单 | js/constants.js RADAR_PLAYLISTS | 7 个网易云榜单 ID | 同上 |
| 默认雷达勾选 | js/constants.js DEFAULT_RADAR_GENRES | 热歌榜/新歌榜/飙升榜 | 同上 |
| 同步键集合 | js/constants.js STORAGE_KEYS_TO_SYNC | 15 个前端状态键 | 同上 |
💡 说明:音质、雷达榜单、搜索源三项在运行期可通过界面调整——双击桌面端左上角 Logo(移动端双击顶部标题栏)呼出隐藏设置面板;只有「增删选项本身」才需要改源码。
六、生产配置模板
6.1 模板 A:个人/家庭最小配置(1 核 1 GB、10 GB 磁盘、内网使用)
name: solara-v216-stack
services:
solara:
image: ghcr.io/akudamatata/solara:2.1.6
container_name: solara-v2.1.6-app
restart: unless-stopped
init: true
ports:
- "8136:8787"
environment:
- PASSWORD=q1w2e3r4
- API_BASE_URL=https://music-api.gdstudio.xyz/api.php
volumes:
- ./data:/data
networks:
solara-net:
ipv4_address: 10.89.65.10
networks:
solara-net:
driver: bridge
ipam:
config:
- subnet: 10.89.65.0/24
适用说明:内存 195 MiB 级、磁盘 < 1 MB 数据、镜像 765 MB;不加 language(Docker 下无效,省一行);口令必须设置(内网也建议设)。
6.2 模板 B:反向代理 + HTTPS(2 核 2 GB、20 GB SSD、公网暴露)
Nginx 侧(假设 Solara 在 8136,域名 music.example.com):
server {
listen 443 ssl;
server_name music.example.com;
ssl_certificate /etc/letsencrypt/live/music.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/music.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8136;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https; # 让 Solara 下发 Secure Cookie
proxy_read_timeout 300s; # 上游解析慢时留足时间
}
}
配套编排(只监听回环,强制走反代):
ports:
- "127.0.0.1:8136:8787"
environment:
- PASSWORD=q1w2e3r4
- API_BASE_URL=https://music-api.gdstudio.xyz/api.php
适用说明:X-Forwarded-Proto https 会让登录接口在 Cookie 上追加 Secure 属性;proxy_read_timeout 300s 用于兜住上游偶发的长耗时(实测热歌榜曾 180 秒超时,属上游问题,超时阈值给足只影响等待体验)。
⚠️ 注意:反向代理场景下不要把宿主端口做成
0.0.0.0暴露,否则https://IP:8136可绕过 TLS 直达服务。上面的127.0.0.1:8136:8787写法即限定本机访问。
6.3 模板 C:上游故障时的备用源配置(4 核 4 GB、50 GB 磁盘、多人共用)
environment:
- PASSWORD=q1w2e3r4
- API_BASE_URL=https://music-api.example.com/api.php
适用说明:当默认 GD音乐台持续返回 Challenge/超时(实测出现过搜索 6.45 秒、热歌榜 180 秒超时),换自建或备用聚合 API 是唯一根治手段。切换后必须重建容器并做一次搜索冒烟:
docker compose up -d --force-recreate
curl -s -b cookies.txt --max-time 60 \
"http://127.0.0.1:8136/proxy?types=search&source=netease&name=test&count=1&pages=1&nocache=true" \
-w "\nHTTP %{http_code}\n"
预期输出形态:
HTTP 200
6.4 三套模板对照
| 维度 | A 家庭最小 | B 反代 HTTPS | C 备用源 |
|---|---|---|---|
| 硬件建议 | 1 核 1 GB / 10 GB | 2 核 2 GB / 20 GB SSD | 4 核 4 GB / 50 GB |
| 端口暴露 | 内网直连 8136 | 仅回环 + Nginx 443 | 内网/反代均可 |
| 口令 | 必设 | 必设 + Secure Cookie | 必设 |
| language | 不加 | 不加 | 不加 |
| 适用人数 | 1-3 人 | 家庭/小团队 | 多人共用 |
| 主要风险 | 内网横向访问 | 证书续期 | 备用源自建成本 |
七、常见问题
Q1:改了 PASSWORD,但用新口令还是登不进去?
只执行了 restart。restart 不重读编排,必须 docker compose up -d --force-recreate。用 docker inspect 确认容器里的 PASSWORD 已是新值。
Q2:想改容器内端口 8787 到别的端口,设 PORT=9000 没用?
入口脚本硬编码 export PORT=8787 覆盖了环境变量(见 5.4)。正确做法是改编排文件 ports 左侧(宿主端口),容器内保持 8787。
Q3:设了 language=ENG,界面仍是中文?
Docker 形态下页面由 Express 直接发静态文件,绕过 Wrangler 的注入中间件,实测 8787 页面 SITE_LANGUAGE 计数为 0、8788 内部请求计数为 1(见 5.3)。这是部署形态限制,不是配置错误。
Q4:搜索有时 6 秒、有时 180 秒超时,是配置问题吗?
不是。耗时几乎全部花在上游聚合 API。实测同一部署:搜索结果 6.45 秒返回,热歌榜 playlist 接口 180 秒超时(HTTP 000)。调 API_BASE_URL 换源,或在反代侧把超时放宽以避免网关先断。
Q5:/api/storage 返回 401?
Cookie 缺失或已过期(48 小时)。重新 POST /api/login 拿 Cookie;注意未登录时 /proxy、/api/*、/palette 都返回 401 JSON,只有页面请求才 302 跳登录。
Q6:想让收藏持久化到别的位置?
只能通过 volumes 改宿主侧路径(-v /data1/solara:/data);容器内路径 /data 由 DATA_DIR 固定,不建议改。
Q7:缓存能不能关掉或调短?
没有对应环境变量。要强制回源,在请求里加 nocache=true;要彻底禁用缓存需改源码(server/routes/proxy.js 的 cache.set 调用)后重建镜像。