Browser (Monitors)
The DuckDB deployment plus Node, @playwright/test, and headless Chromium baked in, so browser monitors run inside the container with zero extra moving parts (SYNTHETICS_BROWSER_MODE=embedded is set by default). HTTP and TCP checks work in every image; this image exists only for the browser ones.
Pick this when you want Playwright uptime checks with one container. If you already run another image (SQLite, DuckDB, minimal, or all-in-one), you do not need to switch: set SYNTHETICS_BROWSER_MODE=remote there and execute browser checks with the traceway-runner binary instead. Running Traceway as a plain binary with no Docker at all? See Without Docker below.
Operational notes on top of the DuckDB image:
- The image is significantly larger (Chromium and its system libraries add several hundred MB).
- Chromium needs shared memory. Docker's default 64MB
/dev/shmcrashes tabs on heavier pages; run with--shm-size=1g(the compose file sets it). The backend also passes--disable-dev-shm-usageas a fallback. - Leave memory headroom. Each concurrent browser check runs a Chromium instance (roughly 300 to 500MB);
SYNTHETICS_BROWSER_CONCURRENCYdefaults to 2. BudgetDUCKDB_MEMORY_LIMITaccordingly. - Browser checks execute user-authored scripts inside this container, as root with Chromium's sandbox off (the standard containerized-Playwright trade-off). Anyone with write access to a project can author them; if that trust model does not fit, use
remotemode instead. - The bubblewrap sandbox usually cannot start inside Docker. The image ships
bubblewrapandSYNTHETICS_BROWSER_SANDBOX=auto, but creating a user namespace inside a container is the host's decision, not the image's. Measured on Docker with an Ubuntu 24.04 host kernel, it is refused under the default security options, under--security-opt seccomp=unconfined, and under--cap-add SYS_ADMIN. It works only with--privilegedandsysctl -w kernel.apparmor_restrict_unprivileged_userns=0on the host. Expectsandbox: offin the startup log on a normal Docker host, which is the same isolation this image has always had: the container boundary and the env allowlist. Check the log line if you care which one you got. When check authors are not fully trusted,remotemode on a dedicated host is the configuration that actually sandboxes.
Quick Start
docker pull ghcr.io/tracewayapp/traceway:browser
docker run -d --name traceway \
-p 80:80 \
--shm-size=1g \
-v "$(pwd)/traceway-data:/data" \
-e JWT_SECRET="your-jwt-secret-min-32-characters-long" \
-e APP_BASE_URL="https://traceway.example.com" \
-e DUCKDB_MEMORY_LIMIT="2GB" \
ghcr.io/tracewayapp/traceway:browserOr with compose: docker compose -f docker-compose.browser.yml up -d.
After starting, open http://localhost/register to create your first account, then create a monitor under Monitors.
Build from Source
docker build -f Dockerfile.browser -t traceway:browser .The pinned @playwright/test version lives in docker/playwright/package.json; the matching Chromium build is downloaded at image build time, never at runtime.
Without Docker
Embedded mode does not actually require this image. The image is packaging; the real requirements are node on PATH and a harness directory containing @playwright/test plus a downloaded Chromium. If you run the Traceway backend as a plain binary (a single EC2 instance, a bare-metal box), you can enable browser monitors on that same host:
# One-time harness setup (Node 18+ required)
sudo mkdir -p /opt/traceway-playwright && cd /opt/traceway-playwright
npm init -y && npm i @playwright/test
npx playwright install --with-deps chromiumThen add to the backend's environment and restart:
SYNTHETICS_BROWSER_MODE=embedded
SYNTHETICS_PLAYWRIGHT_DIR=/opt/traceway-playwrightThe backend validates the harness at startup and fails fast with a pointer here if node or the Playwright CLI is missing. --with-deps covers apt-based distros; on rpm-based distros (Amazon Linux) install Chromium's shared libraries with your package manager.
Keep in mind what embedded means: browser checks are user-authored scripts executing on the host that runs your backend, and each concurrent Chromium costs roughly 300 to 500MB (SYNTHETICS_BROWSER_CONCURRENCY, default 2). If either bothers you, run the checks somewhere else with a remote runner instead. Both paths work without Docker.
Configuration
Everything from the DuckDB page applies unchanged. On top of that:
| Variable | Default | Description |
|---|---|---|
SYNTHETICS_BROWSER_MODE | embedded (in this image) | off, embedded, or remote. Other images default to off. |
SYNTHETICS_BROWSER_CONCURRENCY | 2 | Concurrent Chromium instances. |
SYNTHETICS_HTTP_CONCURRENCY | 8 | Concurrent http/tcp probes. |
SYNTHETICS_POLL_SECONDS | 15 | Scheduler tick for due checks. |
SYNTHETICS_ALLOW_PRIVATE_TARGETS | true | Set false to refuse checks that resolve to private/LAN addresses (re-checked at connect time). |
SYNTHETICS_SCREENSHOT_RETENTION_DAYS | 30 | Days to keep failure screenshots under /data/storage/synthetics/. 0 disables the cleanup. |
SYNTHETICS_PLAYWRIGHT_DIR | /opt/traceway-playwright | The baked-in Playwright harness; only override for custom builds. |
Access Points
Identical to the DuckDB image. /api/health/deep additionally reports a synthetics block (queue depth, checks down, connected runners); it is gated by the HEALTH_DEEP_TOKEN deploy secret.