SSD Nodes Learn 🎉 VPS from $4.99/mo
Guides Matt ConnorBy Matt Connor

Self-host LiveContext, an n8n alternative

LiveContext CE is a six container Docker stack with a Java backend that wants 8 GB. Size it, pin the version, put Traefik in front, and back up both stores.

What LiveContext is, and what it costs to run

To self-host LiveContext you need a VPS with about 8 GB of RAM. LiveContext CE is an open source automation platform that runs AI agents inside the automation itself, and it ships as a Docker Compose stack of six containers built around a Java backend. The upstream README asks for 4 GB minimum and 8 GB recommended, and the compose file shows where that memory goes.

The project is at livecontext-ai/livecontext-ce on GitHub, licensed AGPL-3.0. The current release as of August 2026 is v0.2.11, published on 3 August 2026. Every image is built for linux/amd64 only, which rules out the cheap Arm plans. This guide pins that tag, puts the stack behind a reverse proxy, and covers the backup procedure the upstream docs do not include.

Size the VPS before you self-host LiveContext

Every service in the shipped compose file carries an explicit memory limit, so you can size the box before you rent it. These are the limits written into the v0.2.11 compose file, not measured usage.

ChartMemory limits in the LiveContext CE v0.2.11 compose file, MB
The data behind this chart
[
  {
    "label": "livecontext (backend)",
    "memory_limit_mb": 1536
  },
  {
    "label": "bridge",
    "memory_limit_mb": 512
  },
  {
    "label": "redis",
    "memory_limit_mb": 384
  },
  {
    "label": "postgres",
    "memory_limit_mb": 256
  },
  {
    "label": "minio",
    "memory_limit_mb": 256
  },
  {
    "label": "websearch (optional)",
    "memory_limit_mb": 2048
  },
  {
    "label": "searxng (optional)",
    "memory_limit_mb": 512
  },
  {
    "label": "renderer (optional)",
    "memory_limit_mb": 1024
  }
]

The backend alone is capped at 1536 MB. That cap sits over a Java 21 process, so the JVM will grow into most of it and stay there. The five base services add up to a little under 3 GB, and the frontend carries no limit at all, so it takes what Node asks for. On a 4 GB VPS that leaves almost nothing for the kernel and the page cache, which is why 4 GB is written as a minimum rather than a recommendation.

The optional profiles are what push the box to 8 GB. The browser agent profile adds a Chromium container capped at 2048 MB next to a SearXNG search instance, and the renderer profile adds another 1024 MB for screenshots and PDFs. Neither starts unless you enable its profile, so leave both off until you need them.

If you already run n8n, plan to replace it rather than to add to it. The stack in our guide to running n8n on a VPS with Docker and HTTPS is one Node process next to Postgres, and it is comfortable on a small box. LiveContext reserves more for its backend alone than that whole stack uses. Two automation platforms on one 8 GB VPS will fit right up until both run a job at the same minute. If you do share a host, put explicit limits on everything else too, using the method in our post on setting memory limits in Docker Compose, so one runaway workflow cannot take the machine down with it.

Install LiveContext with Docker Compose, pinned to a tag

Start from a clean Ubuntu 24.04 VPS with Docker Engine 24 or newer and Compose v2. If Docker is not installed yet, follow our Docker Compose basics for a VPS first, then come back.

The README offers npx livecontext as a one line start. That is fine on a laptop. On a server you want the compose file sitting in a directory you control, because then an upgrade is a git checkout and you can read exactly what changed.

sudo apt update && sudo apt install -y git
git clone https://github.com/livecontext-ai/livecontext-ce.git
cd livecontext-ce
git tag --list 'v*' | tail -5
git checkout v0.2.11
cp docker/.env.ce.example docker/.env.ce
chmod 600 docker/.env.ce

The compose file already pins every image to its release tag, for example ghcr.io/livecontext-ai/livecontext-ce:v0.2.11. Checking out the matching git tag is what keeps the compose file and the images in step, because the compose file for v0.2.11 was written against those images. Do not edit the tags to latest. A latest tag moves under you, and the backend runs its database migrations on every start, so an accidental pull can move your schema forward at 3 a.m. with no way back except a restore.

Edit docker/.env.ce before the first start (the next section lists what to change), then bring the stack up.

docker compose --env-file docker/.env.ce up -d
docker compose --env-file docker/.env.ce ps

