┌────────────────────────────────────────┐
│ $ rgcc compile main.cpp │
│ Remote Compiler: Preparing main.cpp... │
│ Uploading and compiling... │
│ │
│ Compilation successful! │
│ Duration: 0.84s │
│ Artifacts saved to: dist/ │
└────────────────────────────────────────┘Offload C/C++ builds from a resource-constrained device to a real machine. Encrypted end-to-end, single binary on each side, no daemon babysitting required.
Compiling C++ on a phone in Termux works, technically - until you hit a template-heavy header, -O2 on a 2000-line file, and your battery drops 4% waiting for g++. RGCC started as a way to point rgcc compile main.cpp at a spare machine on the network and get a binary back a few seconds later, without setting up SSH, rsync, or a full remote dev environment.
It grew from there into a general-purpose remote compiler: manifest-driven builds, cross-compilation, reproducibility checks. But the core use case is still the original one - a thin client on a weak device, a build server on a strong one.
- Unified package - one
pip installgives you bothrgcc(client) andrgccd(server). - Manifest-driven builds - full control over standard, defines, flags, and link targets via
build.json. - Cross-compilation -
--targettriples and--sysrootoverrides for Linux/Windows/macOS targets. - Encrypted transport - ECDH key exchange + AES-256-GCM for the payload (see Security Model for what this does and doesn't protect against).
- Reproducibility checks -
--verify-reproducibleruns two independent builds and diffs the binary hash. - Shell autocompletion - Bash, Zsh, Fish, PowerShell.
rgcc compile main.cppcollects the source tree, generates a build manifest, and packs it into a tarball.- The client performs an ECDH handshake with the server (authenticated by a shared
auth_token), deriving a session key. - The tarball is encrypted (AES-256-GCM) and uploaded.
- The server validates the manifest, filters compiler/linker flags against a safety allowlist, and runs the actual compiler in a subprocess (no shell).
- The resulting binary + logs + build info are packed, encrypted, and sent back.
- The client decrypts and extracts the artifacts into
dist/.
Read this before exposing the server beyond localhost.
What is protected:
- The build payload (source code, flags, resulting binary) is encrypted in transit with AES-256-GCM, keyed via an ECDH exchange tied to your
auth_token. - The server only executes a whitelisted set of compiler binaries (
gcc,g++,clang, …), never an arbitrary path from the client. - Compiler and linker flags are filtered against a list of known dangerous flags (
-B,-specs,-wrapper, etc.) before being passed to the subprocess. - Archive extraction on both ends is hardened against path traversal (Tar-slip).
What is not protected:
- There is no TLS and no server identity verification. The ECDH handshake authenticates the session using the shared
auth_token, but that token itself is sent as a bearer header during the handshake. An attacker who can position themselves on the network path (rogue AP, ARP spoofing, compromised router) can intercept the token and either read the handshake or man-in-the-middle the whole session. - This means "encrypted" here is not a substitute for TLS. It protects against passive network logging (e.g., a nosy ISP or a shared network snooping traffic), not against an active attacker.
- The server has no built-in rate limiting. Don't expose it to the open internet without a reverse proxy in front that handles this.
Practical guidance:
| Deployment | Recommendation |
|---|---|
Same machine / 127.0.0.1 only |
Fine as-is. |
| Same trusted LAN (phone + home server) | Acceptable for most people. If your Wi-Fi isn't trusted, tunnel it (see below). |
| Different networks / over the internet | Do not expose port 4444 directly. Put it behind a TLS reverse proxy (Caddy, nginx) or a VPN/tunnel (WireGuard, Tailscale, ssh -L). |
Additional hardening:
rgccd.yamlandrgcc.yamlcontain the auth token in plaintext - the tool setschmod 600on them automatically, but double-check on shared systems.- Run the server container as a non-root user (the provided
Dockerfile.serveralready does this) and drop capabilities: see the Docker section. - This project has not undergone a formal third-party security audit. Treat it as solid for personal/trusted-network use, and apply the guidance above before anything more exposed.
RGCC runs on Linux, macOS, and Windows. Both entry points - rgcc (client) and rgccd (server) - ship as a single Python package. Install it with an isolated-environment tool such as pipx or uv; a plain pip install into the system interpreter is not a supported path: on PEP 668 systems (Arch, Debian 12+, Fedora, Homebrew's Python) pip refuses outright, and everywhere else it scatters the package and its dependencies across the global environment.
pipx install "remote-compiler @ git+https://github.com/whaiman/remote-compiler.git"Don't have pipx yet?
| OS | Command |
|---|---|
| Arch | sudo pacman -S pipx |
| Debian/Ubuntu | sudo apt install pipx |
| Fedora | sudo dnf install pipx |
| macOS | brew install pipx |
| Windows | py -m pip install --user pipx (or scoop / choco) |
| Any OS with Python | python -m pip install --user pipx (fallback if none of the above apply) |
uv tool install "remote-compiler @ git+https://github.com/whaiman/remote-compiler.git"Don't have uv yet?
| OS | Command |
|---|---|
| Arch | sudo pacman -S uv |
| macOS | brew install uv |
| Windows | winget install --id=astral-sh.uv -e |
Or the standalone installers, no package manager needed:
curl -LsSf https://astral.sh/uv/install.sh | shpowershell -ExecutionPolicy ByPass -c "irm <https://astral.sh/uv/install.ps1> | iex"uvx executes the tool straight from cache, no install step:
uvx --from "remote-compiler @ git+https://github.com/whaiman/remote-compiler.git" rgcc --help# pipx
pipx reinstall remote-compiler # always fetches the latest commit
pipx uninstall remote-compiler
# uv
uv tool upgrade remote-compiler # add --reinstall to force the latest commit
uv tool uninstall remote-compilerNotes:
pipxanduvputrgccandrgccdon your PATH (~/.local/binon Linux/macOS,%USERPROFILE%\.local\binon Windows). If the commands are not found, runpipx ensurepathoruv tool update-shelland restart the terminal.- The machine running
rgccdneeds a compiler toolchain; a client-only device does not:- Linux:
sudo pacman -S gcc/sudo apt install build-essential/sudo dnf install gcc-c++ - macOS:
xcode-select --install(Apple clang) orbrew install gcc - Windows: MinGW-w64 via MSYS2, or
winget install LLVM.LLVM
- Linux:
- Server-only machine? The Docker image ships
rgccdwith GCC, Clang, and MinGW preinstalled - the client still has to be installed on the device you compile from. - Termux (the phone-client case): Termux's Python isn't externally managed, so
pkg install python && pip install "remote-compiler @ git+https://github.com/whaiman/remote-compiler.git"is the normal install path there. - Not yet packaged for distro repositories (AUR, nixpkgs, Homebrew) - if you package it, a README PR is welcome.
To work on RGCC itself, see Development.
On the machine that will do the compiling, make sure gcc, g++, or clang is installed, then:
rgccdOn first run this generates rgccd.yaml with a random auth token (chmod 600 applied automatically):
server:
auth_token: <auto-generated> # copy this to the client
host: 0.0.0.0
port: 4444Override host/port if needed:
rgccd --host 127.0.0.1 --port 5000 # loopback only, no warning
rgccd --reload # dev mode, auto-restartIf you bind to anything other than
127.0.0.1/localhost,rgccdprints a warning reminding you that the handshake isn't TLS-authenticated. See Security Model.
On the device you're compiling from (phone, laptop, whatever):
# rgcc.yaml
client:
endpoint: http://<server-ip>:4444
auth_token: <paste-from-rgccd.yaml>rgcc compile main.cppYour binary lands in ./dist/.
# Basic compile, platform/standard auto-detected
rgcc compile main.cpp
# Custom output name and standard
rgcc compile main.cpp -o my_app --std c++20
# Cross-compile linux -> windows
rgcc compile main.cpp --target x86_64-w64-mingw32
# Custom sysroot for less common targets
rgcc compile main.cpp --target aarch64-linux-gnu --sysroot /usr/aarch64-linux-gnu
# Compile only, don't link
rgcc compile main.cpp --compile-only
# Pack and inspect the payload locally without sending it
rgcc compile main.cpp --dry-run
# Two independent remote builds, diff the output hash
rgcc compile main.cpp --verify-reproducible
# Interactive setup, saved to build.json
rgcc compile main.cpp -ibuild.json (created via rgcc init or -i) persists your build configuration:
{
"compiler": "clang++",
"standard": "c++20",
"entry_point": "main.cpp",
"output": "main.exe",
"platform": "win64",
"flags": ["-Wall", "-O3", "-static"],
"defines": ["DEBUG=1"]
}Dockerfile.server builds a self-contained build daemon with GCC, Clang, and MinGW preinstalled, running as a non-root user.
make docker-build
# Create your server config first (see Quickstart), then:
docker run -d \
--name rgcc-server \
--read-only \
--tmpfs /tmp \
--cap-drop=ALL \
--security-opt no-new-privileges \
--pids-limit 256 \
--memory 2g \
--cpus 2 \
-p 127.0.0.1:4444:4444 \
-v "$(pwd)/rgccd.yaml:/app/rgccd.yaml:ro" \
rgcc-server:latestNote the -p 127.0.0.1:4444:4444 - this publishes the port on loopback only. Put a TLS reverse proxy in front if you need to reach it from elsewhere (see Security Model).
To publish images to a registry (GHCR, Docker Hub, etc.), set up CI for it - this repository doesn't currently ship an automated build/publish workflow, so images have to be built locally with the command above until one is added.
git clone https://github.com/whaiman/remote-compiler.git
cd remote-compiler
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev]"(Debian/Ubuntu: if python -m venv fails, install it first - sudo apt install python3-venv.)
Already using uv? It does the same thing in one step:
uv sync --extra devmake install Install the unified package (-e .)
make install-dev Install + dev tools (-e ".[dev]")
make dev-client Dry-run compile of sample/main.cpp
make dev-server Run server on 127.0.0.1:4444 (reload mode)
make docker-build Build the server image
make docker-run-server Run the server container
make test Run the test suite
make lint ruff + black --check
make format ruff format + fix
make clean Remove build artifacts and caches
uv sync --extra dev reads pyproject.toml, creates .venv if it doesn't exist yet, and installs the project in editable mode together with [project.optional-dependencies].dev - the same PEP-668-safe approach as the install options above, so there's nothing extra to remember between "using RGCC" and "hacking on RGCC".
Don't have uv? See Option 2 above.
remote-compiler/
├── rgcc/
│ ├── core/ # crypto, config, manifest, checksum
│ ├── client/ # CLI, source collection, transport
│ └── server/ # HTTP daemon, compiler runner, job store
├── pyproject.toml
└── Makefile
PRs welcome. For anything touching rgcc/core/security.py, rgcc/server/compiler/runner.py, or the crypto/auth path, please open an issue first to discuss before submitting - that's the code where a mistake actually matters.
- Fork the repo
git checkout -b feature/your-thingmake test && make lint- Open a PR describing what changed and why
AGPL-3.0. Modified versions - including ones run as a network service - must also release their source. See LICENSE.