Install Ferry
Install the Ferry server and CLI, create your account and connect the CLI to your server.
Ferry is two programs: ferryd, the server, and ferry, the CLI. On a fresh Ubuntu or Debian server, one command installs the two programs and starts the server.
Install with one command
Run this command on the server, as root or with sudo.
curl -fsSL https://github.com/rogerbentcha/ferry/releases/latest/download/install.sh | sudo shThe install script works on Ubuntu 22.04, 24.04 and 26.04, and on Debian 12 and 13, with an x86_64 or an arm64 CPU. If you are root and the server has no sudo, end the command with | sh.
The script does all its checks before the first change. If a check fails, the server stays as it was. If the server has no Docker or no git, the script installs them. Then it puts ferryd and ferry in /usr/local/bin, and creates the user ferry and a systemd unit. systemd starts ferryd now and at each boot.
Create your account. On your computer:
1. Open an SSH tunnel to this server (use the address you connect to):
ssh -N -L 7878:127.0.0.1:7878 [email protected]
2. Open this link in your browser:
http://127.0.0.1:7878/setup?code=5b0e…Do the two steps on your computer. The SSH tunnel brings the dashboard to your machine. Then create your account.
Add your domain and HTTPS
curl -fsSL https://github.com/rogerbentcha/ferry/releases/latest/download/install.sh | sudo sh -s -- --base-domain apps.example.com --acme-email [email protected]| Option | Effect |
|---|---|
--base-domain apps.example.com | The base domain: your apps are at <name>.apps.example.com, on port 80. |
--acme-email [email protected] | HTTPS on port 443, with certificates from Let’s Encrypt. It needs a base domain. |
Without options, your apps are at <name>.localhost:8080. The script writes the settings in /etc/ferry/ferryd.env. After a change in this file, run sudo systemctl restart ferryd. Before you use a domain, point its DNS to the server. See Domains and HTTPS.
Upgrade
Run the same command again. The script installs the latest release and restarts ferryd. It keeps /var/lib/ferry and /etc/ferry/ferryd.env. Thus your apps, your data and your settings stay.
For a server on the internet, do the Production checklist.
| Case | Message |
|---|---|
| Another system, or another CPU | The supported systems |
| Docker older than 27.3 | How to upgrade Docker |
| A bad checksum | The script installed nothing |
If /etc/systemd/system/ferryd.service exists and the script did not write it, the script keeps it. To change the unit of the script, run sudo systemctl edit ferryd. A rerun keeps your changes.
Install on another system
Ferry runs on Linux and macOS. On another system, install the two programs yourself.
What you need
| Tool | Version | Use |
|---|---|---|
| Docker | Engine 27.3 or newer, or Docker Desktop | Runs your apps and the builds |
| git | A recent version | Clones repositories for git deploys |
| Rust | 1.89 or newer (rustup) | Builds ferryd and ferry. Only to build. |
| Node.js | 20.19 or newer, with npm | Builds the dashboard. Only to build. |
ferryd finds the Docker daemon through DOCKER_HOST, or through the file /var/run/docker.sock. The daemon must run on the same machine as ferryd. On macOS, Docker Desktop works with no change. Colima and OrbStack use another Docker context. Give its socket to ferryd before you start it:
export DOCKER_HOST=$(docker context inspect --format '{{.Endpoints.docker.Host}}')Download the programs
On Linux x86_64 or arm64, download the two programs from the latest release. You need no build tools.
archive=ferry-$(uname -m)-unknown-linux-gnu.tar.gz
curl -fsSLO https://github.com/rogerbentcha/ferry/releases/latest/download/$archive
curl -fsSLO https://github.com/rogerbentcha/ferry/releases/latest/download/SHA256SUMS
sha256sum -c --ignore-missing SHA256SUMS
sudo tar -xzf $archive -C /usr/local/bin ferryd ferryThe first line selects the archive of your CPU: uname -m prints x86_64 or aarch64. If the checksum is not correct, do not install the archive. Download it again. The programs need glibc 2.35 or newer: Ubuntu 22.04 or newer, Debian 12 or newer.
Build from source
On macOS, build the two programs from the source.
git clone https://github.com/rogerbentcha/ferry
cd ferry
(cd web && npm ci && npm run build)
cargo build --release
sudo install -m 0755 target/release/ferryd target/release/ferry /usr/local/bin/Build the dashboard first. The Rust build puts web/dist into ferryd. Then cargo makes target/release/ferryd and target/release/ferry. The last command puts them on your PATH.
Start the server
If you used the install script, systemd runs ferryd already. Go to Create your account.
On another install, run ferryd as a user that can use Docker.
ferryd Ferry 0.1.0 is running in the background (pid 48213)
Dashboard + API : http://127.0.0.1:7878
Dashboard (proxy): http://ferry.localhost:8080
Apps : http://<name>.localhost:8080
Docker : 29.2.0 (8 CPUs, 7.7 GiB)
Data : /home/you/ferry-data
Limits : 512 MiB / 1 CPU per container (default), 1024 pids, logs rotated at 10 MiB × 3
Free disk check : deploys need 1 GiB free
Create your account: http://127.0.0.1:7878/setup?code=5b0e…
Logs : ferryd logs -f
Stop : ferryd stopThe server continues to run after you close the terminal. To make sure that it answers, run curl http://127.0.0.1:7878/healthz. It prints ok.
If Docker does not run, or another program uses a port, ferryd prints the error. Then it stops with exit code 1. See Troubleshooting.
Create your account
- Open the
Create your accountlink in a browser. - Enter your email and a password of 8 characters or more. The setup code from the link is in the form already.
- Click Create account.
Ferry creates the account and signs this browser in to the dashboard. This account is the only user of the server. Ferry has no teams and no roles.
If you lost the link, run ferryd status. It prints the link again. With the install script, run sudo ferryd status --data-dir /var/lib/ferry. If you forget the password, run ferryd reset-password on the server.
The account controls the full server
A person who signs in can deploy code and read each environment variable of the server. Do not open the API to the internet without HTTPS. See Security.
Set up the CLI
The ferry command sends each of your commands to the API of ferryd. It works on the server, on your laptop or in a CI job.
Install the CLI
The install script, the release archive and the build all give you ferry. It is one binary with no dependencies. To control Ferry from another machine, copy ferry to that machine, for example to /usr/local/bin.
ferry --versionLog in
ferry login --server http://127.0.0.1:7878To connect this terminal, open this page and sign in:
http://127.0.0.1:7878/cli-login?id=d54ce0ee…
Approve the request there if it shows this code: MRDB-M7EE
Waiting for the approval... (Ctrl-C to cancel)The command opens the page in your browser. On a machine with no browser, add --no-browser and open the URL yourself. Sign in, and compare the code with the code in your terminal. Then click Approve.
Logged in to http://127.0.0.1:7878 (Ferry 0.1.0)
Saved to /home/you/.config/ferry/config.jsonThe terminal now has its own API token. A request expires after 10 minutes. To test the connection at a later time, run ferry info.
Reach a remote server
ferryd listens on 127.0.0.1 only. On your laptop, open an SSH tunnel to the server. Then log in to the local address.
ssh -N -L 7878:127.0.0.1:7878 you@your-server &
ferry login --server http://127.0.0.1:7878Log in with a token
If no person can approve the login, give a token. Examples: a CI job, a script, a machine with no browser.
ferry login --server http://127.0.0.1:7878 --token <token>| Token | Where you get it |
|---|---|
| A named API token | The dashboard: Server → Account → API tokens. The dashboard shows it one time. |
| The server token | The file <data-dir>/api_token on the server, for scripts on the server |
A token starts with fy_ and can use the full API. Do not commit a token. Revoke each token that you do not use, in Server → Account.
Where the CLI finds the server
ferry login saves the server URL and the token in the config file ~/.config/ferry/config.json. Only your user can read it (mode 0600). The file keeps one login. A new ferry login replaces it.
Each command uses the first value that it finds:
- The flags
--serverand--token. - The variables
FERRY_SERVERandFERRY_TOKEN. - The config file.
- The default server
http://127.0.0.1:7878, with no token.
The saved token goes only to its own server. For another server, give its token too.
Use the CLI in CI
export FERRY_SERVER=https://ferry.apps.example.com
export FERRY_TOKEN="$FERRY_API_TOKEN" # from your CI secrets
ferry deploy api --follow # exits with 1 if the deploy failsKeep the token in the secrets of your CI, not in the script.
Output and exit codes
| Item | What to know |
|---|---|
| Output | Results go to stdout. Progress, warnings and errors go to stderr. |
--json | Prints the exact JSON answer of the API. A log gives one JSON object on each line. |
--follow, -f | Shows the log until the deploy or the job stops. Ctrl+C stops the follow, not the deploy. |
--yes, -y | ferry delete, db rm, env-group rm, deploy-hook rotate and domains disconnect ask a question first. In a script, they need --yes. |
| Exit codes | 0 success. 1 failure, or a failed deploy with --follow. 2 usage error. 130 Ctrl+C. |
| Quotes | Put a value with a ${{…}} reference in single quotes. If not, your shell changes it. |
The CLI reference has each command and each option.
Ports and URLs
| What | Default address | Flag |
|---|---|---|
| API and dashboard | http://127.0.0.1:7878 | --api-addr |
| Public HTTP proxy, where your apps are | 0.0.0.0:8080 | --proxy-addr |
| Public HTTPS proxy | off | --https-addr with --acme-email |
With the defaults, your apps are at http://<name>.localhost:8080, and the dashboard is also at http://ferry.localhost:8080. Browsers send each *.localhost name to 127.0.0.1. Thus you set up no DNS on your machine.
The API documentation of your server is at http://127.0.0.1:7878/api/docs. Do not open the API to the public. Use an SSH tunnel.
The data directory
The data directory has the full state of the server. Make a backup of it. The default is ./ferry-data, in the folder where you start ferryd. The install script uses /var/lib/ferry.
ferryd --data-dir /var/lib/ferryFERRY_DATA_DIR does the same. The data of a datastore is in a Docker volume, not in this folder.
| Path | Contents |
|---|---|
ferry.db | The database: services, deploys, variables, datastores, the account and its tokens |
api_token | The server token (mode 0600) |
setup_code | The code that creates the account, while there is no account |
ferryd.log | The output of a server in the background |
logs/ | Deploy logs and job logs |
certs/ | The TLS certificates |
Run ferryd in the background
From a terminal, ferryd starts the server in the background and gives the terminal back. From other places, it runs in the foreground: systemd, a container, a pipe or a script. A service manager needs ferryd run in its unit file.
| Command | What it does |
|---|---|
ferryd start | Starts the server in the background. It takes the options of ferryd. |
ferryd run | Runs the server in the foreground, with its log in the terminal. |
ferryd status | Tells you if the server runs and where it listens. The exit code is 0 if it runs, and 3 if not. |
ferryd logs | Prints the last 100 lines of the server log. -f continues with the new lines. |
ferryd stop | Stops the server. |
ferryd reset-password | Replaces the password of the account and signs each browser out. |
stop, status, logs and reset-password find the server through its data directory. Run them in the folder where you started ferryd, or give the same --data-dir.
# A server of the install script
sudo ferryd status --data-dir /var/lib/ferryUnder systemd, the log of ferryd goes to the journal. Read it with sudo journalctl -u ferryd -f.
Stop the server
ferryd stop # stop the server
ferryd # start it againFor a server in the foreground, press Ctrl+C. Under systemd, run sudo systemctl stop ferryd.
When ferryd stops, your containers continue to run. But the proxy is a part of ferryd, thus the public URLs do not answer. At the next start, ferryd puts the routes back.
The stop is a graceful shutdown. Open API requests get up to 10 seconds. The engine stops the jobs in progress and records the deploys in progress as interrupted. To stop immediately, run ferryd stop a second time.