Peter
Peter
发布于 2026-08-12 / 1 阅读
0
0

把 Oracle ARM 云服务器改造成 Codex 小说写作机:从安装、设备授权到 SSH/WinSCP Root 权限踩坑实录

最近我有一个比较具体的需求:把一台长期在线的 Oracle Cloud ARM Ubuntu 服务器改造成一个 Codex 写作环境。

我的目标不是在服务器上部署本地大模型,而是:

Codex CLI
    ↓
加载小说写作 Skill
    ↓
读取小说设定、人物资料和已有章节
    ↓
生成下一章
    ↓
直接保存为 TXT
    ↓
长期维护在服务器目录中

以后服务器可以作为一个长期在线的小说工作区,我只需要通过 WindTerm、WinSCP 或其他终端工具管理文件。

整个过程最终顺利跑通,但实际遇到的问题比“安装一个 Codex”复杂不少,包括:

  • ARM64 Ubuntu 能不能运行 Codex;

  • 2 核 12G、无 GPU 是否够用;

  • 为什么不应该直接用 Root 跑第三方 Skill;

  • 无桌面的服务器如何登录 ChatGPT;

  • Codex 的 Device Code 登录为什么一度显示 Not logged in

  • Codex 为什么提示缺少 Bubblewrap;

  • WinSCP 为什么无法访问 /home/novel

  • 为什么同一把 SSH 私钥能登录 ubuntu,却不能登录 root

  • Windows OpenSSH 为什么拒绝我原来一直在 WindTerm 使用的私钥;

  • WinSCP 为什么出现 Exit Status 142;

  • 最后如何让 WinSCP 和 WindTerm 都使用 Root,而 Codex 继续保持普通用户权限。

这篇文章把整个过程按实际排障顺序记录下来。

为避免泄露真实服务器信息,本文中的公网 IP、Windows 用户名、实例名、SSH 指纹、公钥等均已脱敏。一次性 Device Code、私钥内容、Token 等认证信息不会出现在文章中。


一、服务器环境:配置降低后还能不能跑 Codex

这台机器是一台 Oracle Cloud ARM 实例。

由于我当前 Oracle Cloud 的资源政策和可用配额发生变化,后来对服务器配置进行了调整,目前实际资源大致为:

Ubuntu 24.04.4 LTS
Linux aarch64 / ARM64
2 核 CPU
12 GB RAM
约 193 GB 系统盘
无 GPU

最开始我比较担心两个问题:

  1. ARM64 是否兼容 Codex;

  2. 没有 GPU 是否会严重影响 Codex 的生成速度。

事实证明,对于 Codex CLI 来说,这两个问题基本都不存在。

因为这台服务器并不是在本地运行 GPT 模型。

它真正负责的是:

读取文件
修改文件
运行 Shell
执行脚本
Git 操作
编译 / 测试
保存生成结果

真正的大模型推理主要发生在 OpenAI 服务端。

因此对于我的小说写作工作流:

2 核 CPU    → 足够
12 GB RAM   → 很宽裕
GPU         → 不需要
ARM64       → Codex 有原生 Linux ARM64 版本

真正可能受到 ARM64 限制的,反而是某些第三方软件,比如:

只提供 AMD64 的 Docker 镜像
没有 ARM64 Wheel 的 Python 包
只提供 x86_64 Binary 的闭源程序
某些 Native Node.js 依赖

但 Codex 本身没有遇到架构问题。

所以这台服务器更准确的定位不是:

AI 推理服务器

而是:

长期在线的 Codex Agent 执行环境
+
小说文件存储
+
Linux Shell

对于这种用途,即使配置降低到了 2C / 12G,也完全够用。


二、为什么没有直接让 Codex 使用 Root

我平时通过 1Panel 管理服务器。

进入 1Panel 的 Web 终端后,默认就是:

whoami

输出:

root

最简单的做法当然是直接在 Root 下安装 Codex。

但我最终没有这么做。

原因是我准备使用的小说 Skill 并不是自己写的,而是从网上下载的第三方 Skill。

一个 Codex Skill 并不一定只有提示词,它还可能包含:

