Documentation
API reference

Start here

Search every guideesc close

Install

Run your tofa server

Get your tofa server running in a few minutes on Linux, macOS, Windows, or your NAS.

15 min read

This guide installs the server, which stores your library and streams it to your devices. To watch on a computer, install the separate desktop player or use app.tofa.tv. If someone has shared their server with you, you do not need to install one.

Quick install#

Pick your platform. Every path ends in the same place: tofa running at http://localhost:33333, ready to claim with your account. If you installed on a NAS or another computer, use its network address in place of localhost. After installation, continue with Claim your server and Add your media.

The setup we recommend. One line on any machine with Docker, whether that is a Linux box, a NAS, or Docker Desktop:

curl -fsSL https://get.tofa.tv/docker | sh

It is a short, readable script. Open get.tofa.tv/docker in a browser first if you want to read it before you run it. It writes a compose file for one container that manages everything itself, including its own database, asks where your media lives, starts the server, and points you at the claim page.

Prefer to write the compose file yourself? Set it up by hand below walks through every line.

Set it up by hand#

Prefer to write the files yourself, or want to see what each piece does? The rest of this page is the manual Docker walkthrough. One container runs and manages everything, including its own database and automatic backups, and it takes about ten minutes.

What you need#

  • A computer that stays on: a Linux box, a NAS, a mini PC, or a Mac. It doesn't need to be powerful. On an Unraid server, follow Install on Unraid instead.
  • Docker with the Compose plugin. If you don't have it, install Docker Engine (Linux) or Docker Desktop (Mac, Windows) from docker.com. Compose is included with both.
  • Your media in folders on that machine.
  • A tofa account with a verified email address.

The image runs natively on 64-bit Intel and AMD (x86-64) and on ARM, including Apple Silicon and ARM NAS boxes. Docker pulls the right build automatically.

01Build your compose file#

Make a folder for tofa, answer the questions below, and copy the result into a file named docker-compose.yml in that folder.

Everything here can be changed later, and skipped questions fall back to safe defaults. There are no secrets to set up: on first start tofa generates what it needs, including the key it signs sessions with, and stores it in its own data.

02Start it#

From the folder with your compose file:

docker compose up -d

The first start takes a minute or two while tofa sets up its database. To watch it come up:

docker compose logs -f

Ctrl+C stops the log view, not the server.

03Claim your server#

Open a browser to:

http://localhost:33333

If tofa runs on a different machine (a NAS or a server), use that machine's address on your network instead, for example http://192.168.1.50:33333.

Sign in with the same tofa account you created at app.tofa.tv and follow the steps to claim your server. Once claimed, continue to Add your media.

Claiming from another device#

For security, a brand-new server only accepts a claim from its own local network. Opening it on the same machine (localhost) or by its LAN address (like 192.168.1.50) works out of the box. If the only way you can reach it is by a hostname, a public address, or through a reverse proxy, the claim page will refuse with a security notice.

For those cases the installer prints a one-time claim link that carries a setup token and works from anywhere:

http://your-server:33333/setup?setup_token=…

Lost it, or set the server up by hand? The server prints the same link in its own logs on every start while it is unclaimed:

# Docker
docker compose logs tofa | grep setup_token

# Native (systemd)
journalctl -u tofa | grep setup_token

Open that link from any device and claim as normal. The token stops working the moment the server is claimed.

Choose your own setup token#

If you deploy with a script or playbook, you can pick the token yourself instead of reading it from the logs. Set SETUP_ACCESS_TOKEN in the server's environment, then build the link from it:

environment:
  SETUP_ACCESS_TOKEN: "paste-a-long-random-value-here"
https://tofa.example.com/setup?setup_token=paste-a-long-random-value-here

Anyone holding this token can claim a server that has not been claimed yet, so treat it like a password:

  • Make it long and random. We do not enforce a minimum length, but use at least 32 characters. openssl rand -hex 32 gives you a good one.
  • Stick to letters, digits, - and _. The token travels in a link, and characters such as +, &, #, %, or spaces get changed in transit and stop matching.
  • Surrounding whitespace is ignored. An empty value counts as not set.

