Deployment
Airnode is a single long-lived process. Deployment means keeping it running reliably with automatic restarts and secure key management.
Prerequisites
- The
airnodebinary on yourPATH(or a known install path) - A validated
config.yaml - A
.envfile withAIRNODE_PRIVATE_KEY
Direct
airnode start -c config.yaml
systemd
Create a service file for automatic restarts and boot persistence:
# /etc/systemd/system/airnode.service
[Unit]
Description=Airnode
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=airnode
WorkingDirectory=/opt/airnode
ExecStart=/usr/local/bin/airnode start -c /opt/airnode/config.yaml
Restart=always
RestartSec=10
EnvironmentFile=/opt/airnode/.env
# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/airnode
[Install]
WantedBy=multi-user.target
Enable and start:
sudo systemctl daemon-reload
sudo systemctl enable airnode
sudo systemctl start airnode
View logs:
journalctl -u airnode -f
For JSON log aggregation, set LOG_FORMAT=json in the .env file.
Docker
FROM oven/bun:1
WORKDIR /app
COPY package.json bun.lockb ./
RUN bun install --frozen-lockfile
COPY . .
EXPOSE 3000
CMD ["bun", "src/cli/index.ts", "start"]
Build and run:
docker build -t airnode .
docker run -d --name airnode --restart unless-stopped \
-p 3000:3000 \
-v $(pwd)/config.yaml:/app/config.yaml:ro \
-e AIRNODE_PRIVATE_KEY=0x... \
airnode
Pass secrets via environment variables or Docker secrets. Do not bake them into the image.
Docker Compose
# compose.yaml
services:
airnode:
build: .
restart: unless-stopped
ports:
- '3000:3000'
env_file: .env
volumes:
- ./config.yaml:/app/config.yaml:ro
docker compose up -d
Environment variables
| Variable | Required | Description |
|---|---|---|
AIRNODE_PRIVATE_KEY | Yes | Hex-encoded private key (with 0x prefix). Signs all responses. |
LOG_FORMAT | No | text (default) or json. |
LOG_LEVEL | No | debug, info (default), warn, or error. |
Any ${VAR} referenced in your config must also be set in the environment.
Graceful shutdown
Airnode handles SIGINT and SIGTERM for clean shutdown. The server stops accepting new requests, in-flight requests
complete, the cache is cleared, and the process exits.
# Manual stop
kill -TERM $(pgrep -f "airnode start")
# systemd
sudo systemctl stop airnode
# Docker
docker stop airnode
Key management
The AIRNODE_PRIVATE_KEY controls the airnode's on-chain identity and signs all responses. Protect it accordingly:
- Never commit the private key to version control. Use
.envfiles (gitignored) or secret managers. - Restrict file permissions:
chmod 600 .envso only the airnode user can read it. - Use secret managers in cloud environments: AWS Secrets Manager, GCP Secret Manager, or HashiCorp Vault.
- Separate keys per environment: use different private keys for testnet and mainnet.
- Back up the key securely: if lost, the airnode address changes and all on-chain associations must be re-established.
Health checks
The /health endpoint returns the node's status, version, and airnode address:
curl http://localhost:3000/health
{
"status": "ok",
"version": "2.0.0-alpha.0",
"airnode": "0x..."
}
Use this for Docker HEALTHCHECK, load balancer probes, or uptime monitoring.