SKILL.md
脚本
Shell 命令
Python 程序
外部工具调用
文件操作规则

如果直接让:

第三方 Skill
    ↓
Codex
    ↓
Root

那么这个 Skill 理论上就能够接触整台服务器。

没有这个必要。

所以我专门创建了一个普通 Linux 用户:

adduser novel

然后:

su - novel

最终权限结构变成:

root
├── 1Panel
├── Docker
├── Nginx
├── 系统配置
└── 人工维护服务器

novel
├── Codex
├── 小说 Skill
├── 小说设定
└── 章节文件

后面我一直保持这个原则:

人工管理服务器 → Root

Codex / 第三方 Skill → novel

这也是整个方案里我认为最重要的一个设计。

方便不应该以让 AI Agent 获得整台服务器 Root 权限为代价。


三、在 ARM64 Ubuntu 上安装 Codex CLI

服务器环境确认如下:

uname -m

输出:

aarch64

系统版本:

cat /etc/os-release | head

得到:

Ubuntu 24.04.4 LTS

切换到 novel 用户后:

su - novel

开始安装 Codex:

curl -fsSL https://chatgpt.com/codex/install.sh | sh

安装器正确检测到了:

Detected platform: Linux (ARM64)

Resolved version: 0.147.0

安装位置类似:

/home/novel/.codex/packages/standalone/releases/
0.147.0-aarch64-unknown-linux-musl

也就是说 Codex CLI 本身直接提供了 ARM64 Linux 版本。

安装完成之后,我执行:

codex --version

结果却提示:

Command 'codex' not found

一开始看起来像安装失败。

实际上只是当前 Shell 没有重新加载 PATH。

安装器已经把:

/home/novel/.local/bin

加入了:

/home/novel/.bashrc

所以执行:

source ~/.bashrc

重新测试:

codex --version

成功输出:

codex-cli 0.147.0

第一关结束。


四、无桌面的 Ubuntu 服务器如何登录 ChatGPT

这台机器没有图形桌面,因此没有办法像普通电脑一样弹出浏览器完成 OAuth 登录。

Codex 提供了 Device Code 登录方式:

codex login --device-auth

第一次执行时,Codex 提示需要先在 ChatGPT 安全设置里开启:

Codex 设备代码授权

于是我先在本地电脑进入:

ChatGPT
→ 设置
→ 安全
→ Codex 设备代码授权

临时开启。

然后重新执行:

codex login --device-auth

服务器会给出:

设备授权网页
+
一次性设备代码

我在自己的电脑浏览器中打开授权页面,登录 ChatGPT,然后输入一次性代码。

浏览器最终显示:

已登录 Codex
你现在可以关闭此页面

理论上到这里就完成了。


五、Device Auth 的一个小坑:不要重复执行 login

这里我实际踩了一个操作坑。

第一次登录完成后,服务器已经显示:

Successfully logged in

并返回:

novel@instance-****:~$

但我以为还需要再执行一次:

codex login --device-auth

结果 Codex 又开启了第二次设备代码授权,并生成了另一组新 Device Code。

我随后用:

Ctrl + C

中断了第二次登录。

再运行:

codex login status

结果竟然显示:

Not logged in

所以最后重新完整进行了一次 Device Auth。

这次浏览器授权完成、服务器出现:

Successfully logged in

之后,不再执行第二遍 login,而是直接:

codex login status

最终得到:

Logged in using ChatGPT

至此登录成功。

随后我又把 ChatGPT 安全设置里的:

Codex 设备代码授权

关闭了。

因为这项功能主要用于给新的无桌面设备登录。

服务器已经成功保存认证状态以后,没有必要一直保持 Device Code 授权入口开放。


六、创建小说工作目录并测试 TXT 写入

Codex 登录完成之后,我没有马上安装第三方 Skill。

先验证最基础的事情:

Codex 能不能真的在服务器上创建和修改小说 TXT 文件?

创建工作目录:

mkdir -p ~/novel/chapters
cd ~/novel

最终目录:

/home/novel/novel/
└── chapters/

然后启动:

codex

第一次进入这个目录时,Codex 提示:

