Symfony LAMP (Linux, Apache, PHP, MySQL) Setup


In this beginner friendly tutorial you will learn how to setup the LAMP stack on a new Digital Ocean Droplet.

For complete clarity, LAMP is:

  • Linux
  • Apache
  • MySQL
  • PHP

PHP apps and Linux play very nicely together. We will be using Ubuntu flavoured Linux, but feel free to swap out for any distro you prefer. Please note that if you do not use Ubuntu, some of the demonstrated package management commands in this tutorial will not work.

We will make use of Apache as our webserver.

We will install MySQL for our database.

PHP 7.0 will be installed as part of this tutorial. This is not the latest and greatest, but is sufficient for our needs, and is available to install without additional complexity.

This is not intended to be a secure, or production optimised environment.

This is intended to get you comfortable with the basics of a LAMP stack, from which we can experiment with deploying (primarily Symfony) applications.

We will get onto the more real-world deployments later in this series.

A Drop In The Ocean

To begin with we are going to create a new Digital Ocean Droplet using the $10 plan, installing a fresh copy of Ubuntu 16.04.3 x64 as our virtual server / droplet Operating System.

You can follow this process on a different VPS provider such as Linode, or Amazon AWS.

If you do not yet have a Digital Ocean account, please create one now. By using this link you will get $10 initial credit, which is going to be more than enough to complete all the examples in this course. Full disclosure: this is an affiliate link.

Be sure to upload your SSH key(s) as available. If you do not have an SSH key, then please follow this guide.

Creating your new Droplet should take about 30 seconds.

Once done, you should be able to SSH into the box by running:

$ ssh root@165.227.110.26

The authenticity of host '165.227.110.26 (165.227.110.26)' can't be established.
ECDSA key fingerprint is SHA256:Hwc/UjUJAz6151hRh1QBqAzocuO/HGMr6Gugcd+YuVU.
Are you sure you want to continue connecting (yes/no)? yes

Warning: Permanently added '165.227.110.26' (ECDSA) to the list of known hosts.
Welcome to Ubuntu 16.04.3 LTS (GNU/Linux 4.4.0-93-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  Get cloud support with Ubuntu Advantage Cloud Guest:
    http://www.ubuntu.com/business/services/cloud

0 packages can be updated.
0 updates are security updates.

The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

root@ubuntu-1gb-nyc03-01:~#

Cool, we are in.

Now, connecting as root is not good. But as mentioned, we are not concerned with security at this stage. In fact, once done here we will be destroying this droplet.

Because we are root, we don't need to use sudo before any of our commands. That's why you will see e.g. apt-get update, rather than sudo apt-get update sprinkled throughout this tutorial.

Our Fake Domain

Before we go further let's talk about the domain we will be using.

You can use a real domain name for this tutorial, if you have one.

You can use a subdomain of an existing domain, if you're feel adventurous (and know what you're doing / or there are no consequences if you break the root domain by accident).

But you can also make use of a host file entry. Or, to put it another way, you can save yourself a bit of cash and just make one up.

On Linux / Mac, to do this you need to edit your /etc/hosts file:

sudo vim /etc/hosts

At the bottom of this file add in a new line containing the IP address of your Digital Ocean Droplet, and the fake domain name you have made up.

If not using Vim then edit the /etc/hosts file accordingly.

The key combination in vim is rather strange.

shift + G

Takes you to the bottom of the open file.

o (the letter), makes a new line and puts you in INSERT mode.

From here, type as normal. In my case this line will be:

104.236.215.199   crvfakeexample.com

After this, press esc, then :wq to write and quit.

If at any point you make a mistake, press esc, then type :q! to quit without saving. Then just repeat the process till you get it right. Such is the beginners way with vim :D

At this point you should be able to ping your new fancy made up domain name and get a response from your real DO Droplet:

$ ping crvfakeexample.com

