Community Blog Setting up Caddy with PHP & MySQL Stack on Ubuntu 16.04

Setting up Caddy with PHP & MySQL Stack on Ubuntu 16.04

In this guide, we have presented the advantages - and simplicity of Caddy with PHP and MySQL stack, installed on an Alibaba Cloud ECS instance with Ubuntu 16.

By Tonino Jankov, Alibaba Cloud Tech Share Author. Tech Share is Alibaba Cloud's incentive program to encourage the sharing of technical knowledge and best practices within the cloud community.

It has been a long time coming - the web industry has been warning the market about the inevitable switch to https and http/2. Then in February 2018, Chrome team announced that from July 2018, Google Chrome will mark all http - protocol websites insecure. Only https protocol will be considered safe.


Having in mind Chrome's overwhelming dominance and increasing market share, especially on mobile, as well as Google considering https as an SEO ranking factor, it's easy to see that neither http/2 nor https are going away. The importance of this, secure version of the protocol is only increasing and becoming a default standard.

The trend of adopting https standard (and http/2) as the default isn't stopped even by the fact that this encryption often marginally decreases website loading speed / TTFB, because encryption takes up a couple of processing cycles on the server.

In fact, the demand for more secure http everywhere is growing year by year. The Internet Security Research Group, a public benefit organization, backed by Electronic Frontier Foundation (EFF), Mozilla, Cisco, Akamai, OVH, has started a certificate authority project Let's Encrypt that streamlines and simplifies the issuing of TLS certificates with the goal of making https protection ubiquitous.

By eliminating payment, web server configuration, validation email management and certificate renewal tasks, it is meant to significantly lower the complexity of setting up and maintaining TLS encryption.

Up until that point, setting up https protection on a server was a rather involved process, with a lot of command-line back and forth, certificate generation, downloads, uploads, not to mention payments, verifications and so on.

Now, even with Let's Encrypt and big improvement of the whole process, https setup with major server vendors like Apache and NGINX is still not a one-click process, and for many users, not straightforward.


In 2015, Matthew Holt, a Go developer who "codes stuff with his bare hands", released first version of Caddy, an open-source web server written in Go. It is a HTTP/2 enabled web server that serves requests through https by default.

Caddy, by Light Code Labs, comes with dual licensing. The open-source version, available on Github, is offered under Apache license and is free for both personal and commercial projects. This version needs to be compiled, and in this case, desired plugins need to be added at compile time. If we choose personal or commercial (paid) version, Light Code Labs will provide a build server that does this for us, and we can avail ourselves of available plugins, created by them and the community, and hosted by Light Code Labs. We can select desired plugins and download our build.

Whether we choose Caddy's build server or we compile it ourselves, Caddy is cross-platform, meaning it is available on Windows, Linux, macOS, Unix, and even on Android

Features that make Caddy worth considering as an option are:

  1. Inherent security - Https is enabled by default, with redirections. Caddy features On-Demand TLS. This means Caddy can obtain a certificate for your site during the first TLS handshake for a hostname that does not yet have a certificate. This means no hassle with obtaining a certificate. It uses Automatic Certificate Management Environment, a protocol that allows server to obtain https certificate automatically (it uses the same protocol that certbot by EFF uses, only automated). It obtains certificate from Let's Encrypt by default, but it can connect to any ACME compatible Certificate Authority. ACMEv2, which Caddy supports, allows for wildcard certificates. Caddy is able to detect some versions of Man-in-the-Middle attacks.
  2. It is configured to support HTTP/2 and server push by default - a feature that has been lacking, until recently, in major servers like Nginx and Apache, and is still not as straightforward as it should be.
  3. It supports WebSocket connections directly to local programs' stdin/stdout streams .
  4. It supports brotli compression, as long as the client supports it.
  5. Due to being written in Go, Caddy is memory-safe, and invulnerable to bugs like Heartbleed.