Do you trust the contents of this directory?

1. Yes, continue
2. No, quit

这是因为可信目录内可能加载:

项目级配置
Hooks
Exec Policies
AGENTS.md
其他 Codex 配置

但这个目录是我刚刚自己创建的空目录,所以选择:

Yes, continue

进入后看到:

OpenAI Codex

model: gpt-5.6-sol
directory: ~/novel

为了测试,我只让它执行一个非常简单的任务:

在当前目录的 chapters 文件夹中创建 test.txt,
内容仅为 Codex write test,
不要修改其他文件。

执行完成以后退出 Codex,再检查:

cat ~/novel/chapters/test.txt

成功得到:

Codex write test

至此最重要的链路已经打通:

ChatGPT
    ↓
Codex
    ↓
远程 Ubuntu
    ↓
Linux 文件系统
    ↓
TXT

这意味着以后小说 Skill 写完一章后,完全可以直接:

生成正文
↓
保存到 chapters/
↓
生成 001.txt
↓
002.txt
↓
003.txt
...

而不是复制粘贴回本地。


七、Codex 提示缺少 Bubblewrap

第一次进入 Codex 时还出现了:

Codex could not find bubblewrap on PATH.

不过紧接着又提示:

Codex will use the bundled bubblewrap in the meantime.

所以这不是错误,只是 Warning。

Codex 自带了临时可用的 Bubblewrap。

但考虑到后面准备运行第三方 Skill,我还是决定安装系统版本。

退出 Codex 后切回 Root:

exit

安装:

apt update
apt install -y bubblewrap

检查:

bwrap --version

然后重新:

su - novel
cd ~/novel
codex

对于我的场景,这样相当于建立了两层边界:

第三方 Skill
    ↓
Codex Sandbox
    ↓
novel 普通 Linux 用户
    ↓
服务器

而不是:

第三方 Skill
    ↓
Root

这显然更合理。


八、另一个问题出现了:WinSCP 无法访问 /home/novel

Codex 写 TXT 已经成功,但很快遇到一个实际使用问题:

我在 Windows 本地使用 WinSCP 时,无法方便地访问 /home/novel

原来的 WinSCP 会话使用:

ubuntu

登录服务器。

而 Codex 是:

novel

用户。

Linux Home 目录存在权限边界,所以:

/home/ubuntu

和:

/home/novel

并不是天然互通的。

最直接的方案当然是:

WinSCP 再建一个 novel 用户会话

但我的服务器不只有小说目录。

我平时还需要访问:

/etc
/opt
/var
/home
1Panel 相关目录
Docker 数据目录
其他项目目录

如果每类文件都切不同用户,会非常麻烦。

于是我决定:

WinSCP → Root

Codex → novel

这样人可以全盘管理,但 Codex 继续保持普通用户。


九、为什么 WinSCP 用 Root 密码无法登录

首先检查 SSH Server 当前配置:

sshd -T | grep -E \
'permitrootlogin|passwordauthentication|pubkeyauthentication'

结果:

permitrootlogin without-password
pubkeyauthentication yes
passwordauthentication no

含义是:

Root SSH 登录:允许
Root 密码登录:禁止
SSH 公钥认证:允许
所有密码认证:禁用

也就是说:

root + 密码

必然失败。

而:

root + SSH 私钥

是允许的。

所以没有必要为了 WinSCP 去修改:

PasswordAuthentication no

这种安全配置。

正确做法是继续使用 SSH Key。


十、原来 WindTerm 使用的 SSH 私钥为什么 OpenSSH 不认

我并不需要重新生成 SSH Key。

因为创建 Oracle 实例时已经有一把私钥,而且一直被 WindTerm 使用。

原始文件类似:

D:\WindTerm_2.7.0\key\oracle-server.key

于是我尝试在 PowerShell 中读取对应公钥:

ssh-keygen -y -f "D:\WindTerm_2.7.0\key\oracle-server.key"

结果报错:

WARNING: UNPROTECTED PRIVATE KEY FILE!

Permissions for ... are too open.

This private key will be ignored.

这里一开始容易误以为私钥损坏。

