Until 2026-11-15, an xOneRS node served JSON-RPC in plain HTTP, and the advice was to put a TLS reverse proxy in front of it. On main the node can now do three things itself: serve HTTP and WebSocket RPC over TLS (PR #1078), require a client certificate, and give each caller its own list of allowed methods through a JWT and --rpc.acl (PR #1099). None of this is in v0.1.0. For the limits that apply to every request, see exposing RPC safely.

How do I serve RPC over TLS?

xone --network apothem --http --http.addr 0.0.0.0 \
  --http.tls.cert /etc/xone/rpc.crt --http.tls.key /etc/xone/rpc.key
REFERENCE TABLEScroll to explore all columns →
Flag Meaning
--http.tls.cert, --http.tls.key PEM certificate and key for the HTTP listener
--ws.tls.cert, --ws.tls.key The same for the WebSocket listener
--http.tls.clientca, --ws.tls.clientca A PEM CA file: clients must present a certificate issued by it
  • An invalid or incomplete pair stops the node from becoming ready, and the error names the file path, never the key material.
  • A failed handshake drops the connection.
  • If HTTP and WebSocket share one port, the listener uses one TLS setting: HTTP's if set, else WebSocket's. See HTTP and WebSocket on one port.

How do I give each caller its own methods?

Two flags work together. --rpc.jwtsecret <file> (32 bytes, hex) makes HTTP and WebSocket require an HS256 bearer token; IPC is not affected. --rpc.acl <file> adds a JSON map from the token's sub to the method patterns that caller may use:

{
  "dapp":     ["eth_*", "net_version"],
  "indexer":  ["eth_*", "trace_*", "ots_*"],
  "operator": ["*"]
}

A pattern is *, a prefix with * such as eth_*, or an exact method name. When the map is set, a caller whose sub is not in it is refused. A token may also carry a methods claim, which narrows that caller further. The check covers single calls, every member of a batch, and subscriptions.

How does a client make a token?

The token is HS256 over the shared secret, with iat (issued-at, in seconds) within 60 seconds of the node's clock. So a client signs a fresh token often, not once. A minimal Python version with only the standard library:

import base64, hashlib, hmac, json, time

def b64(b): return base64.urlsafe_b64encode(b).rstrip(b"=")

def token(secret_hex, sub, methods=None):
    head = b64(json.dumps({"alg": "HS256", "typ": "JWT"}).encode())
    claims = {"iat": int(time.time()), "sub": sub}
    if methods: claims["methods"] = methods
    body = b64(json.dumps(claims).encode())
    sig = hmac.new(bytes.fromhex(secret_hex), head + b"." + body, hashlib.sha256).digest()
    return (head + b"." + body + b"." + b64(sig)).decode()

# Authorization: Bearer <token("…64 hex digits…", "dapp")>

What errors does a refused caller see?

REFERENCE TABLEScroll to explore all columns →
Case Answer
No token, a bad signature, iat more than 60 s off, or alg not HS256 HTTP 401 Unauthorized (a WebSocket handshake also gets 401); the reason is not told to the client
With --rpc.acl: no sub, or a sub that is not in the map HTTP 401 Unauthorized
A method outside the caller's patterns JSON-RPC error -32601, method <name> is not allowed

From crates/xone-rpc/src/policy.rs and transport.rs. If --rpc.acl is set without --rpc.jwtsecret, every HTTP and WebSocket request is refused with 401, so set both. The namespace list (--http.api, --ws.api) still applies first: the ACL can only narrow what a listener serves, not add a namespace to it.

Do I still need a reverse proxy?

Not for TLS or for per-caller method lists. A proxy can still help with things the node does not do, such as certificate renewal, rate limits per API key that your billing uses, or several nodes behind one name. The node's own request bounds and quotas apply either way. Keep the token secret file readable only by the node's user.

How does this compare with other clients?

The HS256 bearer token with a fresh iat is the scheme of the Engine API, which geth and the other Ethereum clients use on their authenticated port; the xOne code names geth's jwtHandler as its model. A per-principal method ACL on the public RPC is an xOne setting (issue #541); we did not survey whether other clients offer one, so we make no comparison here.

Frequently asked questions

How do I enable HTTPS on an xOne RPC endpoint?

Start the node with --http.tls.cert and --http.tls.key pointing to PEM files, on a build from main after PR #1078.

Can I require client certificates for xOne RPC?

Yes. Set --http.tls.clientca (or --ws.tls.clientca) to a PEM CA file; clients must present a certificate issued by that CA.

How do I allow only eth_ methods for one API user?

Use --rpc.jwtsecret and --rpc.acl with a map such as {"dapp": ["eth_*"]}, and give that user tokens with sub set to dapp.

Why is my JWT refused after a minute?

The node accepts a token only while its iat is within 60 seconds of the node's clock. Sign a new token for each request or each minute.

Sources