Deploy OpenZeppelin Relayer (AWS KMS)
OpenZeppelin Relayer with Redis, signing with your own AWS KMS key
OpenZeppelin Relayer (AWS KMS)
Just deployed
Just deployed
/data
Deploy and Host OpenZeppelin Relayer with AWS KMS on Railway
OpenZeppelin Relayer is open-source software (AGPL-3.0) that sends blockchain transactions for your backend: it assigns nonces, prices gas, resubmits stuck transactions and tracks confirmations. This template runs it with Redis and signs with your own AWS KMS key, so the private key stays in AWS and never reaches the server.
This is not an official OpenZeppelin template. Nonceworks publishes and maintains it, and Nonceworks is not affiliated with OpenZeppelin.
About Hosting OpenZeppelin Relayer
The template deploys two services. Relayer runs the official openzeppelin/openzeppelin-relayer image, version 1.9.0, pinned by digest. Redis 8.2 (official image, pinned by digest) stores the relayer's signers, transactions and nonce counters on a volume, so they are kept across restarts and redeploys; the signer, notification and API key records in it are encrypted with a key generated at deploy. The two talk over Railway's private network. The relayer's config.json is built from template variables and written to a file when the container starts, so no custom image is needed. The API gets a public HTTPS domain and requires a generated API key on every call except the health and readiness checks.
Common Use Cases
- Send transactions from a backend or bot without keeping a private key in an environment variable
- Move a relayer that signed with a local keystore onto an AWS KMS key
- Self-host the relayer after OpenZeppelin Defender's shutdown
- Run keeper or scheduled transactions through one queue that manages nonces and gas
Dependencies for OpenZeppelin Relayer Hosting
- An AWS KMS key: asymmetric, key usage Sign and verify, key spec
ECC_SECG_P256K1 - An IAM identity with an access key, allowed only
kms:GetPublicKeyandkms:Signon that key - An RPC endpoint for your chain (the default is Base Sepolia's public endpoint)
- Native gas funds on the relayer's address, which the relayer derives from the key
Deployment Dependencies
- OpenZeppelin Relayer documentation: https://docs.openzeppelin.com/relayer/
- OpenZeppelin Relayer source: https://github.com/OpenZeppelin/openzeppelin-relayer
- Our note on the KMS key, the IAM policy and revoking access: https://nonceworks.com/notes/relayer-aws-kms-permissions.html
Implementation Details
Bring your own AWS KMS key
-
In AWS KMS, create an asymmetric key with key usage Sign and verify and key spec
ECC_SECG_P256K1. Note its ARN and region. -
Create an IAM user (or role with an access key) with only this policy, using your key's ARN:
{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": ["kms:GetPublicKey", "kms:Sign"], "Resource": "arn:aws:kms:us-east-1:123456789012:key/11111111-2222-3333-4444-555555555555" }] } -
Deploy the template and fill in
AWS_REGION,AWS_KMS_KEY_ID(key id, ARN or alias),AWS_ACCESS_KEY_IDandAWS_SECRET_ACCESS_KEY. For another chain, also setCHAIN_ID,RPC_URL,NETWORK_NAME,NATIVE_SYMBOL,IS_TESTNETandAVERAGE_BLOCKTIME_MS. After the first deploy, sealAWS_SECRET_ACCESS_KEYon the Relayer service's Variables tab (the variable's 3-dot menu, Seal): Railway keeps passing it to the relayer but never shows it again in the dashboard or the API. A sealed variable cannot be unsealed, only replaced. Railway then lists the seal as a pending change; press Deploy to apply it. The relayer keeps reading its key from KMS through that and every later deploy. -
Read the relayer's address (copy
API_KEYfrom the Relayer service's variables):curl -H "Authorization: Bearer $API_KEY" https:///api/v1/relayers/kms-relayer -
Send gas funds to that address. Until it holds a balance the relayer marks itself disabled; it rechecks on its own and enables itself once the funds arrive (about 20 seconds in our tests).
-
Send a transaction:
curl -X POST -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" \ -d '{"to":"0x...","value":1,"data":"0x","gas_limit":21000,"speed":"fast"}' \ https:///api/v1/relayers/kms-relayer/transactions
To stop all signing at once, disable the key in AWS KMS or detach the IAM policy. The note linked above has the timings we measured for each.
Changing the configuration later. Every setting lives in RELAYER_CONFIG_JSON, which is built from the other variables. With Redis storage the relayer reads that config only into empty storage. To load a change, redeploy once with RESET_STORAGE_ON_START=true, then set it back to false. That start drops stored transactions and nonce counters, so do it only when nothing is in flight. Never change STORAGE_ENCRYPTION_KEY after the first start.
If the deploy fails its health check. Open the Relayer logs. The relayer's first call to KMS is GetPublicKey. If the credentials cannot use the key (a wrong key id, the wrong region or a missing permission), that call fails, the log shows AWS KMS get_public_key failed and the relayer exits; we tested the wrong-key-id case. An empty number field, such as CHAIN_ID, leaves the config invalid, and the log shows Failed to load config file with a JSON error.
Things to know.
- The API is public so callers outside Railway can reach it. If every caller runs in the same Railway project, remove the Relayer's public domain and call
http://relayer.railway.internal:8080instead. - Redis has no public domain in this template and is reachable only from services in the same project environment.
- The image is pinned to Relayer 1.9.0 by digest; newer releases are not picked up automatically.
What it costs on Railway. Railway bills usage at its published rates: $10 per GB of RAM a month, $20 per vCPU a month, $0.15 per GB of volume a month and $0.05 per GB of egress. The Hobby plan is $5 a month and includes $5 of usage. In our local tests of Relayer 1.9.0, idle on a chain with one-second blocks, the relayer used 32 to 47 MB of RAM and 3 to 17 percent of one CPU, and Redis 6 to 8 MB and under 4 percent, which at those rates comes to roughly $1 to $5 a month. A relayer sending many transactions uses more.
Why Deploy OpenZeppelin Relayer on Railway?
Railway runs both services from one click, keeps Redis on a private network with a persistent volume, gives the API an HTTPS domain, and restarts the relayer if it fails. You keep the signing key in your own AWS account the whole time.
Hosted help
If you would rather not run the relayer yourself, Nonceworks can host OpenZeppelin Monitor and Relayer for your team, signing with your own key, and offers fixed-price moves off Defender or off a raw server key: https://nonceworks.com
Template Content
AWS_REGION
Region of your AWS KMS key, for example us-east-1.
AWS_KMS_KEY_ID
Your KMS key: key id, key ARN, alias or alias ARN. Asymmetric, usage Sign and verify, key spec ECC_SECG_P256K1.
AWS_ACCESS_KEY_ID
Access key of an IAM identity allowed only kms:GetPublicKey and kms:Sign on that one key.
AWS_SECRET_ACCESS_KEY
Secret for AWS_ACCESS_KEY_ID. After the first deploy, seal it on the Relayer's Variables tab (the variable's 3-dot menu, Seal), so Railway passes it to the relayer but never shows it again.