When the variable is not set, the server makes a token of its own on first start and keeps it in identity/setup_key.secret inside its data directory, so the link stays the same across restarts.

After the claim, tofa gets its secure certificate automatically so your devices can connect directly. There is nothing to restart.

From here you can manage it at this address or from app.tofa.tv.

04Add your media#

In the web interface, add a library and choose your media folder.

On a native install, select the folder on the server machine where your movies or shows live. On Docker, use the path inside the container: /media, or a subfolder like /media/Movies. If you mapped extra folders in your compose file (say /media/TV or /media/Kids), point each library at the container path you gave it, the right side of the colon. tofa scans, matches, and fills in artwork on its own.

Return to app.tofa.tv. The first-server page checks automatically when you return and while it is open, so your claimed server should appear without refreshing. If you are still waiting, choose I’ve installed it. Check for my server.

Once your server appears, select it. You can also open any tofa app and sign in with the same account. Let the first scan find your titles, then open one and press Play.

Everyday commands#

If you installed with a get.tofa.tv one-liner (native or Docker), you already have the tofa helper on your PATH. It detects how your server is installed and gives you one set of commands everywhere:

Task Command
Update to the latest beta tofa update
Is it running? What version? tofa status
Follow the logs tofa logs
Restart, stop, start tofa restart / tofa stop / tofa start
Print the local address tofa url

If you set Docker up by hand, the compose commands do the same jobs. Run them from the folder with your compose file:

Task Command
See the logs docker compose logs -f
Stop the server docker compose down
Start it again docker compose up -d
Restart it docker compose restart
Update to the latest beta docker compose pull then docker compose up -d

When a new build is out, the Software Update card under Admin, then Settings tells the admin. Linux one-liner, macOS, and Windows installs can apply the update from that card; Docker installs get the matching commands shown instead. Your data and settings survive updates on every platform. The full story, including channels and rollback, is in Keep your server up to date.

Remote access and local playback#

