Self-host Asobi
Asobi is fully open-source and designed to be run on your own infrastructure. This guide walks through three deployment targets: Docker Compose (dev), a single server (production), and Kubernetes (scale).
Prefer managed? Asobi Cloud is coming — fully managed game servers, EU-sovereign hosting, per-environment scaling. Join the waitlist at asobi.dev/cloud.
Deployment targets
Docker Compose
Single machine, everything local. Great for dev, prototyping, and small productions.
Single VPS
One Hetzner/DigitalOcean box, Erlang release, systemd. Supports hundreds of CCU.
Kubernetes
Scaleway Kapsule or similar. Container-per-game-env, full isolation, scale horizontally.
Docker Compose
The quickest way to run a real Asobi stack. Save this as docker-compose.yml:
services:
postgres:
image: postgres:17
environment:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: asobi
volumes: [pgdata:/var/lib/postgresql/data]
ports: ["5432:5432"]
asobi:
image: ghcr.io/widgrensit/asobi_lua:latest
depends_on: [postgres]
environment:
ASOBI_DB_HOST: postgres
ASOBI_DB_NAME: asobi
ASOBI_DB_USER: postgres
ASOBI_DB_PASSWORD: postgres
ERLANG_COOKIE: ${ERLANG_COOKIE}
ports: ["8080:8080"]
volumes:
- ./game:/app/game:ro
volumes:
pgdata:Generate a cookie, then boot the stack:
export ERLANG_COOKIE=$(openssl rand -hex 32)
docker compose up -dAsobi is now running on http://localhost:8080. Deploy your game with asobi deploy ./game and you're live.
Single VPS
For production on a single machine — a Hetzner AX41 (€40/mo) comfortably handles hundreds of concurrent players. Build a release from the Asobi source:
git clone https://github.com/widgrensit/asobi
cd asobi
rebar3 as prod release
# The release is at _build/prod/rel/asobi/
# Copy it to the server, run with:
bin/asobi daemonConfigure the release via config/prod_sys.config.src — environment variables, database credentials, and TLS settings are all there. See the config directory for full examples.
Systemd unit
# /etc/systemd/system/asobi.service
[Unit]
Description=Asobi game backend
After=network.target postgresql.service
[Service]
Type=notify
User=asobi
Environment=ERLANG_COOKIE=generate-a-real-one
Environment=HOME=/var/lib/asobi
ExecStart=/opt/asobi/bin/asobi foreground
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.targetReverse proxy (Caddy)
game.example.com {
reverse_proxy localhost:8080
}Caddy auto-issues TLS certs and handles WebSocket upgrades without config. Nginx works equally well — make sure proxy_set_header Upgrade $http_upgrade is set.
Kubernetes
For multi-tenant or multi-game deployments, run one pod per game-env. Our reference infra repo (widgrensit/asobi-infra) ships a Helm stack for Scaleway Kapsule: cert-manager, Prometheus, Loki, Velero, and CloudNativePG.
A minimal Deployment looks like this:
apiVersion: apps/v1
kind: Deployment
metadata:
name: asobi-my-game-live
namespace: tenant-widgrensit
spec:
replicas: 1
template:
spec:
containers:
- name: engine
image: ghcr.io/widgrensit/asobi_lua:latest
env:
- name: ASOBI_DB_HOST
valueFrom:
secretKeyRef: { name: pg-credentials, key: host }
- name: ERLANG_COOKIE
valueFrom:
secretKeyRef: { name: erlang-cookie, key: cookie }
ports:
- containerPort: 8080
resources:
requests: { cpu: 100m, memory: 256Mi }
limits: { cpu: 1000m, memory: 1Gi }See the asobi-infra repo for the full cluster setup, NetworkPolicies, and tenant isolation patterns.
Backups
- Postgres: everything Asobi persists lives in Postgres. Back up continuously (WAL shipping to S3-compatible storage) or at least nightly.
- Lua bundles: your game source lives in git. That's the backup.
- Zone snapshots: persistent worlds snapshot their state to Postgres every tick interval. They're restored automatically on startup.
Rate limits
Asobi ships with three Seki limiter groups out of the box. Defaults are tuned for a single internet-facing node:
Path prefix | Limiter | Default (req/sec/IP)
-------------------|---------------------|-----------------------
/api/v1/auth/* | asobi_auth_limiter | 5
/api/v1/iap/* | asobi_iap_limiter | 10
everything else | asobi_api_limiter | 300Override per environment via the asobi, rate_limits env — see the Configuration page.
Operator hygiene
Recommended deploy posture beyond the obvious "rotate the cookie, terminate TLS at the proxy":
- Mount the game dir read-only. The runtime supports hot reload via filesystem polls; it does not need write access to
/app/game.docker run -v ./game:/app/game:ro --read-only --tmpfs /tmp. - Bind distributed Erlang to localhost. For single-node deploys, uncomment the
-kernel inet_dist_use_interfaceline invm.args.srcso EPMD and the dist port range are unreachable from the public internet. - Use TLS for distribution if you cluster. Set an explicit dist port range plus
-proto_dist inet_tls; the cookie alone is not sufficient on a public network. - Ship the Apple root CA in a known location. Default is
priv/apple_root_ca.peminside the asobi app; override viaapple_root_ca_pathif you mount it elsewhere. - Run the engine as non-root. The shipped Dockerfile already does this; bare metal should too.
- Enable Postgres SSL for cross-host connections. Required for any deploy that does not co-locate Postgres on the same machine.
- Treat deploy keys like passwords. Rotate on employee offboarding; never commit them to your game repo.
For the full threat model and the audit findings these recommendations come from, see the Security section.
Upgrades
Asobi releases are hot-code-loadable on the BEAM. For minor version bumps, deploy the new release and existing matches finish on the old code; new matches use the new code. No downtime. For major version bumps (breaking schema changes), run migrations via rebar3 kura migrate in a maintenance window.
Where next?
- Core concepts — understand what the engine runs.
- asobi-infra — reference Helm stack for managed k8s.
- Asobi Cloud — managed hosting, coming soon.