Self-hosted service
jlesage/docker-firefox avatar
jlesage/docker-firefox

docker-firefox: a browser in a container with a real desktop behind it

Docker container for Firefox

2,556 stars439 forksShellMIT

At a glance

What is it?
Unofficial but carefully built Firefox image that puts the full graphical browser in a container, reachable over a web interface or any VNC client, with a terminal and file manager attached.
Who is it for?
What makes this container worth a look is not that it runs Firefox, which is a solved problem, but what it puts around the browser. A web terminal, a file manager that edits the same filesystem Firefox sees, host clipboard sync, a PWA install path, and a documented reverse-proxy section covering both hostname and URL-path routing are the parts a hand-rolled container tends to lack.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 14 days ago.
What is it written in?
Mainly Shell, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 28, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One docker run gives you a desktop in a browser tab

The quick start is a single container start with one port and one volume:

shell
docker run -d \
    --name=firefox \
    -p 5800:5800 \
    -v /docker/appdata/firefox:/config:rw \
    jlesage/firefox

You then browse to `http://your-host-ip:5800` and get the full graphical interface. The README frames this as no downloads, installs or setup on the client side, and adds that any VNC client works as an alternative, which matters because the web interface is a nice-to-have layered on top of a VNC server rather than a replacement for it.

The README carries an important note on that command: it is an example, and parameters should be adjusted to suit your needs. That is a small thing to write and a useful thing, because the defaults are chosen for a NAS rather than a workstation. The volume it mounts, `/docker/appdata/firefox` to `/config`, is the one piece of state that has to persist, since it holds configuration, application state and logs.

It also states plainly that the container is entirely unofficial and not made by the creators of Firefox. That is the correct framing for what follows: not a Mozilla project, but a competent packaging of Firefox by someone who has clearly had to solve the awkward parts.

The interface layers a terminal and file manager over the browser

The web interface is described as offering audio playback, clipboard sharing with the host, an integrated file manager and terminal for reaching the container's files and shell, and desktop notifications. Each of those is a small feature that removes a specific friction when you are running a browser inside a container.

The terminal and file manager matter most, because they turn the container from a black box into something you can inspect. When a profile refuses to load or an extension misbehaves, having a shell pointed at the same filesystem Firefox is using is the difference between debugging and guessing. The same reasoning applies to the web control panel, which the README lists as its own section.

The README also documents installing the interface as an application on a computer or phone, which arrived with the base image update in v26.09.1. That release also fixed host clipboard synchronization disabling itself, an amusing failure mode that suggests the clipboard bridge has been the fragile part of this setup. Treating the container as a progressive web app is a small addition, but it is the difference between opening a browser tab and having something that behaves like an installed desktop application.

Firefox 151 with NSPR rebuilt to work around a musl limit

The Dockerfile pins `FIREFOX_VERSION=151.0.3-r0` and installs it from Alpine packages. The interesting part is what happens around it. The image rebuilds NSPR from source, and the comment explains why in one line: Alpine's package caps `PR_Seek64` at 2GiB on musl. The build script is `src/nspr/build.sh`, driven by the cross-compilation helpers from `tonistiigi/xx`, and the resulting shared libraries are verified with `xx-verify` before use.

That detail connects directly to a release note. v26.08.3, published on 2026-08-26, contains exactly one change: Firefox uploads stalling at 2GiB. A file offset ceiling on the C library, rebuilt at the source level, is what fixes an upload limit. This is the clearest single illustration of what this project is: not a wrapper around a package, but a place where the package, the C library and the kernel all have to agree.

The Dockerfile also carries commented-out lines for `profile-cleaner` and for pulling Firefox from Alpine's edge repositories rather than pinning the stable package. Those are switches the maintainer has used, left in place rather than removed.

Running as a configurable user rather than root

The environment variable table is the practical reference for the container, and its first three entries all deal with identity. `USER_ID` and `GROUP_ID` default to `1000` and determine what the application runs as. `SUP_GROUP_IDS` takes a comma-separated list of supplementary groups, which is how you grant access to a mounted media directory without going back to root.

The reasoning is that the container writes to volumes you own on the host, and hardcoded IDs produce files the wrong user cannot read or delete later. Setting these to match your own host account is the difference between a mounted config directory that works and one that leaves root-owned files behind after every crash.

`UMASK` defaults to `0022`, documented as keeping files readable by all but writable only by the owner, and `LANG` defaults to `en_US.UTF-8` with the full `language[_territory][.codeset]` format spelled out. `TZ` defaults to `Etc/UTC`, and the README notes the timezone can also be set by mapping `/etc/localtime` between host and container, which avoids the variable entirely. `KEEP_APP_RUNNING` is the one to notice: when set to `1`, the application is restarted automatically rather than letting a closed browser stop the container.