其实不是。

Windows OpenSSH 对私钥 ACL 有要求。

如果一个私钥文件可以被其他 Windows 用户读取,它就认为权限过宽,从而直接拒绝使用。

WindTerm 自己可以读取这把 Key,并不意味着 Windows OpenSSH 也接受这个文件权限。


十一、把私钥复制到 .ssh 并收紧 ACL

为了不影响 WindTerm 原始文件,我没有直接修改原文件,而是复制了一份到:

C:\Users\<Windows用户名>\.ssh\oracle-server.key

然后用:

icacls

关闭继承权限,只保留当前 Windows 用户读取。

处理完成后:

ssh-keygen -y -f "$HOME\.ssh\oracle-server.key"

成功得到:

ssh-rsa AAAA...

说明私钥本身完全正常。

为了确认复制过程中没有破坏文件,我又比较了 SHA-256:

Get-FileHash $src -Algorithm SHA256
Get-FileHash $dst -Algorithm SHA256

两个文件:

大小一致
SHA256 一致
修改时间一致

最终确认:

原 WindTerm 私钥       ✅
复制后的 OpenSSH 私钥 ✅
私钥内容一致           ✅
Windows ACL 正常       ✅

十二、期间一个很迷惑的 Windows 路径问题

这部分也值得记录。

PowerShell / 聊天界面显示:

C:\Users\<用户名>\.ssh

时,\. 在某些文本显示环境下很容易看起来像:

C:\Users\<用户名>.ssh

一度让我以为错误创建了一个:

<用户名>.ssh

目录。

最后重新通过:

$HOME
$env:USERPROFILE
Get-ChildItem

确认实际目录结构后才确定:

C:\Users\<Windows用户名>\.ssh

从始至终就是正常的 .ssh 文件夹。

没有额外产生所谓的“报废 SSH 目录”。

这个问题本质上只是文本显示造成的误判。

以后处理这类路径,我更倾向直接使用:

Join-Path

或者:

[IO.Path]::Combine(...)

而不是靠肉眼拼字符串。


十三、为什么同一把私钥能登录 ubuntu,却登录不了 root

这是整个 SSH 排障里最值得理解的一件事。

很多人会把 SSH Key 理解成:

这把私钥可以登录这台服务器

实际上更准确的关系是:

用户名 + 私钥

服务器会根据你填写的 Linux 用户名,去检查对应用户自己的:

~/.ssh/authorized_keys

例如:

ubuntu + 私钥

服务器检查:

/home/ubuntu/.ssh/authorized_keys

而:

root + 同一把私钥

服务器检查:

/root/.ssh/authorized_keys

Oracle 创建实例时,本来就把我的公钥配置给了:

ubuntu

所以原来的:

WindTerm
WinSCP
SSH

一直都是:

ubuntu + 私钥

正常登录。

但 Root 并不会自动继承 Ubuntu 用户的 SSH Key。


十四、直接通过 SSH Fingerprint 把问题定位清楚

为了不再靠猜,我直接比较 Key Fingerprint。

Windows 本地私钥对应指纹:

SHA256:******

Ubuntu 用户:

ssh-keygen -lf /home/ubuntu/.ssh/authorized_keys

得到:

SHA256:******

与 Windows 私钥完全一致。

而 Root:

ssh-keygen -lf /root/.ssh/authorized_keys

得到的是:

SHA256:******

另一把 ED25519 Key。

这一步直接证明:

Windows 私钥
        ↓
匹配 ubuntu authorized_keys
        ↓
ubuntu 能登录

Windows 私钥
        ↓
不匹配 root authorized_keys
        ↓
root 登录失败

问题至此完全清楚。

这也是我以后排 SSH Key 问题会优先使用的方法:

ssh-keygen -lf ...

比较 Fingerprint,而不是肉眼看几百字符的:

ssh-rsa AAAA...

十五、把原来的 Ubuntu 公钥同时授权给 Root

既然已经证明:

Windows 私钥
=
ubuntu authorized_keys 中的公钥

就不需要重新生成 Key。

只需要让 Root 也信任它。

修改:

