A Docker base image to simplify the creation of downstream containers that run Linux GUI apps in a web browser.
- Linux apps in your browser
- Rootless runtime - Never needs root, and runs as any
--useryou choose. - Integrated clipboard - Seamless copy-paste between app and browser.
- Audio forwarding - Stream audio from the app to your browser seamlessly.
- Automatic restart - Apps relaunch automatically when closed.
- HTTPS redirect – Enforces secure connections over HTTPS, by default.
- Launch apps from UI –
.desktopentries are exposed and can be launched via the UI.
This image is designed to be used as a base for Dockerfiles.
Install a desired GUI app and call the following to launch it.
CMD ["start-app","[--no-restart]", "<app>", "[args...]"]# Prefer version pinning (at least a major, e.g. :v1)
# Pinning to <major>.<minor> (e.g. :v1.1) limits updates to patches only.
FROM aandree5/gui-web-base:v1.1
# Install app
USER root
RUN apt-get update && \
apt-get install -y my-app && \
&& apt-get autoremove \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
USER gwb
# Start app
CMD ["start-app", "xterm"]# Build the image
docker build -t gui-web-xterm .
# Run it
docker run -d -p 443:5443 gui-web-xtermTo access the app open
https://localhostin the browser.
These can be set using --build-arg during docker build to define default values baked into the image.
| Argument | Description | Default | Example |
|---|---|---|---|
GWB_RUN_BASE |
Base directory for per-user runtime state. | /run/gwb |
--build-arg GWB_RUN_BASE=/var/gwb |
UMASK |
Default file creation mask applied at runtime. | 077 |
--build-arg UMASK=027 |
These can be overridden by any downstream image or container using ENV or -e flags.
| Variable | Description | Default | Example |
|---|---|---|---|
APP_DIRS |
Space-separated list of directories the app must be able to write to. Checked at startup, missing ones are created where possible, and the container exits with a clear error if any are not writable by the running user. | (unset) | ENV APP_DIRS="/myapp/config /var/cache" or -e APP_DIRS="..." |
GWB_RUN_BASE |
Base directory for per-user runtime state. Each user gets <base>/<uid>/. |
/run/gwb |
ENV GWB_RUN_BASE=/var/gwb or -e GWB_RUN_BASE=/var/gwb |
UMASK |
File creation mask used during startup. Controls default permissions for generated files. | 077 |
ENV UMASK=027 or -e UMASK=027 |
ALLOW_HTTP |
Allows plain HTTP connections. When false, HTTP is redirected to HTTPS. |
true |
ENV ALLOW_HTTP=false or -e ALLOW_HTTP=false |
ALLOW_HTTPis recomended set tofalseto keep all traffic secure, even with self-signed certificates. In some cases it can be usefull to allow HTTP access, shuch as if the app is going to be behind a reverse proxy, which is handling SSL certificates.
The container never runs as root. It runs as the default gwb user, or as whatever identity you pass to --user.
-
Running as any user. Pass
--user <uid>:<gid>to match a mounted folder's ownership, with no rebuild and no root:# Run as the current host user so mounted folders line up docker run -d -p 443:5443 \ --user "$(id -u):$(id -g)" \ -v "$PWD/data:/myapp/data" \ -e APP_DIRS="/myapp/data" \ my-app
All runtime state (home directory,
XDG_RUNTIME_DIR, SSL certificate, NGINX logs and temp files) are created at startup under/run/gwb/<uid>/, so they are always owned by the user actually running the container. Everything else in the image is read-only to the app. -
Mounted folders only need to be writable by the uid/gid the container is running as. Any directory listed in
APP_DIRSis checked at startup and the container exits with a clear error if it isn't writable. -
Persistence. Mount a volume at
/run/gwbto keep the generated SSL certificate and runtime state between runs. Otherwise a new self-signed certificate is generated on each start (and whenever the uid changes). A read-only root filesystem works too, as long as the paths written at runtime stay writable:docker run -d -p 443:5443 --read-only \ --tmpfs /run/gwb:mode=1777 \ --tmpfs /run/dbus:mode=1777 \ --tmpfs /tmp:mode=1777 \ --tmpfs /tmp/.X11-unix:mode=1777 \ my-app
-
Hardening. Because nothing in the image ever needs to escalate privileges, downstream images can be run with
--security-opt no-new-privileges. -
Downstream Dockerfiles inherit
USER gwb, so switch back torootfor any build step that writes outside/run/gwb— installing packages, adding files, or runningconfigure-xpra, then switch back before the final image:FROM aandree5/gui-web-base:v1.1 USER root RUN apt-get update && apt-get install -y my-app && apt-get clean RUN configure-xpra --content-type class-instance:my-app=text COPY my-config/ /opt/my-app/config/ USER gwb CMD ["start-app", "my-app"]
These options can be passed to CMD in your Dockerfile to customize app behavior.
| Option | Description | Default | Example |
|---|---|---|---|
--no-restart |
Prevents the app from restarting when its window is closed. | (enabled) | CMD ["start-app", "--no-restart", "my-app"] |
--title |
Sets the browser tab title for the web interface. | GUI Web Base |
CMD ["start-app", "--title", "My Web App", "my-app"] |
--min-quality * |
Sets the minimum image encoding quality (1–100). Lower values save bandwidth. | 0 (auto) |
CMD ["start-app", "--min-quality", "80", "my-app"] |
--min-speed * |
Sets the minimum encoding speed (1–100). Higher values reduce latency. | 0 (auto) |
CMD ["start-app", "--min-speed", "50", "my-app"] |
--auto-refresh-delay * |
Delay (in seconds) before sending a lossless refresh after lossy updates. | 0.25 |
CMD ["start-app", "--auto-refresh-delay", "0.2", "my-app"] |
* See the Xpra manual for more information.
Use the configure-xpra script during build to append content-type rules to Xpra’s config files.
Pass mappings using --content-type in the format [fallback:]<type>:<key>=<value>.
# Multiple flags can be passed
# If the value contains spaces or special characters, wrap the value in quotes.
USER root
RUN configure-xpra \
--content-type role:gimp-dock=text \
--content-type "title:- Gmail -=text" \
--content-type class-instance:xterm=text \
--content-type commands:my_special_command=picture \
--content-type fallback:role:browser=browser
USER gwb| Type | Format Example | Description |
|---|---|---|
role |
role:gimp-dock=text |
Matches the window's internal role name (e.g. toolbars, docks, dialogs). |
title |
title:- Gmail -=text |
Matches the window title shown in the title bar. |
class-instance |
class-instance:xterm=text |
Matches the X11 class/instance name of the window. |
commands |
command:my_special_command=picture |
Matches the command used to launch the application. |
fallback |
fallback:role:browser=browser (generic fallback) |
Applies when no other match succeeds and is evaluated last as a catch-all rule. |
For more details, see the Xpra tuning documentation.
This image includes a built-in freedesktop-compliant menu file that allows installed apps with .desktop files to be discovered and launched from the UI.
If an app provides a .desktop entry (installed either to /usr/share/applications or ~/.local/share/applications), it will automatically appear in the browser-based menu, no extra configuration needed.
This project follows Semantic Versioning and uses automated releases.
| Format | Example | Description |
|---|---|---|
latest |
- | Always the newest, may include breaking changes. |
v<major> |
v1 |
Latest stable for a major version. No breaking changes. |
v<major>.<minor> |
v1.1 |
Latest patch for a minor version. No new featues. |
v<major>.<minor>.<patch> |
v1.1.0 |
Fixed version, only changes if manually updated. |
Contributions are welcome! Please follow these steps to get set up:
-
Clone the repository:
git clone https://github.com/Aandree5/gui-web-base.git cd gui-web-base -
Install pre-commit hooks (for license headers, linting, etc.):
pip install pre-commit pre-commit install
-
Follow Conventional Commits for commit messages:
feat:- New featurefix:- Bug fixdocs:- Documentation changeschore:- Maintenance or toolingci:- CI/CD or workflow updatesrefactor:- Code improvements without changing behaviorrevert:- Revert a previous commit
-
Open a Pull Request against
main.
-
Debian
trixie-slim
Stable Linux base, optimized for performance and size. -
Xpra
Enables remote access to Linux desktop apps via the web. -
Xpra HTML5 Client
For interacting with GUI apps through Xpra.
If you find the project useful, consider supporting its development! Your donations help cover costs and fund future improvements.
You can support through:
