nightlight

nightlight

Docker app from sauso's Repository

Overview

Nightlight is a self-hosted baby monitor with low-latency multi-camera streaming from RTSP cameras, installable as a web app (PWA) on your phone. No cloud, no subscription - runs entirely on your own network. One container includes the app, MediaMTX (RTSP to WebRTC/HLS bridge), and FFmpeg (audio transcoding) together. Nightlight needs a routable LAN address so WebRTC (the low-latency viewing mode) works correctly. Host networking (the default below) is the simplest way to get one and needs no extra setup; a dedicated ipvlan/macvlan address on a custom Docker network is also supported if you'd rather avoid host-mode port conflicts - see the Networking modes section of docs/networking.md (github.com/sauso/nightlight) for both options. Set the data path below to somewhere under your appdata share before starting. After starting, open the WebUI and you'll be prompted to create the first admin account.

Nightlight — your cameras, your baby monitor

A private, self-hosted baby monitor built around the cameras you already own.

Nightlight brings your nursery cameras together in one place. Check in on your little ones, listen to live audio, follow sleep activity and get optional alerts from your phone or computer — without a subscription or a Nightlight-hosted video service.

Built for parents. Friendly to self-hosters. Open source.

Website · Quick start · Documentation · Report an issue

Important: Nightlight is a convenience tool, not a safety or medical device. Streams and alerts can fail. It must never replace adult supervision or be relied on to detect a child in distress.

See Nightlight in action

Live view A child's last night Morning check
Live view of two cameras on a phone A child's overview with last night's sleep summary on a phone The morning check asking whether the wake time is right, on a phone

See the full walkthrough, from first-run setup to a caregiver's view. These are captures of a made-up household with a synthetic camera picture, not live footage or real data, and they may lag behind the latest UI.

Why Nightlight?

  • Use your existing cameras. Connect compatible RTSP cameras. On supported ONVIF cameras, Nightlight can fill in the stream details from the camera's IP address.
  • Watch with less delay. WebRTC provides low-latency live video, with an HLS compatibility option.
  • Keep things in your hands. Nightlight runs on your own Docker host and stores its settings and recordings locally.
  • One place for the nursery. Group cameras by child and manage access for caregivers.
  • More than a live feed. Explore sleep tracking, camera controls, recording and optional notifications.

Nightlight is designed for local-network use first. Remote viewing is possible, but requires additional setup.

Quick start

You'll need an always-on Linux host running Docker (such as Unraid or an arm64 Raspberry Pi) and a camera that exposes an RTSP stream. ONVIF is useful but optional. Performance depends on your hardware, camera count and enabled analysis features, and there isn't a published minimum-hardware benchmark. What you need, and what has been tested says what is known and what isn't.

On Unraid? Jump to Running on Unraid. Anywhere else, run Nightlight on a trusted home network:

docker run -d \
  --name nightlight \
  --network host \
  --restart unless-stopped \
  --log-opt max-size=10m \
  --log-opt max-file=3 \
  --stop-timeout 30 \
  -e PUID=99 \
  -e PGID=100 \
  -e TZ=UTC \
  -v /path/to/your/data:/app/data \
  sauso/nightlight:latest

Replace /path/to/your/data with a persistent folder on your host. PUID=99 and PGID=100 suit Unraid; on other hosts, choose the appropriate non-root user and group. Set TZ to your timezone if desired (it sets log timestamps and the names of the video buffer files; the times the app shows follow the timezone in Settings → General).

--stop-timeout 30 gives Nightlight time to finish saving a recording when the container is stopped; without it Docker can kill the container first. --log-opt stops Docker's logs growing without limit.

Open http://<server-ip>:4000 from a device on the same network. Create your administrator account, add a child, then connect a camera from the Cameras tab.

Prefer Compose, or need different networking or storage settings? See the installation guide.

Running on Unraid

In Community Applications, search for Nightlight, select Install, check the data directory and apply. No extra plugin is needed. Then open http://<server-ip>:4000 and follow the steps above to create your administrator account.

Already installed from an older template? Unraid keeps your saved template, so it doesn't pick up the shutdown setting by itself. Edit the container and make sure Extra Parameters contains --stop-timeout 30, so recordings can finish saving when the container stops.

Manual template install and other setup details

What can it do?

Live monitoring. Watch multiple cameras, use audio and picture-in-picture, and switch between low-latency WebRTC and compatibility playback.

