现充|junyu33

How I forced VSCode Remote+Codex to work inside Ubuntu-in-Termux on Android

Ever since I rapidly got into vibe coding last December, I wanted to try installing the Codex extension on every machine that could run VSCode. So my next target was that abandoned Android phone. In theory, Android (before Google hadn't yet done all the bad things it could) can install Termux, and the latter even has a script to nest Ubuntu inside it. So in theory, installing Remote SSH and Codex on that Android phone should be possible. But in practice...

Configure SSH to connect directly to the Ubuntu inside Termux

The first problem was how to configure SSH to connect directly to the Ubuntu inside, instead of going through Termux as an intermediate layer (because vscode server does not support nested Remote SSH). This was actually the simplest step in the whole process: just start a separate sshd inside Ubuntu, and use a port that does not conflict with Termux's sshd. For example, run the following in Ubuntu:

apt update
apt install -y openssh-server curl bash
mkdir -p /run/sshd
ssh-keygen -A
sed -i 's/^#\?Port .*/Port 2222/' /etc/ssh/sshd_config
/usr/sbin/sshd

This corresponds to port 2222.

For convenience, I used the default root user here, set a password with passwd, and then I could access it with:

ssh -p 2222 root@phone_ip

Next, set up passwordless login:

ssh-copy-id -p 2222 root@phone_ip

Then write an alias in the local ~/.ssh/config, for example phone-ubuntu:

Host phone-ubuntu
    HostName phone_ip
    Port 2222
    User root
    ServerAliveInterval 30
    ServerAliveCountMax 6

Test ssh phone-ubuntu. If that works, then VSCode should be able to use Remote SSH normally as well, assuming nothing unexpected happens.

VSCode reports Signature verification failed with 'UnknownError' error.

Then I tried using Remote SSH to install Codex, and the strange part began. I got the following error:

Signature verification failed with 'UnknownError' error.

My first intuition was that this ubuntu-in-termux was only a pseudo-Linux environment built with proot, but at the very least I needed to figure out what this UnknownError actually was. So I started looking for the context of this error:

For the former, just jump to that location directly and press Ctrl+F. For the latter, the path was:

grep -niE 'signature|UnknownError' \
~/.vscode-server/data/logs/20260320T154741/remoteagent.log \
~/.vscode-server/data/logs/20260320T154741/exthost2/remoteexthost.log \
~/.vscode-server/data/logs/20260320T154741/exthost1/remoteexthost.log 2>/dev/null

(Note: replace the timestamped path under logs with your own.)

Unfortunately, those three paths gave no result at the time. So I then chose to inspect the recent local logs from the last 10 minutes:

find ~/.config/Code/logs -type f \( -iname '*shared*' -o -iname '*window*' -o -iname '*renderer*' \) -mmin -10 -print0 2>/dev/null \ | xargs -0 grep -nEi 'Signature verification failed|UnknownError|signature|codex|openai|install' 2>/dev/null

This time I did get some results:

sharedprocess.log:122 Extension signature verification result for github.copilot-chat: Success
sharedprocess.log:134 Extension signature verification result for llvm-vs-code-extensions.vscode-clangd: Success
renderer.log:299 Remote Install Error Name SignatureVerificationInternal
renderer.log:301 Signature verification failed with 'UnknownError' error.

This ruled out a problem with local VSCode signature verification (that is, the failure point was the remote installation of vscode server). At this point there were two options:

For the former, I first needed to consider whether the Codex extension was pure JS, i.e. run:

find ~/.vscode/extensions/openai.chatgpt-* -type f | grep -E '\.node$|bin/|dist/.*(linux|arm64|x64)|\.(so|dll|exe)$'

On my machine the result was:

/home/junyu33/.vscode/extensions/openai.chatgpt-26.318.11754-linux-x64/bin/linux-x86_64/rg 
/home/junyu33/.vscode/extensions/openai.chatgpt-26.318.11754-linux-x64/bin/linux-x86_64/codex

This clearly distinguished architecture and platform, so the route of directly copying files could be abandoned.

Next, I had to figure out how to obtain the Codex VSIX package. I could not find a corresponding VSIX download link on the extension's Marketplace page. After a round of battle of wits with GPT, I ended up with a download script that could freely choose the version number:

for v in 26.318.11754 26.313.41514 26.313.41036 26.304.20706 0.4.79 0.4.60; do
  echo "=== $v ==="
  curl -sI "https://marketplace.visualstudio.com/_apis/public/gallery/publishers/openai/vsextensions/chatgpt/$v/vspackage?targetPlatform=linux-arm64" | sed -n '1,10p'
  echo
done

The latest version, 26.318.11754, downloaded as a VSIX (zip) wrapped in gzip, which looked fine. Next I tried copying the VSIX to the server, and then another problem appeared:

SCP transfer failed

When I ran scp openai-chatgpt-26.318.11754-linux-arm64.vsix phone-ubuntu:, I got the following "error":

** WARNING: connection is not using a post-quantum key exchange algorithm. 
** This session may be vulnerable to "store now, decrypt later" attacks. 
** The server may need to be upgraded. See https://openssh.com/pq.html 
scp: Connection closed

At first I thought OpenSSH had disabled non-post-quantum key exchange algorithms, but then I realized this was only a warning, and the key part was the last line: scp: Connection closed. GPT's explanation was that the Ubuntu-side sshd had been started manually (that is, by directly running /usr/sbin/sshd, instead of via systemctl or similar), which meant my SSH could only log in but had no SFTP subsystem for file transfer. A simple check was:

sftp -P 2222 phone-ubuntu

I tested it, and indeed it did not work. GPT provided two solutions:

Given that my client OpenSSH version was 10.2, while the server (Ubuntu) was 8.2, and the server was a non-standard Linux environment, the latter might introduce other compatibility issues. So I chose the simpler solution: just remember to add -O every time.


In short, after adding -O to the scp command, file transfer finally worked. Then the last step was offline installation of the VSIX:

code --install-extension ~/openai-chatgpt-26.318.11754-linux-arm64.vsix

And then it installed successfully.

Codex could not log in properly

Because of the special network situation in China, combined with my bizarre environment, after I entered the account and password in the browser and allowed the VSCode client to log in, the callback seemed unable to return correctly to my phone, so I got stuck at the Codex login step.

My thought was that login should involve an authentication token, so could I just copy the credentials from my local machine to the phone? The answer was yes. The official Codex docs state the following:

If you can complete the login flow on a machine with a browser, you can copy your cached credentials to the headless machine.

  1. On a machine where you can use the browser-based login flow, run codex login.
  2. Confirm the login cache exists at ~/.codex/auth.json.
  3. Copy ~/.codex/auth.json to ~/.codex/auth.json on the headless machine.

To be safe, I also copied the corresponding config.toml, which in my case translated to:

ssh phone-ubuntu 'mkdir -p ~/.codex'
scp -O ~/.codex/auth.json phone-ubuntu:~/.codex/auth.json
scp -O ~/.codex/config.toml phone-ubuntu:~/.codex/config.toml
chmod 600 ~/.codex/auth.json ~/.codex/config.toml

Note: this also applies to codex-cli, meaning the Codex plugin in VSCode and codex-cli use the same authentication system.

Then reload the window in VSCode, and it should be fine.

Proxy issues

Just when I thought I could finally talk happily with Codex, the network broke again...

The shell proxy was not set up correctly

First, check whether the proxy inside Ubuntu was configured properly. It turned out I had first forgotten to enable Allow LAN on the machine providing the proxy, and then in ~/.bashrc I had written:

http_proxy=http://host_ip:7897
https_proxy=http://host_ip:7897

instead of:

export http_proxy=http://host_ip:7897
export https_proxy=http://host_ip:7897

Sigh, such a low-level mistake...

After enabling LAN access and running source ~/.bashrc, curl google.com worked normally.

Codex reconnecting 1/5 2/5 3/5 4/5 5/5

After fixing the shell proxy, I did not expect Codex to still keep reconnecting. I first confirmed that the proxy setting in remote VSCode was empty (i.e. it should use the system proxy by default), which seemed fine. Then I continued looking at the vscode server logs:

grep -RniE 'backend-api/codex/responses|Reconnecting|stream disconnected|proxy' ~/.vscode-server/data/logs ~/.config/Code/logs 2>/dev/null | tail -100

This gave the following results:

/root/.vscode-server/data/logs/20260320T154741/exthost13/remoteexthost.log:1075:2026-03-20 17:44:52.997 [trace] ProxyResolver#tls.connect [{"highWaterMark":16384,"ca":"[290 certs]","servername":"chatgpt.com","session":"null","localAddress":"null","ALPNProtocols":"http/1.1","port":443,"host":"chatgpt.com"}] 
/root/.vscode-server/data/logs/20260320T154741/exthost13/remoteexthost.log:1076:2026-03-20 17:44:53.016 [trace] ProxyResolver#tls.connect [{"highWaterMark":16384,"ca":"[290 certs]","servername":"ab.chatgpt.com","session":"null","localAddress":"null","ALPNProtocols":"http/1.1","port":443,"host":"ab.chatgpt.com"}] 
/root/.vscode-server/data/logs/20260320T154741/exthost13/openai.chatgpt/Codex.log:38:2026-03-20 17:44:09.945 [error] [CodexMcpConnection] cli: message="codex_api::endpoint::responses_websocket: failed to connect to websocket: IO error: failed to lookup address information: Try again, url: wss://chatgpt.com/backend-api/codex/responses" 
/root/.vscode-server/data/logs/20260320T154741/exthost13/openai.chatgpt/Codex.log:39:2026-03-20 17:44:09.950 [warning] [CodexMcpConnection] cli: message="codex_core::session_startup_prewarm: startup websocket prewarm setup failed: stream disconnected before completion: failed to lookup address information: Try again" 
/root/.vscode-server/data/logs/20260320T154741/exthost13/openai.chatgpt/Codex.log:41:2026-03-20 17:44:14.994 [error] [CodexMcpConnection] cli: message="codex_api::endpoint::responses_websocket: failed to connect to websocket: IO error: failed to lookup address information: Try again, url: wss://chatgpt.com/backend-api/codex/responses" 
/root/.vscode-server/data/logs/20260320T154741/exthost13/openai.chatgpt/Codex.log:42:2026-03-20 17:44:14.997 [warning] [CodexMcpConnection] cli: message="codex_core::codex: stream disconnected - retrying sampling request (1/5 in 198ms)..." 
/root/.vscode-server/data/logs/20260320T154741/exthost13/openai.chatgpt/Codex.log:47:2026-03-20 17:44:20.214 [error] [CodexMcpConnection] cli: message="codex_api::endpoint::responses_websocket: failed to connect to websocket: IO error: failed to lookup address information: Try again, url: wss://chatgpt.com/backend-api/codex/responses" 
/root/.vscode-server/data/logs/20260320T154741/exthost13/openai.chatgpt/Codex.log:48:2026-03-20 17:44:20.216 [warning] [CodexMcpConnection] cli: message="codex_core::codex: stream disconnected - retrying sampling request (2/5 in 376ms)..."

The result was that the extension itself was using VSCode's proxy, but Codex's own websocket still seemed to have connection problems. At that point, the problem became much simpler: I only needed to check whether Codex had received the proxy-related environment variables.

So first I updated ~/.bashrc again:

export http_proxy=http://host_ip:7897
export https_proxy=http://host_ip:7897
export HTTP_PROXY=http://host_ip:7897
export HTTPS_PROXY=http://host_ip:7897
export all_proxy=http://host_ip:7897
export ALL_PROXY=http://host_ip:7897
unset no_proxy NO_PROXY

Then I completely restarted vscode server, and refreshed the environment variables again:

pkill -f vscode-server
source ~/.bashrc

Then I tested whether the codex-cli binary itself was working properly:

~/.vscode-server/extensions/openai.chatgpt-26.318.11754/bin/linux-aarch64/codex exec "Say pong and nothing else."
OpenAI Codex v0.116.0-alpha.10 (research preview) 
-------- 
workdir: /root
model: gpt-5.4 
provider: openai 
approval: never 
sandbox: read-only 
reasoning effort: medium 
reasoning summaries: none 
session id: 019d0aa5-e037-7952-98b8-ded673f4d1ba 
-------- 
user 
Say pong and nothing else. 
warning: Codex could not find system bubblewrap at /usr/bin/bwrap. Please install bubblewrap with your package manager. Codex will use the vendored bubblewrap in the meantime. 
mcp startup: no servers 
codex 
pong 
tokens used 
1,101

It looked normal, so after reopening vscode server, Codex also finally came back to life. The end, confetti!