Installation Guide
Trailer.dev ships as as pre-built binaries.
- There are binaries available for Linux, Windows and macOS (Darwin) for the server component.
- There are binaries available for Linux and Windows for the agent component.
- There are binaries available for Linux and Windows for the standalone mode.
Trailer.dev binaries are pre-built for arm64 and amd64 architectures.
All pre-built binaries are signed by our minisign key. The public part can be found in our Community repository.
Trailer.dev also ships as an OCI image.
- There images based on an Alpine base image for our standalone, agent and server components.
All official OCI images are signed by cosign and can be verified with our public cosign key found in our Community repository.
Deployment modes
Section titled “Deployment modes”Trailer runs in one of three modes:
- Standalone: server and Docker agent in one process. Easiest single-host setup.
- Server: the API, database, and web UI only. Pair it with one or more remote agents.
- Agent: connects to a server and reconciles workspaces against a container runtime.
The standalone and agent deployments require a Docker unix socket. See the Architecture Overview for how the pieces interact.
Using Docker (recommended)
Section titled “Using Docker (recommended)”The published images are standalone, server, and agent.
-
Pull the standalone image:
Terminal window docker pull ghcr.io/trailer-dev/standalone:latest -
Run it. The agent talks to the host Docker daemon, so mount the socket. Mount a volume for the database so data survives restarts:
Terminal window docker run -d \--name trailer \-p 8090:8090 \-v /var/run/docker.sock:/var/run/docker.sock \-v trailer_data:/trailer_data \ghcr.io/trailer-dev/standalone:latest
The web interface listens on port 8090 by default. Both the host and the port (as well as the app’s public URL) can be configured.
Check the configuration reference for supported configuration keys and their default values.
Using Docker Compose
Section titled “Using Docker Compose”For a persistent setup it is often easier to describe the deployment in a docker-compose.yml file. Pick the tab that matches your deployment mode:
An agent connects to a remote server and manages workspace containers on its host. Point -S at the server URL you control, and give the agent its own name with -D.
services: trailer: image: ghcr.io/trailer-dev/agent:latest container_name: "trailer" restart: unless-stopped command: -S "https://your-domain.example" -D your-agent-name volumes: - /var/run/docker.sock:/var/run/docker.sock - ~/traefik/config:/traefik - ./config.yml:/.config/trailer/config.yml - /etc/machine-id:/etc/machine-idThe server hosts the API, database, and web interface. It does not manage containers, so it needs no Docker socket. Set -S to the address it should bind to.
services: trailer: image: ghcr.io/trailer-dev/server:latest container_name: "trailer" restart: unless-stopped command: -S "http://0.0.0.0:8090" volumes: - /path/to/trailer_data:/trailer_data - ./config.yml:/.config/trailer/config.ymlStandalone runs the server and a built-in agent in one process. Set -S to the local bind address.
services: trailer: image: ghcr.io/trailer-dev/standalone:latest container_name: "trailer" restart: unless-stopped command: -S "http://0.0.0.0:8090" volumes: - /path/to/trailer_data:/trailer_data - ~/traefik/config:/traefik - /var/run/docker.sock:/var/run/docker.sock - ./config.yml:/.config/trailer/config.yml - /etc/machine-id:/etc/machine-idStart the stack with:
docker compose up -dWhat the command does
Section titled “What the command does”command: passes startup flags to the process. -S sets the server address. On a server or standalone process it is the address to bind to: http://0.0.0.0:8090 exposes the web interface on the host’s network interfaces (not only from inside the container) on port 8090. On an agent it is instead the URL of the server to connect to, a domain you control. The agent and standalone modes also take -D to name the agent as it appears in the instance.
What each volume is for
Section titled “What each volume is for”/trailer_data(server and standalone): the persistent data directory. It holds the platform’s database, uploaded files, and other state. Keep this on durable storage so nothing is lost when the container is recreated. Replace/path/to/trailer_datawith a real path on your host./var/run/docker.sock(agent and standalone): the host’s Docker socket. The built-in agent needs it to create and manage workspace containers on the host.config.yml(all modes): the static process configuration file. Mounting your ownconfig.ymllets you set options such as the public URL and directories. See the Configuration Reference for the available keys.machine-id(agent and standalone): a small file that gives the agent a stable identity. It is the standard/etc/machine-idfile used by Linux systems. On a fresh container this identity is generated randomly, so recreating the container would otherwise register a brand-new host and leave the previous one behind. Mounting a persistentmachine-idfile keeps the identity stable, so after a recreation the agent re-registers as the same host instead of appearing as a new one./traefik(agent and standalone): optional. Only include this mount if you run a separate, external Traefik instance and want the platform to share routing configuration with it. If you do not, omit this line entirely.
Running as a non-privileged user
Section titled “Running as a non-privileged user”By default the container runs as root. If you prefer, you can run it as your own user instead. Start the container with your host user id and group id, and add the host’s docker group so the process can still reach the Docker socket.
Runtime:
docker run -it --rm \ -u $(id -u):$(id -g) \ --group-add $(getent group docker | cut -d ':' -f 3) \ -v /var/run/docker.sock:/var/run/docker.sock \ -v ./config:/.config \ -v ./cache:/.cache \ -v ./trailer_data:/trailer_data \ ghcr.io/trailer-dev/standalone:latestCompose:
# Export the docker group id first:# export DOCKER_GROUP_ID=$(getent group docker | cut -d ':' -f 3)services: trailer: image: ghcr.io/trailer-dev/standalone:latest user: "${UID}:${GID}" group_add: - ${DOCKER_GROUP_ID} volumes: - ./trailer_data:/trailer_data - /var/run/docker.sock:/var/run/docker.sock - ./config:/.config - ./cache:/.cacheWhat each part does:
-u $(id -u):$(id -g)(oruser:in Compose) runs the container as your own user id and group id instead of root.- The container still needs the Docker socket to manage workspace containers. The socket is owned by the host’s
dockergroup, so add that group to the container with--group-add(runtime) orgroup_add:(Compose).getent group docker | cut -d ':' -f 3reads the numeric id of that group on your host. - The mounted config, cache, and data directories must be writable by that user id on the host. Create them ahead of time and make sure your user owns them.
Using pre-built binaries
Section titled “Using pre-built binaries”Each release publishes archives for the standalone, server, and agent builds (Linux, macOS, and Windows where applicable; amd64 and arm64).
-
Download the archive for your platform from the GitHub releases page. Archives are named like
trailer-standalone-linux_amd64,trailer-server-..., andtrailer-agent-.... The binary inside is namedtrailer. -
Move it onto your PATH:
Terminal window sudo mv trailer /usr/local/bin/ -
Run it:
Terminal window trailer
Running as a systemd service
Section titled “Running as a systemd service”If you installed the binary (see above), you can run Trailer as a background service managed by systemd. Create a unit file at /etc/systemd/system/trailer.service. Pick the tab that matches your deployment mode:
An agent connects to a remote server. Set -S to a server URL you control, and give the agent its own name with -D.
[Unit]Description=Trailer AgentAfter=network.target
[Service]Type=simpleExecStart=/usr/local/bin/trailer -C /home/youruser/.config/trailer.dev/config.yml -D your-agent-name -S https://your-domain.exampleWorkingDirectory=/tmpRestart=on-failureRestartSec=5User=youruserGroup=youruser
[Install]WantedBy=multi-user.targetThe server hosts the API, database, and web interface. Set -S to the address it should bind to.
[Unit]Description=Trailer ServerAfter=network.target
[Service]Type=simpleExecStart=/usr/local/bin/trailer -C /home/youruser/.config/trailer.dev/config.yml -S http://0.0.0.0:8090WorkingDirectory=/tmpRestart=on-failureRestartSec=5User=youruserGroup=youruser
[Install]WantedBy=multi-user.targetStandalone runs the server and a built-in agent in one process. Set -S to the local bind address, and optionally name the built-in agent with -D.
[Unit]Description=Trailer StandaloneAfter=network.target
[Service]Type=simpleExecStart=/usr/local/bin/trailer -C /home/youruser/.config/trailer.dev/config.yml -D your-agent-name -S http://0.0.0.0:8090WorkingDirectory=/tmpRestart=on-failureRestartSec=5User=youruserGroup=youruser
[Install]WantedBy=multi-user.targetAdjust the example values for your setup:
-Cis the path to the configuration file.-Sis the server URL. For an agent it is the address of the server to connect to, such ashttps://your-domain.example(use a domain you control). For a server or standalone process it is the address to bind to, such ashttp://0.0.0.0:8090.-D(agent and standalone modes) is the agent’s name as it appears in the connected instance. Choose your own name here.UserandGroupshould be your own system user and group.- Replace
/home/youruser/...with the real path to your configuration file.
Then reload systemd, enable the service, and start it:
sudo systemctl daemon-reloadsudo systemctl enable --now trailerConfiguration
Section titled “Configuration”Runtime config is read from ~/.config/trailer.dev/config.yml (XDG config home). The file is created with defaults on first run if it does not exist. Every value can be overridden by a CLI flag or environment variable.
Common options (see trailer --help):
--server-url(defaulthttp://localhost:8090): address the server listens on, and the address the agent connects to.--deployment-name: name shown for this agent in the connected instance (defaults to the hostname).--data-directory(defaulttrailer_data): directory for the database.--build-directory(default/tmp): where the agent builds images.
For the complete list, see the Configuration Reference.
Verify the install
Section titled “Verify the install”-
Check the container is running:
Terminal window docker ps | grep trailer -
Inspect the logs:
Terminal window docker logs trailer -
Open http://localhost:8090 in a browser. A fresh instance redirects you to the first user setup page.