# Run your own Hearth server

This is the first public-server foundation, built from source. It is **not a
published Docker image or a Windows server installer yet**. The desktop Shell
installer remains a client; it does not install the server.

## Docker

With a source checkout of Hearth, open its `distribution/` directory. Copy `.env.example` to `.env`, choose your host library and
download folders, then run:

```sh
docker compose up -d --build
```

Open `http://localhost:8770`, create your owner password, and open **Systems →
Server setup**. Start with **Setup checks**, then use Libraries, Connections,
Source logins, Schedules and Appearance. Checks exercise the configured media,
browser and gaming-host connections and identify unavailable game folders. They
do not sign in to sources or start downloads. An unconfigured optional service
does not prevent the rest of Hearth from working.
The initial bind is loopback. Set `HEARTH_BIND` deliberately for LAN access after
setting the owner password. Only the web service should be exposed; the media
API is an internal service that can write files and holds service credentials.

- **Libraries:** mount a host folder at `/libraries` in both services. Register
  paths such as `/libraries/games` or `/libraries/films`. A selected game
  destination receives new URL, upload and torrent imports. Existing-game
  updates stay in the original game folder. Scan a registered game folder to
  index builds already on disk; repeat scans preserve names, covers and history.
- **Media:** new downloads stage in the media data folder, then move into
  `<destination>/.hearth-library/<library-id>/<item-id>/`. The media data volume
  retains metadata, thumbnails, subtitle tracks and stable references. Changing
  the default does not move existing items. Missing destinations fail without
  deleting staged bytes. Keep staging space available for an import. Existing
  folder removal and bulk relocation are not implemented.
- **Appearance:** rename any Games, Videos or Images split. The default Anime
  label replaces Hentai; existing `hentai` record IDs/classification fields stay
  readable. Labels are shared by the server, not stored independently per PC.

## Bring an existing video collection

In **Systems → Server setup → Libraries**, add a Videos folder visible to the
media service. Choose **Read-only folder** for an archive mounted with `:ro`, or
leave it writable if you also want it to receive new downloads. For that folder,
choose Videos, Anime, Toons or VR, then press **Scan videos**.

Scans run in the background, one video at a time. Progress, failures and Cancel
stay with the folder, including after a page reload. A server restart marks a
running scan interrupted; **Resume scan** safely checks the folder again.
Completed entries remain available. Hidden folders, symlinks, Hearth's data
directory and managed download folders are skipped.

Existing originals remain in place. Hearth reads them for metadata and a poster,
and stores references and previews in its media data volume. It does not remux
the source or change its modification time. Repeat scans add new paths and leave
curated titles, ratings, lane assignments and watch progress alone. The lane
picker affects new entries only; VR starts with the existing 180° side-by-side
default, which you can adjust on the item. Playback still depends on the browser
supporting the original codec. Hover sprites can be generated with the existing
preview backfill control.

Removing a scanned video from Hearth keeps the original and excludes that path
from future scans. Check **Include previously removed videos** to add it again.
An unavailable folder never deletes library entries. Renaming or moving a source
file is currently treated as a new path; automatic rename tracking and scheduled
watching are follow-up work. Back up these folders along with Hearth's data.

## Optional connections

### Login browser and download worker

The optional package supplies two persistent Firefox profiles: one where you
sign in, and a separate worker for browser-assisted downloads. Set a unique
`HEARTH_BROWSER_PASSWORD` in `.env` (an internal desktop access password, separate
from your Hearth owner password), then run from this directory:

```sh
docker compose -f compose.yml -f compose.browser.yml up -d --build
```

Open **Systems → Server setup → Source logins → Open server login browser**.
Sign in to your source there, return to Systems, import its browser login and
test it. The source's own login/MFA/challenge still applies. Your ordinary
device browser and the server browser have separate sessions.

