Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
d4b3d7a
webdav: serve archive contents read-only via HTTP, #9942
ThomasWaldmann Jul 23, 2026
e7047c4
webdav: implement WebDAV (class 1), so archives can be mounted, #9942
ThomasWaldmann Jul 23, 2026
4ea6241
webdav: fix HTTP response splitting via file names, harden Location
ThomasWaldmann Jul 23, 2026
5c662e3
webdav: make the heading a breadcrumb for quick navigation
ThomasWaldmann Jul 23, 2026
4838896
webdav: reject DTDs in PROPFIND bodies (XML bomb defense)
ThomasWaldmann Jul 23, 2026
b6110ba
webdav: cache decrypted chunks (BORG_MOUNT_DATA_CACHE_ENTRIES)
ThomasWaldmann Jul 23, 2026
ccbd51e
webdav: fix tests on Windows (illegal characters in file names)
ThomasWaldmann Jul 23, 2026
b12edb0
webdav: silence bandit B405/B314 for the (guarded) XML parse
ThomasWaldmann Jul 23, 2026
4959c06
webdav: daemonize by default, like borg mount
ThomasWaldmann Jul 23, 2026
bc4b2ae
webdav: test non-ASCII file name percent-encoding on all platforms
ThomasWaldmann Jul 23, 2026
7c80afc
webdav: parse PROPFIND with expat, drop xml.etree.fromstring
ThomasWaldmann Jul 23, 2026
7aa9381
webdav: download any directory as a (PAX) tar archive
ThomasWaldmann Jul 23, 2026
6bafdbe
webdav: sanitize + suppress response-splitting on the tar Content-Dis…
ThomasWaldmann Jul 23, 2026
56bf4f0
webdav: don't link the current directory in the breadcrumb heading
ThomasWaldmann Jul 23, 2026
dffca42
webdav: test the command itself, special files and request limits
ThomasWaldmann Jul 23, 2026
ad4818d
webdav: make header CR/LF sanitization explicit (response splitting)
ThomasWaldmann Jul 23, 2026
6d0937d
webdav: document known WebDAV client issues
ThomasWaldmann Jul 23, 2026
5e76210
webdav: TCP_NODELAY and output buffering at the HTTP level
ThomasWaldmann Jul 24, 2026
49835eb
webdav: keep the query string when redirecting to add a trailing slash
ThomasWaldmann Jul 24, 2026
8f896b7
webdav: abort when a non-empty item has no chunks list
ThomasWaldmann Jul 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 172 additions & 0 deletions docs/man/borg-webdav.1
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
.\" Man page generated from reStructuredText
.\" by the Docutils 0.22.4 manpage writer.
.
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "borg-webdav" "1" "2026-07-23" "" "borg backup tool"
.SH Name
borg-webdav \- Serve archive contents via a read-only WebDAV / HTTP server on localhost.
.SH SYNOPSIS
.sp
borg [common options] webdav [options]
.SH DESCRIPTION
.sp
This command serves the contents of the selected archives via a read\-only
WebDAV / HTTP server, so the archive contents can be:
.INDENT 0.0
.IP \(bu 2
browsed and downloaded with a web browser,
.IP \(bu 2
mounted as a read\-only network file system, using the WebDAV client
built into most operating systems and file managers.
.UNINDENT
.sp
Mounting examples:
.INDENT 0.0
.IP \(bu 2
Windows Explorer: \(dqMap network drive\(dq \-> \fBhttp://localhost:8000/\fP
(or on the command line: \fBnet use Z: http://localhost:8000/\fP).
.IP \(bu 2
macOS Finder: \(dqGo > Connect to Server\(dq (Cmd\-K) \-> \fBhttp://localhost:8000\fP\&.
.IP \(bu 2
GNOME Files / KDE Dolphin: open \fBdav://localhost:8000/\fP\&.
.IP \(bu 2
Linux kernel mount: \fBmount \-t davfs http://localhost:8000/ /mnt/point\fP
(needs the davfs2 package).
.UNINDENT
.sp
The server listens on localhost (127.0.0.1) only and offers no
authentication and no encryption \- anything that can connect to
localhost TCP ports on the machine can read the served archive contents.
.sp
The top level lists the selected archives (use the archive filter options
to select fewer archives); below that, the archive contents can be
browsed like a directory tree. The directory tree of an archive is built
in memory when it is first entered, so expect some delay for big archives.
.sp
Any directory can be downloaded as a tar archive by appending \fB?tar\fP to its
URL (the web browser listings show a download icon next to the heading for this).
Unlike a plain file
download, the tar preserves POSIX metadata (owner, group, mode, sub\-second
timestamps, symlinks, special files, xattrs, ACLs), so it is the metadata\-
lossless way to restore a whole directory tree over this server. It is a PAX
format tarball, streamed uncompressed.
.sp
Notes:
.INDENT 0.0
.IP \(bu 2
Plain (non\-tar) file downloads do not preserve any POSIX metadata (owner,
group, mode, timestamps, xattrs, ACLs). Use the \fB?tar\fP download above, or
\fBborg extract\fP / \fBborg export\-tar\fP, for full\-fidelity restores.
.IP \(bu 2
Symbolic links and special files (devices, fifos, sockets) are shown
in the web browser listings, but are neither followed nor downloadable
individually, and they are not visible in WebDAV\-mounted directories
(WebDAV has no concept of them). They are, however, included in \fB?tar\fP
downloads.
.IP \(bu 2
Damaged files (with chunks missing in the repository) cause the
download connection to be aborted \- the server never silently serves
corrupted file content.
.IP \(bu 2
The Windows WebDAV client limits file downloads to about 47 MiB by
default (\fBFileSizeLimitInBytes\fP registry value) \- use a web browser
or another WebDAV client to download bigger files.
.UNINDENT
.sp
Recently used file content chunks are kept decrypted in an in\-memory cache,
so that the many small, sequential range requests a mounted file system
does for a big file do not re\-fetch and re\-decrypt the same chunk over and
over. As for \fBborg mount\fP, the \fBBORG_MOUNT_DATA_CACHE_ENTRIES\fP environment
variable sets the number of cached chunks (default: number of CPUs);
additional memory usage can be up to the chunk size times this number.
.sp
Unless the \fB\-\-foreground\fP option is given, the command daemonizes and runs
in the background until it is stopped by sending it a signal (e.g. \fBkill\fP
sends SIGTERM), which shuts the server down and releases the repository lock.
In the foreground, ^C / SIGINT stops it. Daemonizing is not available on
Windows, so the command always stays in the foreground there.
.SH OPTIONS
.sp
See \fIborg\-common(1)\fP for common options of Borg commands.
.SS options
.INDENT 0.0
.TP
.B \-f\fP,\fB \-\-foreground
stay in foreground, do not daemonize
.TP
.BI \-\-port \ PORT
TCP port to listen on (on localhost); default: 8000
.UNINDENT
.SS Archive filters
.INDENT 0.0
.TP
.BI \-a \ PATTERN\fR,\fB \ \-\-match\-archives \ PATTERN
only consider archives matching all patterns. See \(dqborg help match\-archives\(dq.
.TP
.BI \-\-sort\-by \ KEYS
Comma\-separated list of sorting keys; valid keys are: timestamp, archive, name, id, tags, host, user; default is: timestamp
.TP
.BI \-\-first \ N
consider the first N archives after other filters are applied
.TP
.BI \-\-last \ N
consider the last N archives after other filters are applied
.TP
.BI \-\-oldest \ TIMESPAN
consider archives between the oldest archive\(aqs timestamp and (oldest + TIMESPAN), e.g., 7d or 12m.
.TP
.BI \-\-newest \ TIMESPAN
consider archives between the newest archive\(aqs timestamp and (newest \- TIMESPAN), e.g., 7d or 12m.
.TP
.BI \-\-older \ TIMESPAN
consider archives older than (now \- TIMESPAN), e.g., 7d or 12m.
.TP
.BI \-\-newer \ TIMESPAN
consider archives newer than (now \- TIMESPAN), e.g., 7d or 12m.
.UNINDENT
.SH EXAMPLES
.INDENT 0.0
.INDENT 3.5
.sp
.EX
# Serve all archives of the repository on http://127.0.0.1:8000/,
# then browse and download files with a web browser.
$ borg webdav

# Serve only one archive on a different port.
$ borg webdav \-\-port 8123 \-\-match\-archives my\-archive
.EE
.UNINDENT
.UNINDENT
.SH SEE ALSO
.sp
\fIborg\-common(1)\fP
.SH Author
The Borg Collective
.\" End of generated man page.
1 change: 1 addition & 0 deletions docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ Usage
usage/info
usage/analyze
usage/mount
usage/webdav
usage/recreate
usage/tar

Expand Down
66 changes: 66 additions & 0 deletions docs/usage/webdav.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
.. include:: webdav.rst.inc

Examples
~~~~~~~~

::

# Serve all archives of the repository on http://127.0.0.1:8000/,
# then browse and download files with a web browser.
$ borg webdav

# Serve only one archive on a different port.
$ borg webdav --port 8123 --match-archives my-archive


Client notes and known issues
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

WebDAV's rough edges are almost all on the client side, and a *read-only* server
(like this one) hits a specific subset of them. A plain web browser avoids most of
these - the notes below matter mainly when *mounting* the server as a file system.

**Windows Explorer** (the "WebClient" / mini-redirector)

- Downloads are limited to about 47 MiB by default (the ``FileSizeLimitInBytes``
registry value). Bigger files fail when copied from a mapped drive - use a web
browser (including for the ``?tar`` directory download) or another WebDAV client.
- The ``WebClient`` service must be running for ``net use`` / "Map network drive"
to work; if it is stopped, mounting silently fails.
- Windows refuses HTTP Basic authentication over plain HTTP by default (only over
HTTPS). This does not matter now (the server has no authentication), but it is a
wall for any future networked, authenticated setup.
- Explorer is chatty (a PROPFIND per navigation, many short connections), so
browsing large directories over a mount can feel slow.

**macOS Finder** (``mount_webdav`` / WebDAVFS)

- Finder tries to write ``.DS_Store``, ``._*`` (AppleDouble) and ``.Trash`` files
into every folder it opens. On this read-only server those writes are rejected
(the file system is read-only); Finder tolerates it but may occasionally show a
spurious "operation could not be completed" dialog. This is harmless.
- WebDAVFS caches directory listings; a stale view usually clears on unmount and
remount.

**Linux davfs2**

- davfs2 uses WebDAV locking by default and will try to LOCK files it opens, which
a read-only server rejects. Set ``use_locks 0`` in ``davfs2.conf`` (or the
per-mount config) to avoid the failed lock attempts. davfs2 also caches whole
files in a local cache directory.
- The GNOME (gvfs) and KDE (KIO) DAV backends work without such tweaks, but are
also PROPFIND-heavy on large directories.

**Protocol-level (any client)**

- ``PROPFIND`` with ``Depth: infinity`` (a recursive enumeration that can be very
expensive) is refused with ``403``, as permitted by RFC 4918. Well-behaved
clients use ``Depth: 0`` or ``1``.
- Collections must be addressed with a trailing slash; a request for ``/dir`` is
redirected to ``/dir/``.
- Symbolic links and special files (devices, fifos, sockets) have no
representation in WebDAV, so they are not visible in a mounted file system. They
are shown in the web browser listings and are included in ``?tar`` downloads.
- WebDAV transfers file contents plus modification time and size, but no owner,
group, mode, xattrs or ACLs. Use the ``?tar`` directory download (or
``borg extract`` / ``borg export-tar``) when you need a full-fidelity restore.
Loading
Loading