Running a shared server¶
noodlelab serve on your own machine needs no setup: no logins, one local user. This page is for a server other people use.
Which pages may use the server¶
A browser lets any website send requests to a server on your machine, so the server checks where they come from:
Without logins (the default on your own machine), it answers only to this machine’s names:
localhost, a loopback address and the--hostit was started with. With--host 0.0.0.0 --auth noneit also answers to IP addresses, so reach it from other machines ashttp://192.168.1.5:8000, not by a host name. This stops DNS rebinding, where another site points its own name at your machine.Pages from other websites cannot open the editor’s WebSocket or save, run, upload or delete anything: those requests must come from the editor’s own page. On a shared server, the page’s host name must be the one the request was sent to (
Host, orX-Forwarded-Hostfrom a reverse proxy that rewritesHost).
Programs (the CLI, the MCP server, scripts) send no Origin header and are not affected.
Roles and guest links¶
On a shared server (--auth users), each person has one role in each workspace. A workspace is a project, and its managers are the project managers.
Role |
Can |
|---|---|
Viewer |
Open graphs, browse files, and look at runs and reports. |
Runner |
Everything a viewer can, plus run graphs and export them to Python. |
Editor |
Everything a runner can, plus change and save graphs, upload files and copy examples. |
Manager |
Everything an editor can, plus add members, set roles, create guest links, and finalise or delete anyone’s runs. |
Where roles are set:
Admins are managers of every workspace. They set members and roles under Admin → Workspaces → Share….
Managers do the same from the editor, with Share → Workspace members… in the top bar.
Everyone else signed in gets a workspace’s default role. It can be no access, which means the workspace is for members only.
A user who adds their own folder, when allow user workspaces is on, becomes its manager, and nobody else can open it until they share it. The folder may not contain or lie inside another workspace, the server’s home or its scratch, checkpoint and mount folders.
A guest link gives someone without an account view-only or view-and-run access to one workspace. It lasts until it expires (at most 30 days by default) or is revoked. Only a hash of its token is stored, so the link is shown once, when it is made. Guest links can be turned off in Admin → Settings. A calculator link is a guest link for one graph’s calculator (see the editor guide): it can fill in and run that form, and open nothing else.
The server enforces all of these rules. In the editor, viewers and runners get a read-only canvas marked View only or Run only.
Files stay inside the workspace. On a shared server, graphs, previews and the file browser reach only the workspace’s own folder and the mounts an admin configured, for admins too. Absolute paths (/data/run1.csv), ~ and paths that leave the workspace (../other-project) are refused, so one workspace cannot read another’s files or the server’s config.json. To share a folder on the server, add it as a mount (see Remote storage). Servers upgraded from earlier versions: graphs that used absolute paths such as /data/... need them changed to a mount (data://...).
Remote storage¶
Admins can mount S3, Google Cloud Storage, Azure, SFTP or a network share under a
short name that graphs use in file paths (lab-s3://2026/run1.csv), for every
workspace or only some. Remote storage explains how. A folder on the
server itself is a mount too, with the URL local:///data/shared: on a shared
server this is the only way to reach files outside a workspace.
Slurm clusters¶
A shared server can send runs to a Slurm cluster as batch jobs. Turn it on under Admin → Cluster: set the partition, account, time limit and resources, add setup lines such as module load, and press Test connection. People who may run graphs then get a Run on menu next to Run, with the choices On the server and On the cluster.
A cluster run looks the same in the editor: progress, previews and reports show up as usual, with the job state (Slurm job 1234 · pending) until it starts, and Stop cancels the job.
It needs:
the workspaces on a file system shared with the compute nodes;
noodlelab installed where the jobs run;
a server that can run
sbatch, directly or throughssh.
docs/slurm.md explains the setup and what a job looks like.
Runs and memory¶
Each run executes in a process of its own, not in the server’s. When a run needs more memory than there is, it fails on its own: the node that was running shows Ran out of memory in node ‘Load table’ [3]: the run used 3.8 GB, over its limit of 3.6 GB, the run’s record says the same, and the server and everyone else’s runs carry on. (A run in the server’s process could not do this: when memory runs out, the system kills the process that holds it, and with it the server, or the whole container.)
The limit. A run is stopped just before it uses more than
run_memory_mb(Admin → Settings). Left at 0, it is the memory noodlelab may use, its container’s limit or else the machine’s, less 10 % (at least 512 MB) kept for the server. Processes a run starts count towards it. If a run takes memory faster than it is measured (five times a second), the system stops the run’s process instead, never the server’s, and the node says so.The spare process. A process with the node packs already loaded waits for the next run, so runs start as quickly as before. It takes memory while it waits: roughly what the server itself takes with the same packs. When two runs start at the same moment, the second waits a few seconds for a process of its own to load them.
Results between runs. A run’s process ends with the run, so what it computed is kept in its checkpoints (
checkpoints_enabled), not in the server’s memory. Rerunning reads results back from disk, and previews while editing use checkpoints of up to 32 MB. Results that were quick to compute and larger than that are computed again.Turning it off.
isolated_runs(Admin → Settings) off runs graphs in the server’s process again: reruns reuse results from memory, but a run that runs out of memory stops the server.NOODLELAB_ISOLATED_RUNS=0turns it off for the whole server.
Runs from the command line (noodlelab run, verify) and from an agent’s MCP
server already have processes of their own, and are unchanged. The Resources
panel of a run shows its own process (Run process), with the limit.
In Docker, give the container a memory limit (mem_limit in
docker-compose.yml): runs then stop at that limit, less the server’s share,
rather than at the machine’s. As a systemd service, set OOMPolicy=continue in
the unit: by default systemd stops the whole service once the system has killed
any of its processes for memory, a run’s included.
Docker¶
You need Docker and git.
Step 1. Get the code.
git clone https://github.com/nkalis/noodlelab.git
cd noodlelab
Step 2. Make an admin token (your admin password).
echo "NOODLELAB_ADMIN_TOKEN=$(openssl rand -hex 32)" > .env
Step 3. Start it. This runs the released image; add --build to build it from the code
instead.
docker compose up -d
Step 4. Open http://localhost:8000 and sign in with the token from .env (cat .env shows it). Create a token for each person under Admin → Users.
Later¶
Update: from the editor (see Updates), or
docker compose pull && docker compose up -dStop:
docker compose down(your data stays in thenoodlelab-datavolume)Logs:
docker compose logs -f
Options¶
None of these is needed for the steps above.
Another port: add
NOODLELAB_HOST_PORT=8080to.env.Existing project folders: uncomment the
/srv/projectsvolume line indocker-compose.yml, then add the folder as a workspace at/admin.The real version number in provenance records: start with
make docker-upinstead of step 3 (needs make and uv). Otherwise the build reports 0.0.0.The image includes Claude Code for the Agent panel (see below).
A public demo: set
NOODLELAB_DEMO=1for guests only, one run at a time and a 25 MB file limit.render.yamldeploys it on Render’s free plan.
Updates¶
noodlelab looks for new versions of itself and of its official plugins on PyPI once a day
(Admin → Settings: check_for_updates, update_check_hours, update_prereleases). When
there are some, the plugin light in an admin’s editor turns amber. File → Check for updates…
(or Admin → System) shows what is new, with a link to the release notes, and a preview of
every package the update would change. Update installs it and restarts the server once no
runs are active; every open editor reloads into the new version by itself, and unsaved changes
are kept as drafts. auto_update installs updates without asking: official plugins only, or
noodlelab too.
How it installs depends on how noodlelab runs; the dialog says which:
A virtualenv or a
uv toolinstall: the update goes into that environment, and the server restarts into it. History → Roll back puts the previous versions back. The same from a terminal:noodlelab update.Docker: an update is a new image. noodlelab pulls
ghcr.io/nkalis/noodlelab:<version>-<tier>, then a short-lived helper container replaces this one: same name, volumes, ports, networks and settings, on the new image. If the new container does not report healthy within three minutes, the old one is started again and the editor says why. Plugins you installed are installed again from the lockfile when the new container starts.This needs the Docker socket, and the socket gives the container control of Docker on the host, as root would have. So it is off until you turn it on, in
docker-compose.yml: mount/var/run/docker.sock, setNOODLELAB_DOCKER_UPDATES: "1", and add the socket’s group (stat -c %g /var/run/docker.sock) undergroup_add. Without it, the dialog shows the commands to run instead. An image you built yourself (docker compose up --build) is updated by building it again.uvx, a source checkout, or an environment noodlelab cannot write to: the dialog shows the command to run.
The Agent panel on a shared server¶
The Agent panel runs Claude Code or Codex CLI as the server’s user, so it is offered to admins only when logins are on, never on a demo server (NOODLELAB_DEMO=1), and only while Admin → Settings → agent terminal is on. Each agent session gets an API token of its own, revoked when the session ends.