Security is documented as several independent layers

The README has a security section that breaks into SSVNC, certificates, the VNC password and web authentication. Reading them as separate layers rather than one mechanism is the right frame. SSVNC is the server underneath the web interface, certificates cover the web side, and a VNC password covers direct VNC connections, so tightening one does not cover the other.

Web authentication has its own subsection on configuring user credentials. That is the piece most self-hosted containers skip, and the reason it matters here is that the web interface includes a terminal. An unauthenticated web shell exposed on a port is not a small problem, and the README's willingness to spend a section on credentials is a reasonable signal about how the author thinks about it.

Two more sections cover deployment in ways that are easy to miss. There is a reverse proxy section, split into routing based on hostname and routing based on URL path, which is what you need if this is going on a shared domain alongside other services. And there is a section on allowing the `membarrier` system call, which the repository supports with its own `membarrier_check.c` source file and a build stage in the Dockerfile that compiles the checker statically. Some kernel operations, sandboxing in particular, refuse to run without it, so on a NAS with an older kernel this is a known failure point rather than an unknown one.

Versioned tags, GPU acceleration, and what the README leaves out

The project has its own section on Docker image versioning and tags, and the release naming follows a `YY.MM.PATCH` scheme: v26.09.1 on 2026-09-22, v26.08.3, and v26.08.2 before it. The repository is not archived and the last push was on 2026-09-22, matching the most recent release, and the license is MIT. Open issues sit at 93 against roughly 2,556 stars, which is a normal ratio for a container that people depend on operationally.

GPU acceleration has a documented section, which is where most browser containers stop working properly. Video playback acceleration in particular tends to fall back to software without it. The README treats it as a supported configuration rather than a caveat, and the table of contents also lists a troubleshooting section with a subsection specifically on crashes.

What the README does not do is explain the design. There is no architecture document and no rationale for the choice of an unofficial base image, and the Docker Hub page carries the project-specific metadata separately in `DOCKERHUB.md` while `appdefs.yml` describes the application for the Synology and unRAID ecosystems the README specifically calls out. If you want to know why a piece is structured a certain way, the Dockerfile and `rootfs/` are where the answers are, and they are readable.

Editorial conclusion

What makes this container worth a look is not that it runs Firefox, which is a solved problem, but what it puts around the browser. A web terminal, a file manager that edits the same filesystem Firefox sees, host clipboard sync, a PWA install path, and a documented reverse-proxy section covering both hostname and URL-path routing are the parts a hand-rolled container tends to lack. Two details are worth understanding before you deploy it. The container runs as a non-root user whose ID you set, and the README treats the VNC and web authentication layers as a real security surface with its own certificate and password sections rather than assuming a private network. And it is entirely unofficial, which the README says plainly. Start with the quick start command, then read the security and reverse proxy sections, because those are where this container differs from a bare image.

Frequently asked questions

Is there a Docker container for Firefox?

Yes, and this is one. It provides the full Firefox graphical interface from any modern web browser with nothing to install on the client, or over any VNC client. The web interface also adds audio playback, host clipboard sharing, an integrated file manager and terminal, and desktop notifications. The container is unofficial and not made by the creators of Firefox.

How do I start the container and keep my browser data?

Map a host directory to `/config` with write access and expose port 5800. The quick start command is `docker run -d --name=firefox -p 5800:5800 -v /docker/appdata/firefox:/config:rw jlesage/firefox`, then open `http://your-host-ip:5800`. The `/config` mount holds configuration, application state and logs, so it is the only volume you strictly need to keep.

Which user does the application run as inside the container?

A configurable non-root user. `USER_ID` and `GROUP_ID` both default to `1000`, and `SUP_GROUP_IDS` takes a comma-separated list of supplementary group IDs if you need extra group access to a mounted directory. Setting them to match your host account avoids leaving files on the mounted volume that you cannot later read or delete.

Is the web interface secured?

The README documents it as separate layers rather than one mechanism: SSVNC underneath, certificates for the web side, a VNC password for direct VNC connections, and web authentication with configurable user credentials. That last one matters most here because the interface includes a web terminal. There are also sections on reverse proxy routing by hostname or URL path for shared domains.

Why do large uploads stall at 2GiB?

Alpine's musl C library caps the `PR_Seek64` seek call at 2GiB, so file offsets beyond that fail even though the underlying filesystem supports more. This image rebuilds NSPR from source in a separate build stage to get 64-bit file offsets, and v26.08.3 shipped with exactly one change: a fix for Firefox uploads stalling at 2GiB.

Official sources

  1. Issues
  2. jlesage/docker-firefox on GitHub
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/jlesage-docker-firefox.svg)](https://hysenlabs.com/projects/jlesage-docker-firefox)