Camera controls. Add a camera by its IP address and let ONVIF fill in the stream details where it is supported, or set up the RTSP stream by hand. Use pan/tilt and two-way audio on cameras that support them.

Sleep and recordings. Review sleep activity and, if enabled, save motion/sound clips, wake clips or recordings you start yourself. See how sleep tracking works and recording options. A separate recordings folder must be writable by the app's PUID/PGID, or clip recording turns off; see recording storage and fixes.

Caregiver access. Create accounts for people who need access to your nursery.

Optional alerts. Configure a supported notification provider to receive events when you're away from the app. Learn how notifications work.

Mobile access. Use the installable web app or the Android and iOS companion apps, including supported background audio features. The apps are installed from GitHub rather than an app store (the iOS app is sideloaded).

Privacy and safety

Nightlight doesn't require a Nightlight cloud account or send your video to a Nightlight-hosted service. That doesn't mean every optional connection stays on your network:

  • The default WebRTC setup uses a public Google STUN server, which can see connection metadata such as your public IP. You can disable it or use your own STUN server.
  • Push notifications use whichever external or self-hosted provider you configure under Settings → Integrations → Push notifications.
  • Camera credentials and other secrets are stored unencrypted in the local database. Protect your data directory and backups.

Read privacy, security and networking details before exposing Nightlight outside your home network. For vulnerabilities, follow SECURITY.md.

Documentation

Start with the documentation hub, or jump directly to:

Help make Nightlight better

Found a bug or have an idea? Open an issue. Please don't post camera passwords, private video, tokens or other sensitive information in public reports.

Nightlight is MIT licensed. See LICENSE.

Download Statistics

61,524
Total Downloads

Related apps

Details

Repository
sauso/nightlight
Last Updated2026-10-18
First Seen2026-09-19

Runtime arguments

Web UI
http://[IP]:[PORT:4000]/
Network
host
Shell
sh
Privileged
false
Extra Params
--log-opt max-size=10m --log-opt max-file=3 --stop-timeout 30

Template configuration

WebUI PortPorttcp

Used ONLY to build the WebUI link above - with Host networking (the default), changing this number does NOT change the port the app actually listens on. To actually change the port, set the PORT variable below to the SAME number as this field.

Target
4000
Default
4000
Value
4000
PORTVariable

OPTIONAL - the port the app actually listens on. Leave blank for the default (4000). If you set this, also change WebUI Port above to the same number, or the WebUI link will point at the wrong port.

Data DirectoryPathrw

Stores the database (your cameras, children and settings) and the app's secrets, in an owner-only private folder, plus snapshots and, unless you map the Recordings Directory below, the clips. Upgrading from 0.43 or earlier moves the database into that private folder at the first start; it is one way, so read docs/operations.md (The private folder) at github.com/sauso/nightlight first.

Target
/app/data
Default
/mnt/user/appdata/nightlight
Value
/mnt/user/appdata/nightlight
Recordings Directory (optional)Pathrw

OPTIONAL - where event-recording clips are stored. Leave unset and clips go under the Data Directory (your SSD cache). To keep large clips off the SSD, map this to a folder on your array (e.g. /mnt/user/nightlight-clips) AND set the CLIPS_DIR variable below to /recordings. Retention caps (Settings - Recording) protect the disk either way. The folder must be writable by PUID/PGID (default 99:100), or clip recording is disabled; see https://github.com/sauso/nightlight/blob/main/docs/recording.md#where-recordings-are-stored.

Target
/recordings
CLIPS_DIRVariable

OPTIONAL - set to /recordings only if you mapped the Recordings Directory above to store clips on your array instead of under the Data Directory (a trailing slash is fine). Leave blank otherwise. The folder must be writable by PUID/PGID (default 99:100), or clip recording is disabled; see https://github.com/sauso/nightlight/blob/main/docs/recording.md#where-recordings-are-stored.

PUIDVariable

User ID that owns files this container creates in the Data Directory - 99 matches Unraid's own 'nobody' convention, so the default should already be correct. (Camera recordings are written by a separate internal user, 1700, while media isolation is on, which is the default; see the operations guide.)

Default
99
Value
99
PGIDVariable

Group ID that owns files this container creates in the Data Directory - 100 matches Unraid's own 'users' convention, so the default should already be correct

Default
100
Value
100
UMASKVariable

