Jump to content

Custom Domains on PMSS

From Pulsed Media Wiki


Every active Pulsed Media service already answers on a free URL that keeps working even when your service moves to another server: the mcx.fi permalink. So putting your own domain in front of your public web folder is usually a short job, not a project. The cleanest way, and the one we recommend, is a small reverse proxy you control. This guide covers that first, then the free zero-setup URLs, then a few other options.

Before you start: do you actually need a custom domain?

Every seedbox and storage box already gives you working URLs at no cost and with no setup:

  • Public subdomain: USERNAME.SERVER.pulsedmedia.com serves your ~/www/public/ folder, no authentication.
  • mcx.fi permalink: a stable, username-free URL per service that survives migration to another server.

Both serve plain HTTP by default; opening them with https:// shows a certificate warning, because the server's certificate is issued for its own hostname. To fix that, run ~/bin/createWebPublicCerts once over SSH. It requests one Let's Encrypt certificate for the permalink only, which is normally in place within a few minutes and renews automatically. For the username subdomain too, run it with --with-username-hostname and type yes when asked; the certificate is public, so that publishes your username in Certificate Transparency logs for good. A server that has not yet installed the PMSS update of 7 October 2026 covers both names without asking.

If all you want is a clean HTTPS link to share, use one of those and stop here. The methods below are for when you specifically want your own domain (for example files.example.com) in the address bar.

How PMSS serves the web (why the naive approach fails)

PMSS fronts every server with a shared nginx proxy on ports 80/443, which routes to your per-user lighttpd behind it. nginx routes by Pulsed Media hostnames and paths (your per-user subdomains and the /public-USERNAME/ path), not by an arbitrary domain you own.

That is the catch. If you just point a plain DNS record for example.com at the server on 80/443, the request falls through to nginx's default site and never reaches your account. To land your own domain on your content you need something that rewrites the Host header to a Pulsed Media hostname the proxy recognises. That is exactly what a small reverse proxy does.

Method 1: A reverse proxy you control (recommended)

Run a small, always-on box that you own, a cheap VPS is plenty, as a reverse proxy between your domain and your seedbox. It terminates TLS for your domain with its own Let's Encrypt certificate, then forwards to your mcx.fi permalink, rewriting the Host header so PMSS routes each request to the right account. Your DNS points straight at your own box. Nothing sits between you and your visitors except infrastructure you control, which is why this is the option we recommend.

The simple version: Caddy

Caddy is the least fuss because it obtains and renews the Let's Encrypt certificate for your domain automatically. Point a DNS A record for example.com at your VPS public IP, then use a two-block Caddyfile:

example.com {
    reverse_proxy https://YOURHASH.mcx.fi {
        header_up Host YOURHASH.mcx.fi
    }
}

Caddy fetches the certificate on first request, and the header_up Host line does the translation PMSS needs. The upstream here is https://, so give your permalink a valid certificate first by running ~/bin/createWebPublicCerts on your seedbox (see above). nginx and HAProxy do the same job with a few more lines of config.

The caching version: Varnish (community-contributed)

Contributed by LowEndTalk community member dbadude, who wrote up these steps and reported them working. If you want an HTTP accelerator in front, Varnish does the host translation in /etc/varnish/default.vcl:

backend pm {
    .host = "YOURHASH.mcx.fi";
    .port = "80";
}

sub vcl_recv {
    if (req.http.host == "example.com" || req.http.host == "www.example.com") {
        set req.backend_hint = pm;
        set req.http.X-Real-Host = req.http.host;
        set req.http.host = "YOURHASH.mcx.fi";
    }
}

That fragment is the core of default.vcl; a complete file also starts with a vcl 4.1; line and keeps a default backend for any request that does not match. Compile and reload with varnishd -C -f /etc/varnish/default.vcl then systemctl restart varnish. Varnish speaks plain HTTP, so put TLS in front of it (Caddy, nginx, or Hitch) or terminate at the edge. For each extra domain, add one more backend and one more host match.

If you cannot run a public-IP VPS: self-hosted tunnels

If your proxy box is behind NAT or has no public IP, a self-hosted tunnel gives it a public presence without handing your traffic to a third party. You run both ends yourself: a small public VPS as the entry point, and a client on your box that dials out to it. All of these are open source and keep you in control:

  • frp (Fast Reverse Proxy): the most established, supports HTTP/TCP/UDP, widely used.
  • rathole: a lightweight, high-performance tunnel written in Rust.
  • Pangolin: a full self-hosted platform where a VPS is the ingress, WireGuard meshes back to your box, and a built-in reverse proxy routes traffic, the closest self-hosted equivalent to a managed tunnel.
  • WireGuard + Caddy/nginx: the do-it-yourself version, a WireGuard link from a public VPS to your box with a reverse proxy on top.

The pattern is the same as Method 1, the tunnel just replaces the requirement for a public IP on your own box.

Other options

Cloudflare (not recommended)

Cloudflare can do this too, either with a Cloudflare Tunnel (cloudflared running in your account, mapping a public hostname to your local service) or with a proxied CNAME plus a URL Rewrite rule pointing at your public subdomain. Both work.

We do not recommend it. Cloudflare is a third party that has interfered with torrent-related services, and routing your traffic through it puts your reachability in someone else's hands. Pulsed Media runs its own infrastructure precisely to avoid that kind of dependency, and the self-hosted reverse proxy above gives you the same result without it. If you already use Cloudflare and want to keep it: a Cloudflare Tunnel forwards the original Host header, so it needs nothing on our side; and if you use the proxied-CNAME route, point it at your mcx.fi permalink (after running ~/bin/createWebPublicCerts so it has a valid certificate) rather than the bare server, or Cloudflare will reject the origin certificate.

A torrent-neutral CDN, if you want a managed edge

If the reason you want a proxy is caching or global reach rather than just a custom domain, a CDN with a neutral acceptable-use policy is the sovereign-friendly choice: BunnyCDN and KeyCDN are both torrent-neutral. Point the CDN's origin at your mcx.fi permalink.

Troubleshooting

  • My proxy or CDN says the origin certificate is invalid. Point it at your mcx.fi permalink or your public subdomain USERNAME.SERVER.pulsedmedia.com, not the bare server IP or a raw hostname, and run ~/bin/createWebPublicCerts once so the permalink gets a valid Let's Encrypt certificate; the subdomain needs --with-username-hostname as well. The certificate is issued on request, not automatically; after that it renews on its own. The default catch-all site does not match your domain.
  • My domain loads the wrong page / the server default page. A plain DNS record on 80/443 falls through to nginx's default site. You need a reverse proxy that rewrites the Host header to your Pulsed Media hostname, not just a DNS record.
  • My reverse proxy returns a 502 / bad gateway. The proxy reached your box but could not get a valid response from the backend. Check that the backend host is your mcx.fi permalink and the upstream Host header is set to that same permalink.
  • The app shows "Host validation failed" or a 400. A self-hosted app does not trust your domain as an incoming Host. Add it to that app's allowed-hosts configuration.

See Also