How to Install and Configure Caddy Web Server with PHP and MariaDB on Ubuntu 20.04
This tutorial exists for these OS versions
- Ubuntu 22.04 (Jammy Jellyfish)
- Ubuntu 20.04 (Focal Fossa)
- Ubuntu 18.04 (Bionic Beaver)
- Ubuntu 16.04 (Xenial Xerus)
On this page
Caddy Web Server is a modern open-source web server written in GO language. It doesn't have any dependencies and runs off of a static binary file and generates and renews SSL certificates automatically. It can work as a static file server, scalable reverse proxy or a powerful dynamic server and can be expanded via plugins. It also includes support for HTTP/2 and experimental HTTP/3 protocols.
In this tutorial, you'll install and configure Caddy to run along with PHP and MariaDB on an Ubuntu 20.04 based server.
Prerequisites
- An Ubuntu 20.04 server with a non-root account having sudo privileges.
- A fully registered domain name pointed to your server's IP address.
Step 1 - Configure Firewall
If you are using UFW (Uncomplicated Firewall), you need to configure it to allow access to HTTP and HTTPS ports for the server to work.
Check the status of the firewall.
$ sudo ufw status
You should see something like the following.
Status: active
To Action From
-- ------ ----
OpenSSH ALLOW Anywhere
OpenSSH (v6) ALLOW Anywhere (v6)
Allow HTTP and HTTPs ports.
$ sudo ufw allow http
$ sudo ufw allow https
Check the status again to confirm.
$ sudo ufw status
Status: active
To Action From
-- ------ ----
OpenSSH ALLOW Anywhere
80/tcp ALLOW Anywhere
443/tcp ALLOW Anywhere
OpenSSH (v6) ALLOW Anywhere (v6)
80/tcp (v6) ALLOW Anywhere (v6)
443/tcp (v6) ALLOW Anywhere (v6)
Step 2 - Install Caddy
There are several ways to install Caddy which includes a docker installation, using official repositories or building from source. The building from source method is useful if you want functionality which can only be added via a 3rd party module/plugin.
For the purpose of this tutorial, we will stick to using the official Caddy repository for Ubuntu/Debian based systems.
Add the Repository to the list.
$ echo "deb [trusted=yes] https://apt.fury.io/caddy/ /" | sudo tee -a /etc/apt/sources.list.d/caddy-fury.list
$ sudo apt update
This will create a caddy repository file in the /etc/apt/sources.list.d
directory with the location to the Caddy's repository.
Install Caddy.
$ sudo apt install caddy
This will automatically install and run the Caddy web server. Open http://
Step 3 - Install PHP
Install Ondrej's PHP repository.
$ sudo add-apt-repository ppa:ondrej/php
Install PHP 7.4 along with some additional packages.
$ sudo apt install php-cli php-fpm php-mysql
Check if PHP is working correctly.
$ php --version
You should see a similar output.
PHP 7.4.6 (cli) (built: May 14 2020 10:03:35) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
with Zend OPcache v7.4.6, Copyright (c), by Zend Technologies
Step 4 - Install MariaDB
MariaDB is a drop-in replacement for MySQL which means commands to run and operate MariaDB are the same as those for MySQL.
Add Mariadb's Official repository. You can opt for a different mirror which is closer to your server's location from MariaDB's repository page.
$ sudo apt-key adv --fetch-keys 'https://mariadb.org/mariadb_release_signing_key.asc'
$ sudo add-apt-repository 'deb [arch=amd64] http://mirror.lstn.net/mariadb/repo/10.4/ubuntu f
ocal main'
To install MariaDB issue the following command.
$ sudo apt install mariadb-server
Check if MariaDB installed correctly.
$ mysql --version
You should see the following output.
mysql Ver 15.1 Distrib 10.4.13-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2
Enable the MariaDB service.
$ sudo systemctl enable mariadb
Step 5 - Configure MariaDB
Run the following command to perform default configuration such as giving a root password, removing anonymous users, disallowing root login remotely and dropping test tables.
$ sudo mysql_secure_installation
With MariaDB 10.4, you will now be asked between using the root password or unix_socket
plugin. The unix_socket
plugin allows you to log in to MariaDB with your Linux user credentials. It is considered more secure though you will need a traditional username/password to use 3rd party apps like phpMyAdmin. We will stick to using unix_socket
plugin for this tutorial. You can still use phpMyAdmin via any user you specific user you create for your databases.
Pressing Enter chooses the default option (the one that is capitalised, Y in this case).
NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB
SERVERS IN PRODUCTION USE! PLEASE READ EACH STEP CAREFULLY!
In order to log into MariaDB to secure it, we'll need the current
password for the root user. If you've just installed MariaDB, and
haven't set the root password yet, you should just press enter here.
Enter current password for root (enter for none): [PRESS ENTER]
OK, successfully used password, moving on...
Setting the root password or using the unix_socket ensures that nobody
can log into the MariaDB root user without the proper authorisation.
You already have your root account protected, so you can safely answer 'n'.
Switch to unix_socket authentication [Y/n] [PRESS ENTER]
Enabled successfully!
Reloading privilege tables..
... Success!
You already have your root account protected, so you can safely answer 'n'.
Change the root password? [Y/n] [ANSWER n]
... skipping.
By default, a MariaDB installation has an anonymous user, allowing anyone
to log into MariaDB without having to have a user account created for
them. This is intended only for testing, and to make the installation
go a bit smoother. You should remove them before moving into a
production environment.
Remove anonymous users? [Y/n] [PRESS ENTER]
... Success!
Normally, root should only be allowed to connect from 'localhost'. This
ensures that someone cannot guess at the root password from the network.
Disallow root login remotely? [Y/n] [PRESS ENTER]
... Success!
By default, MariaDB comes with a database named 'test' that anyone can
access. This is also intended only for testing, and should be removed
before moving into a production environment.
Remove test database and access to it? [Y/n] [PRESS ENTER]
\- Dropping test database...
... Success!
\- Removing privileges on test database...
... Success!
Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.
Reload privilege tables now? [Y/n] [PRESS ENTER]
... Success!
Cleaning up...
All done! If you've completed all of the above steps, your MariaDB
installation should now be secure.
Thanks for using MariaDB!
Log in to the MariaDB's SQL Shell.
$ sudo mysql
Enter your root password when prompted.
Create a test database and user with access permission. Replace database
and user
with your choice. Replace password
with a strong password.
CREATE DATABASE testdb;
CREATE USER 'user' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON testdb.* TO 'user';
Exit the MySQL Shell.
exit
Step 6 - Configure Caddy
Caddy can be configured in several ways - API calls, JSON file or a Caddyfile. Caddyfile is the easiest way to configure Caddy which we will use in our tutorial.
Before we configure Caddy, we should create the root directory for our site.
$ sudo mkdir -p /var/www/example.com/html
-p
flag creates any missing parent directories as well.
We also need to create a directory to store the log files for Caddy.
$ sudo mkdir /var/log/caddy
Caddy server on installation creates a user caddy
which handles its tasks for it. We need to give permissions to the log directory so that Caddy can access and write to it.
$ sudo chown -R caddy:caddy /var/log/caddy
During installation, Caddy generated a default Caddyfile at /etc/caddy/Caddyfile
. Open it.
$ sudo nano /etc/caddy/Caddyfile
It should look something like the following.
# The Caddyfile is an easy way to configure your Caddy web server.
#
# Unless the file starts with a global options block, the first
# uncommented line is always the address of your site.
#
# To use your own domain name (with automatic HTTPS), first make
# sure your domain's A/AAAA DNS records are properly pointed to
# this machine's public IP, then replace the line below with your
# domain name.
:80
# Set this path to your site's directory.
root * /usr/share/caddy
# Enable the static file server.
file_server
# Another common task is to set up a reverse proxy:
# reverse_proxy localhost:8080
# Or serve a PHP site through php-fpm:
# php_fastcgi localhost:9000
# Refer to the Caddy docs for more information:
# https://caddyserver.com/docs/caddyfile
:80
tells Caddy to serve everything over port number 80. root
sets the path for your site's home directory. file_server
enables Caddy to run as a static file server.
Replace the above code with the following code.
{
experimental_http3
}
example.com {
root * /var/www/example.com/html
log {
output file /var/log/caddy/example.com.access.log {
roll_size 3MiB
roll_keep 5
roll_keep_for 48h
}
format console
}
encode gzip zstd
php_fastcgi unix//run/php/php7.4-fpm.sock
tls [email protected] {
protocols tls1.2 tls1.3
}
}
Let us go through all sections of the Caddyfile below.
- The first block in any Caddyfile is a global block unless you specify a hostname which then it becomes a site block. A global block carries directives that are applied to all sites that you host under the server. In our example, we have enabled support for the experimental HTTP/3 protocol. The global block is completely optional and you can always start your Caddyfile with the site block directly.
- Next block is the site block. If you have just 1 site on your server, you don't need to enclose your configuration in a block but if you are going to host multiple sites, you should host each site's configuration in its own block. A site block is marked by curly brackets. Every site block starts with the hostname of the site.
log
enables and configures HTTP request logging. Without thelog
directive, Caddy won't log anything.output
configures where to write the log file to.format
describes how to encode, or format, the logs. Theconsole
formats the log entry for human readability.encode
directive here enables Gzip and Zstandard compression for the site.php_fastcgi
proxies requests to a PHP FastCGI server such asphp-fpm
. Here we are listening to requests over a Unix socket.tls
block configures settings related to SSL certificates and security. Here, we have enabled support for both TLSv1.2 and TLSv1.3 protocols. By default, Caddy supports TLS v1.2 out of the box. Caddy also generates SSL certificates automatically for all sites. If you don't want Caddy to generate SSL for you, you can do so by either using the IP address instead of the hostname or specify the full URL i.e. http://example.com. In such cases, Caddy won't generate the SSL certificate.
So far we have covered the absolute basics of writing a Caddyfile which should help you get started. You can read more about it in the official documentation.
Step 7 - Configure PHP
Now, that our Caddyfile is ready, it is time to configure PHP.
First, we have to change the username for the PHP process. Open the file /etc/php-fpm.d/www.conf
.
$ sudo nano /etc/php/7.4/fpm/pool.d/www.conf
Find the user=www-data
and group=www-data
lines in the file and change them to caddy
.
...
; Unix user/group of processes
; Note: The user is mandatory. If the group is not set, the default user's group
; will be used.
; RPM: apache user chosen to provide access to the same directories as httpd
user = caddy
; RPM: Keep a group allowed to write in log dir.
group = caddy
...
Also, find the lines listen.owner=www-data
and listen.group=www-data
in the file and change them to caddy
.
listen.owner = caddy
listen.group = caddy
Save the file by pressing Ctrl+X and entering Y when prompted.
Restart the PHP-fpm process.
$ sudo systemctl restart php7.4-fpm
Step 8 - Launch Demo Site
Now that we have created a Caddyfile and configured PHP to run with the server, it is time to create and launch a demo website.
Make sure your domain name is pointed to the server's IP address.
Restart Caddy server to apply the changes in the Caddyfile we created above.
$ sudo systemctl restart caddy
Check the status of the Caddy server to make sure it is working properly.
$ sudo systemctl status caddy
? caddy.service - Caddy
Loaded: loaded (/lib/systemd/system/caddy.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2020-05-20 07:09:25 UTC; 2s ago
Docs: https://caddyserver.com/docs/
Main PID: 25410 (caddy)
Tasks: 7 (limit: 1074)
Memory: 17.8M
CGroup: /system.slice/caddy.service
??25410 /usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
May 20 07:09:25 example.com caddy[25410]: 2020/05/20 07:09:25 [INFO][example.com] Obtain: Lock acquired; proceeding...
May 20 07:09:25 example.com caddy[25410]: 2020/05/20 07:09:25 [INFO][cache:0xc0006f8cd0] Started certificate maintenance routine
May 20 07:09:25 example.com caddy[25410]: 2020/05/20 07:09:25 [INFO] acme: Registering account for [email protected]
May 20 07:09:26 example.com caddy[25410]: 2020/05/20 07:09:26 [INFO][example.com] Waiting on rate limiter...
May 20 07:09:26 example.com caddy[25410]: 2020/05/20 07:09:26 [INFO][example.com] Done waiting
May 20 07:09:26 example.com caddy[25410]: 2020/05/20 07:09:26 [INFO] [example.com] acme: Obtaining bundled SAN certificate given a CSR
May 20 07:09:27 example.com caddy[25410]: 2020/05/20 07:09:27 [INFO] [example.com] AuthURL: https://acme-v02.api.letsencrypt.org/acme/authz-v3/4696123289
May 20 07:09:27 example.com caddy[25410]: 2020/05/20 07:09:27 [INFO] [example.com] acme: use tls-alpn-01 solver
May 20 07:09:27 example.com caddy[25410]: 2020/05/20 07:09:27 [INFO] [example.com] acme: Trying to solve TLS-ALPN-01
May 20 07:09:27 example.com caddy[25410]: 2020/05/20 07:09:27 http: TLS handshake error from 127.0.0.1:39466: EOF
You can see from above that Caddy Generated the certificate automatically when we first restarted the server after creating the Caddyfile.
Let us create a test page to verify that Caddy can render PHP and connect to the MariaDB database.
$ sudo nano /var/www/example.com/html/test.php
Paste the following code in the editor. Replace "user"
and "password"
fields with the MariaDB credentials you created before.
<html>
<head>
<title>Caddy Demo Site</title>
<style type="text/css">
#wrap {
width: 900px;
margin: 0 auto;
}
</style>
</head>
<body id="wrap">
<h2>Caddy Demo Site</h2>
<?php echo '<p>Hello,</p>';
// Define PHP variables for the MySQL connection.
$servername = "localhost";
$username = "user";
$password = "password";
// Create a MySQL connection.
$conn = mysqli_connect($servername, $username, $password);
// Report if the connection fails or is successful.
if (!$conn) {
exit('<p>Your connection has failed.<p>' . mysqli_connect_error());
}
echo '<p>You have connected successfully.</p>';
?>
</body>
</html>
Save the file by pressing Ctrl+X and entering Y when prompted.
Visit https://example.com/test.php in a web browser. You should get the following page.
If you see an error message or if the page does not load at all, re-check your configuration
Remove the test file once you are satisfied.
$ sudo rm /var/www/example.com/html/test.php
Conclusion
This concludes our tutorial where we installed Caddy web server along with PHP and MariaDB SQL. If you have any queries, ask them in the comments below.