Self-hosted service
karanhudia/borg-ui avatar
karanhudia/borg-ui

Borg UI: a web front end for BorgBackup, installed with one docker run

Replace complex Borg Backup terminal commands with a beautiful web UI. Create, schedule, and restore backups with just a few clicks.

1,633 stars57 forksPythonAGPL-3.0

At a glance

What is it?
Borg UI wraps the BorgBackup command line in a self-hosted web interface for repositories, schedules and restores. It is an AGPL-3.0 Python application that ships as a multi-architecture container, and the README is explicit about the one case that needs privileged mode.
Who is it for?
Adopt Borg UI if you already run BorgBackup on Linux and want repository health, scheduling and restore browsing in a browser instead of shell history, and if you are comfortable with the AGPL-3.0 obligations that come with it. Skip it if you need Windows as the backup host, if you want a client that pushes from the machine being backed up, or if you would rather not run a privileged container for remote-to-remote SSHFS jobs.
Can I use it commercially?
Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
Is it still maintained?
Yes. The repository last received commits 6 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

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

Editorial analysis

What Borg UI adds on top of the BorgBackup command line

BorgBackup is a deduplicating archiver. It is driven from a terminal, and the README describes Borg UI as a modern web interface that lets you run backups, browse archives, restore files, manage repositories and automate schedules from one place. That is the whole pitch, and it is a narrow one: Borg UI does not replace Borg, it wraps it. The repository layout confirms this. The Python side is a FastAPI application (fastapi, gunicorn, uvicorn and sqlalchemy appear in requirements.txt), and the frontend is a separate Node project with a package.json that only forwards to ./scripts/dev.sh. There is no reimplementation of the Borg format here.

The audience is therefore specific. You are running Borg already, or you intend to, on a Linux host, and the friction you want removed is operational rather than technical: remembering subcommands, reading terminal progress, and reconstructing which archive holds the file you deleted last month. The README also lists remote machine management with SSH key deployment, notifications through Apprise, and support for both BorgBackup 1.x and the BorgBackup 2 beta workflows. Those features point at a homelab or small-server operator with more than one machine to protect, not at an enterprise backup team.

How Borg UI drives Borg: a FastAPI app, a database, and a container that mounts your files

The architecture visible in the repository is a single server process plus a SQLite database plus your filesystem. requirements.txt pins alembic, which means schema migrations are managed rather than hand-rolled, and docker-compose.yml states that DATABASE_URL is auto-configured to /data/borg.db and that SECRET_KEY is auto-generated and persisted to /data/.secret_key. So the state you care about lives in one volume.

The data flow is the part worth understanding before you deploy. Borg UI does not read your files over a network protocol of its own. The container is given filesystem access through bind mounts, and the compose file comments describe the convention: the default mount is ${LOCAL_STORAGE_PATH:-/}:/local:rw, with production examples such as /home/yourusername:/local:rw or /var/www:/local/www:ro. The comment adds that any container path works and /local is just a convention, but that if you pick a different path you must update LOCAL_MOUNT_POINTS to match. That single sentence is the most important line in the deployment documentation. The UI browses what the container can see, so a path that exists on the host but was never mounted is simply invisible, and the failure looks like an empty directory rather than an error.

Repositories themselves are configured in the web UI, not as Docker volumes. The compose file says so directly: repositories can be local paths, SSH/SFTP, or cloud storage. That is a deliberate split. The container holds the application and its database; the repository lives wherever Borg can reach it.

Installing Borg UI with docker run and reaching the first backup

The README's Getting Started section gives a single docker run command. It publishes port 8081, mounts two named volumes for application data and the Borg cache, and bind-mounts a host directory at /local. Replace the host path with the directory you actually want to protect.

bash
docker run -d \
  --name borg-web-ui \
  -p 8081:8081 \
  -v borg_data:/data \
  -v borg_cache:/home/borg/.cache/borg \
  -v /home/yourusername:/local:rw \
  ainullcode/borg-ui:latest

After the container starts, the README says to open http://localhost:8081 and log in with admin / admin123. Change that password before the interface is reachable from anything but your own machine. The README presents those credentials as the way in, not as a hardened default.

If you prefer Compose, the repository ships a docker-compose.yml whose header calls it a zero-configuration setup: SECRET_KEY and DATABASE_URL are derived automatically, LOG_LEVEL defaults to INFO and PORT defaults to 8081. The service maps ${PORT:-8081}:${PORT:-8081} and mounts ${LOCAL_STORAGE_PATH:-/}:/local:rw. That default mounts the entire host root filesystem into the container, and the file labels it development/testing only, with commented production examples underneath.

For a host without Docker, the README offers a native path for Debian or Ubuntu, on bare metal, a VM or an LXC container. It downloads an installer and verifies it against a published SHA-256 checksum before running it:

bash
curl -fsSLO https://github.com/karanhudia/borg-ui/releases/latest/download/install.sh
curl -fsSL https://github.com/karanhudia/borg-ui/releases/latest/download/install.sh.sha256 | sha256sum -c - \
  && sudo bash install.sh

The checksum is fetched over the same channel as the script, so this confirms the download was not truncated or corrupted; it does not establish who produced it. The README points to the installation guide at docs.borgui.com for the full set of native options, and that guide is where the parameters not shown in the README live.

The privileged container and the remote-to-remote case

