Image uploader/browser with only Caddy


Recently a lot of people have been asking me about setting up a file server, mainly to serve their screenshots. As I have helped one of my friends set up his, I will put that into a clean guide in this blog post.

Why Caddy?

When people asked me about methods to do this, they always get creative. Some thought an rsync + NGINX stack would be nice, others suggested a Node.JS application to go along. One even suggested me to use PHP applications with Apache.

So why Caddy? Caddy acts as a web server, similarly to NGINX. However, it has Let’s Encrypt built in, no longer needing certbot. It has WebDAV as a clean extension, no longer needing any PHP/Node.JS application as an uploader. Finally, Caddy has a clean and small config syntax.


In this blog post (guide), I’ll assume the target server runs on Ubuntu, which means it would use systemd for service management. Obviously, if the target server runs on NixOS, things would’ve been easier.

Some more obvious requirements would be an internet connection, a domain, and a static IP.


This guide assumes installation into the user home directory, not the system directory. If your server hosts multiple web applications on different users, this guide is not for you.

1. Creating the folders needed

mkdir ~/Pictures # The directory that pictures will go, our www root

2. Getting Caddy

# Since we need a Caddy with WebDAV for file uploads, we'll install Caddy with
# WebDAV. This script should put Caddy in /usr/bin.
curl | bash -s personal http.webdav

3. Setting up Caddy as a systemd service

This file goes to /etc/systemd/system/caddy.service. Replace properties underneath “REPLACE ME” for this to work.

Description=Caddy HTTP/2 web server


;Do not change these
ExecStart=/usr/local/bin/caddy -log stderr -agree=true -conf=./Caddyfile -root=./.caddy
ExecReload=/bin/kill -USR1 $MAINPID

Reloading systemd services

sudo systemctl daemon-reload

4. Configure Caddy

For this section, we’ll assume your domain is would serve images, which would be CloudFlare protected. would not be CloudFlare protected, as CloudFlare breaks WebDAV.

This file goes to ~/Caddyfile. Replace variables such as $username for this to work. This username and password is only used for uploading. {
    root ./Pictures
} {
    basicauth / $username $password
    webdav / {
       scope ./Pictures/

5. Start Caddy up

sudo systemctl start caddy

Testing Caddy

At this point, should return you a webpage under HTTPS.

Troubleshooting Caddy

To access Caddy logs, do sudo journalctl -u caddy.

Uploading screenshots

curl example - $username and $password

curl --basic --user "$username:$password" -T $FILE_PATH

More advanced usages at

ShareX - <username> and <password>

  "DestinationType": "ImageUploader, FileUploader",
  "RequestMethod": "PUT",
  "RequestURL": "$filename$",
  "Body": "Binary",
  "Headers": {
    "Authorization": "Basic $base64:<username>:<password>$"
  "URL": "$filename$"