Use the same --env-file flag on every compose command in this guide. Compose reads that file fresh on each invocation, so a command without the flag falls back to the defaults baked into the compose file and can publish different ports than the ones you configured.

The backend healthcheck has a start_period of 120s and polls /actuator/health, so docker compose ps reports the livecontext service as health: starting for roughly the first two minutes while the schema migrations and the tool registration run. That is normal. A quick check from the server:

curl -s localhost:8080/actuator/health

This should print {"status":"UP"}. When it does, open the web UI on port 3000. The first account you create becomes the admin, so create yours before the port is reachable by anyone else. This is the single most important reason not to publish port 3000 to the internet on day one.

The env values you must change

The example file ships working defaults so the stack starts on a laptop. Several of them are unsafe on a public server.

POSTGRES_PASSWORD=<random>
MINIO_ROOT_USER=<not minioadmin>
MINIO_ROOT_PASSWORD=<random>
CREDENTIAL_ENCRYPTION_PASSWORD=<random>
CREDENTIAL_ENCRYPTION_SALT=<random>
ANTHROPIC_API_KEY=sk-ant-...
FRONTEND_PORT=3000
BACKEND_PORT=8080
GATEWAY_PUBLIC_URL=https://lc-api.example.com

Generate each random value with openssl rand -base64 32. Notes on the ones that bite:

  • POSTGRES_PASSWORD and MINIO_ROOT_PASSWORD ship as postgres and minioadmin. Neither database port is published to the host, so they are not exposed directly, but any container you later attach to the same network can reach both with the documented default.
  • CREDENTIAL_ENCRYPTION_PASSWORD and CREDENTIAL_ENCRYPTION_SALT are auto-generated when left empty. Set them yourself instead. The credentials your workflows store are encrypted with that pair, so a database dump restored on a new box without the same password and salt gives you credential rows nothing can read. Set them once, then treat docker/.env.ce as part of the backup.
  • FRONTEND_PORT and BACKEND_PORT are substituted into the port mappings as ${FRONTEND_PORT:-3000}:3000 and ${BACKEND_PORT:-8080}:8080. The example env file sets both explicitly, and the values it ships are not always 3000 and 8080. Read your copy rather than assuming.
  • GATEWAY_PUBLIC_URL is the browser-facing origin of the backend. It matters as soon as a reverse proxy is involved. See the next section.
  • The model keys (ANTHROPIC_API_KEY, OPENAI_API_KEY, GOOGLE_API_KEY, and optionally MISTRAL_API_KEY or DEEPSEEK_API_KEY) live here in plain text. Fill in only the provider you actually use.

What the six containers do

  • postgres runs pgvector/pgvector:pg16 as container livecontext-db, holding the database named livecontext. The pgvector extension is there for embedding search, so a plain postgres:16 image will not do.
  • redis runs redis:7-alpine with appendonly yes and --maxmemory-policy noeviction. That policy is deliberate: Redis carries queue and run state here, so when it hits its memory ceiling it returns an error to the writer instead of silently dropping keys. An error you can see beats work that vanishes.
  • minio is the S3-compatible object store for files that move through workflows. A one shot minio-init container runs mc mb myminio/workflow-files --ignore-existing at startup, creates the bucket, and exits. Seeing minio-init as exited (0) in docker compose ps is the healthy state.
  • bridge holds the CLI adapters and the MCP (model context protocol) tools. It listens on 8093 inside the Docker network and is not published to the host.
  • livecontext is the backend, one Java 21 monolith on port 8080. It runs the workflow engine, the schedulers and the agents.
  • frontend is the Next.js web UI on port 3000. Only these last two are published to the host.

State lives in five named volumes: livecontext_data for Postgres, livecontext_redis, livecontext_minio, livecontext_keys, and livecontext_logs. Compose prefixes them with the project name, which defaults to the directory name, so the real volume on disk is called something like livecontext-ce_livecontext_minio. Run docker volume ls and copy the exact names before you write any backup script against them.

docker compose down -v deletes all five volumes. It is the documented way to start over, and it is also the fastest way to lose every workflow you built. The -v is the whole difference.

Put it behind Traefik instead of publishing port 3000

Publishing ports 3000 and 8080 on a public VPS exposes the app with no TLS (transport layer security) and no gate in front of admin registration. A ufw rule is not enough on its own, because Docker inserts its own iptables rules for published ports ahead of the chain ufw manages, so a port published to 0.0.0.0 stays reachable even when ufw says the port is denied.

