Skip to content

Commit d1b0a4a

Browse files
author
Filip Eriksson
committed
update install docs
1 parent 1dd256d commit d1b0a4a

4 files changed

Lines changed: 222 additions & 43 deletions

File tree

‎README.md‎

Lines changed: 180 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,182 @@ catalog data and separate viewing state for each family user.
66

77
## Install
88

9-
The full walkthrough — from an empty machine to a household watching,
10-
downloading to phones, and pairing TVs — is in **[docs/INSTALL.md](docs/INSTALL.md)**.
9+
Two files in a folder, no clone. The server image is pulled from
10+
`ghcr.io/doselibrary/dose`. The full walkthrough, from an empty machine to a
11+
household watching, downloading to phones, and pairing TVs, is in
12+
**[docs/INSTALL.md](docs/INSTALL.md)**.
1113

12-
The short version:
14+
You need Docker with Compose 2.23.1 or newer, your movies and shows in two
15+
folders, and a free [TMDB API read-access token](https://www.themoviedb.org/settings/api)
16+
for artwork and metadata.
1317

14-
1. Copy `.env.example` to `.env`; set `POSTGRES_PASSWORD`, your media paths,
15-
and a TMDB token.
16-
2. Point `dose.local` at this machine (router DNS entry, or a hosts line).
17-
3. `docker compose pull && docker compose up -d` and open `https://dose.local`.
18-
The server image comes from `ghcr.io/doselibrary/dose`, built by GitHub
19-
Actions from the `v2` branch; `compose.build.yaml` builds from source instead.
18+
**1. `.env`** — fill in the password, your media folders, and the token.
19+
Windows paths use forward slashes.
20+
21+
```sh
22+
# Movies and shows, mounted read-only.
23+
DOSE_MOVIES_PATH=D:/Media/Movies
24+
DOSE_SHOWS_PATH=D:/Media/Shows
25+
# Letters, numbers, underscores, and hyphens only.
26+
POSTGRES_PASSWORD=replace-with-a-long-unique-password
27+
# Free TMDB API read-access token (the long v4 one).
28+
TMDB_API_TOKEN=
29+
# Image tag to run: latest, a release like 1.2.3, or sha-<commit>.
30+
DOSE_VERSION=latest
31+
```
32+
33+
**2. `compose.yaml`** — copy as-is. This is the same file the repository ships.
34+
35+
```yaml
36+
# Dose — self-hosted household media server.
37+
#
38+
# Self-contained: this file plus a `.env` next to it is a complete install.
39+
# Nothing else from the repository is needed; the server image is pulled from
40+
# GitHub Container Registry and the proxy config is inlined below.
41+
#
42+
# docker compose pull && docker compose up -d
43+
#
44+
# Needs Docker Compose 2.23.1 or newer (inline `configs: content:`).
45+
46+
services:
47+
dose:
48+
# Published by .github/workflows/docker.yml on every push to v2. Pin a
49+
# release with DOSE_VERSION=1.2.3 in .env; build from source instead with
50+
# compose.build.yaml.
51+
image: ghcr.io/doselibrary/dose:${DOSE_VERSION:-latest}
52+
restart: unless-stopped
53+
depends_on:
54+
postgres:
55+
condition: service_healthy
56+
environment:
57+
NODE_ENV: production
58+
HOST: 0.0.0.0
59+
PORT: 3000
60+
DATABASE_URL: postgresql://${POSTGRES_USER:-dose}:${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env}@postgres:5432/${POSTGRES_DB:-dose}
61+
CONFIG_PATH: /config
62+
TRANSCODE_PATH: /transcode
63+
TMDB_API_TOKEN: ${TMDB_API_TOKEN:-}
64+
# The Caddy proxy in this compose is the only way in; trust its
65+
# X-Forwarded-For so login throttling sees real client addresses.
66+
TRUST_PROXY: "true"
67+
# Transcoding: `auto` tests every GPU encoder at startup and uses the
68+
# fastest that works, `off` forces software, or name one of nvenc / qsv /
69+
# amf / vaapi / videotoolbox. See docs/performance.md for what it is worth
70+
# and why HWACCEL_DECODE is off unless the CPU is slow.
71+
HWACCEL: ${HWACCEL:-auto}
72+
HWACCEL_DECODE: ${HWACCEL_DECODE:-false}
73+
74+
# A GPU has to be handed to the container before any of it applies. NVIDIA
75+
# needs the container toolkit on the host; Intel and AMD need the render
76+
# node. Uncomment the block that matches this machine.
77+
# deploy:
78+
# resources:
79+
# reservations:
80+
# devices:
81+
# - driver: nvidia
82+
# count: 1
83+
# capabilities: [gpu, video]
84+
# devices:
85+
# - /dev/dri:/dev/dri # Intel Quick Sync or AMD VAAPI
86+
87+
# Reached through the proxy; expose a port directly only if you need to
88+
# bypass it (DOSE_PORT=3000 restores the old behaviour).
89+
ports:
90+
- "${DOSE_PORT:-127.0.0.1:3000}:3000"
91+
volumes:
92+
- dose-config:/config
93+
- dose-transcode:/transcode
94+
- ${DOSE_MOVIES_PATH:-./media/movies}:/media/movies:ro
95+
- ${DOSE_SHOWS_PATH:-./media/shows}:/media/shows:ro
96+
healthcheck:
97+
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:3000/api/v1/health"]
98+
interval: 10s
99+
timeout: 3s
100+
retries: 5
101+
start_period: 15s
102+
security_opt:
103+
- no-new-privileges:true
104+
105+
postgres:
106+
image: postgres:17-alpine
107+
restart: unless-stopped
108+
environment:
109+
POSTGRES_DB: ${POSTGRES_DB:-dose}
110+
POSTGRES_USER: ${POSTGRES_USER:-dose}
111+
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env}
112+
volumes:
113+
- dose-postgres:/var/lib/postgresql/data
114+
healthcheck:
115+
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
116+
interval: 5s
117+
timeout: 3s
118+
retries: 10
119+
security_opt:
120+
- no-new-privileges:true
121+
122+
proxy:
123+
image: caddy:2-alpine
124+
restart: unless-stopped
125+
depends_on:
126+
dose:
127+
condition: service_healthy
128+
ports:
129+
- "80:80"
130+
- "443:443"
131+
configs:
132+
- source: caddyfile
133+
target: /etc/caddy/Caddyfile
134+
volumes:
135+
- dose-caddy-data:/data
136+
- dose-caddy-config:/config
137+
security_opt:
138+
- no-new-privileges:true
139+
140+
# Reverse proxy for Dose, serving https://dose.local with a locally generated
141+
# certificate. HTTPS is not cosmetic: installing Dose as an app and holding
142+
# offline downloads both require a secure context on iOS.
143+
#
144+
# Point dose.local at this machine first (router DNS entry, or a hosts line
145+
# on each device). The certificate is Caddy's own local CA: trust it once per
146+
# device or accept the browser warning; a LAN name cannot get a public one.
147+
configs:
148+
caddyfile:
149+
content: |
150+
dose.local {
151+
tls internal
152+
encode gzip
153+
# WebSockets (live catalog updates) are proxied transparently.
154+
reverse_proxy dose:3000 {
155+
# Streaming and downloads move gigabytes; never buffer them.
156+
flush_interval -1
157+
}
158+
}
159+
160+
# Plain HTTP redirects to HTTPS so a typed address still lands somewhere.
161+
http://dose.local {
162+
redir https://dose.local{uri} permanent
163+
}
164+
165+
volumes:
166+
dose-postgres:
167+
dose-config:
168+
dose-transcode:
169+
dose-caddy-data:
170+
dose-caddy-config:
171+
```
172+
173+
**3. Point `dose.local` at this machine** — a DNS entry on your router, or a
174+
hosts-file line on each device.
175+
176+
**4. Start it**
177+
178+
```sh
179+
docker compose pull
180+
docker compose up -d
181+
```
182+
183+
Open `https://dose.local`. The first visit creates the administrator account.
184+
Updating is the same two commands again.
20185

21186
The bundled Caddy proxy serves HTTPS with a local certificate — required for
22187
installing Dose as an app and for offline downloads on iOS. The app container
@@ -28,6 +193,12 @@ Dose configuration, temporary transcodes, and PostgreSQL data use the writable
28193
named volumes `dose-config`, `dose-transcode`, and `dose-postgres`. The Dose
29194
container runs database migrations automatically before starting the server.
30195

196+
To run the code from a checkout instead of the published image:
197+
198+
```sh
199+
docker compose -f compose.yaml -f compose.build.yaml up --build -d
200+
```
201+
31202
## Development
32203

33204
Install Bun 1.3.10, then run:

‎compose.yaml‎

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
# Dose — self-hosted household media server.
2+
#
3+
# Self-contained: this file plus a `.env` next to it is a complete install.
4+
# Nothing else from the repository is needed; the server image is pulled from
5+
# GitHub Container Registry and the proxy config is inlined below.
6+
#
7+
# docker compose pull && docker compose up -d
8+
#
9+
# Needs Docker Compose 2.23.1 or newer (inline `configs: content:`).
10+
111
services:
212
dose:
313
# Published by .github/workflows/docker.yml on every push to v2. Pin a
@@ -83,13 +93,40 @@ services:
8393
ports:
8494
- "80:80"
8595
- "443:443"
96+
configs:
97+
- source: caddyfile
98+
target: /etc/caddy/Caddyfile
8699
volumes:
87-
- ./docker/Caddyfile:/etc/caddy/Caddyfile:ro
88100
- dose-caddy-data:/data
89101
- dose-caddy-config:/config
90102
security_opt:
91103
- no-new-privileges:true
92104

105+
# Reverse proxy for Dose, serving https://dose.local with a locally generated
106+
# certificate. HTTPS is not cosmetic: installing Dose as an app and holding
107+
# offline downloads both require a secure context on iOS.
108+
#
109+
# Point dose.local at this machine first (router DNS entry, or a hosts line
110+
# on each device). The certificate is Caddy's own local CA: trust it once per
111+
# device or accept the browser warning; a LAN name cannot get a public one.
112+
configs:
113+
caddyfile:
114+
content: |
115+
dose.local {
116+
tls internal
117+
encode gzip
118+
# WebSockets (live catalog updates) are proxied transparently.
119+
reverse_proxy dose:3000 {
120+
# Streaming and downloads move gigabytes; never buffer them.
121+
flush_interval -1
122+
}
123+
}
124+
125+
# Plain HTTP redirects to HTTPS so a typed address still lands somewhere.
126+
http://dose.local {
127+
redir https://dose.local{uri} permanent
128+
}
129+
93130
volumes:
94131
dose-postgres:
95132
dose-config:

‎docker/Caddyfile‎

Lines changed: 0 additions & 30 deletions
This file was deleted.

‎docs/INSTALL.md‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ devices. Every step is here in order; skim the headings if you only need one.
1919

2020
## 1. Configure
2121

22-
```sh
23-
cp .env.example .env
24-
```
22+
No clone needed. Make a folder for Dose and put two files in it, both
23+
copied from the [README](../README.md#install): `compose.yaml` as-is, and
24+
`.env` with your values. (In a checkout, `cp .env.example .env` gives the
25+
same starting point.)
2526

2627
Edit `.env`:
2728

0 commit comments

Comments
 (0)