PING crvfakeexample.com (104.236.215.199) 56(84) bytes of data.
64 bytes from crvfakeexample.com (104.236.215.199): icmp_seq=1 ttl=47 time=119 ms
64 bytes from crvfakeexample.com (104.236.215.199): icmp_seq=2 ttl=47 time=124 ms
64 bytes from crvfakeexample.com (104.236.215.199): icmp_seq=3 ttl=47 time=116 ms
^C
--- crvfakeexample.com ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 116.885/120.071/124.142/3.028 ms

We're cooking with gas!

Apache Server Setup

Switch back to your server's terminal session now.

To start with, let's make sure we have the latest list of available packages:

$ apt-get update

Next, we want to install Apache:

$ apt-get install apache2

Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following package was automatically installed and is no longer required:
  grub-pc-bin
Use 'apt autoremove' to remove it.
The following additional packages will be installed:
  apache2-bin apache2-data apache2-utils libapr1 libaprutil1 libaprutil1-dbd-sqlite3 libaprutil1-ldap liblua5.1-0 ssl-cert
Suggested packages:
  www-browser apache2-doc apache2-suexec-pristine | apache2-suexec-custom openssl-blacklist
The following NEW packages will be installed:
  apache2 apache2-bin apache2-data apache2-utils libapr1 libaprutil1 libaprutil1-dbd-sqlite3 libaprutil1-ldap liblua5.1-0 ssl-cert
0 upgraded, 10 newly installed, 0 to remove and 47 not upgraded.
Need to get 1557 kB of archives.
After this operation, 6432 kB of additional disk space will be used.
Do you want to continue? [Y/n] y

This spills a bunch of stuff out to the terminal, then dumps you back to the prompt once done.

Apache is now installed.

Let's add in our site config:

cd /etc/apache2/sites-available/

ls -la

total 20
drwxr-xr-x 2 root root 4096 Oct 14 12:39 .
drwxr-xr-x 8 root root 4096 Oct 14 12:39 ..
-rw-r--r-- 1 root root 1332 Mar 19  2016 000-default.conf
-rw-r--r-- 1 root root 6338 Apr  5  2016 default-ssl.conf

Before going further, let's disable that default site. We don't want it.

a2dissite 000-default

perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
    LANGUAGE = (unset),
    LC_ALL = (unset),
    LC_CTYPE = "en_GB.UTF-8",
    LANG = "en_US.UTF-8"
    are supported and installed on your system.
perl: warning: Falling back to a fallback locale ("en_US.UTF-8").
Site 000-default disabled.
To activate the new configuration, you need to run:
  service apache2 reload

It's telling us to run service apache2 reload, so lets:

service apache2 reload

There's no output here, but we should be good.

We likely also want mod_rewrite enabled so we don't see app.php all the time when browsing our production Symfony site:

a2enmod rewrite
service apache2 restart

Let's now add in our site config:

touch crvfakeexample.com.conf

vim crvfakeexample.com.conf

If you're not used to working with vim then simply copy the following:

<VirtualHost *:80>
    ServerName crvfakeexample.com
    ServerAlias www.crvfakeexample.com

    DocumentRoot /var/www/crvfakeexample.com/web
    <Directory /var/www/crvfakeexample.com/web>
        AllowOverride None
        Order Allow,Deny
        Allow from All

        <IfModule mod_rewrite.c>
            Options -MultiViews
            RewriteEngine On
            RewriteCond %{REQUEST_FILENAME} !-f
            RewriteRule ^(.*)$ app.php [QSA,L]
        </IfModule>
    </Directory>

    # uncomment the following lines if you install assets as symlinks
    # or run into problems when compiling LESS/Sass/CoffeeScript assets
    # <Directory /var/www/crvfakeexample.com>
    #     Options FollowSymlinks
    # </Directory>

    # optionally disable the RewriteEngine for the asset directories
    # which will allow apache to simply reply with a 404 when files are
    # not found instead of passing the request into the full symfony stack
    <Directory /var/www/crvfakeexample.com/web/bundles>
        <IfModule mod_rewrite.c>
            RewriteEngine Off
        </IfModule>
    </Directory>
    ErrorLog /var/log/apache2/crvfakeexample_com_error.log
    CustomLog /var/log/apache2/crvfakeexample_com_access.log combined
