A lightweight Remnawave Node implementation in Go for small Linux servers
Docker quick start · Native Linux · Configuration · Operations · Documentation
Remnanode Lite runs a Remnawave-compatible Node on Linux. It receives configuration from Remnawave Panel, supervises rw-core, manages users and plugin rules, and reports system and traffic statistics. Each Docker image includes the exact rw-core and runtime data selected for that release; published Native lifecycle bundles use the same release-selected assets.
The maintained deployment profile is designed for a server with 512 MiB RAM, 1 vCPU, and 2 GB of disk. Images are available for both linux/amd64 and linux/arm64.
Note
Remnanode Lite is an independent community project. It is not affiliated with or endorsed by Remnawave. Compatibility follows the public behavior of the official Node, while this codebase is developed and maintained independently.
- Implements the Remnawave Node
3.4.1API contract, including optional derived-SNI verification, credential-replacement connection cleanup, GeoCheck, and the current nftables behavior. - Runs the Node as one Go process that directly manages rw-core, without Node.js or s6.
- Uses Docker Compose as the simplest deployment path, with a self-contained Native Linux option for hosts that cannot run Docker.
- Includes the same maintained low-memory profile for container and Native services on 512 MiB servers.
- Supports live user updates, statistics, connection management, and the official plugin rule formats, including pre-start stale Unix-socket cleanup enabled by trusted Panel configuration.
- Publishes multi-architecture images to GHCR with SBOM, provenance, and build attestations.
- Native Linux support provides transactional install, upgrade, rollback, and repair through
rnlctl. - Uses one Compose file for Docker deployment. Compose automatically creates and manages the
remnanode-statecache volume, and.envremains optional.
| Docker Compose | Native Linux | |
|---|---|---|
| Choose it when | Docker Engine with Compose v2 is already available. This is the default path. | Docker cannot be installed, or its daemon and container-runtime overhead are not appropriate for the host. |
| Installation | Download the Release Compose asset and set the Panel Secret in .env or an intentional inline mapping. |
Download one exact Release, verify install.sh, and run the installer as root. |
| Update and rollback | Select an exact image tag or digest, then pull and recreate the container; restore the previous image reference to roll back. | Use rnlctl upgrade --to VERSION and rnlctl rollback; one verified previous generation is retained. |
| Host service | Requires the Docker Engine daemon and its container runtime. | Does not require the Docker Engine daemon or a container runtime, but remnanode-lite still runs as a systemd service or, on a listed Alpine profile, an OpenRC service. |
| Version reference | Exact tag or manifest digest is recommended; moving latest and preview are opt-in channels. |
Exact X.Y.Z or X.Y.Z-rnl.N Releases only; moving image channels are never resolved. |
Both paths use host networking and require NET_ADMIN. Do not run them beside another Node that uses the same Panel or proxy ports.
You need Docker Engine with Compose v2, a Node created in Remnawave Panel, and the complete Secret Key for that Node. The port must be reachable from the Panel. Commands below assume a root shell; use sudo where needed.
Choose a version shown on the GitHub Releases page, then download the Compose file and environment template from that exact Release. A source version or a candidate image is not a downloadable Release:
mkdir -p /opt/remnanode-lite
cd /opt/remnanode-lite
VERSION="<published-version>" # for example: X.Y.Z or X.Y.Z-rnl.N
BASE="https://github.com/luxiaba/remnanode-lite/releases/download/${VERSION}"
curl -fL \
"${BASE}/docker-compose.single-file.yaml" \
-o docker-compose.yaml
curl -fL \
"${BASE}/remnanode-lite.env.example" \
-o .env
chmod 600 docker-compose.yaml .envThe Compose CLI automatically reads .env from this directory. Both downloaded files select the exact image version from that Release. Set the Node port and complete Secret from the Panel in .env:
NODE_PORT=2222
SECRET_KEY=PASTE_THE_COMPLETE_PANEL_SECRET_KEYThe Compose fallback for NODE_PORT is the official default, 2222. Change it only when the Node record in the Panel uses a different port.
Existing deployments may keep their current custom directory; changing the directory name is not required for an upgrade.
To keep a literal single-file deployment without .env, replace the SECRET_KEY interpolation in docker-compose.yaml with the complete value directly. The following example keeps the default Node port:
environment:
NODE_PORT: "${NODE_PORT:-2222}"
SECRET_KEY: "PASTE_THE_COMPLETE_PANEL_SECRET_KEY"Start the Node:
cd /opt/remnanode-lite
docker compose config --quiet
docker compose pull
docker compose up -d --no-build
docker compose ps
docker compose logs --tail=100 remnanode-liteThe container should become healthy, then the Node should return online in the Panel. Confirm the deployment with real proxy traffic. Container health alone does not check Panel connectivity or rw-core traffic.
The official container's NODE_PORT and SECRET_KEY can be reused when migrating. Stop the old container before starting this one. The Docker deployment guide covers migration, exact-version installs, digest pinning, and rollback.
Use the Native bundle when Docker cannot be installed or the Docker Engine daemon and container runtime are not appropriate for the host. Native does not mean that the Node has no background service: remnanode-lite runs directly under the host service manager. Rocky Linux 9 with systemd is the primary target. See the Native host matrix for compatible hosts, Alpine prerequisites, and the newer distributions currently being qualified.
Install the host prerequisites before running the installer; it does not install or configure system packages.
Native installs never follow a moving channel. Choose a version shown on the
GitHub Releases page, then download install.sh and SHA256SUMS from that
exact Release, verify the installer, and name the release explicitly:
VERSION="<published-version>" # for example: X.Y.Z or X.Y.Z-rnl.N
BASE="https://github.com/luxiaba/remnanode-lite/releases/download/${VERSION}"
curl -fLO "${BASE}/install.sh"
curl -fLO "${BASE}/SHA256SUMS"
grep ' install.sh$' SHA256SUMS | sha256sum -c -
sudo sh ./install.sh --version "$VERSION" --port 2222The installer securely prompts for the complete Panel Secret when one is not already installed. It verifies and installs one complete generation: Node, rnlctl, rw-core, GeoIP, GeoSite, ASN data, and service definitions. After startup:
sudo rnlctl overview
sudo rnlctl status
sudo rnlctl doctor
sudo rnlctl logs node --lines 100overview is the concise human entry point. It combines lifecycle and service
state with the configured non-secret endpoint, then shows commands appropriate
to the current state. It does not contact Panel or generate proxy traffic, and
it has no JSON form; scripts should keep using the unchanged status --json
model. doctor ends with a summary and specific next commands when it finds a
problem. Successful install, activation, upgrade, rollback, and repair commands
also print useful next steps; failed lifecycle mutations suggest safe local
diagnostics without running them. Long operations adapt their
progress to interactive terminals or redirected logs. Global --quiet/-q,
--no-color, and --progress auto|plain|never options may appear anywhere in
an rnlctl command; install.sh accepts the same progress modes. Shell
completion, output behavior, signal handling, systemd log time filters, and
upgrade dry-runs are covered in the
Native Linux guide.
Native runtime settings live in /etc/remnanode-lite/node.env; rnlctl config
is the safe way to inspect and edit that file, not a second configuration
store. It shows only administrator-editable, non-secret values. For example:
sudo rnlctl config show
sudo rnlctl config set NODE_PORT=2222 --apply
sudo rnlctl secret set --file /root/new-node-secret.key --applyThe Secret command reads a protected file and never accepts the Secret itself on the command line. A port change must also be made in the Panel and host firewall. See the configuration reference for validation, stopped/prepared installations, and rollback behavior.
Native bundles carry the same contract as their matching Release. Read the Native Linux guide before fleet rollout; it covers prerequisites, unattended and offline installation, exact-version upgrades, rollback, repair, and uninstall.
Most deployments only need to set NODE_PORT and SECRET_KEY. The maintained Compose files interpolate exactly these eleven variables:
| Variable | Required in .env |
Compose fallback | Purpose |
|---|---|---|---|
REMNANODE_IMAGE |
No | Exact image selected by the Release Compose file | Image tag or name@sha256:...; used by Compose and not passed to the Node. |
NODE_PORT |
No | 2222 |
HTTPS port used by the Panel. It must match the Node port configured there. |
NODE_BIND_ADDR |
No | Empty | Listen on a specific local address. Empty listens on all local addresses. |
SECRET_KEY |
Yes, unless set directly in YAML | None; interpolation fails when empty | Complete base64 or base64url Secret supplied by the Panel. |
LOW_MEMORY |
No | 1 |
Enables the low-memory limits used by the small-server profile. |
DISABLE_HASHED_SET_CHECK |
No | false |
Debug-only switch that forces every start request to restart rw-core. |
SNI_VERIFICATION |
No | false |
Enables the optional derived-SNI certificate-selection gate. mTLS and JWT remain mandatory when disabled. |
NFTABLES_LOGGING |
No | true |
Logs ingress and Torrent Blocker drops to the kernel log. |
NFTABLES_ACCEPT_REPLY_TRAFFIC |
No | false |
Accepts conntrack reply-direction traffic before ingress block sets. |
BODY_LIMIT_MB |
No | Empty (automatic) | Overrides the Node API body limit. Low-memory mode selects 16 MiB automatically. |
GOMEMLIMIT |
No | Empty (automatic) | Overrides the Go runtime soft memory limit. Low-memory mode selects 180 MiB automatically. |
For interpolation, precedence is shell environment > .env > the fallback written in the Compose file. The :- form uses its fallback when the resolved value is unset or empty. Compose passes only the ten runtime variables explicitly listed under environment; REMNANODE_IMAGE is Compose-only, and unknown keys in .env are not injected into the container.
Keep the mapping form shown above. Do not write - SECRET_KEY="...": in that list form the quote characters become part of the value and the Secret cannot be decoded. Keep the Compose file private because Docker stores inline environment values in its local metadata.
See the configuration reference for every runtime setting, accepted value, and precedence rule.
Follow the Node logs:
docker compose logs --tail=100 -f remnanode-liteFollow rw-core output and errors:
docker exec -it remnanode-lite sh -c \
'tail -n 50 -F "$LOG_DIR/xray.out.log" "$LOG_DIR/xray.err.log"'Check the running version:
docker exec remnanode-lite remnanode-lite versionTo move between exact versions, first use the Compose template attached to the
target Release, preserving .env and any intentional local overrides. This is
required when upgrading from 3.0.0 to 3.2.2 because the newer deployment
adds the remnanode-state volume. Then change REMNANODE_IMAGE in .env, or
the inline image: value when intentionally deploying without .env, and
recreate the container:
docker compose pull
docker compose up -d --no-build --force-recreatelatest is only checked when you pull; it never updates a running container by itself. rw-core logs live in tmpfs, while Node logs use Docker's rotating json-file driver. See the operations guide for health checks, troubleshooting, rollout, and rollback.
| Tag | Use |
|---|---|
X.Y.Z |
Stable Release aligned with the corresponding official Node contract. Recommended for production and rollback. |
X.Y.Z-rnl.N |
A tested Remnanode Lite iteration for work ahead of or beyond an official alignment point. |
latest |
The most recently completed stable Release. It moves, so it is not a rollback reference. |
preview |
The most recently promoted rnl.N prerelease. It never advances latest. |
sha-<commit> |
Immutable image built from a specific main commit. Use it to verify a release candidate. |
edge |
Current main image for short-lived testing only. |
For a fleet, prefer one exact version or manifest digest and keep the previous value for rollback. The full policy is in Versioning and image tags.
| Item | Current baseline |
|---|---|
| Native Linux bundles | Exact published Releases |
| Native hosts | Distribution-specific; see the Native host matrix |
| Node contract | 3.4.1 |
| rw-core | v26.7.28 |
| Platforms | linux/amd64, linux/arm64 |
| Whole-host target | 512 MiB RAM / 1 vCPU / 2 GB disk |
| Compose service limit | 448 MiB RAM, no additional swap |
The whole-host size is a design target. The maintained Compose profile strictly limits the container to 448 MiB / 1 CPU with no additional container swap, leaving room for the host.
The resource target is the baseline for the maintained Compose profile, not a promise that every traffic pattern or plugin configuration fits the same machine. Measurements and limits are documented in the resource budget.
flowchart LR
Panel["Remnawave Panel"] -->|"mTLS + JWT"| Node["Remnanode Lite"]
Node -->|"configuration, users, stats"| Core["rw-core"]
Node --> Rules["nftables and connections"]
Core --> Traffic["Proxy traffic"]
The Node owns the rw-core process and current runtime state. The Panel remains the source of truth for the active Xray configuration. The remnanode-state persistent volume created by Compose does not store that configuration; it only caches Panel-derived custom Core and GeoData assets. Normal configurations require no manual volume management, and bundled assets remain the fallback. Read Architecture and runtime design for package boundaries, lifecycle rules, and data flows.
| Goal | Start here |
|---|---|
| Deploy or migrate a Node | Docker Compose · Native Linux |
| Configure and operate it | Configuration · Operations |
| Understand the project | Project scope · Architecture |
| Work on the code | Development guide · Testing · Contributing |
| Understand versions and Releases | Versioning · Release process |
| Report or review security issues | Security policy |
The documentation index contains the complete English documentation and links to the Chinese and Russian translations.
Ordinary unit tests do not need a Panel, Secret, or running rw-core:
git switch dev
go mod download
go test -count=1 ./...
mkdir -p bin
go build -trimpath -o bin/remnanode-lite ./cmd/remnanode-lite
go build -trimpath -o bin/rnlctl ./cmd/rnlctl
./bin/remnanode-lite version
./bin/rnlctl versionLinux network integration, real rw-core behavior, and Panel compatibility are separate test layers. Start with the development guide before changing those areas.
Docker and Native services use the host network namespace and hold NET_ADMIN, so they can change networking state on the host. Run only trusted release artifacts and prefer an exact version or manifest digest. Keep the Compose directory or /etc/remnanode-lite private, and restrict access to the Docker socket and host administrator accounts.
Do not post Secrets, certificates, real Node details, or vulnerability exploits in a public Issue. Follow SECURITY.md for private reporting.
Remnanode Lite is licensed under AGPL-3.0-only.