MHOSTMHOST

Caddy: automatic HTTPS

Caddy is a web server that obtains and renews Let's Encrypt TLS certificates by itself — no certbot, no manual cron jobs. In this article you'll install Caddy on your mHost VPS, describe a site in a Caddyfile with automatic HTTPS, and set up reverse_proxy so Caddy accepts HTTPS traffic from the outside and forwards it to your application.

What you'll need

  • An mHost Linux VPS: Ubuntu 22.04/24.04, Debian 11/12, or AlmaLinux/Rocky Linux 8/9.
  • SSH access — as root or a user with sudo.
  • A domain name whose A record points to the server's IP address (mHost VPS are IPv4-only, so no AAAA record is needed).
  • Open ports 80 and 443 — without them Caddy can't obtain a certificate (details in Step 2).

Step 1. Check that the domain points to the server

Automatic HTTPS only works when the certificate authority (Let's Encrypt or ZeroSSL) can reach your server through that exact domain — so DNS must already point to it before you start Caddy.

  1. Find your server's IP address — in the VMmanager 6 panel / my.mhost.ee, or right on the server:

``bash curl -4 ifconfig.me ``

  1. Check where the domain points (replace example.com with your own):

``bash dig +short example.com A ``

If dig isn't installed, install the DNS utilities package:

``bash sudo apt install -y dnsutils # Ubuntu/Debian sudo dnf install -y bind-utils # AlmaLinux/Rocky ``

  1. Compare the dig output with the server's IP address — they must match.
Important: if you've just changed the DNS record, propagation can take anywhere from a few minutes to a couple of hours. Until the domain points to the server, Caddy won't be able to issue a certificate — don't try to start Caddy before that.

Step 2. Open ports 80 and 443

Port 80 is needed for the HTTP-01 domain challenge and the automatic HTTP-to-HTTPS redirect, port 443 for HTTPS itself and the TLS-ALPN challenge. Caddy uses both ports by default — there's nothing extra to configure inside Caddy — but the server's firewall must let them through.

Ubuntu and Debian (ufw)

bash
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

AlmaLinux and Rocky Linux (firewalld)

bash
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
Important: for a detailed walkthrough of ufw commands and firewall logic, see "Setting up the UFW firewall". If there's another firewall in front of the server (at the provider or in a control panel), open ports 80 and 443 there too.

Step 3. Install Caddy

There's no ready-made VMmanager 6 recipe for Caddy, so we install the package manually from the official repository. For the full list of what you can set up in one click, see "Ready-made VMmanager 6 recipes".

Ubuntu and Debian

bash
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpg
sudo chmod o+r /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy

AlmaLinux and Rocky Linux

bash
sudo dnf install -y dnf-plugins-core
sudo dnf copr enable @caddy/caddy
sudo dnf install caddy
Tip: dnf copr enable and dnf install may ask you to confirm enabling the third-party repository and importing its GPG key — answer y.

The package creates a systemd service and already starts Caddy. Enable it to start on boot and check its status:

bash
sudo systemctl enable --now caddy
sudo systemctl status caddy
Done: if the status is active (running), Caddy is installed and running (with an empty config for now).

Step 4. A minimal Caddyfile with automatic HTTPS

Caddy's configuration lives in /etc/caddy/Caddyfile. Open it in an editor:

bash
sudo nano /etc/caddy/Caddyfile

Replace the contents with a minimal site block — the domain name in the block's header is all Caddy needs to turn on automatic HTTPS:

caddyfile
example.com {
    respond "Caddy on mHost works over HTTPS!"
}

Replace example.com with your own domain (the same one you checked in Step 1) and save the file. There's no certbot, no separate certificates, no renewal cron job to set up — on the first request to the site, Caddy will obtain a certificate from Let's Encrypt itself (falling back to ZeroSSL if that fails) and keep renewing it before it expires.

Tip: to get email notifications from Let's Encrypt about certificate problems, add a global options block { email admin@example.com } before the site block — it must come first in the file, before any site blocks.

How to apply the changes and check the result is covered in Steps 6 and 7 below.

Step 5. A reverse_proxy example — proxying to an application

If you already have your own application running on the server (Node.js, Python, Java, etc.) listening on a local port, replace the block from Step 4 with this one:

caddyfile
example.com {
    reverse_proxy localhost:3000
}

Replace 3000 with the port your application actually listens on. Caddy will accept HTTPS traffic from the outside and forward it to that port over plain HTTP inside the server. Save the file and move on to Step 6 to apply the changes.

Tip: have your application listen on 127.0.0.1 (localhost) rather than 0.0.0.0 — that way it's reachable only through Caddy, not directly on its port bypassing HTTPS.

Step 6. Validate the config and reload it

After any change to /etc/caddy/Caddyfile, first check the syntax, then reload the configuration without stopping the service:

bash
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy

validate catches configuration errors before they're applied, and reload picks up the changes on the fly — without dropping existing connections or any site downtime, unlike restart.

If something goes wrong, check the service logs:

bash
sudo journalctl -u caddy -f
Important: don't use sudo systemctl stop caddy followed by start to apply changes — that causes site downtime. Always use reload to change the configuration.

Step 7. Check that HTTPS works

bash
curl -I https://example.com

You should see a response like HTTP/2 200 with no certificate errors. On the very first request, Caddy may delay the response by a few seconds while it obtains the certificate.

Done: if the browser shows a padlock next to the site's address and curl doesn't complain about the certificate, automatic HTTPS is set up and working.

What's next

You can add more blocks to /etc/caddy/Caddyfile for other domains — each with its own reverse_proxy or other directives — and Caddy will automatically issue a certificate for each of them too. After every edit, repeat Step 6 (validate + reload). If a new site uses ports other than 80/443, open them the same way as in Step 2 — see "Setting up the UFW firewall" for details.