Building a Vagrant box with Debian 8, Nginx, PHP 7.0, MySQL, NodeJS and Gulp

In this tutorial I’m gonna show you how to build a Debian Vagrant box with the following technologies

  • Nginx
  • MySQL (MariaDB)
  • PHP 7.0
  • NodeJS
  • Gulp

The vagrant box will install all of this software automatically when you type in vagrant up into your shell. This tutorial assumes you already got Vagrant and a VM provider (in this tutorial Virtualbox) and have a basic understanding of Vagrant (e.g. what a Vagrantfile is, what a provisioning script is, etc.). Scroll to the end if you simnply want the complete Vagrantfile and the files needed for the provisioning script

When you see the string „projectname“ in the tutorial you can replace this string with the name of your project

Step 1: Initializing Vagrant in your project.

To initialize Vagrant in your project, open up your shell, navigate to the directory where your project is and type in vagrant init. This will create a Vagrantfile in your project.

Step 2: Building the Vagrantfile

Before building the Vagrantfile make sure you – you don’t have to though – have installed the Vagrant Hostupdater

The Vagrantfile is only 11 lines long and only contains some information for the box itself and the path to the script in which we will later install all packages and do the configurations we need.

Vagrant.configure(2) do |config|
    config.vm.box = "debian/jessie64"
    config.vm.network "private_network", ip: "192.168.60.98"
    config.vm.hostname = "www.projectfantasy.dev"
    config.vm.provision :shell, path: "vagrant_ressources/bootstrap.sh"
    config.vm.synced_folder ".", "/var/www/projectname/www/", type: "nfs", mount_options: ['rw', 'vers=3', 'tcp', 'fsc' ,'actimeo=2']
end

Let’s break this down into pieces

config.vm.box = "debian/jessie64"

This line defines which box we want to use. In this case it would be the most recent version of Debian Jessie (8.4)

config.vm.network "private_network", ip: "192.168.60.98"
config.vm.hostname = "www.projectname.dev"

These lines tell the box to run under the IP 192.168.60.98 and then tell the Vagrant Hostupdater plugin to create the host-entries automatically so you can call www.projectname.dev directly to see your project.

config.vm.provision :shell, path: "vagrant_ressources/bootstrap.sh"

This line simply tells the box which script to run when we are provisioning the box

config.vm.synced_folder ".", "/var/www/projectname/www/", type: "nfs", mount_options: ['rw', 'vers=3', 'tcp', 'fsc' ,'actimeo=2']

This line maps the project root folder with /var/www/projectname/www. It also tells the box which type of syncing it should use and which options. You can change the synced folder to /var/www/ or something else if you want.

Step 3: Creating files needed for the provisioning script (nginx config, fastcgi  configs, etc.)

This step will explain you how to create the files needed from the provisioning script in order to function correctly. You need to place this files into the folder vagrant_ressources which should be at the same level as the Vagrantfile

Filename: fastcgi_params

fastcgi_param   QUERY_STRING      $query_string;
fastcgi_param  REQUEST_METHOD    $request_method;
fastcgi_param  CONTENT_TYPE      $content_type;
fastcgi_param  CONTENT_LENGTH    $content_length;

fastcgi_param  SCRIPT_FILENAME       $request_filename;
fastcgi_param  SCRIPT_NAME       $fastcgi_script_name;
fastcgi_param  REQUEST_URI       $request_uri;
fastcgi_param  DOCUMENT_URI      $document_uri;
fastcgi_param  DOCUMENT_ROOT     $document_root;
fastcgi_param  SERVER_PROTOCOL       $server_protocol;

fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE       nginx/$nginx_version;

fastcgi_param  REMOTE_ADDR       $remote_addr;
fastcgi_param  REMOTE_PORT       $remote_port;
fastcgi_param  SERVER_ADDR       $server_addr;
fastcgi_param  SERVER_PORT       $server_port;
fastcgi_param  SERVER_NAME       $server_name;

fastcgi_param  HTTPS        $https if_not_empty;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param  REDIRECT_STATUS       200;

Since I blatantly copied this config, I can’t explain you what exactly it does and what you could change here.

Filename: locale.gen 

