Caddy on a VPS: A Simple Way to Deploy PHP Applications with Automatic HTTPS
Learn what Caddy is, how to use it to deploy PHP applications and APIs on a VPS, how it compares to Apache and Nginx, and when it is or is not the right choice.

When we think about deploying a web application on a VPS, three names usually come up quickly: Apache, Nginx, and, more recently, Caddy.
Apache and Nginx are extremely established choices. Caddy, on the other hand, has gained attention mainly among developers who want to reduce the amount of configuration required to put an application online, especially when HTTPS, reverse proxying, and multiple domains are involved.
But is Caddy actually better?
The answer depends on the problem you are trying to solve.
In this article, we will look at what Caddy is, how to use it on a VPS, its main differences and advantages compared with Apache and Nginx, and, most importantly, when it makes sense to use it.
What is Caddy?
Caddy is a web server and reverse proxy written in Go.
It can serve static files, act as a reverse proxy for HTTP applications, forward requests to PHP-FPM, and automatically manage TLS certificates for public domains. (caddyserver.com)
One of Caddy’s most well-known features is automatic HTTPS.
When you configure a domain in Caddy, it can automatically request a certificate from an ACME certificate authority, configure HTTPS, and handle certificate renewal. HTTP-to-HTTPS redirects are also handled automatically. (caddyserver.com)
This removes a significant amount of manual configuration that is often required with other web servers.
For example, a very simple configuration could be:
example.com {
reverse_proxy localhost:3000
}With this configuration, Caddy receives requests for example.com and forwards them to an application running locally on port 3000.
The same concept can be used with APIs, Node.js applications, Python services, Go applications, Java applications, and virtually any application that exposes HTTP.
Caddy does not replace PHP-FPM
For PHP developers, there is an important distinction to make.
Caddy is the web server.
It is not the PHP interpreter.
In a traditional PHP application, we can have an architecture like this:
Internet
│
▼
Caddy
│
▼
PHP-FPM
│
▼
PHP Application
│
▼
MySQL / PostgreSQLCaddy receives the HTTP request, determines that it needs to be processed by PHP, and forwards the execution to PHP-FPM using FastCGI.
Caddy provides the php_fastcgi directive specifically for this scenario. It encapsulates much of the configuration required to work with PHP-FPM and applications whose index.php acts as the entry point. (caddyserver.com)
A simple example could be:
example.com {
root * /var/www/example/public
php_fastcgi unix//run/php/php-fpm.sock
file_server
}The exact socket path depends on the Linux distribution and the PHP version installed on the server.
In a Symfony application, for example, the public directory would normally be:
/var/www/example/publicThis is important because internal application files such as .env, src/, config/, and vendor/ should never be directly exposed to the internet.
What would a simple VPS deployment look like?
A basic setup could look like this:
VPS
├── Caddy
├── PHP-FPM
├── Symfony Application
├── MySQL
└── RedisCaddy would be responsible for the HTTP layer.
PHP-FPM would execute the PHP code.
The database would store application data.
Redis could handle caching, sessions, or queues depending on the architecture.
A simple Caddy configuration for a PHP application might look like this:
app.example.com {
root * /var/www/app/public
encode gzip zstd
php_fastcgi unix//run/php/php-fpm.sock
file_server
}The official Caddy packages for distributions such as Debian and Ubuntu also integrate with systemd, allowing the service to start automatically at boot and be managed as a standard system service. (caddyserver.com)
What about reverse proxying?
Caddy does not have to serve PHP directly.
This is one of the scenarios where it becomes particularly interesting.
Imagine a VPS running:
Internet
│
▼
Caddy :443
│
├── app.example.com → localhost:3000
├── api.example.com → localhost:8080
└── admin.example.com → localhost:9000Each application can continue running internally on its own port.
Caddy centralizes:
- HTTPS
- certificates
- domains
- routing
- reverse proxying
- headers
- compression
- HTTP rules
The reverse_proxy directive supports multiple upstreams, load balancing, health checks, and other capabilities. (caddyserver.com)
This means a VPS can host several applications without exposing their internal ports directly to the internet.
Caddy vs Apache
Apache remains an excellent choice, especially in environments that already depend heavily on its architecture.
One important difference is how configuration is commonly organized.
In a traditional Apache environment, it is common to work with:
/etc/apache2/sites-available/
/etc/apache2/sites-enabled/Many older PHP applications also rely heavily on .htaccess.
With Caddy, configuration is usually much more centralized in the Caddyfile.
For example:
example.com {
root * /var/www/example/public
php_fastcgi unix//run/php/php-fpm.sock
file_server
}This simplicity can be particularly attractive for a small VPS that is managed directly by the developer.
An important difference: .htaccess
Older applications may rely heavily on .htaccess rules.
In that situation, migrating to Caddy does not mean simply copying the file.
The rules need to be translated into Caddy configuration.
Therefore, an older application with dozens of Apache-specific rules may make migration to Caddy more complicated than it initially appears.
For a modern application fully controlled by the developer, this is usually less of an issue.
Caddy vs Nginx
Nginx is also extremely common in production environments.
The architecture is often very similar:
Internet
│
▼
Nginx
│
├── PHP-FPM
├── Node.js
└── APIThe main difference is not necessarily what both servers can do, but rather how configuration and operations are handled.
A typical Nginx configuration for PHP might look like this:
server {
listen 443 ssl;
server_name example.com;
root /var/www/example/public;
location / {
try_files $uri /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php-fpm.sock;
include fastcgi_params;
}
}With Caddy, the equivalent configuration can be much shorter:
example.com {
root * /var/www/example/public
php_fastcgi unix//run/php/php-fpm.sock
file_server
}Caddy was designed to provide a simpler configuration experience, while Nginx offers an extremely mature and extensive configuration model.
There is no rule saying that an application running behind Caddy will automatically be faster or better than the same application running behind Nginx.
For most PHP projects, final performance also depends on the application itself, PHP-FPM, the database, caching, queries, infrastructure, and traffic volume.
The web server should be chosen based primarily on operational and architectural requirements.
One of the biggest advantages: automatic HTTPS
This is probably the feature that attracts the most attention.
With Caddy:
example.com {
reverse_proxy localhost:3000
}you are already declaring the domain that should be served.
When the domain points correctly to the server and the required ports are accessible, Caddy can automatically obtain and renew the TLS certificate. (caddyserver.com)
This significantly reduces the number of manual tasks involved.
With a traditional setup, you may need to think about:
Certificate
↓
Private key
↓
Virtual Host
↓
HTTPS
↓
HTTP → HTTPS redirect
↓
RenewalWith Caddy, much of this process is built into the web server.
This does not mean that DNS, firewall rules, or infrastructure configuration can be ignored.
A public deployment still needs to be correctly configured to receive traffic on HTTP and HTTPS ports. (caddyserver.com)
Where is Caddy commonly used?
Caddy can be used in many types of infrastructure.
Small and medium-sized VPS projects
This is one of the most interesting scenarios.
Imagine a VPS running:
Ubuntu
Caddy
PHP 8.x
PHP-FPM
Symfony
MySQL
RedisFor a developer managing their own infrastructure, the configuration can be very straightforward.
Reverse proxy
Another common use case is using Caddy only as the entry point to the infrastructure:
Internet
│
▼
Caddy
│
├── Symfony
├── Node.js
├── API
└── FrontendIn this model, each application can remain isolated internally.
Docker
Caddy can also be used as a reverse proxy in front of containers.
For example:
Internet
│
▼
Caddy
│
├── frontend-container
├── backend-container
└── api-containerThis can be particularly useful when you want only Caddy to expose ports to the internet while the other services remain accessible only through an internal network.
Homelabs
Caddy is also an interesting option for personal labs.
You might have:
grafana.example.internal
git.example.internal
api.example.internal
home.example.internaland centralize HTTP access through a single server.
Caddy also supports locally trusted certificates for internal environments, in addition to the traditional flow of public certificates for externally accessible domains. (caddyserver.com)
When is Caddy not the most natural choice?
Despite its advantages, Caddy should not be chosen simply because its configuration is smaller.
There are situations where Apache or Nginx may be more appropriate.
Applications heavily dependent on Apache
If an application makes extensive use of:
.htaccess
mod_rewrite
Apache-specific modules
Apache-specific configurationthe migration may require additional work.
In that scenario, keeping Apache may reduce operational risk.
Infrastructure standardized on Nginx
In organizations where the entire infrastructure already uses Nginx, monitoring, templates, documentation, automation, and operational procedures may already be built around it.
Introducing another web server simply because of personal preference may not provide enough benefit to justify the change.
Highly specialized environments
Some infrastructures have specific requirements related to:
- modules;
- observability;
- integrations;
- internal policies;
- automation;
- operational support;
- existing tooling.
In these cases, the decision should consider the entire ecosystem rather than just the web server.
Developers who need Apache/Nginx knowledge
There is also a professional consideration.
Apache and Nginx have an enormous presence in the market.
Even if you choose Caddy for your personal projects, it is still worth understanding both.
Learning Caddy should not mean abandoning Apache and Nginx.
The important thing is to understand the concepts that transfer between them:
HTTP
TLS
DNS
Reverse Proxy
FastCGI
PHP-FPM
Headers
Caching
Compression
Load Balancing
Logs
FirewallThese concepts remain relevant regardless of the web server you choose.
Does Caddy make deployment easier?
For many small and medium-sized projects, yes.
But it is important to separate deployment from the web server.
Caddy can simplify:
HTTPS
Reverse Proxy
Routing
HTTP serviceBut it does not solve:
Git
Composer
Database
Migrations
Workers
Cron
Queues
Backups
Monitoring
Application logs
Secrets
Firewall
System updatesA complete Symfony deployment, for example, can still involve:
git pull
composer install --no-dev --optimize-autoloader
php bin/console doctrine:migrations:migrate
php bin/console cache:clearand potentially restarting workers, updating assets, or running other application-specific tasks.
Caddy solves one part of the infrastructure.
It does not replace a deployment strategy.
A simple VPS with Caddy
For a personal project, a very interesting setup could look like this:
INTERNET
│
▼
┌───────────┐
│ Caddy │
│ :443 │
└─────┬─────┘
│
┌────────┴────────┐
│ │
▼ ▼
PHP-FPM API
│ │
▼ ▼
Symfony Service
│
▼
PostgreSQLThe Caddy configuration could remain relatively small:
example.com {
root * /var/www/example/public
encode gzip zstd
php_fastcgi unix//run/php/php-fpm.sock
file_server
}And a separate API could use:
api.example.com {
reverse_proxy 127.0.0.1:3000
}Caddy then becomes the entry point for the infrastructure.
Caddy, Apache, or Nginx?
Perhaps this is the wrong question.
Instead of asking:
Which web server is better?
I prefer asking:
Which web server reduces the complexity of my environment without creating important new limitations?
For a new VPS, a modern application, and infrastructure managed directly by the developer, Caddy can be extremely interesting.
For legacy applications that strongly depend on Apache, keeping Apache may be simpler.
For environments already standardized on Nginx, continuing to use Nginx may make more operational sense.
And for larger infrastructures, the decision should consider observability, automation, team expertise, internal standards, and specific requirements.
Conclusion
Caddy’s biggest differentiator is not simply that it is another web server.
Its most interesting proposition is the combination of:
Simple configuration
+
Reverse Proxy
+
Automatic HTTPS
+
PHP-FPM integration
+
Good operational experienceFor someone managing a VPS alone, this combination can significantly reduce the work required to publish an application.
For a PHP developer, it makes it possible to build a relatively lean infrastructure:
Caddy
↓
PHP-FPM
↓
Symfony / Laravel / PHP
↓
PostgreSQL / MySQLBut configuration simplicity should not be confused with absolute superiority.
Apache is still relevant.
Nginx is still relevant.
And Caddy is another tool worth knowing.
The best choice is the one that fits the application, the infrastructure, and the way you intend to operate the environment.
In the end, the goal is not to choose the most popular web server.
It is to choose the one that solves the problem with the least operational complexity possible.
References
- Caddy official documentation — installation and service setup. (caddyserver.com)
- Caddy official documentation — automatic HTTPS. (caddyserver.com)
- Caddy official documentation —
php_fastcgi. (caddyserver.com) - Caddy official documentation —
reverse_proxy. (caddyserver.com)