Examples
Here are some examples to get you started with Neko. You can use these examples as a reference to create your own configurations.
Every example below is also available as a self-contained, runnable folder in the examples/ directory of the repository, so you can browse, clone or download it directly. Each file is heavily commented, showing the available options and linking to the relevant documentation inline.
Simple Browser
A basic Firefox setup. Includes commented volume mounts for persisting the browser profile or mounting your own pre-configured one, and a list of other browser images you can swap in.
Browse: examples/simple-browser
# Neko - Simple Browser Example
#
# Runs Firefox in Neko. Firefox is the default, most tested image, but Neko
# supports many other browsers and applications - see the full list here:
# https://neko.m1k1o.net/docs/v3/installation/docker-images#apps
#
# Other browser images you can swap in below:
# ghcr.io/m1k1o/neko/chromium
# ghcr.io/m1k1o/neko/google-chrome
# ghcr.io/m1k1o/neko/brave
# ghcr.io/m1k1o/neko/vivaldi
# ghcr.io/m1k1o/neko/microsoft-edge
# ghcr.io/m1k1o/neko/tor-browser
# ghcr.io/m1k1o/neko/waterfox
services:
neko:
image: "ghcr.io/m1k1o/neko/firefox:latest"
restart: "unless-stopped"
shm_size: "2gb"
ports:
- "8080:8080"
- "52000-52100:52000-52100/udp"
# volumes:
# Persist Firefox settings, bookmarks, extensions and history across
# container restarts by mounting the profile directory.
# See: https://neko.m1k1o.net/docs/v3/customization/browsers#persistent-profile
# - "./profile:/home/neko/.mozilla/firefox/profile.default"
# Or mount your own pre-configured Firefox profile instead of an empty one.
# See: https://neko.m1k1o.net/docs/v3/customization/browsers#persistent-profile
# - "./my-custom-profile:/home/neko/.mozilla/firefox/profile.default"
environment:
NEKO_DESKTOP_SCREEN: '1920x1080@30'
NEKO_MEMBER_MULTIUSER_USER_PASSWORD: neko
NEKO_MEMBER_MULTIUSER_ADMIN_PASSWORD: admin
NEKO_WEBRTC_EPR: 52000-52100
NEKO_WEBRTC_ICELITE: 1
# See: https://neko.m1k1o.net/docs/v3/configuration/webrtc#nat1to1
# NEKO_WEBRTC_NAT1TO1: <your-IP>
See also: Persistent Browser Profile and Browser Policy Files.
Kiosk Browser
Runs Firefox in kiosk mode (no address bar, tabs or browser chrome) and opens a fixed URL automatically on startup. This is useful for app-like setups such as streaming services or dashboards, and works by mounting a persistent copy of the Firefox supervisor config and overriding the command directly.
This setup is intentionally stateless - no browser profile is persisted, so logins are lost on every restart. See the comments in the example for how to add a persistent profile if you need to stay logged in.
Browse: examples/kiosk-browser
# Neko - Kiosk Browser Example
#
# Runs Firefox in kiosk mode (no address bar, tabs or browser chrome) and
# opens a fixed URL automatically on startup. Useful for turning a smart
# display, thin client or dedicated terminal into an app-like experience.
#
# This works by overriding the Firefox supervisor command, see ./firefox.conf
# and the Supervisord Configuration docs:
# https://neko.m1k1o.net/docs/v3/customization#supervisord
services:
neko:
image: "ghcr.io/m1k1o/neko/firefox:latest"
restart: "unless-stopped"
shm_size: "2gb"
ports:
- "8080:8080"
- "52000-52100:52000-52100/udp"
volumes:
- "./firefox.conf:/etc/neko/supervisord/firefox.conf:ro"
# NOTE: this setup is intentionally stateless - no profile is persisted,
# so cookies and logins are lost every time the container restarts. If
# you want the kiosk session to stay logged in across restarts, mount a
# persistent profile directory as well:
# See: https://neko.m1k1o.net/docs/v3/customization/browsers#persistent-profile
# - "./profile:/home/neko/.mozilla/firefox/profile.default"
environment:
NEKO_DESKTOP_SCREEN: '1280x720@30'
NEKO_MEMBER_MULTIUSER_USER_PASSWORD: neko
NEKO_MEMBER_MULTIUSER_ADMIN_PASSWORD: admin
NEKO_WEBRTC_EPR: 52000-52100
NEKO_WEBRTC_ICELITE: 1
# See: https://neko.m1k1o.net/docs/v3/configuration/webrtc#nat1to1
# NEKO_WEBRTC_NAT1TO1: <your-IP>
[program:firefox]
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s",DISPLAY="%(ENV_DISPLAY)s"
; Replace <YOUR-KIOSK-URL> with the page to open automatically on startup,
; e.g. https://www.disneyplus.com/ for a dedicated streaming kiosk.
command=/usr/bin/firefox --kiosk --no-remote -P default --display=%(ENV_DISPLAY)s -setDefaultBrowser -width 1280 -height 720 <YOUR-KIOSK-URL>
stopsignal=INT
autorestart=true
priority=800
user=%(ENV_USER)s
stdout_logfile=/var/log/neko/firefox.log
stdout_logfile_maxbytes=100MB
stdout_logfile_backups=10
redirect_stderr=true
For some workflows, passing the target URL directly to Firefox is more reliable than using homepage policies, because session restore can otherwise override the start page. See also: Supervisord Configuration.
ARM64 Browser
Firefox on a generic ARM64 host (e.g. Apple M1/M2 under virtualization, AWS Graviton, Oracle Cloud ARM free tier). The same multi-arch image used on amd64 works here - no special image tag is required.
DRM (Widevine) support is limited on ARM64 and needs extra setup for protected streaming content, see DRM for ARM64. If your device exposes a V4L2 M2M hardware encoder, you can reuse the pipeline from the Raspberry Pi Browser example.
Browse: examples/arm64-browser
# Neko - ARM64 Browser Example
#
# Runs Firefox on a generic ARM64 host (e.g. Apple M1/M2 under virtualization,
# AWS Graviton, Oracle Cloud ARM free tier). The same multi-arch image used
# on amd64 works here - no special image tag is required.
#
# See supported architectures and per-app availability:
# https://neko.m1k1o.net/docs/v3/installation/docker-images#availability
services:
neko:
image: "ghcr.io/m1k1o/neko/firefox:latest"
restart: "unless-stopped"
shm_size: "2gb"
ports:
- "8080:8080"
- "52000-52100:52000-52100/udp"
environment:
NEKO_DESKTOP_SCREEN: '1920x1080@30'
NEKO_MEMBER_MULTIUSER_USER_PASSWORD: neko
NEKO_MEMBER_MULTIUSER_ADMIN_PASSWORD: admin
NEKO_WEBRTC_EPR: 52000-52100
NEKO_WEBRTC_ICELITE: 1
# See: https://neko.m1k1o.net/docs/v3/configuration/webrtc#nat1to1
# NEKO_WEBRTC_NAT1TO1: <your-IP>
# DRM (Widevine) support is limited on ARM64 and needs extra setup for
# protected streaming content:
# See: https://neko.m1k1o.net/docs/v3/customization/browsers#arm64-drm
# GPU ACCELERATION OPTION: if your ARM64 device exposes a V4L2 M2M
# hardware encoder (common on SBCs like Raspberry Pi), reuse the same
# pipeline as in the Raspberry Pi example:
# https://github.com/m1k1o/neko/tree/main/examples/gpu-raspberry-pi-browser
See supported architectures and per-app availability in the Availability Matrix.
GPU Browser Examples
Neko supports hardware-accelerated video encoding and browser rendering on several GPU vendors. Each example below accelerates both video encoding and browser rendering; see the "ENCODE-ONLY OPTION" comments in the examples for accelerating just the encoding.
Nvidia
To use this feature, you need to have the Nvidia Container Toolkit installed on your system. You can find the installation instructions here. Check if your GPU supports hardware encoding with this list.
You can test if the GPU is used by running nvtop or nvidia-smi, which should show the GPU usage of both the browser and neko. In the browser, you can run the WebGL Aquarium Demo to test the GPU usage.
If you only want to accelerate the encoding, not the browser rendering, see the commented "ENCODE-ONLY OPTION" blocks in the example - they switch to the plain firefox image and a videoconvert-based pipeline instead of nvidia-firefox with cudaupload/cudaconvert.
Browse: examples/gpu-nvidia-browser
# Neko - Nvidia Browser Example
#
# Runs Firefox with full Nvidia GPU acceleration (both browser rendering and
# video encoding) using CUDA. Requires the Nvidia Container Toolkit:
# https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html
#
# Check if your GPU supports hardware encoding:
# https://developer.nvidia.com/video-encode-decode-gpu-support-matrix
#
# Other GPU-accelerated flavors are listed here:
# https://neko.m1k1o.net/docs/v3/installation/docker-images#nvidia
services:
neko:
image: "ghcr.io/m1k1o/neko/nvidia-firefox:latest"
# ENCODE-ONLY OPTION: if you only want to accelerate video encoding, not
# the browser rendering, use the plain firefox image instead - see the
# matching commented pipeline/env vars further down.
# image: "ghcr.io/m1k1o/neko/firefox:latest"
restart: "unless-stopped"
shm_size: "2gb"
ports:
- "8080:8080"
- "52000-52100:52000-52100/udp"
environment:
# ENCODE-ONLY OPTION: uncomment these two when using the plain firefox
# image above, so the container can still see the GPU for encoding.
# NVIDIA_VISIBLE_DEVICES: all
# NVIDIA_DRIVER_CAPABILITIES: all
# `nvautogpuh264enc` (GStreamer 1.22+) is recommended for NVIDIA driver
# 590+; it auto-selects CUDA or system memory. On older drivers or
# GStreamer versions, use `nvh264enc` instead. If your GPU does not
# support CUDA, drop `cudaupload`/`cudaconvert` below (see the
# ENCODE-ONLY pipeline further down for that variant).
NEKO_CAPTURE_VIDEO_PIPELINE: |
ximagesrc display-name={display} show-pointer=true use-damage=false
! video/x-raw,framerate=25/1
! cudaupload ! cudaconvert ! queue
! video/x-raw(memory:CUDAMemory),format=NV12
! nvautogpuh264enc
name=encoder
preset=2
gop-size=25
spatial-aq=true
temporal-aq=true
bitrate=4096
vbv-buffer-size=4096
rc-mode=6
! h264parse config-interval=-1
! video/x-h264,stream-format=byte-stream
! appsink name=appsink
# ENCODE-ONLY OPTION: replace the active pipeline above with this one
# when using the plain "firefox" image - it swaps cudaupload/cudaconvert
# for a plain videoconvert, since the browser itself no longer needs CUDA:
# NEKO_CAPTURE_VIDEO_PIPELINE: |
# ximagesrc display-name={display} show-pointer=true use-damage=false
# ! video/x-raw,framerate=25/1
# ! videoconvert ! queue
# ! video/x-raw,format=NV12
# ! nvautogpuh264enc
# name=encoder
# preset=2
# gop-size=25
# spatial-aq=true
# temporal-aq=true
# bitrate=4096
# vbv-buffer-size=4096
# rc-mode=6
# ! h264parse config-interval=-1
# ! video/x-h264,stream-format=byte-stream
# ! appsink name=appsink
NEKO_CAPTURE_VIDEO_CODEC: "h264"
NEKO_DESKTOP_SCREEN: 1920x1080@30
NEKO_MEMBER_MULTIUSER_USER_PASSWORD: neko
NEKO_MEMBER_MULTIUSER_ADMIN_PASSWORD: admin
NEKO_WEBRTC_EPR: 52000-52100
NEKO_WEBRTC_ICELITE: 1
# See: https://neko.m1k1o.net/docs/v3/configuration/webrtc#nat1to1
# NEKO_WEBRTC_NAT1TO1: <your-IP>
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
See available Nvidia Docker Images.
Intel
Uses hardware acceleration via VAAPI. This requires the host to expose /dev/dri and have the Intel graphics driver installed.
This example accelerates both video encoding and browser rendering using the intel-firefox image. If you only want to accelerate the encoding, not the browser rendering, see the commented "ENCODE-ONLY OPTION" in the example, which switches to the plain firefox image.
Browse: examples/gpu-intel-browser
# Neko - Intel Browser Example
#
# Runs Firefox with Intel GPU hardware acceleration (VAAPI) for both browser
# rendering and video encoding. Requires the host to expose /dev/dri and have
# the Intel graphics driver installed.
#
# Other GPU-accelerated flavors are listed here:
# https://neko.m1k1o.net/docs/v3/installation/docker-images#intel
services:
neko:
image: "ghcr.io/m1k1o/neko/intel-firefox:latest"
# ENCODE-ONLY OPTION: if you only want to accelerate video encoding, not
# the browser rendering, use the plain firefox image instead:
# image: "ghcr.io/m1k1o/neko/firefox:latest"
restart: "unless-stopped"
shm_size: "2gb"
ports:
- "8080:8080"
- "52000-52100:52000-52100/udp"
devices:
# Required for VAAPI hardware acceleration - gives the container access
# to the GPU's render node. The render group is detected automatically.
- "/dev/dri:/dev/dri"
environment:
# The intel-firefox image already sets NEKO_HWENC=vaapi by default.
# Uncomment to be explicit, or when using the plain firefox image above
# for encode-only acceleration:
# NEKO_HWENC: "vaapi"
NEKO_DESKTOP_SCREEN: '1920x1080@30'
NEKO_MEMBER_MULTIUSER_USER_PASSWORD: neko
NEKO_MEMBER_MULTIUSER_ADMIN_PASSWORD: admin
NEKO_WEBRTC_EPR: 52000-52100
NEKO_WEBRTC_ICELITE: 1
# See: https://neko.m1k1o.net/docs/v3/configuration/webrtc#nat1to1
# NEKO_WEBRTC_NAT1TO1: <your-IP>
See available Intel Docker Images.
Raspberry Pi
Firefox tuned for a Raspberry Pi (or similar ARM SBC). Works out of the box with software rendering/encoding. See the commented "GPU ACCELERATION OPTION" in the example for enabling hardware-accelerated encoding via the Broadcom VideoCore V4L2 M2M encoder, available on Raspberry Pi 3/4 (not Pi 5).
Browse: examples/gpu-raspberry-pi-browser
# Neko - Raspberry Pi Browser Example
#
# Runs Firefox on a Raspberry Pi (or similar ARM SBC). Works out of the box
# with software rendering/encoding; see below for optional hardware-
# accelerated encoding on boards with a V4L2 M2M encoder (e.g. Pi 3/4).
#
# See supported architectures and known caveats:
# https://neko.m1k1o.net/docs/v3/installation/docker-images#availability
services:
neko:
image: "ghcr.io/m1k1o/neko/firefox:latest"
restart: "unless-stopped"
# increase on Pi's with more than 1gb ram.
shm_size: "520mb"
ports:
- "8080:8080"
- "52000-52100:52000-52100/udp"
# note: required for the GPU ACCELERATION OPTION below, alternatively
# mount the specific /dev/video* devices instead of running privileged.
# privileged: true
environment:
# GPU ACCELERATION OPTION: enable hardware encoding via the Broadcom
# VideoCore V4L2 M2M encoder (available on Raspberry Pi 3/4, not Pi 5).
# Requires `privileged: true` above (or the matching /dev/video* devices).
# NEKO_CAPTURE_VIDEO_PIPELINE: |
# ximagesrc display-name={display} show-pointer=true use-damage=false
# ! video/x-raw,framerate=25/1
# ! videoconvert ! queue
# ! video/x-raw,format=NV12
# ! v4l2h264enc
# name=encoder
# extra-controls="controls,h264_profile=1,video_bitrate=1250000;"
# ! h264parse config-interval=-1
# ! video/x-h264,stream-format=byte-stream
# ! appsink name=appsink
# NEKO_CAPTURE_VIDEO_CODEC: "h264"
NEKO_DESKTOP_SCREEN: '1280x720@30'
NEKO_MEMBER_MULTIUSER_USER_PASSWORD: neko
NEKO_MEMBER_MULTIUSER_ADMIN_PASSWORD: admin
NEKO_WEBRTC_EPR: 52000-52100
NEKO_WEBRTC_ICELITE: 1
# See: https://neko.m1k1o.net/docs/v3/configuration/webrtc#nat1to1
# NEKO_WEBRTC_NAT1TO1: <your-IP>
OAuth
Authenticates members through an external OAuth 2.0 / OpenID Connect provider instead of the built-in multiuser passwords. OAuth has many settings, so this example sets them via a mounted config.yaml instead of environment variables.
Browse: examples/oauth
# Neko - OAuth Example
#
# Authenticates users via an external OAuth 2.0 / OpenID Connect provider
# instead of the built-in multiuser passwords. OAuth has many settings, so
# they are set via a mounted config.yaml instead of environment variables.
#
# See: https://neko.m1k1o.net/docs/v3/configuration/authentication#member.oauth
services:
neko:
image: "ghcr.io/m1k1o/neko/firefox:latest"
restart: "unless-stopped"
shm_size: "2gb"
ports:
- "8080:8080"
- "52000-52100:52000-52100/udp"
volumes:
- "./config.yaml:/etc/neko/neko.yaml"
environment:
NEKO_DESKTOP_SCREEN: '1920x1080@30'
NEKO_WEBRTC_EPR: 52000-52100
NEKO_WEBRTC_ICELITE: 1
# See: https://neko.m1k1o.net/docs/v3/configuration/webrtc#nat1to1
# NEKO_WEBRTC_NAT1TO1: <your-IP>
# See: https://neko.m1k1o.net/docs/v3/configuration/authentication#member.oauth
member:
provider: "oauth"
oauth:
enabled: true
# When true, visiting the Neko root page immediately starts OAuth login.
auto_redirect: true
name: "Example SSO"
admin_emails: ["admin@example.com"]
user_emails: [] # if empty, any authenticated user is allowed to log in
client_id: "<client-id>"
client_secret: "<client-secret>"
# For OpenID Connect providers, issuer_url alone is enough - Neko
# discovers the authorization, token and user-info endpoints from
# /.well-known/openid-configuration.
issuer_url: "https://id.example.com"
scopes: ["openid", "profile", "email"]
# Configure these to match the JSON returned by the user-info endpoint.
subject_field: "sub"
username_field: "name"
avatar_field: "picture"
success_redirect: "/"
user_profile:
is_admin: false
can_login: true
can_connect: true
can_watch: true
can_host: true
can_share_media: true
can_access_clipboard: true
sends_inactive_cursor: true
can_see_inactive_cursors: false
admin_profile:
is_admin: true
can_login: true
can_connect: true
can_watch: true
can_host: true
can_share_media: true
can_access_clipboard: true
sends_inactive_cursor: true
can_see_inactive_cursors: true
See OAuth 2.0 Provider for all available options.
TURN Server
WebRTC needs a direct connection between the client and the server. When that is not possible (e.g. both sides are behind restrictive NATs or firewalls), a TURN server relays the traffic instead. This example runs a Coturn TURN server alongside Neko.
Browse: examples/turn-server
# Neko - TURN Server Example
#
# WebRTC needs a direct connection between the client and the server. When
# that is not possible (e.g. both sides are behind restrictive NATs or
# firewalls), a TURN server relays the traffic instead. This example runs a
# Coturn TURN server alongside Neko.
#
# See: https://neko.m1k1o.net/docs/v3/configuration/webrtc#iceservers
services:
neko:
image: "ghcr.io/m1k1o/neko/firefox:latest"
restart: "unless-stopped"
shm_size: "2gb"
ports:
- "8080:8080"
- "52000-52100:52000-52100/udp"
environment:
NEKO_DESKTOP_SCREEN: '1920x1080@30'
NEKO_MEMBER_MULTIUSER_USER_PASSWORD: neko
NEKO_MEMBER_MULTIUSER_ADMIN_PASSWORD: admin
NEKO_WEBRTC_EPR: 52000-52100
NEKO_WEBRTC_ICELITE: 1
# Tell the client to use the TURN server below as a fallback ICE
# server. Replace <MY-COTURN-SERVER> with the LAN or public IP address
# the TURN server is reachable at, matching the coturn service below.
# See: https://neko.m1k1o.net/docs/v3/configuration/webrtc#iceservers
NEKO_WEBRTC_ICESERVERS_FRONTEND: |
[{
"urls": [ "turn:<MY-COTURN-SERVER>:3478" ],
"username": "neko",
"credential": "neko"
}]
coturn:
image: "coturn/coturn:latest"
restart: "unless-stopped"
network_mode: "host"
command: |
-n
--realm=localhost
--fingerprint
--listening-ip=0.0.0.0
--external-ip=<MY-COTURN-SERVER>
--listening-port=3478
--min-port=49160
--max-port=49200
--log-file=stdout
--user=neko:neko
--lt-cred-mech
# Replace <MY-COTURN-SERVER> above with your LAN or Public IP address.
# Open ports 3478/tcp (control) and 49160-49200/udp (relay) on your
# firewall. More info: https://github.com/coturn/coturn
Replace <MY-COTURN-SERVER> with your LAN or Public IP address, and allow ports 49160-49200/udp and 3478/tcp.