Skip to content

Deployment

dEXploarer edited this page Mar 10, 2026 · 1 revision

Deployment

Milady runs locally by default, but can also be deployed as a container (Railway, Docker, VPS). This page covers container deployment using the included Dockerfile.


Docker

A Dockerfile is included at the repo root. It uses node:22-bookworm as the base, installs Bun, builds the project, and starts Milady in headless mode.

Build

docker build -t milady .

Run

docker run -d \
  -p 2138:2138 \
  -v /data/.milady:/data/.milady \
  -e MILADY_API_TOKEN=your-secure-token \
  milady

The container CMD is:

MILADY_PORT=2138 node milady.mjs start

Railway sets PORT dynamically; the CMD maps it to MILADY_PORT.


Environment variables (container-specific)

The Dockerfile sets these defaults for container deployments:

Variable Container default Description
NODE_ENV production Node environment
MILADY_API_BIND 0.0.0.0 Bind to all interfaces (required in containers)
MILADY_STATE_DIR /data/.milady State directory (config, db, logs)
MILADY_CONFIG_PATH /data/.milady/milady.json Config file path
PGLITE_DATA_DIR /data/.milady/workspace/.eliza/.elizadb PGLite database directory

Important: Always set MILADY_API_TOKEN when MILADY_API_BIND=0.0.0.0. Without it, anyone who can reach the server has full access.


Persistent volume

Mount /data as a persistent volume so config, the database, and agent state survive redeploys:

docker run -v /host/path:/data milady

On Railway, attach a persistent volume at /data.


Railway

Deploy directly from the GitHub repo. Recommended env vars:

MILADY_API_TOKEN=<generated>
ANTHROPIC_API_KEY=<your-key>
TELEGRAM_BOT_TOKEN=<your-token>

Attach a persistent volume at /data.


Headless mode

In container/server deployments, always run headless:

milady start --headless

This suppresses the TUI and browser popup. The Dockerfile CMD already does this.


Logs

In headless/daemon mode, logs go to ~/.milady/logs/ (or MILADY_STATE_DIR/logs/ in containers). Use --verbose for log level info or --debug for debug.


Daemonizing (non-container)

Milady does not ship a built-in daemon manager. Use your preferred process manager.

systemd:

[Unit]
Description=Milady AI Agent
After=network.target

[Service]
ExecStart=/usr/local/bin/milady start --headless
Restart=on-failure
Environment=MILADY_API_TOKEN=your-token

[Install]
WantedBy=multi-user.target

pm2:

pm2 start "milady start --headless" --name milady
pm2 save

Git LFS (Docker builds)

The Dockerfile handles Git LFS assets (VRM avatars, animations) with a multi-step fallback:

  1. Runs git lfs pull if .git is present in the build context
  2. Falls back to cloning from the origin repo if LFS pointers remain unresolved
  3. Falls back to media.githubusercontent.com for VRM files as a last resort

VRM pointer files that are still unresolved after all fallbacks will fail the build. Animation pointer files will produce a warning but not fail.

Pass GITHUB_TOKEN as a build arg for private repo access:

docker build --build-arg GITHUB_TOKEN=ghp_... -t milady .

Pass MILADY_DOCKER_APT_PACKAGES to install additional system packages:

docker build --build-arg MILADY_DOCKER_APT_PACKAGES=ffmpeg -t milady .

Clone this wiki locally