---
title: Sync servers
description: What tagwerk's built-in sync needs from a WebDAV server, which address to enter for each kind of server, and how to find out why a connection fails.
reviewed: 2026-10-29
---

## What tagwerk needs from a server {#requirements}

The built-in sync speaks plain WebDAV. It needs no app, plug-in or account on the server beyond a
user that may read and write one folder. This chapter is for whoever runs that server; how to set
up the sync in the app is in [Sync](../sync/index.md#setup).

| Method | What tagwerk uses it for |
| --- | --- |
| `OPTIONS` | The connection test and the start of a sync. The answer has to carry a `DAV` header. |
| `PROPFIND` | `Depth: 0` to find the WebDAV address and check the notes folder; `Depth: 1` to list folders. `Depth: infinity` is tried once for the whole tree; a refusal is remembered and asked again after two weeks. |
| `GET` | Downloading a note, a template, the tag colours or the licence. |
| `PUT` | Uploading. Answered with 200, 201 or 204. |
| `MKCOL` | Creating the notes folder and the folders below it (year, month, `templates/`, `settings/`). |
| `DELETE` | Removing the connection test's file, a template removed in the app, and the tag colours file once every colour is cleared. A day note is never deleted. |

Beyond the methods:

- **Conditional writes.** A new file is sent with `If-None-Match: *`, a changed one with
  `If-Match` and the ETag tagwerk last saw. A server that holds something else has to answer
  `412 Precondition Failed`; tagwerk then compares with what is really there instead of
  overwriting it. A weak ETag (`W/"..."`) is accepted for comparing; a write based on it goes out
  without a condition, because `If-Match` cannot match a weak tag. A `PUT` answered without an
  ETag is fine too: tagwerk asks for it with a `PROPFIND`.
- **Basic authentication on every request**, the credentials encoded as UTF-8. No cookies and no
  session: each request carries its own credentials, so one account's session can never stand in
  for another's. Servers that accept only other methods (NTLM, OAuth or OpenID Connect tokens)
  cannot be used.
- **HTTPS.** `http://` works and is warned about, because Basic authentication sends the password
  readable to anybody on the way. Certificates have to be valid for the name in the address;
  tagwerk has no way to accept a self-signed one.
- **Redirects.** A redirect within the same scheme, host and port is followed with the credentials.
  One to another host or from `http://` to `https://` is followed without them, and the app then
  names the address it was sent to. From `https://` to `http://` is not followed at all.
- **Status codes tagwerk acts on.** `401` is a rejected sign-in, `403` on a `PUT` a read-only
  folder, `507` a full quota, `412` a version that changed in between. `5xx`, timeouts and lost
  connections are retried three times before they are reported.

tagwerk uses the system's proxy settings. HTTP/2 is used where the server offers it, HTTP/1.1
otherwise.

## Which address to enter {#address}

The wizard needs the address of the account's WebDAV root. For Nextcloud and ownCloud it finds that
itself; for every other server, enter it in full.

| Server | Enter | tagwerk uses |
| --- | --- | --- |
| Nextcloud, ownCloud | `https://cloud.example.org` | `https://cloud.example.org/remote.php/dav/files/USER/` |
| Nextcloud in a sub-path | `https://example.org/nextcloud` | `https://example.org/nextcloud/remote.php/dav/files/USER/` |
| An address with `remote.php` or `/dav/` in it | the address as it is | the address as it is |
| Any other WebDAV server | the full WebDAV address of the account | the address as it is |

An address without a scheme gets `https://`. Unless the address already names a WebDAV path,
tagwerk asks three candidates with `PROPFIND` and `Depth: 0`: first the derived Nextcloud path
`remote.php/dav/files/USER/`, then `remote.php/webdav/` - the same files for whoever signed in,
which is what a Nextcloud answers when the sign-in name is an email address rather than the user
id - then the address as entered. The first that answers `207 Multi-Status`
is used - any other answer, `200` and `405` included, does not count. When neither answers `207`,
the strongest refusal is reported: a rejected password before a forbidden path before a server
error.

## The folder on the server {#layout}

In step 2 of the wizard the user picks or creates a folder below the WebDAV root. Below it, the sync
writes:

```
Tagwerk/
  2026/
    10/
      2026-10-28.md
  templates/
    template.md
    template-monday.md
  settings/
    tagwerk.colors
    tagwerk.license
```

`Tagwerk/` stands for the chosen folder. Day notes are filed by year and month, whatever layout the
notes folder on the device has. The connection test writes `.tagwerk-connection-test.txt` into the
folder and deletes it again. Any other file in the folder is left alone; conflict copies stay on the
device that made them and are never uploaded.

A day note is only ever replaced, never deleted. What the sync carries and by which rule is in
[Sync](../sync/index.md#what-moves).

## Notes on particular servers {#providers}

Most WebDAV servers need nothing beyond an address, a name and a password. The notes below are the
places where a server behaves differently from what its address suggests - learnt on real accounts,
dated where it matters. A server that is not listed here is not a server that will not work.

### Nextcloud {#nextcloud}

- Enter the plain server address; the WebDAV path is derived.
- The browser sign-in (*Sign in through the browser (Nextcloud)*) uses Nextcloud's Login Flow v2:
  the server issues an app password for tagwerk, which appears under *Settings → Security → Devices
  & sessions* and can be revoked there. Tested against a real Nextcloud in September 2026.
- With two-factor authentication on the account, the account password fails at *Sign-in
  accepted*. Use the browser sign-in or an app password.
- Nextcloud refuses `Depth: infinity` by default. tagwerk then lists the folders one by one: one
  request for the folder, one per year, one per month.
- On some installations writing is many times slower than reading. *Server speed* in the app shows
  reads and writes apart, with a text to hand to the hosting provider.
- An app password without access to the file system, or a rule of the "Files access control" app,
  lets the sign-in through and keeps it from every folder. The app says *The sign-in works, but the
  server keeps it away from the files.*
- After several wrong passwords Nextcloud's brute-force protection delays its answers and may
  answer `423`. Wait before trying again.
- A shared folder appears only after the account has accepted the share, inside the folder that
  account files received shares into.

### ownCloud {#owncloud}

- ownCloud Server takes the same address as Nextcloud; the path is derived the same way.
- The browser sign-in is Nextcloud's. With ownCloud, enter the account password or an app password.
- ownCloud Infinite Scale and OpenCloud sign in through OpenID Connect and serve WebDAV under other
  paths. tagwerk signs in with Basic authentication only and has not been tested against them.

### Synology {#synology}

- Install the *WebDAV Server* package in DSM and enable HTTPS there; its default HTTPS port is
  5006 (5005 for HTTP).
- Enter the address with the port, for example `https://nas.example.org:5006`.
- A NAS usually starts with a self-signed certificate, which tagwerk does not accept: the test stops
  at *Connection and encryption*. Give the NAS a certificate from a public authority, for example
  Let's Encrypt in DSM, and use exactly the name it was issued for - not the IP address.
- Not yet tested against a real DiskStation.

### HiDrive {#hidrive}

- Enter the WebDAV address your provider gives in its help pages.
- The top level is read-only: creating folders or files there answers `403`. Your own folder is
  `/users/USER/`; in step 2 of the wizard open `users`, then your account, and create or pick the
  notes folder there.
- HiDrive answers `403` rather than `404` for every path it does not have. tagwerk tries the next
  candidate and tries to create a missing folder before it believes a `403`.
- WebDAV is not part of every plan. At IONOS the basic plans include it; at STRATO the private plans
  get it only with the protocol package. Without it the test fails although address and password
  are right. Tested with an IONOS account in August 2026.

### Hetzner Storage Box {#storage-box}

- Every sub-account has a host of its own: `https://u123456-sub1.your-storagebox.de`, not the box's
  `https://u123456.your-storagebox.de`. At the box's own name a sub-account is rejected with `401`,
  which looks exactly like a wrong password. The app recognises the case and names the right address.
- Enter `https://`. With `http://` the box redirects to `https://`, the credentials are dropped on
  the way, and the app reports the redirect.
- The box is Apache with `mod_dav`, so everything in the next section applies. Tested in August and
  September 2026, including two devices on one folder.

### Apache with mod_dav, and nginx {#apache-nginx}

- Apache marks the ETag of a file weak (`W/"..."`) during the second it was written and strong
  afterwards. tagwerk compares the two spellings as one version, so a note it has just uploaded is
  not downloaded again.
- The `Allow` header of an `OPTIONS` answer may leave out `PUT` and `MKCOL` although both work.
  tagwerk does not read it.
- `Depth: infinity` may be refused with `403`; tagwerk lists folder by folder instead.
- nginx's own WebDAV module answers neither `PROPFIND` nor `OPTIONS`; it needs the `dav-ext`
  module as well. Not yet tested.

### Other servers {#other-servers}

Not yet tested, and the next on the list: magentaCLOUD (Nextcloud-based, with an app password),
Infomaniak kDrive and Koofr. Any server that speaks WebDAV with Basic authentication over HTTPS
should work; the [checklist](#checklist) below says within minutes whether it does.

## Troubleshooting {#troubleshooting}

The connection test (*Test connection*, and every step of the wizard) stops at the first stage that
fails and shows its message. Behind a system proxy the stages *Server name resolves* and
*Connection and encryption* are passed without a check, because the proxy makes the connection;
problems there show at *Sign-in accepted*.

| Stage | Message | Usual cause | Fix |
| --- | --- | --- | --- |
| *Network available* | *This device has no network connection.* | The device is offline. | Check Wi-Fi or mobile data. |
| *Server name resolves* | *The server address is not a valid URL.* | A typo in the address. | Enter it as in a browser. |
| *Server name resolves* | *The server name could not be found.* | A typo, a stale dynamic-DNS name, or a name that exists only in the home network. | Correct the name; use one that resolves everywhere. |
| *Connection and encryption* | *The server name resolves, but the server does not answer.* | Server offline, firewall, missing port forwarding, wrong port. | Check the port in the address and the forwarding on the router. |
| *Connection and encryption* | *The server takes too long to answer.* | A weak connection, a VPN or proxy, an overloaded server. | Try again; look at *Server speed*. |
| *Connection and encryption* | *The server's security certificate is not trusted.* | A self-signed certificate. | A certificate from a public authority, e.g. Let's Encrypt. |
| *Connection and encryption* | *The certificate belongs to a different server name.* | An IP address or another name than the certificate's. | Use exactly the name on the certificate. |
| *Connection and encryption* | *The server's security certificate has expired.* | The renewal did not run. | Renew the certificate. |
| *Connection and encryption* | *The encrypted connection could not be established.* | Only outdated TLS versions, or a proxy in between. | Check the server's TLS configuration. |
| *Sign-in accepted* | *The server answers but rejects the sign-in.* | Wrong password, two-factor authentication without an app password, or the wrong host for a sub-account. | Check name and password; use an app password; check the host. |
| *Sign-in accepted* | *The server sent the request somewhere else, and that address refused it.* | `http://` where the server wants `https://`, or a bare domain forwarded to `www.`. | Enter the address the message shows. |
| *Sign-in accepted* | *Signed in, but access to this area is denied.* | The account may not open that path. | Check the account's permissions or the address. |
| *Sign-in accepted* | *The address answers, but not as a WebDAV server.* | No candidate answered `207`: a web page, a router login, the wrong path. | Enter the full WebDAV address. |
| *Sign-in accepted*, *Write test* | *The server reports an internal error.* | A fault on the server. | Read the server's log. |
| *WebDAV and notes folder* | *The address answers, but not as a WebDAV server.* | The `OPTIONS` answer has no `DAV` header. | Enable WebDAV for this path. |
| *WebDAV and notes folder* | *The notes folder does not exist and could not be created.* | `MKCOL` was refused. | Create the folder in the web interface, or choose one the account may write to. |
| *WebDAV and notes folder* | *Signed in, but access to this area is denied.* | The folder answered `403` and refused `MKCOL` too. | Grant access, or choose another folder. |
| *Write test* | *Reading works, but writing is not allowed.* | `PUT` answered `403`: read-only share or folder. | Grant write access. |
| *Write test* | *The storage on the server is full.* | `PUT` answered `507`. | Free up space or raise the quota. |

A `401` at the wrong host cannot be told apart from a wrong password by the answer alone. Before
checking the password a third time, check the address - the host above all.

## A checklist for admins {#checklist}

The requests the app makes can be repeated with `curl`, which prompts for the password. Replace
the address with the WebDAV root and `USER` with the account.

1. The WebDAV root answers with a `DAV` header:

   ```
   curl -i -u USER -X OPTIONS https://dav.example.org/remote.php/dav/files/USER/
   ```

2. The root and the notes folder list themselves with `207 Multi-Status`:

   ```
   curl -i -u USER -X PROPFIND -H "Depth: 0" https://dav.example.org/remote.php/dav/files/USER/Tagwerk/
   ```

3. A file can be written and deleted; the `PUT` answers 200, 201 or 204:

   ```
   curl -i -u USER -T test.md https://dav.example.org/remote.php/dav/files/USER/Tagwerk/test.md
   curl -i -u USER -X DELETE https://dav.example.org/remote.php/dav/files/USER/Tagwerk/test.md
   ```

4. Conditional writes are honoured: the second of these two must answer `412`.

   ```
   curl -i -u USER -T test.md -H "If-None-Match: *" https://dav.example.org/remote.php/dav/files/USER/Tagwerk/test.md
   curl -i -u USER -T test.md -H "If-None-Match: *" https://dav.example.org/remote.php/dav/files/USER/Tagwerk/test.md
   ```

5. On a `401`, run the same request against the other names the server has, and add `-v` to see
   whether the answer comes from the host that was asked or from one it redirected to.
6. Delete the test files afterwards.

Do not repeat a failed sign-in in quick succession: Nextcloud and Storage Boxes count failed
attempts and slow down or lock the account. In the app, *Settings → Help → Server speed* gives the
timings of every request type as text for a support request.

## The alternative: a folder of your own {#own-folder}

Without the built-in sync, the server needs nothing from tagwerk. The notes lie in a folder on the
device (*Settings → Storage → Choose folder...*), and a program of your choice carries that folder:
Syncthing, or a client that keeps a local folder in two-way sync with a server. tagwerk reads the
files that program writes; if it writes the day you are typing in, that version is kept beside it
as a conflict copy.

Conflicts follow the rules of that program. tagwerk recognises the copies these programs write and
lists them under *Days that exist twice*, beside its own:

| Written by | Name of the copy |
| --- | --- |
| tagwerk | `2026-10-28.sync-conflict-tagwerk.md` |
| Syncthing | `2026-10-28.sync-conflict-20261028-101010-ABCDEFG.md` |
| Nextcloud client | `2026-10-28 (conflicted copy 2026-10-28 101010).md` |
| Dropbox | `2026-10-28 (Tom's conflicted copy 2026-10-28).md` |

Copies of templates are recognised the same way, for example
`template-monday.sync-conflict-20261028-101010-ABCDEFG.md`. How to settle a conflict is in
[Sync](../sync/index.md#conflicts-settle).