If no direct path is available, apps try the tofa relay. Your server still needs to be running and connected to the internet for remote playback. tofa sets up faster direct paths where it can:

  • At home, devices connect straight to the server over your own network at full quality. On Linux this needs nothing from you. On Docker Desktop tofa can't see your machine's address by itself, so tell it under Settings, then Remote Access, then local network address (the setup wizard's remote access step shows the same control). Prefer keeping it in your compose file? The ADVERTISED_LAN_IP variable from step 1 does the same thing.

  • Away from home, the server asks your router to open a port automatically (Linux setup). If your router doesn't allow that, forward a port yourself and enter it under Settings, then Remote Access. Otherwise the relay covers it.

  • Through a tunnel or your own domain, if you already have one. Add its address under Settings, then Remote Access, then custom access URLs, and apps use it as a direct path. See Use your own tunnel or domain.

Settings, then Remote Access shows which path is active, and has a test button that checks the home-network address from the device you're on. If it reports carrier-grade NAT or double NAT, automatic port mapping may not be enough; Local, direct, or relay covers what helps.

Backups#

tofa backs up its database on a schedule, keeps the recent ones, and verifies each backup can be restored. Backups live in the tofa-data volume. You can see them, take one manually, or restore one under Settings, then Database. Back up your server covers restores, disaster recovery, and what to copy yourself.

Put backups on a second disk

By default, backups sit on the same disk as the database. To survive a disk failure, add TOFA_BACKUP_DIR: /backups under environment: and a line like /mnt/other-disk/tofa-backups:/backups under volumes:. The Database page confirms the new location and can move existing backups over.

Use your own PostgreSQL#

tofa runs its own bundled database, and that is the setup we recommend and support. If you would rather use a PostgreSQL server you already run, see Use your own PostgreSQL for what it needs and how to set it up.

Remove tofa#

Removing the program never touches your media files, and your library database is kept unless you delete it yourself, so a later reinstall picks up right where you left off.

Docker. Run docker compose down in the folder with your compose file, which removes the container and keeps its data. The default compose file stores your database in a named tofa-data volume. If you used a host folder instead, the data stays there. Keep that volume or folder to reuse your library on a later install.

Windows. Uninstall tofa from Settings, then Installed apps, like any other program. The uninstaller asks whether to remove your library data. Keep it to preserve C:\ProgramData\tofa for a later reinstall.

macOS. Quit tofa from the menu bar, then paste these lines into Terminal one at a time. Some may answer "No such process", which is fine.

sudo launchctl bootout system/com.tofa.server
launchctl bootout gui/$(id -u)/com.tofa.server.agent
launchctl bootout gui/$(id -u)/com.tofa.tray
sudo rm -f /Library/LaunchDaemons/com.tofa.server.plist
rm -f ~/Library/LaunchAgents/com.tofa.server.agent.plist ~/Library/LaunchAgents/com.tofa.tray.plist
sudo rm -rf /Applications/tofa.app ~/Library/Logs/tofa

If you installed from the terminal one-liner, two small helpers were added that you can remove the same way:

sudo rm -f /usr/local/bin/tofa /etc/tofa/manage.env

Your library database stays in ~/Library/Application Support/tofa; delete that folder if you don't want to keep it.

Linux package install. Remove the package with your package manager, for example sudo apt remove tofa on Debian and Ubuntu or sudo dnf remove tofa on Fedora. Your library data stays in the tofa data directory.

Linux one-liner install. This installs a systemd service, not a package. Stop and disable it before removing the program:

sudo systemctl disable --now tofa.service
sudo rm -f /etc/systemd/system/tofa.service /usr/local/bin/tofa /etc/tofa/manage.env
sudo rm -rf /opt/tofa
sudo systemctl daemon-reload

Your library data stays in /home/tofa/.tofa, and environment overrides stay in /etc/tofa/tofa.env. Keep both if you plan to reinstall.

If something is off#

  • The page won't load at localhost:33333. Give it another minute on the very first start, and check docker compose logs -f for a line saying it's listening. If Docker is on another machine, use that machine's IP, not localhost.

  • The claim page refuses with a security notice. A new server only accepts a claim from its local network. Reach it by its LAN address (like http://192.168.1.50:33333) from a device on the same network, or use the setup_token link from the installer output or the server logs. See Claiming from another device.

  • Port 33333 is already in use. Move tofa to a free port by setting the environment variable TOFA_PORT, for example TOFA_PORT: 34000 in your compose file's environment: block. The server then listens, advertises, and is reached on that port everywhere, browser and apps alike. A Docker port remap ("34000:33333") also works for the browser, but the server doesn't know about the outside number, so apps are still told to connect on 33333. If you remap instead of setting TOFA_PORT, put the outside port in Settings → Remote Access → Local network address as address:port so apps hear the right one.

  • My media isn't showing up. Every media line is host-path:container-path, with a colon between the two. A line missing the colon (like - /mnt/media or - /mnt/media/TV/) makes Docker create an empty throwaway volume instead of mounting your files, so tofa sees an empty folder. Check that the left side is the real path on your machine, that the folder has files in it, and that every media line keeps its colon. To confirm tofa can see the files, run docker exec tofa ls /media (or docker exec tofa ls /media/TV for a folder you mapped): it should list your shows and movies, not come back empty.

  • Playback at home feels limited or slow. Use the test button under Settings, then Remote Access. If the address isn't reachable, correct the local network address on that same page. It should be your machine's address on your home network, not an address from inside Docker. (ADVERTISED_LAN_IP in your compose file sets the same thing.)

  • The logs warn that /dev/shm is small, or mention could not resize shared memory segment. tofa's database keeps working memory in /dev/shm, and Docker gives containers only 64MB of it unless told otherwise. Compose files from before October 2026 don't set it. If you installed with the one-line Docker installer, run it again from where you first ran it (the folder that holds the tofa folder, not the tofa folder itself, and with the same TOFA_DIR if you set one). For a compose file it wrote, it adds these for you, keeps a copy of your old file, and restarts tofa. Otherwise add these lines under tofa:, next to restart:, then run docker compose up -d:

        shm_size: 512m
        ulimits:
          nofile:
            soft: 65536
            hard: 65536

    shm_size is a ceiling, not memory set aside, and ulimits lets the server keep enough files open on a large library. With docker run, the same settings are --shm-size=512m --ulimit nofile=65536:65536.

Still stuck? Getting help & feedback covers what to send us.