---
name: webdav-hetzner
description: >
  Upload / download / list files on Mark's Hetzner VPS (62.238.27.20) over WebDAV, and hand back a
  public CDN URL. Trigger on "залий по вебдаву", "webdav", "webdav-hetzner", "/webdav-hetzner",
  "кинь на цдн через вебдав", "curl PUT на vps", or whenever a file needs a public URL and a plain
  curl (no MCP connector) is the simplest path — e.g. deploying from a shell, Termux, or a cron
  script. For slicing-related uploads inside an MCP session use kiri-slicer / kiri-files instead.
---

# webdav-hetzner

Thin wrapper over the WebDAV endpoint on `webdav.mandrock-files.duckdns.org` (nginx `dav_methods`,
served from the Hetzner VPS `62.238.27.20`). Pure `curl` — no MCP connector, no bearer token. Use it
when you have a file and want it on the CDN with a public link, from any curl-capable environment.

## Endpoints (dual)

| Endpoint | User | Maps to | Public URL of an uploaded file |
|---|---|---|---|
| `/cdn/<path>`  | `claude`      | `/root/cdn/<path>`   | `https://mandrock-files.duckdns.org/<path>` |
| `/html/<path>` | `claude`      | `/var/www/html/<path>` | `http://62.238.27.20/<path>` (bare-IP CDN, kiri-files docroot) |
| `/full/<path>` | `claude-full` | `/root/<path>` (whole VPS — privileged) | not web-served; deploy/backup only |

Prefer **`/cdn/`** for public links — it gives a clean HTTPS URL on `mandrock-files.duckdns.org`
(the `location /` there is open, no auth). Use `/full/` only for writing outside the web roots
(backups, config, deploys); it exposes all of `/root`, so scope paths carefully.

`create_full_put_path on` — intermediate dirs are created automatically on PUT. `autoindex on` —
`PROPFIND`/browser listing works on any directory.

## Credential loading

Creds live in **Craft**, doc **"🔑 Credentials & API Keys"** → section **`### WebDAV —
webdav.mandrock-files.duckdns.org`** (migrated off ClickUp). Read them via `craft_read` (search
`WebDAV`), never hardcode. Two logins:

- `claude` — free endpoint (`/`, `/cdn/`, `/html/`)
- `claude-full` — full endpoint (`/full/`)

**Gotcha:** the key is **case-sensitive** and mixed-case. Copy it verbatim from Craft — a lowercased
copy returns `401`. Keep the secret out of argv/shell-history: write it to a `chmod 600` curl config
and pass `-K`, don't inline `-u user:pass`.

```
# /tmp/dav.conf  (chmod 600)
user = "claude:<KEY-verbatim-from-Craft>"
```

## Upload

```bash
B=https://webdav.mandrock-files.duckdns.org
# Public HTTPS via mandrock-files:
curl -K /tmp/dav.conf -T ./report.pdf "$B/cdn/docs/report.pdf"
#   -> https://mandrock-files.duckdns.org/docs/report.pdf

# Bare-IP CDN (kiri-files docroot):
curl -K /tmp/dav.conf -T ./img.png "$B/html/img.png"
#   -> http://62.238.27.20/img.png

# Privileged (whole VPS), needs claude-full creds:
curl -K /tmp/dav-full.conf -T ./backup.tar.gz "$B/full/backups/backup.tar.gz"
```

Expected: `201 Created` (new) or `204 No Content` (overwrite). Always verify with a `curl -I` on the
public URL → `200`.

## Download

```bash
curl -K /tmp/dav.conf -o out.pdf "$B/cdn/docs/report.pdf"
# public files (under /cdn/, /html/) are also just plain GETs, no auth:
curl -o out.pdf https://mandrock-files.duckdns.org/docs/report.pdf
```

## List

```bash
# WebDAV PROPFIND (depth 1) — directory listing:
curl -K /tmp/dav.conf -X PROPFIND -H "Depth: 1" "$B/cdn/docs/"
# or the human autoindex page:
curl -K /tmp/dav.conf "$B/cdn/docs/"
```

## Delete / move

```bash
curl -K /tmp/dav.conf -X DELETE "$B/cdn/docs/report.pdf"
curl -K /tmp/dav.conf -X MOVE -H "Destination: $B/cdn/docs/final.pdf" "$B/cdn/docs/report.pdf"
```

## When to use this vs kiri-files

- **webdav-hetzner (this):** direct file mount over HTTP — arbitrary paths, any curl-capable
  environment (shell, Termux, cron), no MCP session needed. Best for ad-hoc "publish this file and
  give me a URL" and for writing outside the MCP allowlist (via `/full/`).
- **kiri-files (MCP):** tool-call wrapper (`upload`/`list`/`delete`, bearer token, allowlisted to
  `/var/www/html` + `/root/projects/3d_print/output`). Best inside an MCP-connected Claude session,
  especially the slicing flow. Safer default there because of the allowlist.

Rule of thumb: **from a shell → WebDAV; from an MCP tool session → kiri-files.** Same files can end
up on the same CDN; they're two transports, not two stores.