The clean fix is to publish nothing and let the proxy reach the containers over a shared Docker network. Create docker-compose.override.yml in the repo root:

services:
  frontend:
    ports: !override []
    networks:
      - default
      - proxy
  livecontext:
    ports: !override []
    networks:
      - default
      - proxy

networks:
  proxy:
    external: true

Two details decide whether this works. !override replaces the ports list instead of merging with it, which needs Compose v2.24 or newer: check with docker compose version, because on an older Compose the two lists merge and the ports stay published. And default has to stay in each networks list, because naming any network replaces the default one, so leaving it out cuts the frontend off from Postgres and Redis. Confirm the merged result before starting anything:

docker compose --env-file docker/.env.ce config

The routers, the certificate resolver and the HTTP to HTTPS redirect are the same as for any other app, so follow our Traefik reverse proxy guide for running multiple apps on one VPS rather than writing new TLS config here. Route one hostname to frontend on port 3000 and a second to livecontext on port 8080.

The second hostname is not optional. The web UI calls the backend from the browser, so the backend needs its own origin that a browser can reach. Set GATEWAY_PUBLIC_URL in docker/.env.ce to that backend URL, for example https://lc-api.example.com. Skip it and the page loads normally while every action fails, because the UI resolved the backend origin from the address you opened it with and is calling a port your proxy never published.

Where the model key goes, and why an idle instance still costs money

Agents run inside the automation here, which changes the economics compared with a plain workflow tool. The provider key sits in docker/.env.ce as ANTHROPIC_API_KEY or OPENAI_API_KEY, is read by the backend and the bridge at startup, and applies to the whole instance. It is not scoped per user. Anyone who holds an account on your instance and can build an agent is spending that key, and the first person to register is an admin.

Three habits keep the bill predictable. Create a separate provider key for this VPS so you can revoke it without touching anything else. Set a hard spend cap in the provider console, because that limit is the only one outside the machine you are securing. Then use the per-agent credit budgets and per-agent metrics that LiveContext exposes, so a single loop cannot drain the key before you notice.

Idle cost is not zero once an agent sits on a schedule. A schedule trigger fires whether or not anyone is watching, and every firing sends tokens. A five minute schedule is 288 runs a day, and an agent that reads a page and decides to do nothing still pays for reading the page. Put your first agents on a webhook or a chat trigger, watch the real spend for a week, and move to a schedule after you know the per-run cost.

Back up Postgres and the object store

There are two data stores plus one secret, and losing any of the three loses your instance. Take the database and the bucket in the same window, with the backend stopped, so a file cannot be written after its database row was dumped.

cd ~/livecontext-ce
mkdir -p ~/backups
docker compose --env-file docker/.env.ce stop livecontext frontend
docker compose --env-file docker/.env.ce exec -T postgres \
  pg_dump -U postgres -d livecontext --clean --if-exists \
  | gzip > ~/backups/livecontext-db-$(date +%F).sql.gz

Use whatever you set as DB_USERNAME in place of postgres if you changed it. Then copy the object store volume, using the prefixed name that docker volume ls printed:

docker run --rm \
  -v livecontext-ce_livecontext_minio:/data \
  -v ~/backups:/backup \
  alpine tar czf /backup/livecontext-minio-$(date +%F).tgz -C /data .
docker compose --env-file docker/.env.ce start livecontext frontend
cp docker/.env.ce ~/backups/env.ce.$(date +%F)

Check the dump is not empty before you trust it: gunzip -c ~/backups/livecontext-db-*.sql.gz | head -20 should show CREATE TABLE and DROP TABLE statements, not a one line error. Then copy all three files off the server. A backup that lives only on the machine it protects is not a backup.

To restore onto a fresh box, install the same tag, put the saved docker/.env.ce back so the credential encryption password and salt match, start the stack once so the volumes exist, stop the backend, then load the dump:

gunzip -c livecontext-db-2026-08-10.sql.gz \
  | docker compose --env-file docker/.env.ce exec -T postgres psql -U postgres -d livecontext

Upgrades, and getting back when one goes wrong

Take a dump first, every time. The backend applies its schema migrations on startup and migrations only move forward, so checking out the older tag after a bad upgrade leaves old code running against a newer schema. Rollback means restoring the dump, which is why the dump comes first.

