Installation
This guide walks you through setting up a CoderFlow server. Before exposing the server to a network you do not fully trust, review Security & Hardening.
Install with the installer
The installer sets up CoderFlow Full on your own Linux server. It creates a separate account to install and run the server.
Supported systems are Ubuntu 22.04 or 24.04 LTS and Debian 12 or 13, on x86-64 or arm64, with systemd and cgroup v2. Install Docker Engine first. Use an ordinary account with sudo permission and access to the local Docker socket.
-
Download the installer as an ordinary Linux user.
curl --fail --location --proto '=https' --proto-redir '=https' -o install.sh https://coderflow.ai/install.sh -
Read the script and check your host.
--preflight-onlychecks prerequisites without changing the host or invoking sudo.less install.shbash install.sh --preflight-only -
Run the installer. Review the plan and confirm when prompted.
bash install.sh -
The output prints the server address and Machine ID. Decline the offer to create an administrator in the terminal to receive a one-time setup link. Open that link, create the administrator, and install your license on the License page that follows. The link works on an unlicensed server. Once the key is accepted, the page says Restart the server to finish applying the license. Run
sudo systemctl restart coderflow.serviceon the host, refresh the page, then open the dashboard for the Setup guide. The installer's last note names the same command. See Restart after the first license for--no-systemdand other hosts. If you created the administrator in the terminal instead, sign in with that account and follow the same license steps.
Standalone mode needs Python 3, curl and the other distribution tools listed by preflight. It downloads the server archive as your operator account and verifies npm's SHA-512 integrity value. It keeps temporary files private and removes them on exit. The checks may download these temporary files, but install no software.
:::note Package registry
The current installer downloads CoderFlow from registry.npmjs.org, which stops
at 0.16.0, so --version cannot select a later release. After installing,
upgrade once with the
steps for installer-based servers.
Do not set --registry to npm.profoundlogic.com: it serves only @profoundlogic
packages, and --registry applies to every dependency. See
Profound Logic package registry.
:::
What changes on the host
- A dedicated
coderflowaccount with a home and no password, unless a suitable account already exists. - Membership of the
dockergroup for that account. This grants host-level access. - A
coderflow.serviceunit, enabled for boot and started after setup. - Verified installer copies in a root-owned
/opt/coderflow-installer-…directory. - NVS, Node.js 24, the server package, setup repository and data in the account's
home. The installer also adds
NODE_ENV=productionto its.profile. - Permission for the chosen privileged port, only if you request
--authbind.
The installer does not install Docker or authbind. It does not accept passwords or license keys as arguments. Root never runs code from the account's home.
To read the root helper before allowing any privileged work, run
bash install.sh --print-root-helper. Use bash install.sh --dry-run to see the
commands. After confirmation, the installer stages the files itself and prints
both their SHA-256 hashes and their root-owned directory.
Options
| Option | Purpose |
|---|---|
--user NAME | Dedicated account; default coderflow |
--port NUMBER | Listen port; default 3000 |
--authbind | Allow a port below 512; ports 512–1023 are refused; install authbind first |
--version X.Y.Z | Choose a published version, including a prerelease |
--package /absolute/server.tgz | Use a local server archive |
--registry HTTPS_URL | Use an npm mirror; credentials in the URL are refused |
--setup-path /absolute/repository | Reuse an existing setup repository without modifying it |
--setup-remote=hosted|none | Remote for a new setup repository; the installer defaults to hosted |
--check-host HOST | Add an outbound HTTPS warning check; repeatable |
--help | Print help offline, without downloads or host checks |
--preflight-only | Check prerequisites only |
--print-root-helper | Print the privileged helper for review |
--dry-run | Check prerequisites and print the conditional command plan |
--yes | Skip questions; never create an admin interactively |
--force | Back up and replace a different unit or authbind permission |
--no-systemd | Use daemon startup on a supported systemd host |
--skip-base-image | Skip the installer's explicit base-image build; the server's automatic build is controlled separately below |
Paths must be absolute and contain no spaces, shell characters or .. components.
--yes uses noninteractive sudo. Authorize sudo beforehand if your policy requires
it.
Install a specific version or local package
For a published version, replace X.Y.Z with its version number:
bash install.sh --version X.Y.Z
For a release candidate, copy install.sh and the server archive onto the host:
bash install.sh --package /absolute/server.tgz
There is no unpacking or manual staging step. The installer takes its helpers and the server from the same archive. A registry download is verified against its published integrity value. A local archive is checked for server-package contents and its SHA-256 is printed; verify that digest with the archive's supplier.
The archive is streamed to private staging owned by the dedicated account. It is not downloaded again. Dependencies may still need npm. NVS and Node need GitHub and nodejs.org, and images need Docker Hub. This is not an offline installation.
Run again or resume
Rerun the same command after fixing a reported failure. Completed steps remain
in place. The installer preserves an existing account's identity and setup
repository. Identical staged files and an identical service unit are reused.
A different service unit needs --force and receives a backup.
Partial setup or NVS directories are left for inspection. Base-image failure
warns without undoing installation. To upgrade, select a new version or archive
and restart the service in a maintenance window. Standalone mode resolves
latest on each run; pin a version or keep your archive for an identical rerun.
First admin and the one-time link
Interactive installation offers coder-server create-user --admin. That command
prompts for the password itself. Verify the account as described in the manual
admin instructions below when creating it while the server is running.
If you decline, or use --yes, the installer sends a one-time link directly to
your terminal. It lasts 60 minutes by default. Creating another link cancels the previous
one. An existing user prevents a new first-admin link. See First sign-in for the browser steps.
Without a controlling terminal, the installer creates no link. Sign in as the
dedicated account and run coder-server setup-link in a terminal later. During
installation, the CLI’s localhost fallback, license and failure notes also go
directly to your terminal. They are not copied into installer logs or redirected
output. Do not record the terminal while a real link is displayed.
Logs
Private installer logs are ~/.coderflow-install.*.log in the dedicated account's
home. Their mode is 0600. They contain fixed progress messages and never the setup
link. Command results are shown on screen.
To inspect service diagnostics:
sudo journalctl -u coderflow.service --since today
Noninteractive startup writes a fixed NO SERVER ADMIN reminder, never a setup
link. Preflight reports an inspection it cannot perform as CAN'T TELL. Required
failures and unknowns stop installation. AI-provider connectivity and rotational
storage produce warnings.
Remove the installation
There is no automatic uninstall. Back up the data you need and inspect the unit before removing it:
sudo systemctl disable --now coderflow.service
sudo unlink /etc/systemd/system/coderflow.service
sudo systemctl daemon-reload
Restore a reviewed unit backup if needed. Remove only the authbind permission for the chosen port. Uninstall the npm package as the dedicated account.
If the installer created the account, stop its processes and run
sudo userdel coderflow without -r. This leaves its home for deliberate archival
or removal. Do not delete an account that was reused. Docker, images and server
data need separate retention decisions. Reviewed staging directories under /opt
can be removed after checking their contents and that they are not links.
For manual staging, detailed checks, older-package compatibility and VM acceptance,
read the shipped dist/deploy/install/README.md. Existing installations with direct
TLS or a custom server data directory should use the manual path below.
Prerequisites
The rest of this page is the manual installation path. Run it as the dedicated server account except where a command explicitly needs root.
After preparing the host, install the server and create a setup repository. Then choose either order:
- In the terminal before the first start: install the license
with
coder-server license set, create the administrator withcoder-server create-user --admin, then start the server. - In the browser after the first start: start the server, create the administrator with the one-time link, then install the license on the License page that follows.
A Linux server with the following installed:
- Docker — Install Docker Engine
- Git — Available via your distribution's package manager
Optionally, if you'd like the server to listen on a port below 1024 (such as 443 or 80):
- On Ubuntu and Debian-based distros - Install authbind via APT package manager.
- Other distros - See your distro's documentation for enabling non-root users to bind network services to privileged ports
Root Permissions
Only a few parts of the installation process require root permissions.
Do not use root permissions (i.e. sudo or su) except where specifically instructed.
The server installs and runs as a non-root user.
Create a Dedicated Linux User For Each Installation
Each installation of CoderFlow server should run under a unique and dedicated user account, rather than your personal account or root. This provides better security isolation and makes it easier to manage the service.
Create a dedicated user (we suggest coder, but any name works):
# Create the user with a home directory
sudo useradd -m -s /bin/bash coder
# Set a password (optional, if you need interactive login)
sudo passwd coder
# Add the user to the docker group so it can manage containers
sudo usermod -aG docker coder
If coder conflicts with an existing user on your system, choose a different name — the server works the same regardless of the username.
Optional: If Using Server Listen Port Below 1024
If you'd like to use a server listen port below 1024 (e.g. 443), configure authbind to allow the dedicated CoderFlow user to use the port:
For example, for port 443:
sudo touch /etc/authbind/byport/443
sudo chown coder /etc/authbind/byport/443
sudo chmod 500 /etc/authbind/byport/443
Switch to Dedicated CoderFlow User
Switch to the dedicated user before proceeding with installation:
sudo su - coder
Install Node.js via NVS
Use the installation guide to install Node Version Switcher (NVS) in the dedicated user's home directory. This allows each CoderFlow installation/user to use a separate version of Node.js. If you prefer, you can use nvm instead, but NVS will be used in this documentation.
After installing NVS, exit and restart your shell and then install Node 24:
nvs add node/24
nvs use node/24
nvs link node/24
Keep Node.js and task images patched
Use the latest Node 24.x patch (at least 24.22.1). Patched Node 26.x (at least 26.12.1) is also supported. Node 22 and older, Node 23, and Node 25 are not supported by CoderFlow. Newer majors beyond the known security floors are allowed; keep those lines patched too. These minimums include the October 21, 2026 Node.js security fixes. Continue applying later security updates; these minimums are not a permanent guarantee.
Updating CoderFlow from Admin or npm does not update Node.js. As the dedicated server user, repeat the following when a Node 24 patch is released:
nvs add node/24
nvs use node/24
nvs link node/24
node --version
With nvm instead:
nvm install 24
nvm use 24
nvm alias default 24
node --version
Version managers can keep global npm packages in separate version directories.
If needed, reinstall your approved CoderFlow server version under the new Node
installation. Update any service ExecStart or PATH that points at the old
Node directory, reload the service configuration, and restart CoderFlow using
your existing service manager. Check the running Node version in Server Administration → Health (open the CPU Usage card for
system details) after restart; the shell version alone does not prove the server was
updated. Older or unsupported runtimes produce a startup warning and a visible notice
above the Server Version card on Health, as well as in system details,
but do not prevent the server from starting.
Then rebuild the CoderFlow base image first, followed by environment images,
and recreate task containers from those images. Rebuilding images does not
replace existing containers. Base builds explicitly pull the upstream Node 24
image; if the registry is unreachable, they warn and use a locally cached image
when available. This fallback does not guarantee patched Node. For air-gapped
installs, import an approved patched upstream image before rebuilding and verify
node --version inside newly created task containers. Custom Dockerfile stages
or independently managed images require their own upstream refresh and runtime
verification. --no-cache alone does not pull newer base images.
Setup
Install the Server
CoderFlow packages come from
Profound Logic's package registry,
https://npm.profoundlogic.com/. Point the account's npm at it for the
@profoundlogic scope, then look up the current release:
npm config set @profoundlogic:registry https://npm.profoundlogic.com/
npm view @profoundlogic/coderflow-server dist-tags
Install that version, replacing <version> with the latest value printed
above:
npm install -g @profoundlogic/coderflow-server@<version>
Always name the version. Without the scope line, an unpinned install silently gets 0.16.0, the last version on registry.npmjs.org; see Pin the version.
npm 11 may print install scripts not yet covered by allowScripts for bcrypt,
ssh2, bufferutil and protobufjs, then skip their install scripts. This warning
is expected; prebuilt binaries or JavaScript fallbacks can still work. Confirm
these modules load with coder-server doctor on releases that include it. On an
older package, run this as the dedicated account after installation:
node - "$(npm root -g)/@profoundlogic/coderflow-server/package.json" <<'JS'
const requireServer = require('node:module').createRequire(process.argv[2]);
for (const name of ['bcrypt', 'ssh2', 'bufferutil', 'protobufjs']) requireServer(name);
console.log('Native module entry points load');
JS
Loading does not verify native acceleration. Fix failed dependencies before starting; do not blanket-enable scripts to hide the warning.
Create a Setup Repository
The setup repository contains your environments, task templates, and configuration.
If your organization already has a setup repository, clone it:
git clone https://github.com/your-org/mycompany-coder-setup.git
Otherwise, create a new one:
coder-server init mycompany-coder-setup --setup-remote=hosted
This creates a Git setup repository with an empty environments/ directory.
It creates no environment and sets no default environment. You create the first
one in the setup guide after signing in.
--setup-remote=hosted also creates and links a remote kept in this server's hosted setup storage.
Use --setup-remote=none for a local repository without a remote; none is the
CLI default when the option is omitted. The installer defaults to hosted.
Run hosted initialization before starting the server, as the same dedicated
account and with the same server data directory the service will use.
Then configure the server to locate the setup directory using a command like this, specifying the path to the setup directory:
coder-server config set coder_setup_path mycompany-coder-setup
Install License
On a fresh server, create the administrator first, then install the license or trial key on the License page after sign-in. You can start the server without a license to do this. Administrators can later install or replace a license in Server Administration → License. See License administration for status checks, the Ask navigation handoff and limited-mode recovery. Enter credentials in the panel, never in Ask.
For command-line installation instead:
coder-server license set <your-license-key>
Attaching Data to a Seat
Each running CoderFlow server uses one seat of your floating license while it is active. By default, CoderFlow records its own version against the seat, so support can see which version a server is running. This value appears in the User Data column of the Seat Usage view.
You can attach your own label to a seat — for example, to identify which server or environment it belongs to. Set the CODERFLOW_FLOATING_USER_DATA environment variable before starting the server:
CODERFLOW_FLOATING_USER_DATA="Frankfurt production" coder-server start
Your label is placed first and the CoderFlow version is appended after it. The combined value is limited to 50 characters, so a long label may push the version off the end. The label is purely informational — it has no effect on licensing — and is shown in the Seat Usage view and in the output of coder-server license seats.
Set this variable the same way you set other server environment variables (for example, in a systemd unit, a PM2 ecosystem file, or the CoderFlow user's login profile) so that it is present every time the server starts.
Seat Retention on Shutdown
By default, CoderFlow keeps its seat when the server stops. A persistent server starts and stops routinely, and keeping the seat means it can always start back up — including when the licensing server is temporarily unreachable, because the server also keeps its last signed license locally and starts from that within the grace period. A server that is stopped for good has its seat reclaimed automatically once its license pulse expires, so seats are not held forever.
This differs from products designed to run in short-lived containers, which release their seat on every shutdown. If you run multiple CoderFlow servers from one floating license and want a stopped server to release its seat immediately instead of waiting for the pulse to expire, set CODERFLOW_FREE_SEAT_OSD:
CODERFLOW_FREE_SEAT_OSD=true coder-server start
With this set, a clean shutdown releases the seat right away. Leave it unset (the default) for the persistent-server behavior. The trade-off: retaining seats favors always being able to restart, at the cost of a stopped server continuing to hold its seat until its pulse expires.
Licensing-Server Outages
CoderFlow is built to keep running — and to start — even when it can't reach the licensing server. Each running server holds a short-lived, cryptographically signed "pulse" that it refreshes on a heartbeat; if the licensing server is unreachable, returns an error, or can't confirm the seat, the server keeps running on its last valid pulse until that grace window expires. It does not stop or fail to start just because a heartbeat didn't get a clean answer.
The only thing that stops a licensed server within its grace window is an explicit, signed revocation from the licensing server (for example, a license cancelled for non-payment) — or the license's own term expiring. A misconfigured, incomplete, or impostor licensing server cannot take your servers down: without a valid signed revocation, an error or "not found" response is always treated as a temporary outage, not a revocation.
Create Admin User
For a fresh server with no users, use the one-time browser link. Start the server, then run this in another terminal as the dedicated server account, using its configured data directory:
coder-server setup-link
Open the new link and follow First sign-in.
An interactive coder-server start also prints a link when no users exist.
The setup link works without enabling ordinary one-time login links.
To create the administrator directly in the terminal instead, use:
You'll be prompted to set a password.
On a brand-new install, the first created account is automatically granted Server Admin even without --admin (this policy is enforced in the shared user service, so it applies across CLI/API/OIDC auto-provisioning paths).
The commands that change access (create-user, grant-admin and cleanup-users --apply) write the access files directly and do not coordinate with a running server. If the server changes access at the same moment (an administrator editing users, teams, roles or access in the Web UI, or an SSO login that provisions a user), one change can overwrite the other. Run these commands with the server stopped, or, if it is running, check the result afterwards in Administration → People & Access.
Optional: Configure Server Listen Port, TLS, and HTTP/2
By default the server listens on port 3000. To configure an alternate port (e.g. 443):
coder-server config set server_port 443
To configure a certificate for TLS:
Certificate and key files must be in PEM format.
The certificate file must contain the server certificate followed by any intermediate certificates, in that order. Including the root certificate is optional. With Let's Encrypt and most public CAs, use fullchain.pem.
File paths can be given as absolute or relative.
Files must be readable by the dedicated CoderFlow user.
coder-server config set ssl_cert_path mycert.pem
coder-server config set ssl_key_path mykey.pem
A CA certificate bundle (PEM format) can also be configured if your setup requires one:
coder-server config set ssl_ca_path myca.pem
Run coder-server config show to see all configuration keys and their current values.
HTTP Protocol Selection
CoderFlow's default http_protocol setting is auto:
- With both
ssl_cert_pathandssl_key_pathconfigured, CoderFlow automatically serves normal browser traffic over HTTP/2. Clients that do not support HTTP/2 fall back to HTTPS/1.1 on the same port, and terminal, code-server, and task-application WebSockets continue to use the HTTP/1.1 Upgrade mechanism on that port. - Without TLS, CoderFlow keeps its existing cleartext HTTP/1.1 listener. This is also the normal private-backend configuration when a reverse proxy owns the public certificate.
- If only the certificate or only the key is configured, startup fails with an actionable error instead of silently choosing another protocol.
No Nginx, load balancer, or other customer-managed process is required for the built-in HTTP/2 path. You can persist a mode explicitly when you need to control a rollout:
# Default: HTTP/2 when TLS is complete; HTTP/1.1 otherwise
coder-server config set http_protocol auto
# Force HTTP/1.1, including on a direct-TLS installation
coder-server config set http_protocol http1
# Require HTTP/2 mode; startup fails unless TLS is configured
coder-server config set http_protocol http2
Restart CoderFlow after changing the protocol setting. Removing the setting restores auto:
coder-server config remove http_protocol
coder-server restart
An existing direct-HTTPS installation with no http_protocol override begins offering HTTP/2
after upgrading to a version with built-in HTTP/2 support. To stage that transport change
separately, set http_protocol to http1 before restarting the upgraded server, then return it to
auto when ready.
When a reverse proxy terminates TLS, do not also configure CoderFlow's certificate and key on the
private backend. Leave the backend on auto (which resolves to HTTP/1.1 without TLS) or explicitly
set http_protocol to http1. Continue to configure trusted proxy headers as described below.
Verify the Active Protocol
A successful built-in HTTP/2 startup reports the resolved mode, its ALPN protocols, and the WebSocket fallback in the server log:
httpProtocol="HTTP/2 with HTTP/1.1 fallback"
alpn=["h2","http/1.1"]
webSockets="HTTP/1.1 Upgrade on the same TLS port"
coder-server status also reports HTTP/2 + HTTP/1.1 fallback. From another machine, use a curl
build with HTTP/2 support to verify what the public endpoint negotiates:
curl --http2 --silent --show-error --output /dev/null \
--write-out 'HTTP %{http_version}, status %{http_code}\n' \
https://coderflow.example.com/health
The expected result is HTTP 2, status 200. You can also open the browser developer tools Network
panel and add the Protocol column; the main document and ordinary page resources should report
h2. WebSocket requests reporting HTTP/1.1 are expected.
If a TLS endpoint unexpectedly reports HTTP/1.1, check coder-server config show, confirm that both
TLS paths are configured and readable, and inspect the startup diagnostics. When a reverse proxy is
in front, verify HTTP/2 at the public proxy endpoint; the private CoderFlow hop should remain
HTTP/1.1.
Set the Public URL
When TLS is enabled, also set the server's public base URL. Include the port unless the server listens on the default HTTPS port (443) — for example, with the default listen port of 3000:
coder-server config set site_url https://coderflow.example.com:3000
Task containers call back into the server — to fetch Git credentials for cloning and to use the
API — using a URL the server hands them at launch. Tasks started from the web UI use the URL from
your browser's address bar, but background tasks (schedules, webhooks, chat triggers) use site_url
or, when it is unset, a callback URL the server recorded from the first admin request it saw — a
value that is written once and never updated automatically. On an installation that previously ran
without TLS, that recorded URL is a plain http:// address, which stops working the moment the
server switches to HTTPS — background tasks then fail to clone repositories or reach the API, with
no obvious error. Setting site_url avoids this.
Note that the callback URL is injected into each task container when it is created. Task containers that already existed before a protocol or hostname change keep their old URL, so those tasks must be relaunched after the change.
site_url is also used to generate password-setup and login links, so it is worth setting on any
installation reached via a hostname rather than an IP address.
If task containers need to reach the server at a different URL than the public one (for example an
internal address), set the CODERFLOW_INTERNAL_URL environment variable for the server process —
it takes precedence over site_url.
The server logs a warning at startup if TLS is enabled but background task containers would be handed a plain-HTTP callback URL.
Optional: One-Time Login Links
One-time login links are disabled by default. To allow administrators to generate them (for example
with the create-login-link command):
coder-server config set login_links_enabled true
The generated links use site_url as their base, so set it first.
Certificate Renewal
Certificate files are read once, at startup. The server does not watch them for changes, so after a certificate is renewed the server must be restarted to load the new files. Plan for this with any ACME automation — for example, a certbot deploy hook:
#!/bin/sh
# /etc/letsencrypt/renewal-hooks/deploy/coderflow.sh
# Copy the renewed files somewhere the dedicated user (here: coder) can read
# them (Let's Encrypt keeps its live directory root-only), then restart.
install -d -o coder -g coder -m 750 /home/coder/certs
install -o coder -g coder -m 640 \
/etc/letsencrypt/live/coderflow.example.com/fullchain.pem \
/etc/letsencrypt/live/coderflow.example.com/privkey.pem \
/home/coder/certs/
su - coder -c "coder-server restart"
Adjust the paths and user name to your installation, and point ssl_cert_path and ssl_key_path
at the copied files. su - coder starts a login shell, so settings persisted in the dedicated
user's profile — such as NODE_ENV=production and the NVS/nvm Node.js setup — are applied to the
restarted server. If you manage the process with PM2, replace the restart line with
su - coder -c "pm2 restart coderflow --update-env".
Optional: Configure Trusted Proxy Headers
If CoderFlow runs behind nginx, Apache, Cloudflare, or another reverse proxy, enable trusted proxy handling before configuring HTTPS-only integrations such as OAuth providers:
coder-server config set trust_proxy true
The same setting is available as an environment variable, which takes precedence over the configuration key when both are set:
TRUST_PROXY=true coder-server start
You can also enable Trust Proxy later from Server Settings -> General Settings and restart the server. This lets CoderFlow read forwarded protocol, host, and client IP headers correctly. See Server Operations & Monitoring for operational notes.
Your proxy must send the standard X-Forwarded-Proto, X-Forwarded-Host, and X-Forwarded-For
headers. If X-Forwarded-Proto is missing, CoderFlow sees plain-HTTP requests and will generate
http:// URLs — including the callback URLs handed to task containers — even though users reach
the proxy over HTTPS.
Optional: Allow Personal AI Endpoints on Private Networks
By default, server-side tests of personal AI-provider accounts and Gemini task preflight only accept public destination addresses. If users connect to an internal enterprise AI gateway, an administrator can enable private destinations in the server process environment:
CODERFLOW_AI_ALLOW_PERSONAL_PRIVATE_ENDPOINTS=true coder-server start
Persist this variable in the server's launch configuration (for example, the dedicated user's profile or your process manager's environment) and restart the server with the updated environment. Use the exact value true; unset or other values leave private destinations disabled. This is a server environment variable, not a coder-server config set key or a task-container environment setting.
The opt-in applies to all personal accounts on the server and allows RFC1918 IPv4 ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) and IPv6 unique-local addresses (fc00::/7). It also covers DNS names resolving to those ranges. Enable it only when personal accounts should be able to contact private services reachable from this server.
Loopback, link-local/metadata, and other special ranges remain blocked for personal endpoints, including IPv4-mapped IPv6 forms. For a loopback AI gateway, configure a server account under Server Settings → AI Providers instead. Server-managed accounts retain their existing local/private reach without this variable.
For both account scopes, provider connection tests, Gemini preflight, and Claude model-context lookups refuse redirects and compressed responses. Use the final API URL and have gateways honor Accept-Encoding: identity. Requests also have response-size and completion-time limits. These rules cover these server-side checks; they do not grant or restrict task-container network access. See private and local custom endpoints.
Optional: Configure Server Log Retention
CoderFlow keeps recent server output in an in-memory buffer and also writes it to daily files under
server-logs/ in the server data directory. The persisted history is what lets the Logs tab in
Server Administration query further back than the buffer holds, and it survives a server restart.
History is kept for 14 days by default. Set SERVER_LOG_RETENTION_DAYS before starting the
server to change the window, or set it to 0 to disable persistence entirely and keep logs in
memory only:
SERVER_LOG_RETENTION_DAYS=30 coder-server start
Files older than the retention window are deleted when the server starts and when logging rolls over to a new day. Set this variable the same way you set other server environment variables, so it is present every time the server starts.
See Server Operations & Monitoring for how the Logs tab queries this history.
Optional: Keep Feedback Reports on This Server
Send Feedback offers Send to Profound Logic, which sends a report
its author has reviewed to coderflow.ai. On a server that must not connect to the internet, set
CODERFLOW_FEEDBACK_URL=off in the server process environment and restart. The dialog then offers
only Download report, for the person to email the report themselves:
CODERFLOW_FEEDBACK_URL=off coder-server start
Ask CoderFlow usage telemetry is off unless an administrator turns it on, and can be sent to your own processing server instead (see Usage telemetry).
Start the Server
For production installations, set NODE_ENV=production. Persist it in the dedicated user's shell
profile so that every way the server gets started — daemon mode, coder-server restart, PM2, and
deploy hooks — inherits it:
echo 'export NODE_ENV=production' >> ~/.profile
source ~/.profile
Then start the server:
coder-server start
NODE_ENV=production is reflected in the environment field of the startup log line (which
otherwise reports development) and enables production safeguards — for example, the server
refuses to start if authentication has been disabled via DISABLE_AUTH.
If using a listen port below 1024 (e.g. 443, 80) and using authbind to allow that, the server must be started like this instead:
authbind --deep coder-server start
Once running, open the first-admin link or sign in with the admin user you created (default port 3000). Follow First sign-in.
First sign-in
The first-admin link works while the server has no users, including before a
license is installed. It is single use and expires after 60 minutes by default.
coder-server setup-link --ttl=120 gives it a different lifetime in minutes;
the accepted range is 5–1440. Issuing another link cancels the previous one.
Use the link straight away, on a machine you trust, because a browser keeps an
opened address in its history; the link stops working once it is used, replaced
or expired.
- Open the link printed in your terminal. If it uses
localhost, open it on the server or replace that host and port with the server's reachable address. Set the public URL for future links. - Enter Username, Full Name, Email, Password and Confirm Password, then choose Create Administrator. The password needs at least eight characters. A field-validation error lets you correct the field and submit again.
- You are signed in automatically unless the server requires MFA or cannot establish the session. In that case, sign in with the account just created and complete the normal MFA enrollment or challenge.
- On an unlicensed server, the License page follows sign-in. Install your
license or trial key there, using the Machine ID printed by the installer
or shown on that page if needed to obtain a trial. Once the key is
accepted, the page says Restart the server to finish applying the
license and how: on a server installed with the installer, run
sudo systemctl restart coderflow.serviceon the host, then refresh the page. See Restart after the first license. - Open the dashboard. The setup guide opens for Server Admins on a server not yet in use.
This link is no longer valid can mean the link is wrong, expired, used or
replaced, or that the server already has a user. Sign in if you already created
the account. Otherwise, run coder-server setup-link again while no users exist.
The page removes the token from its address; if you reload before submitting,
open the original link again. If account creation fails after consuming the
link, the page says so; issue a new link from the terminal.
Links are printed only to an interactive terminal. They are never printed to a
pipe, redirected output, systemd journal or server log. --print-url-only
removes the surrounding link description but still requires a terminal. Do not
record a terminal session displaying a real link.
Under systemd, open a terminal as the service account and run
coder-server setup-link with the same configuration and server data directory
as the service. For the installer's default account, use sudo -iu coderflow
first. In a containerized server installation, open an interactive terminal
inside the server container as its server account, with its existing data
volume and environment. A task container cannot issue this link. Noninteractive
startup prints only a reminder to create an administrator.
The setup-link command exits with 0 when it prints a link, 1 on failure,
2 when users already exist, or 3 when standard output is not a terminal.
Check an installation
Run doctor as the non-root account that runs CoderFlow, with the same setup and server data paths. It works before or after the server starts:
coder-server doctor
coder-server doctor --json
Doctor reads host prerequisites and the same checks as the
Setup page. It changes no
configuration, installs nothing, builds nothing and acquires no license seat.
It checks such things as the runtime, Docker access, storage, the listen port,
outbound HTTPS and native dependency loading. --json prints a structured
report with host.checks and setup.rows for automation.
| Exit code | Meaning |
|---|---|
0 | The report contains no required Action needed item. Warnings and unknown checks can still remain. |
1 | At least one required item needs action. |
2 | Doctor could not run, for example because of the wrong account, unreadable configuration, invalid arguments or a whole-run timeout. |
Can't tell means an inspection could not determine the answer. It does not mean a prerequisite is absent or healthy. Read the explanation and suggested next step even when the exit code is 0. Doctor cannot certify a real task's build, tests or application from configuration alone.
Set Up Git Providers
Connect code in the setup guide, or follow Git Providers.
Configure Your Environment
A new setup repository has no environment. Use the setup guide to create the first one, or open Environments → Actions → New Environment. Generate from repository proposes a Draft from your code. Review its configuration and Finish setup items, build its image, and set Status to Active when it is ready.
The base image builds automatically
After the first licensed start, CoderFlow starts a background base-image build when it can confirm that the image is missing and no base build is running. An unlicensed start does not use this attempt. An existing image, a build already running, or an unavailable Docker check starts no new build.
The automatic attempt is recorded in the server data directory before it starts. A failed attempt is not retried on every restart. Review the Base image row on Setup and the build output in Build History, then retry manually as shown below. Existing images are not automatically refreshed by this feature.
To disable this first-start build, set the JSON boolean auto_build_base_image
to false in the setup repository's setup.json before starting the server.
Omitting it leaves the feature enabled. The installer's --skip-base-image
option skips its own explicit build command; use the setting to disable the
server's automatic attempt too.
Build Docker Images
Docker images must be built before you can run tasks. There are two ways to build images: through the Web UI or using the CLI.
Build Base Image
If the automatic build has not succeeded, or you need to rebuild later, build the shared base image that environments inherit from.
Web UI:
- Open Environments → Actions → Build Images....
- Select Rebuild base image.
- Review the build options, then choose Build and wait for its result.
CLI:
coder-server build base
The base image bakes in the numeric UID/GID of the dedicated user you created above, so coder-server build base builds the image directly only when it runs as that user — which is the case if you followed Switch to Dedicated CoderFlow User.
Run as any other account (including root), the command instead asks the running server to build, which requires an authenticated session (coder login, or CODER_API_KEY). If you need to trigger a build from a root shell or a provisioning script, switch to the dedicated user with its own environment first:
sudo -iu coder coder-server build base
# or
runuser -l coder -c 'coder-server build base'
Use a login shell (-i / -l) so HOME belongs to the dedicated user; otherwise the command cannot tell which account the server runs as and will fall back to asking the server. The same applies before the server's first start, since the account is identified from the server's data directory — start the server first, as this guide does above.
Build Environment Image
Build your environment's Docker image.
Web UI:
- Navigate to Settings → Environments
- Select your environment, if it's not already selected
- Go to the Build tab
- Click Build Now
CLI:
coder-server build <environment-name>
Replace <environment-name> with the environment you created. Rebuild after changing build settings or scripts.
Set Up LLM Access
Use AI provider in the setup guide, or Server Settings → AI Providers. Choose Add Account, connect a subscription or API key, and select it under Tasks use. See AI Provider Authentication. A server Claude API key separately enables Ask CoderFlow and helper features.
Verify Installation
First, open Administration → Server Administration → Health to check that host metrics load. See Server Operations & Monitoring for details.
Then follow First task to run Get to know this repository, review its build, tests, running app and screenshot, and record a passing named test on the finished task. Check First verified task on Setup for Ready.
Server Management
Running as a Daemon
Use the --daemon flag to run the server in the background:
coder-server start --daemon
Manage the daemon with:
# View logs
coder-server logs
# Stop server
coder-server stop
# Restart
coder-server restart
# Check health
curl http://your-server:3000/health
Using PM2
As an alternative to the built-in daemon mode, you can use PM2 for process management.
PM2 provides additional features like automatic restarts on crash and system boot persistence.
Install PM2 Globally
npm install -g pm2
Start CoderFlow with PM2
If using a listen port below 1024 (e.g. 443, 80) and using authbind to allow that, the server must be started like this:
pm2 start --name coderflow authbind -- --deep coder-server start
Otherwise start like this:
pm2 start --name coderflow coder-server -- start
View Logs
pm2 logs coderflow
Stop/Restart
pm2 stop coderflow
pm2 start coderflow
pm2 restart coderflow
Auto-start On System Boot
Save the PM2 process list to disk:
pm2 save
Generate a PM2 startup script:
pm2 startup
pm2 startup outputs a commmand string to your terminal, which must be run as root, to configure the system's service manager to start up PM2 at system boot.
Rolling Back to an Earlier Version
Ask CoderFlow keeps a record of the changes it proposed and you confirmed, in
the assistant-actions directory of the server data directory. What a
rollback needs depends on the version you go back to. This applies however you
install the earlier version, including from Server Administration (see
Server Updates).
Going back to a version released before this one. An earlier version can read this record only while everything in it is something that version knows. Once this version has run, the record can hold things earlier versions do not know: a saved objective that Ask deleted and, for older versions, also a saved objective that Ask launched or an Ask change from before the upgrade that this version marks as no longer made in Ask. The earlier version then cannot read the record at all. A version that already shows Ask change from another CoderFlow version cards keeps reading it, and shows an Ask change this version no longer makes as an earlier Ask change that cannot be confirmed, in that version's own wording. If this version has ever shown an Ask change from another CoderFlow version card, an earlier version also cannot track the progress of the tasks and deployments Ask started until the directory is moved aside. If you go back without the steps below, Ask still answers questions and looks things up there, but its changes are refused. To roll back safely:
-
Stop the server.
-
In the server data directory (
SERVER_DATA_PATH, by default~/.coder/data), rename theassistant-actionsdirectory out of the way. Do not delete it, and do not edit the files in it:mv ~/.coder/data/assistant-actions ~/.coder/data/assistant-actions.before-rollback -
Start the earlier version. It starts an empty record: earlier Ask cards and Recent actions entries are not shown, and nothing in them is run again.
Going back from a later version to this one, or to any version after it. Keep the assistant-actions directory as it is.
This version reads it, and shows each change the later version made in a way
it does not know as a read-only Ask change from another CoderFlow version
card to the person who made it: it cannot be confirmed or cancelled, and
nothing in it runs. This version keeps those records unchanged, so they show
normally again after you upgrade. If the later version changed the record's
format in a way this version cannot read, Ask's changes are refused as above:
follow the same steps to move the directory aside.
In every case:
- Do not restore a copy of
assistant-actionstaken before the upgrade: changes confirmed since then would show as waiting again and could be confirmed a second time. - Do not edit
state.jsonor the other files in it. - If you moved the directory aside, keep the
assistant-actionsdirectory that is current when you upgrade again: the newer version reads the one the earlier version created. Putting the renamed directory back instead also works, but the Ask cards made on the earlier version in between are then lost.
