Skip to content

Server Setup

Austin Nunn edited this page Nov 10, 2026 · 2 revisions

Server Setup

This page sets up Station Wrapper 43 on tv-server. When you're done, you'll have the dashboard running and Emby or Jellyfin showing your channels as live TV. You'll make the actual channels on the next page, Making Channels.

What you need

  • A Linux PC that is on all the time, with Docker and the Docker Compose plugin. These steps use Ubuntu, but any Linux with Docker works.
  • A regular x86 PC (amd64) or an ARM one (arm64, like a Raspberry Pi 4 or 5). Docker picks the right image on its own. On ARM every stream is encoded by the CPU, so a Pi manages only one or two at once.
  • Your videos, either on this PC or on a NAS share.
  • A few GB of free space on the PC's own disk. Not on a network share. You'll see why below.
  • Emby or Jellyfin, if you want to watch there. It can run on the same PC.

How the videos are laid out

The wrapper doesn't care how your folders are named. These examples use a share with a folder per library:

//192.168.1.10/media
├── tv/          one folder per show, then seasons
├── movies/      one folder (or file) per movie
└── music_videos/

1. Mount your videos (read-only)

Skip this step if the videos are already on this PC.

The server only ever reads your videos. Mounting the share read-only makes sure nothing can change them.

Install the tools for Windows-style (SMB) shares:

sudo apt-get install -y cifs-utils

Save the share's username and password in a file only root can read:

sudo install -m 600 /dev/stdin /root/.smbcredentials <<'EOF'
username=<share user>
password=<share password>
EOF

Make a folder to mount it on, and add a line to /etc/fstab so it mounts at every boot:

sudo mkdir -p /mnt/nas/media
echo '//192.168.1.10/media /mnt/nas/media cifs ro,credentials=/root/.smbcredentials,vers=3.0,uid=1000,gid=1000,iocharset=utf8,_netdev,nofail 0 0' | sudo tee -a /etc/fstab
sudo systemctl daemon-reload
sudo mount /mnt/nas/media
ls /mnt/nas/media

You should see your library folders (tv, movies and so on).

2. Make the install folder

Everything lives in one folder: the compose file, a secrets file, and a data folder.

mkdir -p ~/fieldstation42/data/config ~/fieldstation42/data/catalog
cd ~/fieldstation42

data/ must be on the PC's own disk. It holds a SQLite database and thousands of symlinks. SQLite misbehaves on network shares, and most shares can't store symlinks at all.

3. Write the compose file

Save this as ~/fieldstation42/docker-compose.yml. Change the lines marked CHANGE.

name: fieldstation42

services:
  station-wrapper-43:
    image: ghcr.io/austincnunn/station-wrapper-43
    container_name: station-wrapper-43
    restart: unless-stopped
    ports:
      - "4242:4242"   # FieldStation42's console. It has no login, so keep it off the internet.
      - "5004:5004"   # the dashboard, the player, and the tuner and guide for Emby/Jellyfin
    volumes:
      - ./data/config:/config
      - ./data/catalog:/app/catalog
      - /mnt/nas/media:/mnt/media:ro       # CHANGE: where your videos are on this PC
      - /etc/localtime:/etc/localtime:ro   # use this PC's time zone for the schedule
    tmpfs:
      - /cache:size=6g,mode=1777           # a RAM disk for reading ahead (see PREFETCH below)
    environment:
      # The "pool": one symlink for every video. Only these top-level folders are used.
      SYNC_ENABLED: "1"
      SYNC_INCLUDE: tv,movies,music_videos   # CHANGE: your library folder names
      SYNC_INTERVAL_MINUTES: "60"
      SYNC_FULL_EVERY_HOURS: "24"
      SYNC_REBUILD_HOUR: "4"                 # refresh changed channels around 4 am
      SYNC_REBUILD_WINDOW_HOURS: "2"
      # Genre folders made from .nfo files
      FARM_ENABLED: "1"
      FARM_INTERVAL_MINUTES: "30"
      # Keeps every channel's schedule topped up
      KEEPER_INTERVAL_MINUTES: "30"
      # The dashboard asks for a password (you pick it on the first visit)
      DASHBOARD_LOGIN: "1"
      DASHBOARD_EDIT: "1"
      # Read the next videos from the NAS into RAM, so playback never waits on the network
      PREFETCH: "1"
      PREFETCH_RAM: "1"
      PREFETCH_DIR: /cache
      PREFETCH_MAX_MB: "5400"
      # Show names, descriptions and posters for the guide, from Emby or Jellyfin.
      # Leave the key empty to skip this.
      MEDIA_SERVER_URL: http://192.168.1.20:8096   # CHANGE: your Emby or Jellyfin address
      MEDIA_SERVER_API_KEY: ${MEDIA_SERVER_API_KEY:-}
      MEDIA_SERVER_MEDIA_ROOT: /media             # CHANGE: where Emby/Jellyfin sees the same videos
    logging:
      driver: json-file
      options: { max-size: "20m", max-file: "3" }