</VirtualHost>

Once inside vim, press i. You should see -- INSERT -- at the bottom of your terminal window.

At this point you can right click in the window, and paste the contents in.

Next, press esc to exit insert mode, and then type :wq to write and quit. In other words, save and close.

Boom, done.

Next, enable the site:

a2ensite crvfakeexample.com.conf

perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
    LANGUAGE = (unset),
    LC_ALL = (unset),
    LC_CTYPE = "en_GB.UTF-8",
    LANG = "en_US.UTF-8"
    are supported and installed on your system.
perl: warning: Falling back to a fallback locale ("en_US.UTF-8").
Enabling site crvfakeexample.com.
To activate the new configuration, you need to run:
  service apache2 reload

Then do as you're told:

service apache2 reload

Installing PHP

With Apache installed we can move on to installing PHP. For Symfony 2 or Symfony 3, we can suffice by installing PHP 7.0. Whilst not the very latest release, it is perfectly valid for our needs:

apt-get install -y php7.0 \
  libapache2-mod-php7.0 \
  php7.0-cli \
  php7.0-common \
  php7.0-mbstring \
  php7.0-gd \
  php7.0-intl \
  php7.0-xml \
  php7.0-mysql \
  php7.0-mcrypt \
  php7.0-zip

# or if you prefer a one-liner
apt-get install -y php7.0 libapache2-mod-php7.0 php7.0-cli php7.0-common php7.0-mbstring php7.0-gd php7.0-intl php7.0-xml php7.0-mysql php7.0-mcrypt php7.0-zip

That's PHP done:

php -v
PHP 7.0.22-0ubuntu0.16.04.1 (cli) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies
    with Zend OPcache v7.0.22-0ubuntu0.16.04.1, Copyright (c) 1999-2017, by Zend Technologies

Lastly, to complete our LAMP stack, we will install MySQL.

Installing MySQL

We will need a database. We're going to use MySQL. Again, you can switch this out to anything else you like, so long as you are comfortable working with it.

apt-get install mysql-server

Follow the prompts.

You will be asked to provide a root password.

To make your life as easy as possible, use the password of pass.

This is the default value in use as part of the demo apps coming up during the deploy parts of this series.

Think of this password as being similar - but not the same - as the root user of your server. Only this time, this user will have access to all your database data.

It goes without saying that the root user's password should be something suitably complex.

Outside of this demo environment: Not pass.

Welp, that was easy enough.

Wrapping Up

We have a working LAMP environment in to which we can start deploying our Symfony / other PHP applications.

This environment is neither optimised, nor secure.

This is designed for practicing deployments only.

Server security is a complex and in-depth topic. I do not profess to be a security expert.

What I will demonstrate later in this series are ways you can leverage the expertise of security professionals. But for now, again this is a practice environment.

Episodes

# Title Duration
1 Symfony LAMP (Linux, Apache, PHP, MySQL) Setup 06:58
2 Symfony LEMP (Linux, nginx, PHP, MySQL) Setup 07:15
3 Apache or nginx - You Gotta Get Your Permissions Sorted 02:46
4 Symfony 3.x Demo Deploy Project 02:45
5 Part 1/3 - Deploying with rsync 08:09
6 Part 2/3 - Deploying with rsync - Using builds 07:38
7 Part 3/3 - Deploying with rsync - Shared var 05:02
8 Part 1/3 - Deploying with git 09:42
9 Part 2/3 - Deploying with git - Sharing folders 05:24
10 Part 3/3 - Deploying with git - Adding builds 05:45