/root/.ssh/authorized_keys

加入同一把公钥。

然后确保权限:

chmod 700 /root/.ssh
chmod 600 /root/.ssh/authorized_keys
chown -R root:root /root/.ssh

目录权限检查:

/root                     700
/root/.ssh                700
authorized_keys           600

然后 Windows 测试:

ssh -i "$HOME\.ssh\oracle-server.key" \
root@***.***.***.***

最终成功进入:

root@instance-****:~#

Root SSH 公钥登录正式打通。


十六、WinSCP 曾经出现 Exit Status 142

中间还有一个很特殊的现象。

WinSCP 一度提示:

服务器发送命令的退出状态 142

跳过开始消息时出错。
你的 Shell 可能与本程序不兼容。

同时 Windows SSH 有一次表现为:

Connection closed by ***.***.***.*** port 22

而后来又出现:

Permission denied (publickey)

这里其实有两类错误:

第一类

Connection closed
Exit Status 142

说明 SSH 已经进行到服务器端某个登录流程,但连接随后被主动关闭。

第二类

Permission denied (publickey)

则说明服务器根本没有接受客户端提供的 SSH Key。

最终真正帮助定位问题的不是继续调整 WinSCP Shell,而是前面提到的:

Windows 私钥 Fingerprint
ubuntu authorized_keys Fingerprint
root authorized_keys Fingerprint

直接比对。

Root 的授权 Key 与 Windows 私钥不匹配,才是关键问题。

将正确公钥加入 Root 后,Root SSH 和 WinSCP 都恢复正常。


十七、让 WinSCP 使用 Root 管理整台服务器

Root SSH 打通后,WinSCP 最终配置变成:

文件协议:SFTP
主机:***.***.***.***
端口:22
用户名:root
密码:留空

SSH 私钥:

C:\Users\<Windows用户名>\.ssh\oracle-server.key

于是我现在可以直接通过 WinSCP 管理:

/
├── etc
├── home
│   ├── ubuntu
│   └── novel
├── opt
├── root
├── usr
├── var
└── ...

不再需要:

ubuntu 会话
novel 会话
root 会话

来回切换。

需要强调的是:

Root WinSCP 方便的是“人工管理服务器”,而不是让 Codex 获得 Root。

这两个权限边界还是分开的。


十八、WindTerm 也统一切换到 Root

WinSCP 解决以后,我顺便把 WindTerm 也改成 Root。

原来的 WindTerm 会话是:

ubuntu@instance-****

而 WindTerm 2.7 的会话设置里没有一个特别明显的独立“用户名”输入框。

最后直接把 SSH 主机:

***.***.***.***

修改为:

root@***.***.***.***

端口仍然:

22

私钥继续使用原来的:

oracle-server.key

保存并重新连接以后:

root@instance-****:~#

正常进入。

于是日常管理工具全部统一:

WinSCP   → root
WindTerm → root

而 Codex:

Codex → novel

不变。


十九、最终的权限与工作结构

现在整个服务器大致是:

                    Oracle ARM Ubuntu
                           │
            ┌──────────────┼──────────────┐
            │              │              │
          Codex          WinSCP         WindTerm
            │              │              │
          novel           root           root
            │              │              │
     小说生成工作区     全盘文件管理     系统维护

小说目录:

/home/novel/novel/
├── chapters/
│   └── test.txt
└── 后续小说资料

Codex:

/home/novel/.codex/

第三方 Skill 之后也会由:

novel

用户加载和执行。

最终形成了比较清楚的权限边界:

我自己
    ↓
Root
    ↓
整台服务器

第三方 Skill
    ↓
Codex
    ↓
novel
    ↓
小说工作目录

二十、目前已经完成的部分

到目前为止,整个基础环境已经全部跑通:

Ubuntu 24.04 ARM64         ✅
2C / 12G / 无 GPU         ✅
Codex CLI                 ✅
ARM64 原生版本             ✅
ChatGPT Device Auth       ✅
GPT-5.6-sol               ✅
novel 独立 Linux 用户      ✅
Codex Sandbox             ✅
TXT 文件创建              ✅
小说 chapters 目录         ✅
Windows SSH 私钥 ACL       ✅
SSH Key Fingerprint 排障   ✅
Root SSH 公钥认证          ✅
WinSCP Root               ✅
WindTerm Root             ✅
Codex 不运行在 Root        ✅