Caddy with all its features can compete with Apache, LiteSpeed, NGINX, but its main features are its user-friendliness and simplicity. When downloaded from the build server, it consists of a single binary file which is easily ran with a single command.

In this article we will deploy Caddy with PHP7 and MySQL stack on an Alibaba Cloud Elastic Compute Service (ECS) instance with Ubuntu 16.04.

Setting Up the Instance

Creating an Alibaba Cloud Elastic Compute Service (ECS) instance is pretty straightforward. From the Alibaba Cloud console, we can select Elastic Compute Service in the leftmost menu, and then Instances in the left sub-menu. Then we will be able to click and create the instance we want. We can select between different zones - basically locations of our server, and other parameters, like CPU, RAM, payment scheduling, etc.

Next, we select the software stack. Here we can choose between operating systems, and whole software stacks as prebuilt templates / images, like LEMP stack, WordPress, Drupal and others. For the purpose of this tutorial, we chose a bare Ubuntu 16.04 LTS image.


One of the details to keep in mind when setting up our instance is security group - basically a set of rules that determine which ports will be automatically open when our instance is created. Alibaba Cloud ECS requires ports to be explicitly open - so if we lack the security group with proper ports opened - explicitly defined - we won't be able to access our instance through the web nor through SSH. We can rectify this later, but it is best to ensure that we have proper security group assigned - if it is not there by default, created by the system, we will need to create it ourselves. There is a sub-menu on the left with Security Groups page.

We need to make sure that ports 80, 443 and 80 are opened at the very least.


As we setup our instance, we are given option to either set up our ssh keys for ssh access (Key Pair), or to set up our password. After we have set all our details and confirmed to create the instance, we will wait a couple of minutes for the system to spin up our Ubuntu instance. We will see in the console when it is running, and then we can see it's public IP address in its management page, and we can access it through SSH shell.

ssh root@our-IP-number , from our local computer, will take us to our system shell, where we will update our repositories and upgrade our system - apt-get update and apt-get upgrade.

Alibaba Cloud keeps its own mirrors of Ubuntu repositories, so the system will reach out for those.

After we have done this, we could check which ports are open on our machine, as outlined here, and make sure that no server is listening on web ports - 80 and 443 - by default. If that is the case, we usually need to shut down and uninstall Apache.

Installing Caddy

We use binary builder on Caddy website to choose our options - there is a number of plugins available, but to keep things simple, we choose just barebone server binary:


- we do curl https://getcaddy.com | bash -s personal - and this leaves us with Caddy binary installed in /usr/local/bin/caddy.

We have used personal license here, but for commercial purposes we could have chosen commercial (paid) license, which starts at $25/month per instance. The other option is to clone Caddy's repo from github and build it ourselves, which would add couple of steps to the installation, but would cost nothing at all. More information about that on Caddy's github.

Configuring Caddy

Next we assign proper ownership to the binary (this would have been already done if you followed this guide to the word): sudo chown root:root /usr/local/bin/caddy - and permissions - sudo chmod 755 /usr/local/bin/caddy.

On Linux, ports below 1024 are privileged ports, to which by default only root user / processes can bind, and we don't usually want to run caddy as root - for standard security precautions, so we give binary the ability to bind to ports 443 and 80: setcap 'cap_net_bind_service=+ep' /usr/local/bin/caddy.

User and group www-data usually already exist on newly installed Ubuntu 16.04 LTS image, but if not, we create it as outlined here.

We now create configuration directory for caddy under /etc and assign ownership to root user:

mkdir /etc/caddy
chown -R root:root /etc/caddy

and create and assign ownership for ssl directory for caddy under /etc/ssl, and log directory under /etc/log:

mkdir /etc/ssl/caddy
mkdir /var/log/caddy
chown -R root:www-data /etc/ssl/caddy /var/log/caddy
chmod 0770 /etc/ssl/caddy /var/log/caddy

