Deploy Deploy Caddy for Single Page Apps

Host React, Vue or Svelte single page apps with Caddy

Deploy Deploy Caddy for Single Page Apps

Just deployed

Deploy and Host self hosted Caddy SPA Hosting (Static Hosting for Single Page Apps) on Railway

This template serves your built React, Vue or Svelte app from /srv with try_files falling back to index.html, so a deep link like /settings/profile never 404s on refresh.

About Hosting Caddy SPA Hosting open-source software on Railway (self hosted Caddy for single page apps template)

This template runs one Caddy service named caddy that serves your built React, Vue or Svelte app from /srv, filled from the repo www/ folder.

Why Deploy Caddy SPA Hosting, the Nginx alternative on Railway (Railway Free Trial)

Nginx can serve a React or Vue build, but you have to write the try_files fallback to /index.html yourself. Copy your dist output into www/ and Railway serves it from /srv.

Railway is a singular platform to deploy your infrastructure stack. Railway will host your infrastructure so you don't have to deal with configuration, while allowing you to vertically and horizontally scale it.

By deploying Caddy SPA Hosting on Railway, you are one step closer to supporting a complete full-stack application with minimal burden. Host your servers, databases, AI agents, and more on Railway.

Railway vs Other Hosting Providers and VPS for Caddy SPA Hosting self hosting

This table compares the Railway Caddy SPA template against common raw VPS and cloud options, focused on what you set up yourself for deep links to work.

ProviderWhat You Get with RailwayWhat You Get with the Other Provider
DigitalOceanA Caddy service with the SPA fallback already set, redeployed when you push.A Droplet where you install Caddy, write the try_files fallback, and patch the OS.
AWSThe same Caddy service with no IAM or bucket rules to set before deep links work.S3 or EC2 setups that need error document rules or a CloudFront function for index.html fallback.
HetznerGit-driven redeploys with no SSH or deploy script on your side.Cheap servers with generous bandwidth, but Caddy, systemd and builds are all manual.

A VPS gives you more knobs, while the template gets a React build deep-linking correctly with less upkeep.

Common Use Cases for hosted Caddy SPA Hosting

  • Vite React build with React Router: Run npm run build, copy dist into the repo www/ folder, and push. Deep links like /settings/profile fall back to index.html, so React Router handles them instead of Caddy returning a 404 on refresh.
  • Vue or Svelte history-mode routing: Any SPA using the HTML5 history API gets the same fallback. One try_files {path} /index.html line covers every client route.
  • Long cache headers on hashed assets: Vite emits content-hashed filenames, so assets/ can be cached for a long time. Keep index.html on max-age=0, must-revalidate so new deploys show up right away.
  • A staging copy of a frontend: Deploy a second copy of the template with a different build to check a branch first. It runs as its own Railway service, so production files stay untouched.
  • API behind the same domain later: When your frontend needs a backend on the same origin, set caddy.UPSTREAM to its host:port. Caddy switches to reverse-proxy mode without Caddyfile edits, which sidesteps CORS setup.

Dependencies for Caddy SPA Hosting Docker hosted on Railway

This template runs as one Caddy service, so there is little to wire up. No database, no Redis, no second container.

Deployment Dependencies for Managed Caddy SPA Hosting Service (Web Server)

Run your frontend build, then copy the dist folder into www so it lands at /srv in the container. The service has no deploy-time inputs and no secrets.

Implementation Details for Caddy SPA Hosting (Using Caddy official docker image)

The image is ghcr.io/onepush-dev/caddy:2.11.7, wrapping the official caddy:2.11.7-alpine build with no extra plugins.

How does Caddy SPA Hosting compare against other ways to host a single page app

Caddy SPA Hosting vs Nginx (Nginx Alternative)

  • Config size: The SPA fallback is one line, try_files {path} /index.html. Nginx needs try_files $uri /index.html; inside a location block.
  • Compression and TLS: encode zstd gzip is already set here. Nginx wins if you need a mature module ecosystem or config you've already tuned.
  • Ops familiarity: Plenty of teams already know Nginx's failure modes. Caddy has a short learning curve.

Caddy SPA Hosting vs Netlify (Netlify Alternative)

  • Control: You own the container, the Caddyfile and the cache headers. Netlify includes a CDN and build pipeline that this template doesn't.
  • Builds: Netlify builds on every push. Here you run npm run build yourself and copy dist into www/.
  • Where Netlify wins: Previews, edge functions and global CDN delivery would need to be built yourself with Caddy.

Caddy SPA Hosting vs Vercel (Vercel Alternative)

  • Deploy flow: Vercel creates preview URLs for every branch. This template deploys whatever you last copied into www/.
  • Framework handling: Vercel configures routing for Next.js, Vite and others. Here the try_files line is already set for you.
  • Where Vercel wins: Zero-config previews and framework-aware builds save real time for teams.

