We will optionally install xdebug with PHP.
More specifically, we're going to download the source code and build from scratch, the following packages and versions:
Package | Version |
MySQL | 5.7.11 |
PHP | 5.6.18 |
Nginx | 1.9.12 |
This directory contains not merely this README file, but also a handful of initial configuration files. Hence the version control.
Any installation starts with this directory. During the build, we'll download, unzip, and otherwise create lots of new files in this directory. But even though this directory is under git version control, we don't want to add these new files.
This process will use .tar.gz (or similar) files containing the source code for all of the above. We want to be able to very carefully rebuild the same stack, every time, starting from exactly the same source code. Attempting to do this using the SCM repos of the various programs is needlessly complicated because these programs use several different systems. And attempting to do this using whatever package manager is available on a specific system is troublesome because the different packages will likely contain subtle differences that will likely cause grief. All of the installation is contained within this directory and uses non-standard ports and user names. This stack may thus be easily deleted and rebuilt without affecting other packages on the system. One reason for using non-standard ports, in additional to a minor security boost, is to ensure that we really are dealing with this software and not pre-existing instances that may have been installed previously. This installation my be built and executed as an "ordinary" user, ie. not root, and can be placed anywhere said user has sufficient access rights, such as in his HOME directory. This will however require that we use certain non-standard ports. For example, an ordinary user cannot run a process to bind to port 80. Although Nginx, MySQL, PHP, and php-fpm can all be installed and executed by an ordinary user, the host system still needs a variety of build tools. You will most conveniently need to sudo or root access to install these tools, if they are not already installed.Starting from a fresh install of Ubuntu 15.10, I needed to install the following extra packages to get all this to work:
MySQLPackage name | Why? |
---|---|
cmake | MySQL |
libncurses5-dev | MySQL |
libxml2-dev | PHP |
libssl-dev | PHP |
libpcre3-dev | nginx |
Unfortunately, installing all this is outside the scope of this document, so you're on your own with this.
Ok, here we go...-
Determine a file-system location for this installation. Let's refer to that location as STACK_ROOT. In fact, let's export that as an environment variable.
export STACK_ROOT=/home/myhome/lemp
Warning: If STACK_ROOT is in a user's home directory, you might be tempted to use the ~ as part of the path. Resist the urge because subsequent make install apparently don't like that.
-
p>rm -rf $STACK_ROOT
Remove any prior installation.
mkdir $STACK_ROOT
cd $STACK_ROOT
git clone https://github.com/bostontrader/lemp.git .
Be sure to include the trailing 'dot' That says to clone the repository into 'this' directory.
Let's install MySQL first. This is the most complicated part and if you can get this working then the rest of the installation will be easier. Also, the PHP installation needs MySQL so we need to install this first.
Since our goal is specifically to build from source code, we'll neglect to use any easier installation methods such as package managers. A good starting point for building from source is http://dev.mysql.com/doc/refman/5.7/en/source-installation.html
There are a few issues to consider when installing MySQL:
- Which directory will contain the database files? Not the binaries or configuration, but the database files themselves.
- How do we carefully control where configuration information comes from? This can be confusing because MySQL will routinely look in several places and we can easily mix in config from other installations.
- Which user and group should be the owner of the database files?
That said, let's doit...
Earlier I referenced the starting point in the MySQL docs for building the source code. A more specific reference for our purposes now can be found at:
http://dev.mysql.com/doc/refman/5.7/en/installing-source-distribution.html- export MYSQL_DEFAULT_PORT=3307
Determine a port for the configuration to listen to. The MySQL default port = 3306 so let's secure by obscurity and use a different port:
- export MYSQL_USER=batman
export MYSQL_GROUP=catwomanThe access rights for the various files are customarily set according to a user=mysql and a group=mysql. As with the port, let's again thwart our determined nemeses and use different names.
-
groupadd $MYSQL_GROUP
useradd -r -g $MYSQL_GROUP -s /bin/false $MYSQL_USER
Add the group and user, if necessary. cd $STACK_ROOT
Ensure that you're in the STACK_ROOT directory.wget http://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-boost-5.7.11.tar.gz
This downloads the source code, including some c++ boost source/headers.
tar xvf mysql-boost-5.7.11.tar.gz
cd $STACK_ROOT/mysql-5.7.11
cmake -L
Optional. Gives a brief overview of important configuration parameters. You can change their values by using the -D option. See supra for example.cmake . -DCMAKE_INSTALL_PREFIX=$STACK_ROOT/mysql -DMYSQL_DATADIR=$STACK_ROOT/mysql/data -DWITH_BOOST=$STACK_ROOT/mysql-5.7.11/boost
If you want to start over with cmake, then do rm CMakeCache.txt
make
make test
make install
cd $STACK_ROOT/mysql
sudo chown -R $MYSQL_USER .
sudo chgrp -R $MYSQL_GROUP .
sudo bin/mysqld --initialize --user=$MYSQL_USER
This may take a few moments, so please be patient.
The output from the prior step includes a temporary password for root@localhost. Be sure to write this down!
cd $STACK_ROOT/mysql
sudo mkdir mysql-files
sudo chmod 750 mysql-files
sudo chown -R $MYSQL_USER .
sudo chgrp -R $MYSQL_GROUP .
At this point the MySQL daemon and various utilities are ready to run. Although the installation created a default conf file, we don't want to use it. Instead, we'll feed the binaries whatever options via command line. The following options are typically used for our application:
--no-defaults If we don't carefully suppress the use of any default configuration files, MySQL will diligently try to find some configuration and it may find and use configuration from some other installation. So we generally want to use this option to prevent that.
--user=$MYSQL_USER The actual db files are owned by this user. If we don't specify this then MySQL will typically use the currently logged in user.
--port=MYSQL_DEFAULT_PORT Which TCP/IP port will the program listen on?
--protocol=tcp Sometimes this is required. Sometimes the use of the --port option apparently implies this option as well.
--datadir=? Where are the datafiles?
--log-error=? Where is the error log?
That said... let's crank it up!
sudo $STACK_ROOT/mysql/bin/mysqld_safe
--user=$MYSQL_USER
--log-error=$STACK_ROOT/mysql.err --datadir=$STACK_ROOT/mysql/data
--port=$MYSQL_DEFAULT_PORT
mysqld_safe is the preferred way to execute mysqld. This command will _not_ be daemonized and will consume your terminal window. So append the "&" character to daemonize or open another terminal window for subsequent work.
sudo ps -A | grep mysqld
Verify that mysql is a process.
You should see both "mysqld" and "mysqld_safe"
sudo netstat -lnp | grep mysql
Verify that mysql is listening on the expected port.
Do you see $MYSQL_DEFAULT_PORT and "LISTEN" in there somewhere?
killall -r mysql
Stop the server, ending any processes it had.
$STACK_ROOT/mysql-5.7.11.tar.gz - This is the original installation media.
$STACK_ROOT/mysql-5.7.11 - This is the installation source code as extracted from the above.
$STACK_ROOT/mysql - This contains the MySQL installation that was built from the above.
Now install PHP 5.6.18. This release also includes php-fpm so that will be installed as well. We will however configure php-fpm separately.
cd $STACK_ROOT
Ensure that you're in the STACK_ROOT/ubuntu-nginx-php-mysql directory.tar xvf php-5.6.18.tar.bz2
cd $STACK_ROOT/php-5.6.18
./configure --help
This is optional but possibly useful. Possibly review the modules being loaded and exclude some of them../configure --prefix=$STACK_ROOT/php --enable-fpm --with-mysql=$STACK_ROOT/mysql
make --help Optional.
make
make test This may reveal some minor errors. Don't worry about them.
make install
We need fpm!
Note: After installation, there is no initial php.ini. This will be added later.
$STACK_ROOT/php/bin/php --version
Look for version or info about php.
Does this say 5.6.18?
$STACK_ROOT/php/bin/php --info
Look at the info....
$STACK_ROOT/php/bin/php --info | grep "Loaded Configuration"
Narrow the search for "Loaded Configuration". Is php using the php.ini we expect?
At this point, there should be none loaded at all.
$STACK_ROOT/php/bin/php --info | grep "configure"
This will tell you the exact configuration you used for this build. This is useful when you return to this later and need to configure new options.
$STACK_ROOT/php-5.6.5.tar.bz2 - This is the original installation media. Not under SCM.
$STACK_ROOT/php-5.6.5 - This is the installation source code as extracted from the above. Not under SCM.
$STACK_ROOT/php - This contains the PHP installation that was built from the above. Not under SCM.
php-fpm has already been installed via our installation of PHP. The versioning is not relevant because it's whatever version comes with PHP 5.6.18. We do however need to configure php-fpm and learn a bit about its ways and customs.
Determine a port for the initial configuration to listen to. By default it's port 9000. For this example let's use 9001.
PHPFMP_DEFAULT_PORT = 9001
Use a custom built configuration provided by this project.
The stock configuration is filled with commented out examples. This just confuses everything. The custom built config has nothing except things we specifically want. We'll otherwise just rely on the default operation of php-fpm until and unless we specifically decide otherwise.
ln -s $STACK_ROOT/php-fpm-conf/php-fpm.conf $STACK_ROOT/php/etc/php-fpm.conf
Help, version, info.
$STACK_ROOT/php/sbin/php-fpm --help
$STACK_ROOT/php/sbin/php-fpm -v
$STACK_ROOT/php/sbin/php-fpm -i
$STACK_ROOT/php/sbin/php-fpm -t
Test the configuration file.
$STACK_ROOT/php/sbin/php-fpm
This will start the php-fpm server.
netstat -lnp | grep php-fpm
Verify that php-fpm is listening on the expected port.
Do you see "127.0.0.1:PHP-PFM_DEFAULT_PORT" and "LISTEN"?
ps -A | grep php-fpm
killall php-fpm
Stop the php-fpm server.
Recall that php-fpm was installed with PHP so therefore php-fpm will not have it's own original installation media or extracted source or installation directory.
$STACK_ROOT/php-fpm-conf
This contains the versioned configuration files that we develop.
$STACK_ROOT/php/sbin/php-fpm
This is the executable binary.
$STACK_ROOT/php/etc/php-fpm.conf
This is a link to the configuration file.
Now it's time to install nginx version 1.9.12.
- export NGINX_DEFAULT_PORT=3000
Determine a port for the initial configuration to listen to. As an unprivileged user we cannot use port 80.
cd $STACK_ROOT
tar xvf nginx-1.9.12.tar.gz
cd $STACK_ROOT/nginx-1.9.12
./configure --help
This is not strictly necessary, but it may be useful. Possibly review the modules being loaded and exclude some of them../configure --prefix=$STACK_ROOT/nginx --without-http_gzip_module
Look at the output of configure. It will tell you that the binaries, the configuration, the logs, etc. are all found inside this directory.We don't need gzip compression right now, which requires zlib, and it's easier to omit gzip than to install zlib at this time.
make --help
Optional, but may be useful.make
make install
rm -rf $STACK_ROOT/nginx/conf/\*
Remove the contents of the existing directory.ln -s $STACK_ROOT/nginx-conf/nginx.conf $STACK_ROOT/nginx/conf/nginx.conf
Link to new configThe stock configuration is filled with commented out examples. This just confuses everything. The custom built config has _nothing_ except things we specifically want. We'll just rely on the default operation of nginx until and unless we specifically decide otherwise.
$STACK_ROOT/nginx/sbin/nginx -t
Test the configuration file.
$STACK_ROOT/nginx/sbin/nginx &
Start the server. Recall that the "&" symbol makes this command run as a daemon.
netstat -lnp | grep nginx
Verify that nginx is listening on the expected port. Do you see "0 0.0.0.0:NGINX_DEFAULT_PORT" and "LISTEN"?
From your browser of choice, view this server, using the NGINX_DEFAULT_PORT. For example, what's the IP address of the server? Browse to ip-address:NGINX_DEFAULT_PORT. Do you see the nginx welcome message? As an exercise, find this message and modify it in order to verify that you really understand where this is being served from.
$STACK_ROOT/nginx/sbin/nginx -s reload
Restart the server and reload the config.
ps -A | grep "nginx"
Display any processes running nginx. There should be two processes, unless some other nginx
is running on this server.
$STACK_ROOT/nginx/sbin/nginx -s stop
Stop the server, ending any processes it had.
$STACK_ROOT/nginx-1.9.12.tar.gz - This is the original installation media. Not under SCM.
$STACK_ROOT/nginx-1.9.12 - This is the installation source code as extracted from the above. Not under SCM. Note: this also contains the original configuration.
$STACK_ROOT/nginx - This contains the nginx installation that was built from the above, which is the binaries, configuration, log files, and html to serve. Not under SCM.
$STACK_ROOT/nginx-conf - This contains the versioned configuration files that we develop, that are later copied into the STACK_ROOT/ubuntu-nginx-php-mysql/nginx/conf directory.
Now it's time to modify our configuration so that we can view a .php file, that contains a call to phpinfo() and view this in the browser, via nginx. Since we're using php-fpm, we'll have to get that properly configured as well.
Replace the installed nginx configuration directory with the custom built configuration provided by this project. Note: This is the 2nd custom config that we're using.
Edit $STACK_ROOT/nginx/conf/nginx.conf to replace STACK_ROOT with the real value.
Turn on (or reload) nginx.
Turn on (or reload) php-fpm.
From your browser of choice, navigate to localhost:NGINX_DEFAULT_PORT/phpinfo.php. Do you see the php info message? You do? Congrats! Time for a cold one, a fat one, or both!
ln -sf $STACK_ROOT/nginx-conf/nginx.conf2 $STACK_ROOT/nginx/conf/nginx.conf
Link to new config. This time you'll want to force (f) the link to replace the existing link.