A blog about software development, written by Daniel Diekmeier. Archive.

Deploying SvelteKit on Uberspace

February 19, 2023

This blog is built with SvelteKit and their Static Adapter. Running npm run build gives me a bunch of what we in the business call: “files”. Now I just need to upload them somewhere.

Uberspace is my favourite web host. I’ve been using them since 2012! The Lesetagebuch has been running on Uberspace since 2013. They taught me to use the command line before I ever thought about becoming a software developer. Give them a try!

Over the years, they have made it incredibly easy to deploy a website – Especially if the website only consists of some static files.

Nevertheless, there were a few things I had to figure out, and now I’m telling you about them!

Always add trailing slashes

When I first deployed the site, I could open the root https://diekmeier.de, but none of the articles. I could navigate to the articles from the root, thanks to SvelteKit’s client side navigation, but that was it. If I tried to open the URLs directly, I got a “Permission Denied” error.

Thank god this is not my first rodeo. After looking into the build output, I noticed how the different pages were saved in the form /posts/example.html. I’d assumed they’d be saved as /posts/example/index.html. Indeed, with this hint, I found the relevant part of documentation:

You must ensure SvelteKit's trailingSlash option is set appropriately for your environment. If your host does not render /a.html upon receiving a request for /a then you will need to set trailingSlash: 'always' to create /a/index.html instead.

That’s exactly what I did, and everything started working immediately.

// +layout.ts
export const prerender = true;
export const trailingSlash = 'always';

Don’t forget your cache headers

I have a habit of running most of the sites that I manage through Lighthouse every now and again. (Probably a little too often.) After deploying the first version of this blog, Lighthouse was furious about missing cache headers on all my files.

Luckily, both SvelteKit and Uberspace are prepared for this. SvelteKit actually produces a dedicated immutable folder that contains most assets and generated files. Fittingly, Uberspace makes it incredibly easy to add custom headers for any path:

$ uberspace web header set diekmeier.de/_app/immutable \
    Cache-Control "max-age=31536000"

With this small change, all my immutable assets are cached for a year!

Automatic™ Deployment

I don’t need a Deployment Pipeline for a blog. I can execute a script, like it’s the 80s! The script builds the static files, and then uses rsync to yeet them onto my server. I love rsync. It is one of those tools in my toolbelt that becomes useful again and again and again.

# scripts/sync.sh
npm run build
rsync --verbose --recursive --delete -e ssh ./build/ danjel7@diekmeier.de:/var/www/virtual/danjel7/diekmeier.de

If I time this, it runs in just under 5 seconds:

$ time scripts/sync.sh
# lots of output later
scripts/sync.sh  5.42s user 0.58s system 128% cpu 4.665 total

Not bad!