Who else may read files in the Data Directory. 077 (default; blank also means 077) = owner only: the database holds every stored secret, and each start also takes group/other access off existing files. Range 000-077 (owner digit 0); an invalid value logs a warning and 077 is used. Set 022 for the old world-readable modes if a backup job, another container or a named SMB user reads the folder - set it BEFORE upgrading, since after one start at 077 it only affects new files. It never opens the private folder (the database, secrets, snapshots and backups), which is always 700.

Default
077
Value
077
Session lifetime (days)Variable

OPTIONAL - how many days a sign-in lasts, counted from sign-in (not from last use; there is no idle sign-out). Leave blank for the default (30). Range 7-30 whole days; an invalid value logs a warning and 30 is used. WARNING: a phone is signed out at the same time of day it signed in, this many days later, and gets no Nightlight push alerts until someone opens the app and signs in again (Pushover, ntfy and Gotify are not affected). Lowering it signs out every sign-in older than the new value at its next request; raising it does not lengthen sign-ins already made (one made at 7 still ends on its 7th day).

Target
SESSION_TTL_DAYS
TimezoneVariable

Your local timezone, e.g. Australia/Melbourne - affects log timestamps and video buffer file names only; the times the app shows follow the timezone in Settings under General

Target
TZ
Default
UTC
Value
UTC
JWT SecretVariable

Optional - leave blank and a secure random secret is generated and persisted in the data directory's private folder automatically on first run

Target
JWT_SECRET
Public HostVariable

Your public IP or DDNS hostname - only needed if you want Low Latency (WebRTC) mode to work from outside your home network (also requires forwarding UDP port 8189 on your router, or the WebRTC UDP Port below if you changed it). Must be your public IP or a DNS-only name - NOT a Cloudflare-proxied (orange cloud) hostname, which cannot carry UDP. Leave blank for LAN-only use.

Target
PUBLIC_HOST
WebRTC UDP PortVariable

OPTIONAL - the UDP port Low Latency (WebRTC) video travels on. Enter the number only, no colon. Leave blank for the default (8189). Change it only to run a second Nightlight on the same server (e.g. staging next to production): give each its own port, and forward that same number on your router (1:1, the port in and out must match). Valid range 1-65535.

Target
WEBRTC_UDP_PORT
Cloudflare Web AnalyticsVariable

OPTIONAL. If you do NOT use Cloudflare Web Analytics, leave this blank: nothing changes. If you serve Nightlight through Cloudflare's proxy with Web Analytics turned on, Cloudflare injects its analytics beacon into every page, and Nightlight's security policy (Content-Security-Policy) BLOCKS that beacon unless this is set to 1 (or true, yes, on); every blocked page load also logs a [csp-report] line (at most 10 a minute). So either set it to 1, or, if you do not want those analytics, turn off Web Analytics' automatic setup for the site in the Cloudflare dashboard. Blank (the default), 0, false, no and off keep it blocked; any other value also blocks it and logs a warning. Before this setting existed the beacon was allowed on every install, so set it if you rely on it.

Target
CLOUDFLARE_ANALYTICS
Trusted ProxyVariable

OPTIONAL - leave blank unless you run Nightlight behind a reverse proxy AND that proxy connects from something other than 127.0.0.1 (SWAG reaching it by LAN IP is the common case - see docs/remote-access.md on github.com/sauso/nightlight). Set it to the address your proxy connects FROM, e.g. 10.0.0.20. Accepts an IP or CIDR, a comma-separated list, a hop count (1), or a named range. WARNING: only trust an address you control - too broad a value, or the word true (which trusts every upstream), lets anyone forge X-Forwarded-For and evade the login rate limit. Blank is safe: login attempts are also limited per account. A value Nightlight cannot make sense of is ignored with a warning in the log and the safe default (loopback) is used - it will not stop the app starting.

Target
TRUST_PROXY
STUN ServersVariable

OPTIONAL - which STUN servers Low Latency (WebRTC) uses, in the browser and in the bundled MediaMTX. STUN is only needed for viewers OUTSIDE your home network who are behind NAT; viewing on your own network never needs it. The default is Google's public server, which learns the viewer's public IP and when each live view connected. Accepts a comma-separated list of stun:host or stun:host:port entries. CLEAR THE FIELD (leave it blank) to use no STUN server at all: nothing then contacts Google or any other STUN server. Entries that are not stun: URLs are ignored with a warning in the log (if none is valid, STUN is off).

Target
STUN_SERVERS
Default
stun:stun.l.google.com:19302