Skip to content

Docker Compose

4 min read

deploy/compose/compose.yaml runs Javo on one Docker host. It starts a single-node k3s cluster in a privileged container, then a one-shot installer applies the same Helm chart every other install uses, with the values in deploy/compose/values.yaml.

What you get:

  • Apps served under the web UI’s address: http://localhost:8080/u/<owner>/<app>/.
  • Sharing turned on.
  • Network isolation between apps, enforced by k3s’s built-in NetworkPolicy controller.
  • Home folders on k3s local-path volumes.
  • A local user admin, who is a platform admin.
  • Docker Engine with Compose v2, allowed to run privileged containers (k3s needs it). Tested on Colima (Docker 29, arm64, cgroup v2); cgroup v1 hosts are untested.
  • About 4 GB of free disk for the images, which are stored twice (once in Docker, once in k3s). The k3s node refuses new pods while Docker’s disk has less than 5% free; the installer then stops with DiskPressure.
  • Free host ports: 8080 for the web UI and 6443 for the Kubernetes API (bound to 127.0.0.1 only).
  • On a first start, apps download their packages, so the machine needs internet access (see Environments).

What that means for security:

  • One trust boundary. k3s runs privileged, so an app that escapes its container (a kernel or runtime bug) is root on the Docker host, not just on a node. Apps still run under the restricted pod security (non-root, no capabilities, seccomp), but keep untrusted people off a Compose install, or use the Helm install on a real cluster.
  • route_localnet. The k3s container sets net.ipv4.conf.all.route_localnet=1 so the cluster’s DNS can reach Docker’s resolver at 127.0.0.11. It applies in the k3s container’s network namespace, which is the node every pod runs on. This is the setting behind CVE-2020-8558: with it, packets from pods may reach services the node binds to 127.0.0.1. kube-proxy adds a firewall rule that drops such packets unless they are DNAT replies; do not remove it, and do not bind anything sensitive to loopback inside the k3s container.
  • Plain HTTP on every interface. The web UI is published on 0.0.0.0:${JAVO_PORT} without TLS, so passwords and session cookies cross the network in clear. On anything but your own laptop, put a TLS proxy in front (see Serve it over HTTPS) or publish the port on 127.0.0.1 only.
  • Disk. Homes, the database and its backups share the Docker host’s disk, and local-path does not enforce home sizes; see Storage that ignores sizes.
  1. Get the code.

    Terminal window
    git clone https://github.com/nebari-dev/javo.git
    cd javo/deploy/compose
  2. Build and install. The build profile builds the javo image from the checkout first.

    Terminal window
    docker compose --profile build up -d
  3. Follow the installer. It waits for k3s, copies the image in, installs the chart and creates the admin user. It ends with the URL.

    Terminal window
    docker compose logs -f installer
  4. Read the admin password. It is generated on the first install and never printed in the logs.

    Terminal window
    docker compose exec k3s cat /var/lib/javo-secrets/admin.password
  5. Open http://localhost:8080 and sign in as admin with that password. Next: create a first app.

Set these in your shell or in deploy/compose/.env:

Variable Default What it does
JAVO_PORT 8080 Host port of the web UI.
JAVO_PUBLIC_URL http://localhost:<JAVO_PORT> The URL browsers use. Set it when people reach the machine by another name.
JAVO_API_PORT 6443 Host port of the Kubernetes API, bound to 127.0.0.1.
JAVO_IMAGE_TAG compose Tag of the javo image.
JAVO_IMAGE_REGISTRY empty Empty uses the image built on this host. Set it (for example registry.example.com/javo) to have k3s pull <registry>/javo:<tag> instead, and drop --profile build.

The Compose values are sized for a laptop: Small (0.5 CPU, 1 GiB), Medium (1 CPU, 2 GiB) and Large (2 CPUs, 4 GiB).

Run these from deploy/compose/:

Terminal window
docker compose --profile build down # stop; the cluster, apps and home folders are kept
docker compose up -d # start again with the images already built
docker compose exec k3s kubectl get pods -A

To use kubectl from the host, copy the kubeconfig out. Its server is https://127.0.0.1:6443.

Terminal window
docker compose exec k3s cat /var/lib/javo-kubeconfig/kubeconfig.yaml > kubeconfig
Terminal window
git pull
docker compose --profile build up -d

The installer runs on every up: it copies only changed images into k3s, upgrades the release and keeps the admin user and its password.

Terminal window
docker compose --profile build down -v

The Compose install serves plain HTTP on the published port. To serve it over HTTPS, put a TLS proxy in front, set JAVO_PUBLIC_URL to the https:// address (the session cookie is then marked Secure), and in deploy/compose/values.yaml set the proxy’s address in gateway.trustedProxies.