Running your own Ferdium server

Ferdium works fine without ever creating an account, which is why people who go looking for the self hosted server usually have a specific reason. Either the service list needs to exist on two machines, or the idea of that list sitting on a project run server is unacceptable for the work being done. Those are different problems, and only one of them is solved by running a server.

The setup itself is not difficult. It is a Node application with a Docker image, a database, and a handful of environment variables. What deserves more thought is the question underneath it, which is whether the thing being synced is worth the machine it will run on for the next several years.

What the server stores, and what it never sees

The Ferdium server is a sync backend for configuration. It holds an account record, the list of services added to the sidebar, the workspaces those services are grouped into, and the per service settings attached to each entry. Order, custom name, custom icon, muted notifications, hibernation exclusion, custom URL. All of that is configuration text.

Login sessions are not part of it. Cookies and site storage live on each machine, inside the profile directory of the app itself. Signing into Gmail inside Ferdium on a desktop does not sign that account in on a laptop, whether the server is self hosted or not. Message content never passes through the server either, because Ferdium is loading each service directly from that service.

This distinction is the single most common source of disappointment with the setup. Someone runs the server expecting a second machine to come up ready to work, then finds a sidebar with the right twenty entries and twenty login screens behind them. The sidebar arrived. The sessions did not, and by design never will.

Chrome frames its own sync around the same boundary in its help documentation.

Use the same bookmarks, passwords, and other settings on all your devices. Source: support.google.com

Settings travel. What Chrome adds beyond that is saved passwords, which is a separate credential store rather than a live session. Ferdium has no equivalent, so the login step on a second machine is manual every time.

The accountless route, which is the real alternative

Ferdium can be used with no account at all, chosen during first run. Configuration is then stored on the machine and nowhere else, and the project documents how to back it up by hand. Users already on a cloud account can back up settings, sign out, and switch to accountless afterwards.

The trade is that recovery becomes a manual habit rather than an automatic one. Nothing warns that the last export is four months old, and the configuration directory is the kind of thing a clean install quietly leaves behind. Anyone choosing this route should export once, put the file where the rest of the important files live, and repeat it after any significant reorganisation of the sidebar.

For a single Mac, this is usually the correct answer. The service list is a file, Time Machine already backs it up, and no additional service needs to stay reachable for the app to start. Self hosting a server to sync one machine to itself adds a dependency without adding a capability.

The accountless route stops making sense at two points. The first is genuinely working across two or more machines where the service list changes often enough that copying a file by hand becomes annoying. The second is a team, where several people should end up with the same set of internal dashboards without each of them adding fifteen custom services from a wiki page.

There is a third reason that gets stated as privacy but is really about control. Some work cannot have a list of internal tool names sitting on infrastructure belonging to someone else, even when that list contains no credentials and no content. The names of internal dashboards can describe a company's structure to anyone reading them. If that is the actual constraint, self hosting is the answer and the convenience question does not enter into it.

What running the server involves

The server is an AdonisJS application published as ferdium-server, with a Docker image and a manual install path. The default port inside the container is 3333. Data goes wherever DATA_DIR points, which is the volume that has to survive every future update.

Choosing the database

SQLite is the default, and it is the right default. MySQL, MariaDB and Postgres are supported through DB_CONNECTION and the matching DB_HOST, DB_PORT, DB_USER, DB_PASSWORD and DB_DATABASE values. For a household or a small team, none of that is required. The data being stored is a few kilobytes of configuration per person, and adding a database container to hold it means two things to back up instead of one.

Closing registration before anyone finds it

A server exposed to the internet with open registration will collect accounts that do not belong to anyone. IS_REGISTRATION_ENABLED turns that off, and the intended order is to enable it, create the accounts that are needed, then disable it and restart. IS_DASHBOARD_ENABLED and IS_CREATION_ENABLED control the web side of the same surface. Password recovery by email needs the SMTP_HOST group filled in, so a server without mail configured is a server where a forgotten password is fixed by editing the database.

The manual path

Cloning the repository, installing dependencies, running node ace migration:run, and starting with npm start is the documented alternative to Docker. It is more visible and more fragile. Node version drift over a year or two is the usual failure, and the container avoids that by pinning it.

Pointing Ferdium at it

The client decides which server to talk to during setup, where a custom server URL can be entered instead of the project's own. APP_URL on the server needs to match the address the client will actually use, including whether it is behind a reverse proxy on HTTPS, because links generated for password recovery are built from it.

There is a migration path in from the older lineage. The server exposes an import route at /import, where signing in with Franz or Ferdi credentials creates a matching user and copies over that account's settings, services and workspaces. CONNECT_WITH_FRANZ governs whether that path is available. For anyone who has been on Franz since before the forks, this is the shortest route to a self hosted list.