docker-compose.yml sets privileged: true, and the comment explains why: it is required only for remote-to-remote backups via SSHFS, which mounts remote SSH locations as local filesystems. The same comment states that if you only use local or direct SSH backups, you can disable it. That is a real fork in the deployment, and it deserves more attention than the README gives it.

A privileged container has broad access to the host. Turning the flag off is the right default for the common case, and the project's own file says so. But the moment you want a job that pulls from one remote machine and writes to another, you are back to either enabling privileged mode or restructuring the job. The compose file also carries a warning in capitals to replace the default mount with specific directories in production. Both of these are security-relevant defaults that ship enabled and are documented as comments rather than as prompts in the interface.

The other limitation is platform. Everything in the repository assumes a Linux host: Debian or Ubuntu for the native installer, amd64, arm64 and armv7 for the containers. There is no Windows client mentioned anywhere in the README, and no agent for the machine being backed up in the sense of a desktop sync tool. The pyproject.toml describes a separate package, borg-ui-agent, a lightweight managed agent for Borg UI with a borg-ui-agent console script, but the README's highlights frame remote management as SSH key deployment and storage visibility, not as an installable Windows endpoint. If your source machines are Windows desktops, this is the wrong tool.

Borg UI compared with Borgmatic and with restic front ends

The related searches people run against this project include Borgmatic UI, so the comparison is worth making concrete. Borgmatic is a configuration-driven wrapper: you describe repositories, retention and hooks in YAML, and it runs Borg. Its unit of work is a config file under version control, and its output is a log. Borg UI's unit of work is a record in /data/borg.db, edited through a browser, and its output is a dashboard, live progress and a browsable archive tree. Neither is a superset of the other. A Borgmatic setup is easier to review in a pull request and easier to reproduce on a new host, because the whole configuration is text. A Borg UI setup is easier to operate day to day, because restoring a single file does not require reconstructing an extraction command.

Against restic front ends, the difference is the backend, not the interface. Borg and restic both deduplicate, but Borg UI is bound to Borg's repository format and to the BorgBackup 1.x and 2 beta workflows the README lists. If your existing repositories are restic repositories, a restic UI is the only relevant option; Borg UI cannot read them. The reverse also holds. This is a front end for one archiver, and the search phrase "What is borg ui vs borgbackup" has a short answer: Borg UI is the interface, BorgBackup is the engine that actually writes the deduplicated data.

Licence and the cost of keeping Borg UI current

Borg UI is licensed AGPL-3.0, and the agent package in pyproject.toml declares AGPL-3.0-only. The practical consequence of the AGPL is that if you modify the software and let users interact with it over a network, the licence expects you to offer those users the corresponding source. Running an unmodified container for your own backups does not trigger that obligation in any way that should worry a homelab operator. Forking the interface into something you host for other people is where you need to read the licence text itself rather than a summary. This is a description of the licence, not legal advice.

The maintenance picture is straightforward. The repository is not archived, and the last push was on 2026-09-10. Releases are frequent: v2.2.5 on 2026-06-13, v2.2.6 on 2026-07-15, and v2.3.0-alpha.1 on 2026-08-16. That cadence has a cost that the README does not discuss. The version string in the alpha tag signals that a 2.3 line is in progress alongside the stable 2.2 line, so you are choosing between a stable release and a moving target. requirements.txt is fully pinned, including fastapi==0.141.1, sqlalchemy==2.0.52 and alembic==1.19.1, which means upgrades are deliberate rather than automatic. The alembic dependency also implies that a version upgrade can run a database migration against /data/borg.db, and the README does not document a rollback procedure for that database. Back up /data before upgrading, and treat the alpha tag as something to test on a copy of your setup rather than on the machine whose backups you depend on.

Editorial conclusion

Adopt Borg UI if you already run BorgBackup on Linux and want repository health, scheduling and restore browsing in a browser instead of shell history, and if you are comfortable with the AGPL-3.0 obligations that come with it. Skip it if you need Windows as the backup host, if you want a client that pushes from the machine being backed up, or if you would rather not run a privileged container for remote-to-remote SSHFS jobs. Before trusting it with real data, verify one thing: that a restore you perform through the archive browser produces the files you expect, because the README documents the interface, not a restore verification procedure.

Frequently asked questions

What is Borg UI compared with BorgBackup?

BorgBackup is the deduplicating archiver that writes the repository; Borg UI is a web interface that runs Borg, browses archives, restores files and manages schedules. It does not reimplement the Borg format, so you still need Borg underneath.

What is the default password for Borg UI?

The README says to access the app at http://localhost:8081 with admin / admin123. Those are the starting credentials, so change the password before exposing the interface beyond your own machine.

Which port does Borg UI listen on?

Port 8081. The docker run example publishes 8081:8081, and docker-compose.yml maps ${PORT:-8081}:${PORT:-8081} with the comment that PORT defaults to 8081.

Does Borg UI need a privileged container?

docker-compose.yml sets privileged: true and the comment states it is required only for remote-to-remote backups via SSHFS. The same comment says you can disable it if you only use local or direct SSH backups.

Can Borg UI run without Docker?

Yes. The README gives a native path for Debian or Ubuntu hosts, including bare metal, a VM or an LXC container, using an install.sh script downloaded from the latest release and verified against a published SHA-256 checksum. The README points to docs.borgui.com for the full set of native install options.

Official sources

  1. karanhudia/borg-ui on GitHub
  2. License: AGPL-3.0
  3. Project website
  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/karanhudia-borg-ui.svg)](https://hysenlabs.com/projects/karanhudia-borg-ui)