If you don’t want to set up any languages skip this part, otherwise these are the file contents for adding support for the German language

de_DE ISO-8859-1
de_DE.UTF-8 UTF-8
de_DE@euro ISO-8859-15
en_US.UTF-8 UTF-8

Filename: nginx.conf

This file holds the configuration values for the Nginx server. We set some settings, such as basic settings like timeouts, mime types, enabling gzip and set the values for the error and access logs. Since I’m doing a 1 project, 1 server approach, I will not modify the location of the logs to have the name of the project.

user www-data;
worker_processes 4;
pid /run/nginx.pid;

events {
   worker_connections 768;
}

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    gzip on;
    gzip_disable "msie6";
    
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

Filename: projectname

Name this file like your project is named. This is the vHost config. I copied this config from a site for a Laravel vHost config. It could be that you need to adjust some settings, such as the root folder and the server_name

server {
   listen 80 default_server;
   listen [::]:80 default_server ipv6only=on;

   root /var/www/projectname/www/public;
   index index.php

    # Important for Virtualbox
   sendfile off;

   # Make site accessible from http://www.projectname.dev/
   server_name www.projectname.dev;

   location / {
      try_files $uri $uri/ /index.php$is_args$args;
   }

   # pass the PHP scripts to FastCGI server listening on /var/run/php/php7.0-fpm.sock
   location ~ \.php$ {
       include fastcgi_params;

        fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;

        fastcgi_cache off;

        fastcgi_index index.php;

        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

Filename: sources.list

In this file, we will add the URLs for the repositories that we need for the box. We need to add two repositories, because PHP 7.0 is not available by default in Debian Jessie yet (No idea if it changes in the future)

deb http://httpredir.debian.org/debian jessie main
deb-src http://httpredir.debian.org/debian jessie main

deb http://security.debian.org/ jessie/updates main
deb-src http://security.debian.org/ jessie/updates main

deb http://ftp.hosteurope.de/mirror/packages.dotdeb.org/ jessie all
deb-src http://ftp.hosteurope.de/mirror/packages.dotdeb.org/ jessie all

Only the last two lines are important, because with them we are adding other sources for downloading packages. The first four lines are already in the default sources.list of Debian. I’m using a German mirror, if you want to change this simply visit Dotdeb’s mirrors page and take your own mirror.

Step 4: Creating the bootstrap script to build the box

This is the most important part. The bootstrap script will run if we provision the box (first start or when starting the box with --provision)

Create the file bootstrap.sh inside your vagrant_ressources folder.

The beginning

First, we will set some variables for the box. These variables will be used for the projectname, the projectpath, the root mysql password and the user mysql password. We do this, so we can use variables instead of hard coded strings when using commands inside the box. This has the advantage, that we can simply change  the first four lines of the scripts and have the box work for every project (that wants to use the same technologies)

#!/usr/bin/env bash
projectname='projectname'
projectpath="/var/www/$projectname/www"
r_password=password
u_password=secret

I think that the variables are self-explaining. As you can see, the variable projectpath is already making use of the variable projectname.

The initial update of the box

In this part, we will update the box to be on the most recent state and generate some locales.

apt-get update # Update the box
# OPTIONAL - Only use, when you want to change languages
cp ${projectpath}/vagrant_ressources/locale.gen /etc/ # Copy languages to the box
locale-gen de_DE.UTF-8 # Generate the locales
timedatectl set-timezone Europe/Berlin # Set the timezone

Adding the dotdeb repository

Since PHP 7.0 is not available in the base installation of Debian, we need to add external sources where packages can be downloaded from.

cp ${projectpath}/vagrant_ressources/sources.list /etc/apt/ # Copying the newly created sources file to the box
wget https://www.dotdeb.org/dotdeb.gpg # Downloading the GPG-Key
apt-key add dotdeb.gpg # Adding the GPG-Key
apt-get update # Again, update the box to have the new repositories and be up to date

Installing PHP 7.0 tools and extra software (tmux, curl, wget, nginx, fpm, cli, curl, gd, intl)

This part simply installs PHP 7.0 and some extra tools

apt-get install -y tmux curl wget nginx php7.0-fpm php7.0-cli php7.0-curl php7.0-gd php7.0-intl php7.0-mysql git unzip zip

Creating user and setting permissions

We also create a user that will get the correct permissions for the files and folders of our project and that will be added to the www-data group.

adduser --disabled-login ${projectname} # Creating the user 
adduser www-data ${projectname} # Adding the user to the www-data group
chown -Rf ${projectname}:${projectname} ${projectpath} ### Giving the rights for the project folders to the user
chmod 755 ${projectpath}/ # Changing the permissions of the root folder
chmod 750 ${projectpath}/public # Changing the permissions of the document root folder for the webserver

Initializing database

We will install MariaDB right here. MySQL should be almost the same, with some differences. If people want, I will create an alternative here for using normal MySQL. The problem with installing MySQL-Servers in vagrant, is that most of the time, there will be a GUI which asks for user input. But what we will do is to skip this user input by setting the input beforehand

debconf-set-selections <<< "mariadb-server-10.0 mysql-server/root_password password $r_password" # Set the root password for the MySQL user
debconf-set-selections <<< "mariadb-server-10.0 mysql-server/root_password_again password $r_password" # Just a password confirmation
apt-get install -y mariadb-server # Install MariaDB-Server
/etc/init.d/mysql restart # Restart the Server

mysql -u root -p${r_password} -e "GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '$r_password' WITH GRANT OPTION; FLUSH PRIVILEGES;" # Granting all privileges to the root user (No idea if this is even needed)
mysql -u root -p${r_password} -e "CREATE DATABASE $projectname CHARACTER SET utf8;" # Create the database for the project
mysql -u root -p${r_password} -e "CREATE USER '$projectname'@'%' IDENTIFIED BY '$u_password';" # Create the user for the database for the project
mysql -u root -p${r_password} -e "GRANT ALL PRIVILEGES ON $projectname.* TO '$projectname'@'%';" # Grant all priviliges for the user for the database for the project

Setting up Nginx

We don’t need to do much here. We will just copy our configuration from the vagrant_ressources folder into the correct debian folders

cp {$projectpath}/vagrant_ressources/fastcgi_params /etc/nginx/
cp ${projectpath}/vagrant_ressources/${projectname} /etc/nginx/sites-available/${projectname} # Copy the vhost config to the available sites
ln -s /etc/nginx/sites-available/${projectname} /etc/nginx/sites-enabled/ # Enable the vhost
rm -rf /etc/nginx/sites-available/default # Remove the default vhost

Setting up NodeJS

We need NodeJS for using Gulp. You can skip this step if you don’t need Gulp or NodeJS

curl --silent --location https://deb.nodesource.com/setup_4.x | sudo bash - # Downloading the NodeJS setup and running it
apt-get install --yes nodejs # Install NodeJS
npm install -g gulp # Install Gulp

Setting up Composer

We use composer for dependency management. We won’t do composer install here, because if you have a big list of packages you might run into a Github authentication error for too many requests without being authenticated. So what I do is running composer install from my command line afterwards from the Host OS instead of the Guest oS. These lines are taken directly from the Composer website, so I won’t get into detail what the lines do. They install composer and make it accessible globally.

php -r "readfile('https://getcomposer.org/installer');" > composer-setup.php
php composer-setup.php
php -r "unlink('composer-setup.php');"
mv composer.phar /usr/local/bin/composer

Final step
Now reload nginx

service nginx restart

And you’re done. You can now use vagrant up to start the machine and run all the scripts to have a functioning box. Afterwards you should be able to go to www.projectname.dev in your browser and see all the stuff.

As I said, here are all the files zipped into one file, so you can download them directly, adjust some stuff in the Vagrantfile, bootstrap.sh (projectname, projectpath, languages, etc) and then run the box! If you find anything not working or need more help, please contact me directly and I will adjust this tutorial!

It's only fair to share...Share on FacebookTweet about this on TwitterShare on RedditEmail this to someoneShare on Tumblr

3 thoughts on “Building a Vagrant box with Debian 8, Nginx, PHP 7.0, MySQL, NodeJS and Gulp

Leave a Comment

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.