cd ~/livecontext-ce
git fetch --tags
git tag --list 'v*' | tail -5
TAG=v0.2.11
git checkout "$TAG"
docker compose --env-file docker/.env.ce pull
docker compose --env-file docker/.env.ce up -d
docker compose --env-file docker/.env.ce logs -f livecontext

Set TAG to the tag you picked from the listing that the third command printed. Watch the backend log until the health endpoint answers again. Your docker-compose.override.yml is untracked, so a git checkout leaves it in place, but read the diff on docker-compose.yml between tags, because a new service or a renamed one can make your override stale without any error message.

Failure modes, with the strings you will see

A container keeps restarting and docker compose ps shows exited (137). That is the kernel out-of-memory killer, and docker inspect livecontext-app confirms it with "OOMKilled": true in the state block. The backend hit its 1536M limit, or the host ran out of memory first. Check free -m before raising any limit, because raising a container limit on a host with nothing spare just moves the kill to a different container.

The pull fails with no matching manifest for linux/arm64/v8 in the manifest list entries. The images are published for linux/amd64 only. An Arm VPS cannot run this stack from the published images, and emulation through QEMU is far too slow for a JVM plus Chromium. Move to an x86 plan.

Bind for 0.0.0.0:3000 failed: port is already allocated. Something else on the host already holds that port. Change FRONTEND_PORT in docker/.env.ce, or apply the override above and publish nothing at all.

The UI is up but the login request fails after you add the proxy. The browser is calling the backend on an origin your proxy does not serve. Open the browser network tab and look at the failing request host. Set GATEWAY_PUBLIC_URL to the public backend URL and recreate the frontend container, because that value is read at startup.

Everything is healthy but files uploaded in a workflow vanish. Check that minio-init shows exited (0) rather than a non-zero code. If the bucket workflow-files was never created, the backend has nowhere to put objects.

Choose LiveContext or n8n

Pick LiveContext when the agent is the point: you want the model to build and run the automation, and you accept an 8 GB box and a Java service as the price. Pick n8n when you want deterministic workflows, a large node library and a footprint that shares a VPS with other services. The version numbers here are young, v0.2.11 as of August 2026, so pin your tag and read the release notes before every upgrade. For the wider field, including the tools that sit between these two positions, see our roundup of self-hosted n8n alternatives rather than reading a comparison of only these two.

FAQ

How much RAM does a self-hosted LiveContext need?

Plan for 8 GB. The upstream README lists 4 GB as the minimum and 8 GB as the recommendation, and the shipped compose file matches that: the backend alone is capped at 1536 MB, and the five base services together come to a little under 3 GB before the unlimited frontend container. Enabling the browser agent profile adds another 2048 MB for Chromium plus a SearXNG container, so 8 GB stops being optional at that point.

Can I run LiveContext on an Arm VPS?

No. Every published image is built for linux/amd64, so docker compose up on an Arm plan fails at the pull with no matching manifest for linux/arm64/v8 in the manifest list entries. Running it under QEMU emulation is possible in theory and unusable in practice for a JVM workload. Choose an x86 plan.

Where do I put my model API key?

In docker/.env.ce, as ANTHROPIC_API_KEY, OPENAI_API_KEY or GOOGLE_API_KEY, before the first start. The backend and the bridge read it at startup, and it applies to the whole instance rather than to one user. Keep the file at mode 600, use a key created only for this server so you can revoke it on its own, and set a spend cap in the provider console, because that cap is the only limit that lives outside the machine.

How do I back up LiveContext?

Three things: a pg_dump of the livecontext database, a copy of the MinIO volume, and the docker/.env.ce file. Stop the livecontext and frontend services while you take the first two so the database and the object store agree with each other. The env file matters because the credentials stored in your workflows are encrypted with CREDENTIAL_ENCRYPTION_PASSWORD and CREDENTIAL_ENCRYPTION_SALT, so a restore without those values leaves credential rows that nothing on the new box can read.

Why does the backend sit at health: starting for minutes after boot?

The compose healthcheck sets start_period: 120s and polls /actuator/health, so Docker reports the service as starting while the schema migrations and the tool registration run. Two to three minutes on first boot is expected. If it never turns healthy, read docker compose logs -f livecontext. A stack that stops at the migration step is usually pointed at a database volume from a newer release.