This guide provides comprehensive information about deploying LightNVR using Docker.
- Quick Start
- Container Architecture
- Volume Management
- Network Configuration
- Environment Variables
- First Run Experience
- WebRTC Configuration
- Troubleshooting
- Advanced Configuration
# Clone the repository
git clone https://github.com/opensensor/lightNVR.git
cd lightNVR
# Initialize submodules (required for go2rtc build)
git submodule update --init --recursive
# Start the container (first run will build the image and pull the latest base layers)
docker compose up -d
# View logs
docker compose logs -f
# Access the web UI
# http://localhost:8080
# Default username: admin (password is auto-generated on first run - check logs)docker run -d \
--name lightnvr \
--restart unless-stopped \
-p 8080:8080 \
-p 8554:8554 \
-p 8555:8555 \
-p 8555:8555/udp \
-p 1984:1984 \
-v ./config:/etc/lightnvr \
-v ./data:/var/lib/lightnvr/data \
-e TZ=America/New_York \
ghcr.io/opensensor/lightnvr:latestThe LightNVR Docker container is built using a multi-stage build process:
- Builder Stage - Compiles LightNVR and go2rtc from source
- Runtime Stage - Minimal Debian-based image with only runtime dependencies
- Automatic Initialization - Creates default configs on first run
- Persistent Configuration - Config files survive container restarts
- Protected Web Assets - Web UI files stored in template location
- Health Checks - Built-in health monitoring
- Multi-Architecture - Supports amd64, arm64, and armv7
The container uses two primary volume mounts:
/etc/lightnvr/ # Configuration files
├── lightnvr.ini # Main configuration
└── go2rtc/
└── go2rtc.yaml # go2rtc configuration
/var/lib/lightnvr/data/ # Persistent data
├── database/
│ └── lightnvr.db # SQLite database
├── recordings/
│ ├── hls/ # HLS recordings
│ └── mp4/ # MP4 recordings
└── models/ # Object detection models
/var/lib/lightnvr directly!
Mounting the entire /var/lib/lightnvr directory will overwrite the web assets and break the web UI. Always mount only the subdirectories you need:
✅ Correct:
volumes:
- ./config:/etc/lightnvr
- ./data:/var/lib/lightnvr/data❌ Incorrect:
volumes:
- ./config:/etc/lightnvr
- ./data:/var/lib/lightnvr # This will break the web UI!When using NFS volumes (common with NAS devices like Synology), there are some important considerations:
NFS volumes may have different permission models than local filesystems. If you encounter "Operation not permitted" errors:
-
Check NFS mount options: Ensure your NFS share is mounted with appropriate permissions
volumes: config: driver_opts: type: "nfs" o: "nfsvers=4,addr=192.168.1.100,rw,nolock" # Add nolock if needed device: ":/volume1/docker/lightnvr/config"
-
UID/GID mapping: The container runs as root by default. Ensure your NFS export allows root access or map UIDs appropriately:
- On Synology NAS: Enable "Map all users to admin" or "Squash" options in NFS permissions
- Or use
all_squash,anonuid=1000,anongid=1000in NFS export options
-
Directory pre-creation: For better reliability with NFS, pre-create the directory structure on your NAS:
# On your NAS or NFS server mkdir -p /volume1/docker/lightnvr/config/go2rtc mkdir -p /volume1/docker/lightnvr/data/recordings/mp4 mkdir -p /volume1/docker/lightnvr/data/database mkdir -p /volume1/docker/lightnvr/data/models chmod -R 755 /volume1/docker/lightnvr
If recordings are not being created:
- Check write permissions: The container logs will show write permission test results on startup
- Verify NFS mount: Ensure the NFS volume is actually mounted inside the container:
docker exec lightnvr-latest ls -la /var/lib/lightnvr/data/recordings/mp4 - Check available space: Ensure your NAS has sufficient free space
- Review logs: Check for "Failed to open input" or "Operation not permitted" errors:
docker logs lightnvr-latest | grep -i error
Here's a complete example for Synology NAS with Traefik:
volumes:
config:
driver_opts:
type: "nfs"
o: "nfsvers=4,addr=${IpAddressNFS},rw,nolock"
device: ":/${NFSVolumePath}/${SystemId}/lightnvr-config"
data:
driver_opts:
type: "nfs"
o: "nfsvers=4,addr=${IpAddressNFS},rw,nolock"
device: ":/${NFSVolumePath}/${SystemId}/lightnvr-data"Note: The nolock option can help with some NFS permission issues but may reduce file locking safety. Use with caution in production environments.
Web assets are stored in /var/lib/lightnvr/web and are automatically copied from /usr/share/lightnvr/web-template/ on first run. This ensures:
- Web UI works immediately after container start
- Updates to the container image update the web UI
- Web assets are not lost when mounting data volumes
| Port | Protocol | Service | Description |
|---|---|---|---|
| 8080 | TCP | Web UI | Main web interface |
| 8554 | TCP | RTSP | RTSP streaming server |
| 8555 | TCP/UDP | WebRTC | WebRTC streaming |
| 1984 | TCP | go2rtc API | go2rtc REST API |
services:
lightnvr:
ports:
- "8080:8080"
- "8554:8554"
- "8555:8555"
- "8555:8555/udp"
- "1984:1984"services:
lightnvr:
network_mode: hostNote: Host mode provides better performance but exposes all ports directly on the host.
| Variable | Default | Description |
|---|---|---|
TZ |
UTC |
Container timezone |
GO2RTC_CONFIG_PERSIST |
true |
Persist go2rtc config across restarts |
LIGHTNVR_AUTO_INIT |
true |
Auto-initialize config files on first run |
LIGHTNVR_WEB_ROOT |
/var/lib/lightnvr/web |
Web assets directory |
LIGHTNVR_ONVIF_NETWORK |
(none) | Override ONVIF discovery network (e.g., 192.168.1.0/24) |
environment:
- TZ=America/New_York
- GO2RTC_CONFIG_PERSIST=true
- LIGHTNVR_AUTO_INIT=true
- LIGHTNVR_ONVIF_NETWORK=192.168.1.0/24When running in a container, ONVIF auto-detection skips Docker bridge interfaces by default. To enable ONVIF camera discovery in containerized deployments, set the LIGHTNVR_ONVIF_NETWORK environment variable to specify which network to scan:
services:
lightnvr:
environment:
# Specify the network where your cameras are located
- LIGHTNVR_ONVIF_NETWORK=192.168.1.0/24Network Priority:
- Explicit network parameter (API calls)
LIGHTNVR_ONVIF_NETWORKenvironment variablediscovery_networkin config file ([onvif]section)- Auto-detection (skips Docker interfaces)
Finding Your Network:
# On the Docker host, find your camera network
ip addr show
# Example: If your host IP is 192.168.1.100 with netmask 255.255.255.0
# Use: LIGHTNVR_ONVIF_NETWORK=192.168.1.0/24On first container start, the entrypoint script automatically:
-
Creates Directory Structure
/etc/lightnvr/ /var/lib/lightnvr/web/ /var/lib/lightnvr/data/database/ /var/lib/lightnvr/data/recordings/ /var/lib/lightnvr/data/models/ -
Copies Web Assets
- Copies from
/usr/share/lightnvr/web-template/to/var/lib/lightnvr/web/ - Only if web directory is empty
- Copies from
-
Creates Default Configuration
lightnvr.iniwith sensible defaultsgo2rtc.yamlwith WebRTC/STUN configuration
-
Initializes Database
- Creates SQLite database on first access
- Sets up default admin user
- Username:
admin - Password:
admin
The container includes pre-configured WebRTC support with STUN servers for NAT traversal.
webrtc:
listen: :8555
ice_servers:
- urls: [stun:stun.l.google.com:19302]
candidates:
- "*:8555"
- stun:stun.l.google.com:19302Edit ./config/go2rtc/go2rtc.yaml:
webrtc:
listen: :8555
ice_servers:
- urls: [stun:stun.l.google.com:19302]
- urls: [turn:your-turn-server.com:3478]
username: your-username
credential: your-password
candidates:
- "YOUR_PUBLIC_IP:8555"Restart the container to apply changes:
docker compose restartIf running behind NAT/firewall, forward these ports:
- 8555/TCP - WebRTC signaling
- 8555/UDP - WebRTC media
Symptom: Accessing http://localhost:8080 shows nothing or 404 error
Causes:
- Mounted
/var/lib/lightnvrdirectly (overwrote web assets) - Web assets not copied during initialization
Solution:
# Stop container
docker compose down
# Remove incorrect volume mount
# Edit docker-compose.yml to use /var/lib/lightnvr/data instead
# Remove web directory to force re-initialization
rm -rf ./data/web
# Start container
docker compose up -dSymptom: All streams and settings disappear after container restart
Cause: Data volume not mounted correctly
Solution:
# Verify volume mounts
docker inspect lightnvr | grep -A 10 Mounts
# Should show:
# /etc/lightnvr
# /var/lib/lightnvr/dataSymptom: WebRTC streams fail to connect (ICE connection failures)
Causes:
- ICE candidates not resolving to the correct host IP address
- UDP port 8555 not forwarded
- Firewall blocking WebRTC
- STUN server not reachable
Solution:
The most common fix is setting your host machine's local IP as external_ip in ./config/lightnvr.ini:
[go2rtc]
external_ip = 192.168.1.100 ; Replace with your machine's local IPTo find your local IP:
# Linux
hostname -I | awk '{print $1}'
# macOS
ipconfig getifaddr en0 # or en1 for Wi-FiThen restart the container:
docker compose restartIf that doesn't resolve it, check go2rtc connectivity:
# Check if go2rtc is running
docker exec lightnvr ps aux | grep go2rtc
# Check go2rtc logs
docker exec lightnvr cat /var/log/lightnvr/go2rtc.log
# Test STUN connectivity
docker exec lightnvr nc -vzu stun.l.google.com 19302Symptom: Changes to go2rtc.yaml are lost on restart
Cause: GO2RTC_CONFIG_PERSIST set to false
Solution:
environment:
- GO2RTC_CONFIG_PERSIST=trueMount a custom config file:
docker run -d \
--name lightnvr \
-v /path/to/custom/lightnvr.ini:/etc/lightnvr/lightnvr.ini \
-v ./data:/var/lib/lightnvr/data \
ghcr.io/opensensor/lightnvr:latestservices:
lightnvr-1:
image: ghcr.io/opensensor/lightnvr:latest
ports:
- "8080:8080"
- "8554:8554"
volumes:
- ./config-1:/etc/lightnvr
- ./data-1:/var/lib/lightnvr/data
lightnvr-2:
image: ghcr.io/opensensor/lightnvr:latest
ports:
- "8081:8080"
- "8555:8554"
volumes:
- ./config-2:/etc/lightnvr
- ./data-2:/var/lib/lightnvr/dataservices:
lightnvr:
deploy:
resources:
limits:
cpus: '2'
memory: 2G
reservations:
cpus: '1'
memory: 512Mservices:
lightnvr:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"If you're upgrading from an older version that mounted /var/lib/lightnvr directly, see DOCKER_MIGRATION_GUIDE.md for detailed migration instructions.
# Clone repository
git clone https://github.com/opensensor/lightNVR.git
cd lightNVR
# Initialize submodules (required for go2rtc)
git submodule update --init --recursive
# Build image
docker build --pull -t lightnvr:local .
# Run locally built image
docker run -d \
--name lightnvr \
-p 8080:8080 \
-v ./config:/etc/lightnvr \
-v ./data:/var/lib/lightnvr/data \
lightnvr:localFor issues and questions:
- GitHub Issues: https://github.com/opensensor/lightNVR/issues
- Documentation: https://github.com/opensensor/lightNVR/tree/main/docs