
Caddy gives you a clean way to run a web server with automatic HTTPS and a simple config file. If you want to Install Caddy on Ubuntu 26.04 without guesswork, this guide walks you through the full setup, why each command matters, and how to verify that it works. The goal is not just to make it run, but to help you understand the system like a real sysadmin would.
Caddy is a strong fit for developers and Linux admins because it reduces certificate work and keeps server config readable. In a typical Caddy on Ubuntu 26.04 setup, you install it from the official repository, start the service, open the right firewall ports, then define a site block in the Caddyfile. That same flow also supports static sites and reverse proxy apps, so this Linux server tutorial stays useful beyond a basic install.
Prerequisites
Before you begin, make sure you have the right base setup. These items keep the install clean and reduce avoidable errors later.
- Ubuntu 26.04 LTS server or VM.
- Sudo access or root access.
- A registered domain name if you want public HTTPS.
- Open network access for ports 80 and 443.
- A terminal client such as SSH, Windows Terminal, or local console.
- Basic comfort with editing files in a Linux shell.
Step 1: Update Your System
Why this matters
Start by refreshing your package lists and applying updates. This lowers the chance of broken dependencies and gives you a cleaner base for the Caddy install.
sudo apt update
sudo apt upgrade -y
apt update refreshes the package index. apt upgrade -y installs the latest available updates. On a fresh server, this step often prevents small package issues from turning into install failures later.
Expected output
Reading package lists... Done
Building dependency tree... Done
Calculating upgrade... Done
Step 2: Install Required Tools
Why this matters
Caddy’s official package repo uses HTTPS and signed packages, so your system needs helper tools for secure repository setup. These packages support key handling, transport, and fetching the repo data.
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl downloads the repository key and repo list. The keyring packages help Ubuntu trust the repository in a standard way. apt-transport-https makes sure apt can talk to HTTPS sources properly.
Step 3: Add the Caddy Repository
Why this matters
The official repository usually gives you a current and trusted Caddy version. That is better than relying on an old package from a default repo, especially for server software that depends on active maintenance.
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
This command downloads Caddy’s signing key and stores it in a format apt can use. That matters because your system should verify who published the package before it installs anything.
Now add the repository source list.
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
This tells apt where to find Caddy packages. It keeps the vendor source separate from Ubuntu’s default package sources, which is cleaner and easier to manage.
Expected output
You should see a repo line written to the terminal, usually ending with a Caddy source entry.
Step 4: Install Caddy
Why this matters
Now that Ubuntu trusts the repo, refresh apt again so it can read the new package metadata. Then install the web server itself.
sudo apt update
sudo apt install -y caddy
The second apt update matters because apt cannot install from a repo it has not indexed yet. apt install caddy pulls in the binary, service unit, and default config files in one step.
Check the version
caddy version
This confirms the binary is installed and shows which release you are running. On a healthy install, you should see a version string such as 2.x.x.
Step 5: Start and Enable the Service
Why this matters
A web server should survive reboots without manual work. That is why systemd service management is part of a proper install, not an optional extra.
sudo systemctl enable caddy
sudo systemctl start caddy
enable makes Caddy start at boot. start launches it now so you can test it immediately. This is the standard production pattern for Linux services.
Verify service status
sudo systemctl status caddy
You want to see active (running) in the output.
● caddy.service - Caddy
Loaded: loaded
Active: active (running)
That status tells you the service started correctly and is ready to receive requests.
Step 6: Open the Firewall
Why this matters
Caddy can be installed perfectly and still fail to serve traffic if your firewall blocks the ports it needs. For public sites, port 80 helps with certificate handling, and port 443 carries encrypted traffic.
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw status
If you use UFW, these rules let browsers reach Caddy and let Caddy complete automatic TLS challenges. Without them, HTTPS setup can fail even when the config is correct.
Expected output
Status: active
80/tcp ALLOW Anywhere
443/tcp ALLOW Anywhere
Step 7: Create a Basic Caddyfile
Why this matters
The Caddyfile is the main config file for most Caddy setups. It keeps site config simple and readable, which is one of the biggest reasons admins like Caddy.
Back up the default file first.
sudo cp /etc/caddy/Caddyfile /etc/caddy/Caddyfile.bak
This gives you a safe rollback point. If a new config breaks, you can restore the old one fast.
Now edit the file.
sudo nano /etc/caddy/Caddyfile
For a simple static site, use this example.
example.com {
root * /var/www/example.com
file_server
}
This block tells Caddy to serve files from the site directory. It also tells Caddy to handle file delivery for visitors. If your domain points to the server and ports are open, Caddy can also handle HTTPS automatically.
Create the web root
sudo mkdir -p /var/www/example.com
sudo chown -R caddy:caddy /var/www/example.com
This creates a clean content directory and gives the Caddy service user access to it. That matters because file permission problems are a common cause of startup or access errors on Linux.
Add a test page
cat <<'EOF' | sudo tee /var/www/example.com/index.html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Caddy on Ubuntu 26.04</title>
</head>
<body>
<h1>Hello from Caddy</h1>
</body>
</html>
EOF
This gives you an easy way to confirm that the server is actually delivering content. A simple HTML test page isolates web server setup from application logic.
Step 8: Validate and Reload Caddy
Why this matters
Always validate the config before reloading. This catches syntax mistakes before they reach users.
sudo caddy fmt --overwrite /etc/caddy/Caddyfile
sudo caddy validate --config /etc/caddy/Caddyfile
caddy fmt keeps the file neat and consistent. caddy validate checks whether the config is valid, which helps you avoid downtime caused by a typo.
If validation passes, reload the service.
sudo systemctl reload caddy
Reloading applies the new config without a full stop-start cycle. That is safer for live systems.
Expected output
valid configuration
Step 9: Set Up Reverse Proxy
Why this matters
Many users install Caddy not just for static sites, but to place it in front of apps like Node.js, PHP-FPM, Python services, or Go APIs. A reverse proxy keeps the backend private while Caddy handles public traffic and TLS.
Edit the Caddyfile again.
sudo nano /etc/caddy/Caddyfile
Use this example for a local app on port 3000.
example.com {
reverse_proxy 127.0.0.1:3000
}
This tells Caddy to forward web traffic to your app. The backend stays on localhost, which reduces exposure and keeps the public interface simpler. It also simplifies SSL handling, because Caddy terminates HTTPS at the edge.
Why localhost is better here
If your app only listens on 127.0.0.1, the internet cannot reach it directly. That adds a layer of protection and makes Caddy the only public entry point.
Reload again after saving.
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy
Step 10: Check Everything From the Client Side
Why this matters
Server-side status is not enough. You should always test from a client machine to confirm the site works as users will see it.
curl -I https://example.com
If DNS, firewall, and TLS are correct, you should get an HTTP response header block with a success status such as 200 OK or a redirect if you configured one. Client-side checks help confirm that your public path is really working.
You can also inspect the loaded page in a browser and verify the lock icon. That confirms the server is serving HTTPS properly.
Troubleshooting Common Errors
1. Caddy will not start
Run:
sudo systemctl status caddy
sudo journalctl -u caddy -n 50 --no-pager
This usually points to a bad Caddyfile, a permission issue, or a port conflict. Logs matter because they tell you exactly where the startup failed.
2. Port 80 or 443 is already in use
Check what owns the port:
sudo ss -tulpn | grep -E ':80|:443'
If another service is listening there, Caddy cannot bind to the same port. Stop the other service or move it to a different port before retrying.
3. HTTPS certificate errors
Make sure your domain points to the server and that ports 80 and 443 are open. Caddy needs public reachability for automatic certificate setup on normal public domains. If DNS is wrong or the firewall blocks the request, certificate issuance can fail.
4. Permission denied on site files
Fix ownership or read permissions.
sudo chown -R caddy:caddy /var/www/example.com
sudo chmod -R 755 /var/www/example.com
This ensures the service account can read the web content. On Linux, the wrong owner or mode can break a site even when the config is correct.
5. Config changes do not appear
Always validate and reload.
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy
If the config fails validation, Caddy will not apply it. That behavior protects the server from bad changes, so treat validation as part of your normal workflow.