After the client is connected, adding a service on one machine appears on the other. Removing one removes it. The failure mode to watch for is running the server on a machine that sleeps, since the client wanting to sync while the server is unreachable is a source of confusing states that resolve on their own once it comes back.

Backups, reachability, and the two year question

The interesting part of self hosting is not the install. It is what the setup looks like after the initial enthusiasm has passed, which is worth deciding on the first day rather than the day something breaks.

What actually has to be backed up

With SQLite, the entire state is the directory that DATA_DIR points to. That directory, copied somewhere else on a schedule, is the whole backup story. Restoring means putting it back and starting the container. Anyone who has moved to Postgres has traded that for a database dump, which is a well understood job but a job nonetheless. This is the concrete reason the default database is the right choice at this scale.

The recipes directory is the second mount worth knowing about. Custom recipes placed there are served to clients, which is useful for a team with internal tools that no public recipe covers. It is also state, so it belongs in the same backup.

Reachability decides how it feels

A server on a machine that sleeps, or behind a home connection with a changing address, produces intermittent sync failures that look like bugs in the client. The behaviour is correct and the diagnosis is slow, because the symptom appears while working and disappears while investigating. If the server is going to run at home, it belongs on something that stays awake, with a fixed way of reaching it.

Putting it behind a reverse proxy with a certificate is the normal arrangement, and APP_URL has to carry the public address rather than the internal one. Getting this wrong is quiet. Sync works, and only the password recovery mail arrives with a link nobody can open.

The version that will not upgrade cleanly

Container images get updated, and a database migration runs when the new image starts. This is the moment a backup matters, which is another argument for the setup being one directory to copy. Skipping many versions at once is the pattern most likely to produce a bad afternoon, so a server that is checked every few months is easier to keep than one that is remembered every second year.

Three routes, side by side

Official server Self hosted server No account
Service list on two machines Yes Yes Manual file copy
Configuration stored on Project infrastructure A machine under control The Mac itself
Logins synced No No No
Something extra to maintain No A container and its backups No
Works when the network is down No, for sync No, for sync Yes
Team members sharing a list Yes Yes No

The row that decides most cases is the last one on maintenance. A container running for one person's convenience is still a container to update, to back up, and to notice when it stops.

The part self hosting does not fix

Running the server changes where the configuration lives. It does not change how the app behaves once it is open, and the friction people attribute to the sync setup usually belongs to the app design instead.

Everything still lives in one window with one sidebar. Twenty services means scanning a list of twenty icons, several times an hour, for the rest of the working day. That scan is not made faster by owning the server that holds the list. Comparisons of how this category divides its work across windows are collected in the comparison with Ferdium, and the layout question of giving each app its own space rather than a sidebar row is covered under Workspaces.

Links arriving from outside still open in the system default browser. macOS holds exactly one default, with no way to say that a link from a work calendar belongs to a work account. Every tool in this category inherits that constraint, and no server setting touches it.

Sessions remain per machine, as covered above. A second Mac needs its own logins regardless.

What to change first

Start by writing down which of the three routes matches the actual problem, because a single machine almost never needs a server. If the answer is genuinely two or more machines, run the container with SQLite, set IS_REGISTRATION_ENABLED off after creating the accounts, and stop there. If the remaining friction turns out to be finding things rather than syncing them, a per app layout such as SpaceDeck is the different shape worth comparing, alongside the features that deal with routing rather than storage.

Frequently asked questions

Does a self hosted Ferdium server sync logins between two Macs?

No. The server stores the account, the service list, the workspaces and per service settings. Cookies and site storage stay on each machine, so signing into a service on one Mac does not sign it in on the other. This is true of the official server as well, and is a property of the design rather than a limitation of self hosting.

Is a server needed to use Ferdium at all?

No. An accountless mode is offered at first run, and every feature of the app works without any server. Configuration is kept on the machine and can be backed up by hand following the project documentation. A server only becomes useful when the same service list has to exist on more than one machine or for more than one person.

Which database should the server use?

SQLite is the default and is sufficient for personal or small team use, because the stored data is a small amount of configuration text. Postgres, MySQL and MariaDB are supported through the DB_CONNECTION group of variables. Choosing one of those adds a second thing to back up and monitor for no gain at this scale.

How is an existing Franz or Ferdi account moved over?

The server exposes an import route at /import where signing in with Franz or Ferdi credentials creates a matching user on the new server and copies that account's settings, services and workspaces. Whether the route is available depends on CONNECT_WITH_FRANZ. Afterwards the client is pointed at the custom server address and the imported list appears.

Back to all posts