二十一、下一阶段:真正开始构建小说工作流

到这里其实还没有真正开始“让 Codex 写小说”。

目前完成的只是基础设施。

下一步才是:

检查第三方小说 Skill
↓
确认 Skill 是否带脚本
↓
检查是否存在危险 Shell 操作
↓
安装 Skill
↓
配置小说目录
↓
加入世界观设定
↓
加入人物资料
↓
加入时间线
↓
读取上一章
↓
生成下一章
↓
保存 TXT
↓
更新小说状态

如果后续结构设计合理,甚至可以做到:

/home/novel/novel/
├── bible/
│   ├── world.md
│   ├── characters.md
│   └── timeline.md
│
├── outline/
│   ├── master-outline.md
│   └── chapter-plan.md
│
├── state/
│   ├── current-state.md
│   ├── unresolved-hooks.md
│   └── character-state.md
│
└── chapters/
    ├── 001.txt
    ├── 002.txt
    ├── 003.txt
    └── ...

以后我甚至只需要告诉 Codex:

继续下一章

它就可以完成:

读取设定
↓
读取当前人物状态
↓
读取上一章
↓
生成本章
↓
检查连续性
↓
保存 TXT
↓
更新状态文件

这才是我真正想要的长期写作 Agent。


二十二、这次配置过程中最值得记住的几点

1. Codex 云端使用基本不需要服务器 GPU

Codex CLI 并不是本地大模型。

所以:

2 核 CPU
12 GB RAM
无 GPU
ARM64

仍然可以很好地承担 Agent 执行环境。

服务器性能主要影响:

脚本执行
构建
测试
Docker
本地程序

而不是 GPT 本身的推理速度。


2. 不要为了方便让第三方 Skill 直接运行 Root

更合理的做法:

人工管理员 → Root

Codex Agent → 普通用户

尤其是 Skill 来源于互联网时。


3. SSH Key 必须理解成“用户名 + 私钥”

不要理解成:

一把私钥登录一台服务器

实际上:

ubuntu + Key
root + Key
novel + Key

是三组不同的认证关系。

每个 Linux 用户都有自己的:

~/.ssh/authorized_keys

4. SSH 排障优先比较 Fingerprint

与其肉眼比较:

ssh-rsa AAAA......

不如直接:

ssh-keygen -lf authorized_keys

比较:

SHA256:******

快得多,也可靠得多。


5. Windows OpenSSH 对私钥 ACL 很严格

WindTerm 能读取某个 Key,并不代表:

ssh.exe
ssh-keygen.exe
WinSCP

一定接受它。

如果出现:

UNPROTECTED PRIVATE KEY FILE

优先检查 Windows 文件 ACL,而不是怀疑 Key 损坏。


6. 没必要为了 WinSCP 打开 SSH 密码登录

我的服务器目前仍然保持:

PasswordAuthentication no

这完全不影响:

WinSCP
WindTerm
Windows OpenSSH

使用私钥。


结语

最后得到的并不是简单的一台:

“安装了 Codex 的服务器”

而是一个权限边界比较明确的长期在线 Agent 工作环境:

Oracle ARM Ubuntu
        │
        ├── Root
        │    ├── WindTerm
        │    └── WinSCP
        │
        └── novel
             ├── Codex
             ├── Skill
             ├── 小说设定
             └── 章节 TXT

服务器配置虽然因为当前 Oracle Cloud 的资源政策和可用配额变化降低到了 2C / 12G,但对于这种使用模式影响并不大。

AI 推理由云端完成,服务器真正提供的是:

长期在线
文件系统
Linux Shell
权限隔离
自动化执行环境

这反而比单纯在浏览器里让 ChatGPT 写一章、再手工复制保存更适合长篇小说工作流。

目前基础设施已经完成。

下一步,就是把第三方小说 Skill 正式接进来。


评论