A few notes:

  • Inside the container, your videos are always at /mnt/media. Every link the wrapper makes points there. If you add a remote player later, it mounts the share at that same path, so the links work there too.
  • SYNC_INCLUDE lists the top-level folders to use. Folders not listed are ignored by the dashboard's Files page and by "follow" (more on that in Making Channels).
  • MEDIA_SERVER_MEDIA_ROOT is where Emby or Jellyfin sees the share. If Emby's library points at /media/tv/..., put /media. The wrapper uses it to match a video to Emby's info about it.
  • If the PC doesn't have 6 GB of spare RAM, make the /cache size and PREFETCH_MAX_MB smaller, or turn PREFETCH off.

4. Add the Emby or Jellyfin key (optional)

The key lets the guide show real show names, descriptions and posters.

  1. In Emby: Settings → Advanced → API Keys → New API Key. Name it fieldstation42. (In Jellyfin: Dashboard → API Keys.)
  2. Save it in .env next to the compose file, readable only by you:
cd ~/fieldstation42
printf 'MEDIA_SERVER_API_KEY=%s\n' '<paste the key>' > .env
chmod 600 .env

Docker Compose reads .env by itself. Keep this file out of any git repo.

5. Start it

cd ~/fieldstation42
docker compose pull
docker compose up -d
docker logs -f station-wrapper-43

Press Ctrl+C to stop watching the log. The container keeps running.

6. Set the dashboard password

Open http://192.168.1.20:5004 in a browser. The first visit asks you to choose a password. After that, the management pages need it.

7. Wait for the first pool scan

The first time it starts, the wrapper makes one symlink for every video in your SYNC_INCLUDE folders. This is called the pool. With a big library over a network share, it can take a while. The Files page and "follow" need it to finish first.

Watch for it in the log:

docker logs -f station-wrapper-43 2>&1 | grep -i pool

When it's done, the links are in ~/fieldstation42/data/catalog/media-links/.

8. Connect Emby or Jellyfin

The wrapper pretends to be an HDHomeRun TV tuner. Emby and Jellyfin know how to use those.

In Emby, go to Settings → Live TV:

  1. Tuner Devices → Add → HDHomeRun. Address: http://192.168.1.20:5004
  2. TV Guide Data Providers → Add → XMLTV. Address: http://192.168.1.20:5004/xmltv.xml
  3. If it asks you to map channels, the numbers already match. Just save.

Jellyfin is almost the same: Dashboard → Live TV, then add the tuner and the XMLTV guide with the same two addresses.

There are no channels yet. Make some on the next page: Making Channels.

What runs inside the container

You don't need to manage these. It helps to know they exist when you read the log.

Part What it does
FieldStation42 console FieldStation42's own server. It builds channel lists (catalogs) and schedules. Port 4242.
Tuner and dashboard The fake HDHomeRun, the live video for each channel, the XMLTV guide, and the web dashboard. Port 5004.
Sync Keeps the pool of links matching the share, about once an hour. Refreshes the channels that changed once a day, around 4 am.
Follow For every folder you "follow", links new episodes into its channel. Every 30 minutes.
Keeper Adds schedule days so no channel ever runs out. It adds a day each morning.
Farm Makes genre folders from .nfo files. Videos with no .nfo go into Unclassified.
Prefetch Reads the next videos from the NAS into RAM ahead of time.

Your files

~/fieldstation42/
├── docker-compose.yml
├── .env                    the Emby/Jellyfin key (keep it private)
└── data/
    ├── config/             mounted at /config
    │   ├── confs/*.json          one FieldStation42 config per channel
    │   ├── runtime/fs42_fluid.db the schedule and catalog database
    │   ├── tuner/sources.json    the Sources page (live streams)
    │   ├── follows.json          followed folders
    │   ├── settings.json         keeper settings
    │   └── auth.json             the dashboard password (hashed)
    └── catalog/            mounted at /app/catalog
        ├── media-links/          the pool: one link per video
        └── by-genre/<list>/      the link folders your channels play

Updating

cd ~/fieldstation42
docker compose pull
docker compose up -d

Your channels and schedules are in data/, so they survive updates. To keep a safe copy, see Backups.

Clone this wiki locally