Now we create and set up ownership for our Caddyfile:

touch /etc/caddy/Caddyfile
chown root:root /etc/caddy/Caddyfile
chmod 644 /etc/caddy/Caddyfile

Presuming we will host just one website, we create our root server directory:

mkdir /var/www - and then we assign ownership to www-data user and set up permissions - this is fairly standard procedure that would be valid for other servers, like Apache and NGINX:

chown -R www-data:www-data /var/www
chmod -R 555 /var/www

Most basic setup for our Caddyfile would be

mydomain.com {
    root /var/www

- where mydomain.com is any domain that we have set up to pint to our server's public IP.

We want to run caddy as a service, so for example, in case of system reboot, it will come back online automatically:

wget https://raw.githubusercontent.com/mholt/caddy/master/dist/init/linux-systemd/caddy.service
cp caddy.service /etc/systemd/system/
chown root:root /etc/systemd/system/caddy.service
chmod 644 /etc/systemd/system/caddy.service
systemctl daemon-reload
systemctl start caddy.service
systemctl enable caddy.service

Now the server should be working and serving content on the domain we pointed to our public
IP - and created virtual host in Caddyfile for.

We can create an index.html file in /var/www directory and fill it with some test text, like

<h1>Hello Caddy</h1> - and voila, our page is available online:


Here, we used a test domain ttfb.review for our virtual host. We can see that, without any configuration whatsoever, Caddy has obtained a certificate from Let's Encrypt, and that Chrome recognizes it as valid, and considers our page secure.

Installing MySQL

Now that we have Caddy working, we will install MySQL:

apt-get -y install mysql-server mysql-client - and after we install it, we do mysql_secure_installation

Installing PHP7.0

Now we install PHP and auxiliary libraries:

apt-get -y install curl php7.0-cli php7.0-fpm php7.0-mysql php7.0-curl php7.0-gd php7.0-intl php-pear php-imagick php7.0-imap php7.0-mcrypt php-memcache php7.0-pspell php7.0-recode php7.0-sqlite3 php7.0-tidy php7.0-xmlrpc php7.0-xsl php7.0-mbstring php-gettext

Our server stack is now installed, and we just have to configure our virtual host, by adding a couple of lines to our Caddyfile - to log events and errors, and to proxy requests to php-fpm process.

ttfb.review {
    root /var/www
    log /var/log/caddy/ttfb.review.log 
    errors /var/log/caddy/errors.log
    fastcgi / /run/php/php7.0-fpm.sock php {
        ext .php
        split .php
        index index.php

Then we will restart Caddy and php7.0-fpm: service caddy restart and service php7.0-fpm restart - and then we will create test php file in our web root - /var/www - and name it info.php .

This file should contain just <?php phpinfo(); ?> line. If everything is okay, we should see something like this in our browser:


If there are any issues with restarting Caddy and seeing the results in out browser, we will want to check the ownership and permissions for the directories /var/log/caddy and /etc/ssl/caddy - as these can prevent the server from starting.

To verify that we have set up MySQL correctly, we will download adminer - one-file database manager for MySQL:

wget https://github.com/vrana/adminer/releases/download/v4.6.3/adminer-4.6.3-mysql-en.php in our server root.

We can then rename the file into something more obscure. Then we can visit that file at our url, and login with MySQL details we have set at installation. Then we should be presented with something like



In this guide, we have presented the advantages - and simplicity of Caddy with PHP and MySQL stack, installed on an Alibaba Cloud Elastic Compute Service (ECS) instance. We have seen its efficiency and ease of use in regard to obtaining Let's Encrypt certificate, which gives our website automatic encrypted browsing. Caddy has a lot features and plugins that we didn't cover - we may do that in one of our future guides.

0 0 0
Share on

Alibaba Clouder

2,600 posts | 750 followers

You may also like


Alibaba Clouder

2,600 posts | 750 followers

Related Products