This uses the upstream [LinuxServer Firefox image](https://docs.linuxserver.io/images/docker-firefox/)
with a Hearth profile initializer, download settings, a supervised restart loop
and the existing BiDi bridge. No Firefox ports are published to the host. The
desktop is reached through Hearth's authenticated browser proxy; debugging stays
on the Docker network. Login, worker and shared-download named volumes belong
to this Compose project. Keep its project name stable across upgrades, back up
the volumes with your data, and avoid `down -v` when preserving an installation.

The package wires Connections automatically, so those fields appear managed by
the environment. Containers share the download volume at `/downloads` in
Firefox and `/data/browser-dl` in the web service. It also carries browser
recovery signals. No host-specific paths, old profile copy or manual `docker
exec` setup is needed. Allow roughly 1 GB of shared memory per browser; actual
memory use depends on open tabs and downloads.

Set `HEARTH_FIREFOX_IMAGE` to an upstream tag or digest to pin upgrades. The
default follows upstream `latest`; changing it requires rebuilding this optional
image. Do not replace the entire persisted profile on upgrades. Hearth manages
`user.js` and the desktop launcher; site cookies and other profile data persist.

Firefox's routing is separate from the web and media proxies. To route its
HTTP/HTTPS traffic through Gluetun, set `HEARTH_FIREFOX_PROXY=http://vpn:8888`
and include `--profile vpn` with the same Compose files. This setting is an
HTTP proxy, not a network kill switch. The torrent/VPN overlay can be included
as a third `-f compose.vpn.yml` with the `torrent` and `vpn` profiles.

Use the same file list for later `up`, `stop` and `down` commands. Direct
downloads and manually saved source sessions can work without this package.

### Your existing services

**Steam:** use your own Steam install. Mount its folder read only and enter the
container path in Connections → Steam. Additional roots use semicolons. A Steam
ID and personal Web API key enable owned-game sync. Running Windows games from a
Linux container still needs a gaming host; a library scan is not a Windows runtime.

**BitTorrent:** connect an existing qBittorrent Web UI or start the optional
`torrent` profile: `docker compose --profile torrent up -d`. Its UI is loopback
port 8080. Set your own credentials there, then use `http://qbittorrent:8080` in
Hearth. Saving synchronizes the client connection to the web and media services.
Mount its completed downloads into both services at `/downloads`. qBittorrent
is currently the supported client adapter; other BitTorrent clients are not
claimed compatible. No shared default password is supplied by Hearth.

**VPN:** use your provider's proxy, or enable the optional `vpn` profile and
supply a [custom WireGuard or OpenVPN configuration](https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/custom.md)
under `data/vpn`. Set the web proxy in Systems and `HEARTH_MEDIA_PROXY` for the
media service, then restart the affected services. Web HTTP proxy settings do
not route qBittorrent peer traffic. To put the optional qBittorrent inside
Gluetun's network, use Docker Compose 2.24.4+ and:

```sh
docker compose -f compose.yml -f compose.vpn.yml --profile torrent --profile vpn up -d --build
```

Use `http://vpn:8080` as the qBittorrent URL with that overlay. No VPN account,
provider subscription, key or private fork is bundled.

**Moonlight:** install [Sunshine](https://docs.lizardbyte.dev/projects/sunshine/latest/)
on your gaming PC and [Moonlight](https://moonlight-stream.org/) on the viewing
device. Pair them in Moonlight. Configure your host and Sunshine app in Systems.
Native handoff uses `hearthstream://`; Windows helper setup is in
[`tools/hearthstream`](../tools/hearthstream/README.md). With no launch agent,
Hearth opens the configured Sunshine app and you select the game on its desktop.
Automatic per-game launch requires a configured host agent or the existing Beam
installation. The Steam client can be a Sunshine app named Steam. A TCP test
only verifies reachability, not pairing or successful video streaming.

These are user-supplied services. qBittorrent's upstream
[license](https://github.com/qbittorrent/qBittorrent/blob/master/COPYING) allows
redistribution subject to its GPL terms (binary distribution GPLv3+). A public
binary/image release still needs notices, corresponding source compliance and
a complete dependency/artwork license review. Steam is not bundled. Hearth's
own release license has not been selected by this change.

## Native server development / Windows

Install Node.js 22, FFmpeg/ffprobe, and the dependencies in `web/` and `server/`:

```sh
npm install --prefix web
npm install --prefix server
node distribution/start-server.cjs
```

Windows can launch `Start Hearth Server.cmd`. Both processes stop with the
launcher. Files live under `~/.hearth-server`; set `HEARTH_SERVER_HOME` to choose
another location. `HEARTH_PORT` and `HEARTH_MEDIA_PORT` select distinct ports;
`HEARTH_BIND` controls the web interface only. The native media API always binds
to loopback, including when the web interface is available on the LAN.
This is a **source launcher**, not the promised `.exe` server
distribution. yt-dlp/gallery-dl and archive tools are additional prerequisites
for their respective import paths. Packaging them, a service/tray wrapper,
updates, signed artifacts and a fresh-Windows acceptance test remain release work.

## Configuration and backups

**Systems → Server setup → Source logins** connects the accounts used by this
server's background jobs. F95 accepts a username/password or an `xf_user`
session. Patreon uses `session_id`; itch.io uses a signed-in Cookie header.
Both can import sessions from the configured server login browser. The external
login link opens the source on your device; its cookies do not automatically
appear in the server browser. These are administrator-managed server accounts,
not separate accounts for each household member.

Save, then **Test login**. Blank secret fields retain their saved value;
**Disconnect** explicitly removes the saved account without changing the library.
An imported Patreon browser session may refresh from that browser. A manually
pasted session stays selected until you replace it. Login tests never start a
download, and saving a schedule never starts an immediate update sweep.

**Schedules** controls Patreon polling and optional auto-install, and F95/itch
update cadence, check-only versus installation, download limits, archive size
and browser-assisted methods. Existing servers keep their settings. Newly
initialized public servers start with the update sweep disabled and in
check-only mode. Use Systems → Automations for run status and manual checks.

**Connections → Browser automation** accepts existing Firefox WebDriver BiDi
bridges for the login browser, shared browser and background worker. Use private
HTTP origins with explicit ports, such as `http://browser-worker:9223`, and the
Host header accepted by Firefox (usually `127.0.0.1:9222`). Restart Hearth after
changing them, then test. Bring your own running browsers, or use the optional
`compose.browser.yml` package above. A custom deployment needs the same shared
download mount and Firefox preferences; the supplied package configures both.

**Connections → Server services** also accepts the host agent's access token.
Its test makes an authenticated, read-only `game:running` RPC; it does not launch
or stop a game. Restart Hearth after changing the agent URL or token.

`server-settings.json` is versioned and saved atomically with a previous-copy
backup. Environment variables override UI values and appear locked in Systems.
Proxy and host-agent credentials, and source credentials in
`source-accounts.json`, are encrypted using `.server-settings-key`; back up that
key with both files. Existing F95 and Patreon session fields migrate to the
encrypted store at startup and are removed from their active legacy files.
Older backups may still contain the old fields. Existing Steam/torrent
credential storage is still legacy storage; that migration is outstanding.

Back up the web data, media data **and every library destination** together.
References do not replace the bytes. No automatic migration to SQLite or bulk
path rewrite runs on existing installations. The storage dashboard's drive
gauge still describes the primary data volume; per-drive gauges are follow-up
work. The full release plan and outstanding work are in
`docs/going-public.md` in your source checkout.

## Verify a new installation

`npm run test:server` tests a fresh owner setup with no guard key, settings,
source-account encryption and real web/media video ingestion (requires FFmpeg
and both services' npm dependencies). With Docker and a built web image, run
`node distribution/test/browser-smoke.cjs hearth-web`. It builds the browser
package and checks authenticated desktop access, separate profiles, a real
download into shared storage, and session persistence after container recreation.
Its containers, network and volumes are temporary and are removed on exit.
This checks the browser package; it is not a Windows installer acceptance test.

## Finding your way back

[Hearth home](https://hearth.bobbygames.app/) · [Desktop client downloads](https://hearth.bobbygames.app/__hearth-web/shell/download)

This source guide was checked against the server foundation on 29 September 2026.
Hardware requirements depend on your optional services; no minimum RAM or GPU specification has been certified for the public server release. A Linux library server does not supply a Windows game runtime.

## If the first start needs a hand

- Run `docker compose ps` from `distribution/` to see which service needs attention.
- Run `docker compose logs --tail=100 web media` to read recent startup errors. Check the folder mounts and your chosen ports before retrying.
- A folder in Settings must use the path visible inside the container, such as `/libraries/films`, rather than its host path.
- Set your owner password before exposing the web service. Keep the media API private. A LAN address, your own reverse proxy or a private network such as Tailscale can provide access; an outbound commercial VPN does not itself make your server reachable.
- Use the read-only option for an existing video archive. Keep a separate backup of your originals and Hearth data; the folder scanner does not replace a backup.

## Desktop browser routing

The desktop client has a native local browser. It uses a configured reachable proxy where supported, has route exceptions, and can fall back to a direct connection when the proxy is unavailable. Check the route displayed in the app. A VPN subscription is not included.
