Sunshine 2026.914.233613 配置参数详解
Sunshine v2026.914.233613 配置体系全解:sunshine.conf 语法与 99 个配置键分组详解(默认值/取值范围核对源码 src/config.cpp)、四种修改方式实测与优先级、port 全家端口平移、origin_web_ui_allowed 与 CSRF 实测对照、apps.json 字段与 API CRUD 即时生效、POST /api/config 整体覆盖陷阱、生效机制与日志轮转(实测环境 2026-11-03)。
Sunshine 2026.914.233613 配置参数详解
目标:把 Sunshine 的配置体系讲透——
sunshine.conf语法与文件布局、四种修改方式(文件 / Web UI / REST API / CLI)及优先级、99 个配置键按功能分组逐项详解(默认值与取值范围均核对自 v2026.914.233613 源码src/config.cpp)、apps.json应用清单字段与 API 管理、配置生效机制与日志轮转、常见坑。本文所有回显均为 2026-11-03 在 Ubuntu 24.04.5 LTS 服务器上逐条实测照抄;无 GPU/无显示形态下管理面与配置面完整可用,编码链路仅做参数面说明。
1. 环境信息
| 项目 | 值 |
|---|---|
| 服务器 OS | Ubuntu 24.04.5 LTS(x86_64,内核 7.0.0-38-generic) |
| Sunshine 版本 | 2026.914.233613(commit 63d35f70,发布于 2026-09-15) |
| 运行形态 | root 实例,配置目录 /root/.config/sunshine/ |
| Web UI / API | https://localhost:47990(自签证书,curl 需 -k) |
| 管理凭据 | admin / q1w2e3r4(HTTP Basic) |
| GameStream 端口 | 47989(HTTP)/ 47984(HTTPS)/ 48010(RTSP) |
| 源码核对文件 | src/config.cpp(默认值块 737–913 行、解析块 1626–1976 行)、src/confighttp.cpp(API 面) |
前置阅读:产品与架构见 Sunshine 介绍与选型指南,服务器部署形态见 Sunshine Docker Compose 部署指南。
2. 配置体系总览
2.1 文件布局(实测)
Sunshine 的全部运行态文件落在用户配置目录(Linux 为 ~/.config/sunshine/,root 实例即 /root/.config/sunshine/)。首启后目录实测:
$ ls -la /root/.config/sunshine/
total 56
drwxr-xr-x 3 root root 4096 Nov 3 10:37 .
drwxr-xr-x 7 root root 4096 Nov 3 10:52 ..
-rw-r--r-- 1 root root 679 Nov 3 10:34 apps.json
drwxr-xr-x 2 root root 4096 Nov 3 10:34 credentials
-rw-r--r-- 1 root root 87 Nov 3 10:35 sunshine.conf
-rw-r--r-- 1 root root 258 Nov 3 10:37 sunshine.log
-rw-r--r-- 1 root root 831 Nov 3 10:37 sunshine.log.1
-rw-r--r-- 1 root root 116 Nov 3 10:37 sunshine.log.2
-rw-r--r-- 1 root root 831 Nov 3 10:37 sunshine.log.3
-rw-r--r-- 1 root root 4922 Nov 3 10:37 sunshine.log.4
-rw-r--r-- 1 root root 4792 Nov 3 10:36 sunshine.log.5
-rw-r--r-- 1 root root 144 Nov 3 10:35 sunshine_state.json
| 文件 | 作用 | 写入方 |
|---|---|---|
sunshine.conf | 主配置,key = value 键值行 | 手工编辑,或 Web UI/API 保存 |
apps.json | 流应用清单(JSON) | 手工编辑,或 Web UI/API 保存 |
sunshine_state.json | 管理员凭据(用户名+salt+SHA256)与已配对客户端 | 程序自动 |
credentials/ | CA 与服务端自签证书(Web UI 与 GameStream TLS 共用) | 程序自动 |
sunshine.log(.1~.5) | 运行日志,启动时轮转保留 5 份 | 程序自动 |
sunshine.conf 初始为空文件——所有参数都走内置默认值;只有被显式保存过的键才会落盘。实测一个配置了 4 键的文件:
$ cat /root/.config/sunshine/sunshine.conf
min_log_level = debug
sunshine_name = game-lab
upnp = false
origin_web_ui_allowed = pc
2.2 sunshine.conf 语法(源码解析器语义)
解析逻辑在 src/config.cpp 的 parse_option() / parse_config()(920–1064 行),规则如下:
| 规则 | 说明 |
|---|---|
| 基本格式 | key = value,等号两侧空白任意;键名区分大小写 |
| 注释 | # 起注释到行尾,行内注释也生效(值中 # 之后被剥掉) |
| 空行 / 无等号行 | 直接跳过,不报错 |
| 空值 | key = 后面无内容视为无效条目,跳过 |
| 列表值 | 值以 [ 开头时按括号配对跨行读取(dd_mode_remapping、global_prep_cmd 等 JSON 列表可写多行);缺 ] 会告警 config: Missing ']' in config option: <key> |
| 重复键 | try_emplace 语义——第一行生效,后续同名行被忽略 |
| 未知键 | 不致命,启动时在标准输出打印 Warning: Unrecognized configurable option [<key>](见 7.1) |
2.3 参数规模:99 个键 + 隐藏键 flags
从源码解析块(apply_config(),1626–1976 行)可提取 99 个配置键,即 Web UI Configuration 页与 sunshine.conf 的全部可写项。另有一个不在 99 键之列的隐藏键 flags:值为字符集合,0(PIN 走标准输入)、1(重置状态文件)、2(强制替换视频头)、p(开 UPnP),逐字符翻转对应开关(apply_flags(),1561–1586 行)。CLI 的 -0/-1/-2/-p 参数走的就是同一函数(见 D1)。
99 键按功能分组:网络监听 11、安全访问 6、标识/语言/日志 6、视频通用 10、编码器专属 38、软编 2、显示设备 10、音频 5、输入 18、系统集成 3(file_apps/global_prep_cmd/keybindings)。第 4 节逐组详解。
2.4 配置来源与优先级
一次启动的配置由三层叠加,后者不覆盖前者中已出现的键,实际优先级:
CLI key=value 参数 > 位置参数指定的 conf 文件 > 默认 ~/.config/sunshine/sunshine.conf > 内置默认值
实测:默认配置文件里写 sunshine_name = game-lab,再以 CLI 覆盖启动:
$ sunshine sunshine_name=cli-override origin_web_ui_allowed=pc upnp=false
启动日志逐行回显最终生效值(log_config_settings(),1609–1619 行):
[2026-11-03 02:36:54.200]: Info: config: 'min_log_level' = debug
[2026-11-03 02:36:54.200]: Info: config: 'origin_web_ui_allowed' = pc
[2026-11-03 02:36:54.200]: Info: config: 'sunshine_name' = cli-override
[2026-11-03 02:36:54.200]: Info: config: 'upnp' = false
sunshine_name 取 CLI 值而非文件值——CLI 胜出。日志里出现的每一条 config: 'key' = value 就是"配置文件+CLI 叠加后的显式覆盖集",未出现的键静默用默认值。
3. 四种修改方式(全部实测)
3.1 方式一:直接编辑 sunshine.conf + 重启
最朴素也最可控:加一行 key = value,重启进程生效。deb 安装的用户级服务用 systemctl --user restart sunshine;本实测环境直接重启了服务进程。
实测写入两个键并重启后,API 查询与 GameStream 握手都能看到效果:
$ curl -sk -u admin:q1w2e3r4 https://localhost:47990/api/config
{"min_log_level":"debug","platform":"linux","status":true,"sunshine_name":"game-lab","version":"2026.914.233613"}
$ curl -s "http://localhost:47989/serverinfo?uniqueid=00000000-0000-4000-8000-000000000000&hostaddress=10.89.62.1&protocol=128&appversion=7.1.431" | grep -o "<hostname>[^<]*</hostname>"
<hostname>game-lab</hostname>
启动日志同时留下加载行(见 2.4)。适合版本化管理:把 sunshine.conf 纳入 Git/Ansible,重启即部署。
3.2 方式二:Web UI Configuration 页
浏览器打开 https://localhost:47990(Basic 认证后进主页),Configuration 页按分组列出全部可配项,每项显示当前值与默认值,改完点 Save。
抓包该页前端脚本(config_page 资源)确认它只调两个后端接口:保存 = POST /api/config(把页面上全部表单值整体提交),重启 = POST /api/restart。所以 Web UI 方式本质是 3.3 的批量封装;注意 Save 会重写整个 sunshine.conf(见 3.3 的覆盖语义——UI 提交的是全量表单,正常手编文件的人反而要当心 API 的部分提交)。
3.3 方式三:REST API GET/POST /api/config
POST /api/config 接收 JSON 对象,把每个非空键值写成 key = value 行。实测:
$ curl -sk -u admin:q1w2e3r4 -X POST -H 'Content-Type: application/json' \
-d '{"sunshine_name":"game-lab","min_log_level":"debug"}' \
https://localhost:47990/api/config
{"status":true}
$ cat /root/.config/sunshine/sunshine.conf
min_log_level = debug
sunshine_name = game-lab
两个必须知道的语义(源码 saveConfig(),confighttp.cpp 1529–1567 行):
- 整体覆盖,不是增量合并:
write_file用请求体里的键重写整个文件。实测覆盖前文件有 3 行(min_log_level/sunshine_name/foo_bar),只提交{"sunshine_name":"game-lab"}一次后:
$ cat /root/.config/sunshine/sunshine.conf
sunshine_name = game-lab
其余键全部丢失。Web UI 之所以安全,是因为它每次提交全量表单;用 curl/脚本做 API 自动化时必须先 GET 再合并再 POST,或改用文件编辑。
- null 与空串被跳过:值为
null或空字符串的键不会写入文件(1552 行),即 API 无法把键"置空",只能删除整行(回到默认值需手工编辑或重写全量)。
GET /api/config 返回的是本次启动加载到的显式覆盖集(不含未覆盖的默认值),加 platform/version/status 三个固定字段——空配置文件时它就只有这三样:
$ curl -sk -u admin:q1w2e3r4 https://localhost:47990/api/config
{"platform":"linux","status":true,"version":"2026.914.233613"}
3.4 方式四:CLI——位置参数配置文件 + key=value 覆盖
启动命令支持两类位置参数(实测):
$ sunshine /tmp/my.conf # 第一个非 key=value 参数 = 配置文件路径
$ sunshine sunshine_name=cli-override # key=value 直接覆盖单个键
$ sunshine port=48999 # 见 4.1 端口平移实测
实测用 sunshine /tmp/my.conf 加载了非默认路径的文件,日志回显 config: 'upnp' = false、config: 'sunshine_name' = custom-path;key=value 形态见 2.4 的优先级实测。适合"一份服务器多套 Sunshine 配置"或 CI 冒烟测试。
4. 参数分组详解
以下表格的"默认值"列核对自源码默认块(config.cpp 737–913 行),"范围/取值"核对自解析块;标注【实测】的条目附本文回显证据。未标注者为源码/官方文档口径,在无 GPU 形态下无法端到端验证串流效果。
4.1 网络与监听(11 键)
| 键 | 默认值 | 取值/范围 | 说明 |
|---|---|---|---|
port | 47989 | 1025–65514【实测】 | GameStream HTTP 基准端口,其余端口全部由它派生(见下方端口表) |
address_family | ipv4 | ipv4 / both | both 同时监听 v6 |
bind_address | 空(全部接口) | IP 字符串 | 限定监听地址 |
upnp | false | 布尔 | 路由器自动映射;网络无 UPnP 设备时启动告警【实测】:Warning: Couldn't discover any IPv4 UPNP devices |
external_ip | 空 | IP/域名 | 对外通告地址(NAT 后手动指定) |
ping_timeout | 10000(10s) | -1~INT_MAX,毫秒 | 客户端失联判定 |
packetsize | 0(自动) | 0~协议上限 | UDP 分片大小,MTU 异常网络才需要调 |
fec_percentage | 20 | 0–100 | 前向纠错冗余比例,丢包高的网络加大 |
lan_encryption_mode | 0 | 0–2 | 局域网加密:0=never / 1=opportunistic / 2=强制(源码常量 ENCRYPTION_MODE_NEVER 为默认) |
wan_encryption_mode | 1 | 0–2 | 公网加密,默认 opportunistic |
min_threads | 2 | 整数 | 编码线程下限 |
port 一改,整族端口平移。实测 sunshine port=48999 起临时实例:
[2026-11-03 03:01:08.144]: Info: Configuration UI available at [https://localhost:49000]
$ curl -s "http://localhost:48999/serverinfo?uniqueid=...&protocol=128&appversion=7.1.431"
... state="SUNSHINE_SERVER_FREE" ...
<HttpsPort>48994</HttpsPort>
<ExternalPort>48999</ExternalPort>
端口派生公式(源码常量 + 本文实测汇总):
端口 公式 默认值 48999 实例实测 GameStream HTTP port47989 48999 GameStream HTTPS port - 547984 48994 Web UI / API port + 147990 49000 RTSP port + 2148010 49020 UDP 控制/视频/音频 port + 9/10/1147998/47999/48000 49008–49010 同机第二个实例必须错开
port,否则 RTSP 先撞:Fatal: Couldn't bind RTSP server to port [48010], Address already in use(实测第二实例 fatal 原文)。
4.2 安全与访问控制(6 键)
| 键 | 默认值 | 取值/范围 | 说明 |
|---|---|---|---|
origin_web_ui_allowed | lan | 仅 pc / lan / wan(源码白名单) | Web UI/API 访问面:pc 仅本机回环,lan 加内网段,wan 放开全部 |
cert | credentials/ 下默认证书 | 路径 | TLS 服务端证书 |
pkey | credentials/ 下默认私钥 | 路径 | TLS 私钥 |
file_state | sunshine_state.json | 文件名 | 凭据与配对状态存储 |
credentials_file | 同 file_state | 路径 | 可单独指定凭据文件(解析顺序上先取 file_state 再被本键覆盖,1763–1767 行) |
csrf_allowed_origins | 空(内置 localhost 集始终生效) | https:// 起源列表 | 追加允许携带 CSRF 令牌的浏览器起源 |
origin_web_ui_allowed 三档实测对照(设 pc 后):
| 来源 | 请求 | 结果 |
|---|---|---|
本机 127.0.0.1 | GET https://localhost:47990/ | 200 |
局域网地址 10.89.62.1 | 同上 | 403 |
取值写错(如 all)会被源码白名单拒绝并回退默认——string_restricted_f 语义,配错不生效也不报错,排障时先看日志里 config: 行的实际值。
csrf_allowed_origins 机制(源码 confighttp.cpp 849–906 行 + 实测):内置默认永远包含 https://localhost、https://127.0.0.1、https://[::1] 及各自带 UI 端口(port+1)的变体;用户追加的条目必须以 https:// 开头且长度 > 8,否则日志告警 Invalid 'csrf_allowed_origins' entry rejected: <origin>。校验逻辑:带 Origin/Referer 头且命中允许列表 → 放行;两个头都不带(curl/脚本)→ 直接放行;带了但不命中 → 要求 X-CSRF-Token 头或 ?csrf_token= 查询参数。实测:
$ curl -sk -u admin:q1w2e3r4 -X POST -H 'Content-Type: application/json' \
-H 'Origin: https://evil.example' -d '{"sunshine_name":"hijack"}' \
https://localhost:47990/api/config
{"error":"Missing CSRF token","status":false,"status_code":400}
[2026-11-03 03:01:48.301]: Error: Web UI: [10.89.62.1] -- CSRF protection blocked request from origin: https://evil.example
$ TOKEN=$(curl -sk -u admin:q1w2e3r4 https://localhost:47990/api/csrf-token | jq -r .csrf_token) # 32 字符
$ curl -sk -u admin:q1w2e3r4 -X POST -H 'Content-Type: application/json' \
-H 'Origin: https://evil.example' -H "X-CSRF-Token: $TOKEN" \
-d '{"sunshine_name":"game-lab"}' https://localhost:47990/api/config
{"status":true}
令牌由 GET /api/csrf-token 签发、按客户端(Basic 用户名,否则来源 IP)一次性存储。用反向代理把 UI 暴露到自定义域名时,就要把该域名加进 csrf_allowed_origins,否则浏览器里的 Save 全部 400。
4.3 标识、语言与日志(6 键)
| 键 | 默认值 | 取值/范围 | 说明 |
|---|---|---|---|
sunshine_name | 主机名 | 字符串 | 显示名;进 serverinfo XML 的 <hostname>【实测 game-lab 生效】,也是 Moonlight 列表里看到的名字 |
locale | en | 源码白名单 22 种(含 zh、zh_TW) | UI 语言;GET /api/configLocale 回显【实测】:{"locale":"en","status":true} |
min_log_level | 2(Info) | 字符串 verbose/debug/info/warning/error/fatal/none 或单个数字 0–6 | 见 7.2 的数字坑 |
log_path | ~/.config/sunshine/sunshine.log | 路径 | 日志文件位置 |
system_tray | true | 布尔 | 托盘;无头环境自动失败(Error: System tray is not initialized,实测) |
notify_pre_releases | false | 布尔 | 是否提示预发布更新 |
4.4 视频编码——通用(10 键)
| 键 | 默认值 | 取值/范围 | 说明 |
|---|---|---|---|
qp | 28 | 整数 | 量化参数,越小画质越高码率越大 |
hevc_mode | 0 | 0–3 | H.265 对客户端的暴露档位(0=关,3=强制开,1/2 按硬件/软件支持探测) |
av1_mode | 0 | 0–3 | AV1 同构档位 |
max_bitrate | 0(不限) | 整数 | 码率上限 |
minimum_fps_target | 0(=跟随帧率) | 0.0–1000.0 | 最低帧率目标(浮点) |
encoder | 空(自动探测) | nvenc/vaapi/vulkan/software 等 | 强制编码后端;启动探测顺序实测为 nvenc→vulkan→vaapi→software |
capture | 空(自动) | 平台捕获名 | 强制画面捕获方式 |
adapter_name | 空 | 字符串 | 多显卡时指定编码适配器(Windows 向) |
output_name | 空 | 字符串 | 多显示器时指定输出名 |
fp16_sdr_gamma_encoded | false | 布尔 | FP16 SDR 伽马编码 |
hevc_mode/av1_mode 是"客户端能力协商"开关:Moonlight 端请求 H.265/AV1 时,主机按此档位与自身编码器能力决定是否接受;0 表示只走 H.264。
4.5 视频编码——硬件编码器专属组(38 键)
六组前缀按键名归属:nvenc_*(NVIDIA)、vaapi_*(Linux VAAPI,Intel/AMD)、qsv_*(Intel Quick Sync)、amd_*(AMD AMF,Windows)、vt_*(Apple VideoToolbox,macOS)、vk_*(Vulkan)。跨平台写了不匹配前缀的键不会报错,只是不生效。
| 组 | 键(默认值) | 要点 |
|---|---|---|
| nvenc(8) | nvenc_preset(1–7 范围校验)、nvenc_vbv_increase(0–400)、nvenc_spatial_aq(bool)、nvenc_twopass(枚举:关闭/1/4 分辨率/全分辨率二次编码)、nvenc_h264_cavlc(bool)、nvenc_split_encode(枚举)、nvenc_realtime_hags(true)、nvenc_opengl_vulkan_on_dxgi(true)、nvenc_latency_over_power(true) | 后三个布尔是行为开关:HAGS 实时调度、GL/Vk 走 DXGI、性能模式优先于省电 |
| vaapi(4) | vaapi_quality(auto)、vaapi_rc(auto,字符串枚举)、vaapi_blbrc(false)、vaapi_strict_rc_buffer(false) | Linux 无独显/Intel 核显主路;vaapi_rc 同时接受枚举名与字符串 |
| qsv(3) | qsv_preset(medium)、qsv_coder(auto)、qsv_slow_hevc(false) | Intel;qsv_slow_hevc 换质量耗时 |
| amd(8) | amd_usage(ultralowlatency)、amd_rc(vbr_latency)、amd_quality(balanced)、amd_preanalysis(false)、amd_vbaq(true)、amd_enforce_hrd(false)、amd_max_au_size(不限)、amd_coder(auto) | AMF;usage/rc/quality 三个键各自映射到 H.264/H.265/AV1 三套枚举(源码 1663–1697 行) |
| vt(4) | vt_coder、vt_software、vt_realtime | macOS VideoToolbox(本专栏 Linux 形态不实测) |
| vk(3) | vk_tune(2=low-latency)、vk_rc_mode(2=CBR)、vk_quality(2,接受字符串 speed/balanced/quality→1/2/3) | Vulkan 编码后端,启动探测里排第二 |
4.6 软件编码(2 键)
| 键 | 默认值 | 说明 |
|---|---|---|
sw_preset | superfast | x264/x265 preset 风格字符串;同时映射 SVT-AV1 preset(源码 svtav1_preset_from_view) |
sw_tune | zerolatency | x264 tune;zerolatency 关闭 lookahead,牺牲压缩率换延迟 |
软件编码只在四类硬件后端全探测失败时兜底,高帧率高分辨率不实用(选型见 Sunshine 介绍与选型指南)。
4.7 显示设备 dd_*(10 键,Windows Display-Device 集成)
dd_ 前缀键对接 Windows 侧显示配置(DisplayDevice 库),Linux 形态基本用不到,列出供对照:
| 键 | 默认值 | 说明 |
|---|---|---|
dd_configuration_option | disabled | 是否允许会话中改显示配置 |
dd_resolution_option / dd_refresh_rate_option | automatic | 分辨率/刷新率策略(automatic/manual) |
dd_manual_resolution / dd_manual_refresh_rate | 空 | 手动值 |
dd_hdr_option | automatic | HDR 开关策略 |
dd_config_revert_delay | 3000(ms,范围 0–INT_MAX) | 会话结束后延迟还原 |
dd_config_revert_on_disconnect | 空 | 断连时还原策略 |
dd_mode_remapping | 空 | JSON 列表,可跨行:mixed/resolution_only/refresh_rate_only 三类规则,每条含 requested_resolution/requested_fps/final_resolution/final_refresh_rate(源码 706–731 行) |
dd_wa_hdr_toggle_delay | 0(范围 0–3000) | HDR 切换兼容 workaround 延时 |
4.8 音频(5 键)
| 键 | 默认值 | 说明 |
|---|---|---|
stream_audio | true | 总开关 |
install_steam_audio_drivers | true | 自动装 Steam 虚拟声卡驱动(Windows) |
external_audio | false | 主机继续本地出声 |
audio_sink | 空(默认输出设备) | 抓取哪个输出设备 |
virtual_sink | 空 | 虚拟输出设备名 |
Linux 侧音频抓取依赖 PulseAudio/PipeWire 环境;无头服务器上这组键可配但无实际抓取对象。
4.9 输入设备(18 键)
| 键 | 默认值 | 取值 | 说明 |
|---|---|---|---|
keyboard / mouse / controller | true / true / true | 布尔 | 三类输入注入总开关 |
always_send_scancodes | true | 布尔 | 始终用扫描码传键 |
high_resolution_scrolling | true | 布尔 | 高精度滚轮 |
native_pen_touch | true | 布尔 | 原生笔/触控事件 |
gamepad | auto | 平台支持集 | 虚拟手柄模拟类型;实测 Linux 支持 auto/generic/x360/xone/xseries/ds4/ds5/switch |
gamepad_driver | 平台默认 | all/virtualhid/vigembus/none(源码白名单) | 手柄驱动后端(ViGEmBus 为 Windows 专属) |
ds4_back_as_touchpad_click | true | 布尔 | DS4 返回键映射为触摸板点击 |
motion_as_ds4 / touchpad_as_ds4 | true / true | 布尔 | 客户端手柄体感/触摸板按 DS4 语义重放 |
virtualhid_randomize_mac | true | 布尔 | 虚拟 HID 随机 MAC |
key_rightalt_to_key_win | false | 布尔 | 右 Alt 映射 Win 键(实现即往 keybindings 加 0xA5→0x5B,源码 1834–1839 行) |
back_button_timeout | -1(禁用) | 毫秒 | 长按返回键触发组合 |
key_repeat_delay | 500 | 毫秒 | 按键连发起始延迟 |
key_repeat_frequency | ≈24.9 | >0 | 连发频率(源码默认周期 1/24.9 秒) |
无头/无 uinput 权限环境实测整排告警:Warning: Gamepad auto is disabled due to gamepads.virtualhid-not-available……Warning: No gamepad input is available——手柄链路要主机侧内核模块/权限就绪才可用。
4.10 系统集成(3 键)
| 键 | 默认值 | 说明 |
|---|---|---|
file_apps | apps.json | 应用清单路径;文件不存在时自动从安装资产复制默认模板(源码 1816–1826 行) |
global_prep_cmd | 空 | 全局前置命令列表([{"do":...,"undo":...}],可跨行);每个应用启动前执行,除非应用设 exclude-global-prep-cmd |
keybindings | 内置 3 对映射 | 键码重映射表(0x10→0xA0、0x11→0xA2、0x12→0xA4,即 F13–F15 组合键),UI 与 key_rightalt_to_key_win 都写这张表 |
5. apps.json 应用清单详解
5.1 文件结构与字段表
顶层两个键:env(全局环境变量,支持 $(PATH) 式引用)与 apps(应用数组)。单个应用字段(源码 API 注释 + 实测文件,confighttp.cpp 1137–1165 行):
| 字段 | 类型 | 说明 |
|---|---|---|
name | 字符串 | 显示名,保存时数组按它排序【实测】 |
cmd | 字符串 | 前台命令(进程退出=会话结束) |
detached | 字符串数组 | 后台命令(不等它退出) |
prep-cmd | 对象数组 | 每项 {do, undo, elevated?}:启动前执行 do,结束后执行 undo |
env | 对象 | 应用级环境变量 |
image-path | 字符串 | 封面 PNG 路径(相对或绝对;desktop.png 为内置) |
output | 字符串 | 应用日志输出路径 |
exit-timeout | 整数 | 结束等待秒数(历史版本写成字符串会被自动转换,源码 1104–1119 行) |
exclude-global-prep-cmd | 布尔 | 跳过 global_prep_cmd |
elevated / auto-detach / wait-all | 布尔 | 提权运行 / 自动转后台 / 等待全部子进程 |
5.2 默认模板(实测)
全新环境首启自动生成,实测内容:
{
"env": { "PATH": "$(PATH):$(HOME)/.local/bin" },
"apps": [
{ "name": "Desktop", "image-path": "desktop.png" },
{ "name": "Low Res Desktop", "image-path": "desktop.png",
"prep-cmd": [{ "do": "xrandr --output HDMI-1 --mode 1920x1080",
"undo": "xrandr --output HDMI-1 --mode 1920x1200" }] },
{ "name": "Steam Big Picture",
"detached": ["setsid steam steam://open/bigpicture"],
"prep-cmd": [{ "do": "", "undo": "setsid steam steam://close/bigpicture" }],
"image-path": "steam.png" }
]
}
三个模板覆盖"串桌面 / 串低分辨率桌面 / 串 Steam 大屏",也是字段用法的现成示例。
5.3 API 管理(实测 CRUD)
与 /api/config 不同,应用清单改动即时生效、无需重启(保存后源码调用 proc::refresh(),1227 行)。完整一轮实测:
$ curl -sk -u admin:q1w2e3r4 -X POST -H 'Content-Type: application/json' \
-d '{"name":"Test App","cmd":"echo hello","index":-1}' \
https://localhost:47990/api/apps
{"status":true}
$ curl -sk -u admin:q1w2e3r4 https://localhost:47990/api/apps | jq '[.apps[].name]'
["Desktop", "Low Res Desktop", "Steam Big Picture", "Test App"]
$ curl -sk -u admin:q1w2e3r4 -X DELETE https://localhost:47990/api/apps/3
{"result":"application 3 deleted","status":true}
要点:index: -1 新增、index: N 替换第 N 项;缺 index 直接 400——{"error":"[json.exception.type_error.302] type must be number, but is null","status":false,"status_code":400}(实测原文);保存后文件被重写为 4 空格缩进且对象内键名按字典序(实测 tail 可见 "cmd" 排在 "name" 前)。
5.4 文件缺失自动生成
file_apps 指向的文件不存在时,启动即从安装目录资产复制默认 apps.json 并补 owner 读写权限(源码 1816–1826 行)。隔离配置目录首启实测目录树:
/tmp/iso/.config/sunshine/
├── apps.json # 自动复制的默认模板
├── credentials/ # 自动生成的 CA 与自签证书
├── sunshine.conf # 空文件
├── sunshine.log
└── sunshine_state.json # 首启设凭据后出现
6. 生效机制与日志
6.1 哪些立即生效、哪些要重启
| 改动 | 生效方式 |
|---|---|
apps.json(含 API/Web UI 应用页) | 立即(proc::refresh) |
sunshine.conf 任何键 | 重启进程(配置只在启动时解析一次,apply_config 无热加载路径) |
sunshine_name | 重启后 serverinfo 可见【实测】 |
port | 重启,全家端口平移【实测】 |
6.2 重启路径与无头坑
Web UI 的重启按钮调 POST /api/restart。有头环境优雅重启;无头环境主循环已自行退出(Main loop has exited,进程靠 UI 线程存活),此时触发 restart 会卡:
[2026-11-03 02:37:52.104]: Info: Interrupt handler called
[2026-11-03 02:38:02.105]: Fatal: 10 seconds passed, yet Sunshine's still running: Forcing shutdown
之后进程不退出,需要外部手段拉起(服务管理器 restart)。实测环境用的就是服务级重启替代。
6.3 配置加载日志与轮转
每次启动把显式覆盖集逐行打为 config: 'key' = value(2.4 实测),敏感项在名单内的打 [redacted]。日志轮转:每次启动 sunshine.log → .1,依次后移,保留 5 份(2.1 实测目录里 .1~.5 齐全)。排障时"上一次启动为什么挂了"直接翻对应序号文件。
7. 常见问题
7.1 未知键:只在控制台告警,不进日志文件
sunshine.conf 写错键名不致命:服务照常起(实测 code=200),但 sunshine.log 查不到任何痕迹——警告走 std::cout(源码 1971–1974 行,且要求 min_log_level ≤ 3),只出现在进程标准输出:
Warning: Unrecognized configurable option [foo_bar]
systemd/journal 形态能在服务日志里看到,纯 sunshine.log 里没有。排查"配置不生效"先确认键名在 99 键之列,再看控制台输出。
7.2 min_log_level:字符串或单个数字
解析分支(源码 1937–1962 行):先匹配 7 个字符串(verbose=0 … none=6);否则只看值的首字符是否为 0–6。所以 min_log_level = 1 生效(debug),min_log_level = 10 会被截成 1,min_log_level = 7 及乱写值静默保持默认 2。建议一律写字符串。
7.3 port 改动 = 全家端口平移
防火墙/映射只放行 47989–47990 的脚本在改 port 后全部失效,按 4.1 引用表重算:HTTPS=port-5、UI=port+1、RTSP=port+21、UDP=port+9/10/11。
7.4 API 保存配置丢键
POST /api/config 是整体覆盖(3.3 实测 3 行变 1 行)。脚本化正确姿势:GET /api/config 取回当前覆盖集 → 合并新键 → 全量 POST。
7.5 白名单键配错静默回退
origin_web_ui_allowed、address_family、gamepad_driver、locale 等走源码白名单校验,非法值不报错、维持默认。确认办法:看启动 config: 行 + 行为验证(如 UI 是否 403)。
8. 参考链接
- 官方配置文档(docs.lizardbyte.dev,查询 2026-11-03):https://docs.lizardbyte.dev/projects/sunshine/latest/md_docs_2configuration.html
- 源码
src/config.cpp(默认值与解析)、src/confighttp.cpp(API 与 CSRF):https://github.com/LizardByte/Sunshine - 站内:Sunshine 介绍与选型指南
- 站内:Sunshine Docker Compose 部署指南
- 站内:Sunshine 2026.914.233613 常用 CLI 命令与工具详解