Caddy SPA Hosting vs serve (npm) (serve Alternative)

  • Purpose: npx serve dist is a quick local static server, not a production web server.
  • Cache headers: Caddy lets you set Cache-Control for hashed assets and index.html separately.
  • Where serve wins: For a five-minute local preview with no config, serve is faster.

How to use Caddy SPA Hosting (the OSS web server and reverse proxy)?

Day one is a build, copy, push loop. Caddy serves the built SPA from /srv, which comes from the repo www/ folder.

  1. Fork the template repo so you can change www/ and the Caddyfile.
  2. In your React, Vue or Svelte app, run npm run build to produce dist.
  3. Copy the contents of dist into the repo's www/ folder.
  4. Commit and push. Railway rebuilds the caddy service and serves the new files.
  5. Open a deep link like /settings/profile and refresh. A 200 with your app means the try_files fallback to index.html works.
  6. Add cache headers for hashed assets in the Caddyfile. Cache hashed files for a year and make index.html always revalidate.
try_files {path} /index.html

route {
    header /assets/* Cache-Control "public, max-age=31536000, immutable"
    header /index.html Cache-Control "public, max-age=0, must-revalidate"
}

How to self host Caddy SPA Hosting on other VPS Services (Caddy self hosting guide)

You can run this same Caddy setup on any VPS with Docker. The steps below assume a Linux box with Docker and Git installed, and that your domain points at the server.

Clone the Repository

git clone https://github.com/your-org/caddy-spa-hosting.git
cd caddy-spa-hosting

Build your React, Vue or Svelte app first and copy its dist output into the repo www/ folder. Caddy serves that folder from /srv.

Install Dependencies

The stack needs only Docker and Docker Compose, so there is no Node runtime on the server.

Configure Environment Variables

Create a .env file next to the compose file:

PORT=8080
UPSTREAM=

Leave UPSTREAM empty for static mode. Set it to your-api-host:3000 only if you want Caddy to reverse-proxy an API on the same domain.

Start the Caddy SPA Hosting Application

docker compose up -d --build
curl -I http://localhost:8080/settings/profile

The deep-link request should return 200 and the app's index.html, which is the try_files fallback doing its job.

Official Pricing of Caddy SPA Hosting (Caddy pricing)

Caddy is free and open source under the Apache-2.0 license, so there is no license fee. You pay only for the infrastructure it runs on. Check Railway's pricing page for current rates.

Caddy SPA Hosting cloud vs self hosted comparison (Pricing, features, costs, and more)

Running Caddy SPA Hosting on Railway means paying for one small Caddy service and nothing else. Here's how the two paths compare.

Monthly cost of self hosting Caddy SPA Hosting on Railway

A single Caddy service serving a static React, Vue or Svelte build is light on resources. Confirm current rates on Railway's pricing page, since they change.

System Requirements for Hosting Caddy SPA Hosting on a VPS

Caddy is a single static binary, so a small VPS with a few hundred megabytes of RAM is plenty for a static site. You need Docker or the Caddy binary installed and a public IP for DNS.

Frequently Asked Questions (FAQs)

Why do deep links 404 on some hosts?

Most static hosts look for a file at the exact path, so /settings/profile returns 404 on refresh.

Do I need to set cache headers myself?

Hashed assets under /assets can be cached for a long time, while index.html should revalidate on every load so users get new builds. Add those header rules in a route block in the Caddyfile.

Are environment variables read at build time or runtime?

For Vite-style SPAs, VITE_ variables are baked into the bundle during npm run build. Runtime variables like UPSTREAM only control the server.

How do I attach a custom domain?

Add the domain in Railway's service networking settings and point your DNS at the target Railway gives you. TLS terminates at Railway's edge, so the container runs with auto_https off.

Does Caddy compress files with gzip and zstd?

Yes, the template uses encode gzip zstd, so responses are compressed on the fly for clients that accept either format. Pre-built .br or .zst sidecar files need the separate precompressed option.

When should I set UPSTREAM?

Set caddy.UPSTREAM to host:port when the same domain should proxy API calls to another service, such as a backend on Railway's private network.


Template Content

More templates in this category

View Template
NEW
Openfront Gym
Opensource Mindbody alternative based on Next.js and Keystone.js

Openship
0
View Template
open-excalidraw
Self-hostable collaborative drawing built on Excalidraw

Prateek Mohanty
5
View Template
NEW
Next.js + Prisma + PostgreSQL Starter
Deploy a Next.js app with Prisma ORM and PostgreSQL in one click.

blueorange
0