- Chat with Codex from a private Telegram bot.
- Keep separate Codex conversations for separate Telegram chats.
- Use extra Codex skills and tools you have installed.
- Run the bot continuously on a Linux server with Docker.
- Keep the bot private by pairing it to one Telegram user.
- Codex runs with full access to the server and does not ask for command approval.
- Use a private bot on a server you control.
- Never share the bot token, pairing code, Codex login files, or
runtime/folder. - Run only one bridge for each Telegram bot token.
- The bot uses outbound Telegram connections, so it does not need a domain, public port, or web server.
- A Linux server with SSH access.
- Docker Engine and Docker Compose.
- Git access to this private repository.
- A Telegram bot token from BotFather.
- A Codex account.
-
1. Create a Telegram bot
- Open BotFather.
- Send
/newbot. - Follow the prompts.
- Save the token BotFather gives you.
-
2. Connect to your server
ssh YOUR_USER@YOUR_SERVER_IP
-
3. Install Docker
- Follow Docker's Ubuntu installation guide.
- Check that Docker is ready:
docker --version docker compose version
-
4. Download the project
- Make sure the server has access to the private GitHub repository.
git clone git@github.com:simonbalfe/codex-telegram-bridge.git cd codex-telegram-bridge -
5. Create the private runtime folders
mkdir -p runtime/codex runtime/google-cli runtime/gcloud runtime/neonctl runtime/bin runtime/state touch runtime/local.env runtime/bin/mr chmod 600 runtime/local.env chmod 755 runtime/bin/mr
- The empty
mrfile is a placeholder for an optional integration. - The other optional integration folders can stay empty.
- The empty
-
6. Add the Telegram token
nano .env
TELEGRAM_BOT_TOKEN=PASTE_YOUR_TOKEN_HERE CODEX_MODEL=gpt-5.6-sol
- In Nano, press
Ctrl+O,Enter, thenCtrl+X.
chmod 600 .env
- In Nano, press
-
7. Build the Docker image
docker compose build
-
8. Sign in to Codex
docker compose run --rm --entrypoint codex bridge login --device-auth docker compose run --rm --entrypoint codex bridge login status
- Open the link shown in the terminal.
- Enter the displayed code.
- Return to the terminal after the login succeeds.
-
9. Start the bridge
docker compose up -d docker compose logs -f bridge
- Wait for
Pair with /pair .... - Copy the full
/pair CODEcommand. - Send it to your Telegram bot.
- Press
Ctrl+Cto leave the logs. The bridge will keep running. - Docker will automatically restart the bridge after a server reboot.
- Wait for
-
10. Test it
- Send a normal message to the bot.
- Send
/statusto confirm the bridge and Codex are connected.
/statuschecks the bridge and Codex connection./newstarts a fresh Codex conversation./modelshows the active model./skillslists installed skills and their Telegram commands./skills QUERYsearches the skill list./skill NAME REQUESTruns a named skill.$NAME REQUESTis a shorter way to run a named skill./mcpslists connected Codex integrations.- Edited Telegram messages are treated as new requests.
-
Pull the latest code and rebuild:
git pull docker compose up -d --build docker compose logs --tail=100 bridge
-
Restart the bridge:
docker compose restart bridge
-
Stop the bridge:
docker compose down
-
Do not add
-vto the stop command unless you also want to remove the saved Docker workspace.
.envstores the Telegram token and basic settings.runtime/codex/stores Codex login, configuration, and skills.runtime/state/stores the paired Telegram user and conversation state.runtime/local.envstores private settings for optional integrations.runtime/google-cli/,runtime/gcloud/, andruntime/neonctl/store optional service logins.runtime/bin/stores optional command-line tools used by Codex.- These files are ignored by Git and must be backed up separately.
- If Docker says
permission denied, run the Docker commands withsudo. - If GitHub says
Permission denied (publickey), add the server's SSH key to GitHub. - If the bot does not reply, check
docker compose logs --tail=100 bridge. - If Codex is signed out, run the login commands again.
- If Telegram reports another polling connection, stop the other bridge using the same bot token.
- If a conversation behaves incorrectly, send
/new. - If the container keeps stopping, check that
.envcontains a validTELEGRAM_BOT_TOKEN.
-
Export the Telegram token, run the bridge, and pair using the code shown:
export TELEGRAM_BOT_TOKEN=PASTE_YOUR_TOKEN_HERE go run .
-
Run the tests:
go test ./...