Debian 9 Stretch RC3 Dedicated Web Server Setup Step by Step. Time for PHP7 and MariaDB

Debian 9 (Stretch) release candidate 3 (RC3) is available since April 10th, 2017. Debian 9 RC3 is still a “testing” release (not recommended for production servers). Which is the release date of stable Debian 9? “When it’s ready” is the Debian answer. But, as Full freeze announced on February 5th, 2017 we can suppose that the final stable release will be available in about six months (mid of 2017). Please, note that no major differences are added after Full freeze (only bug fixes).

There are two very important changes in Debian 9 (Stretch):

So, it is crucial to test your projects, probably based on php 5.* and MySQL, in order to use Debian 9 official release in your server.

For this purpose, I setup Debian 9 RC3 in a virtual machine using Virtualbox. As MariaDB is a drop-in replacement for MySQL, moving to MariaDB seems to be easy. Use mysqldump to export your databases and then import them to MariaDB. You may encounter some problems moving to php7, depending on your php code. But generally, the migration is not so difficult. Below I describe my experience.

Base system installation

Debian 9 RC3 can be downloded from this page. I downloaded the netinst amd64 ISO image from here (generally 150-280 MB).

I created a Virtualbox with 200GB disk. The downloaded CD image must be attached to created virtualbox:

I prefer “bridged” network adapter:

Start the virtual machine. It will boot from CD, so the Debian installation will start. See the screenshots below.

Start installation

Power on virtual machine will start Debian setup. Select boot from CD (pressing F12 during start-up.


Configure language, location and keyboard.


DHCP auto configuration, set Hostname and Domain


Set root password and create a common user.

Disk Partitioning

I use EXT4 file system. All partitions are Primary. I prefer to create partitions manually, as following:

  • /boot partition 4 GB
  • / partition 200 GB
  • swap partition the rest of the disk: 10+ GB (usually RAM x 4)

Below is described partition creation in details (please, note: only /boot partition has bootable flag ON).

Base system

Installing the base system.

Package manager

Select Debian archive mirror and apt configuration.

Software installation

Software installation progress.

Popularity contest

Choose if you want to participate in Popularity contest.

Select additional software

After the installation of core system, additional software could be selected for installation. This is a server system, so only SSH server and Standard system utilities have been selected. Any additional software (web server, database server etc) will be installed manually after base installation (see below).

Grub boot loader

Grub boot loader installation.

Finish installation

Base Setup is finished. Reboot and login for first time.

This was the "base system" setup. From this point, I will customize the server according to my needs (LAMP setup etc).

Add static IP

The ifconfig command (included in net-tools package) has been deprecated, so it is missing by default on Debian, starting from Debian 9 (Stretch). To get the IP address you have to use the ip command.

pontikis@stretch-rc3:~$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:4e:4c:15 brd ff:ff:ff:ff:ff:ff
    inet brd scope global enp0s3
       valid_lft forever preferred_lft forever
    inet6 2a02:587:a012:e000:a00:27ff:fe4e:4c15/64 scope global mngtmpaddr dynamic
       valid_lft 46155sec preferred_lft 46155sec
    inet6 fe80::a00:27ff:fe4e:4c15/64 scope link
       valid_lft forever preferred_lft forever

So, to change the autoconfigured with DHCP IP to static

Login as root. Then

nano /etc/network/interfaces

replace this

# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

source /etc/network/interfaces.d/*

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
allow-hotplug enp0s3
iface enp0s3 inet dhcp
# This is an autoconfigured IPv6 interface
iface enp0s3 inet6 auto


# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

source /etc/network/interfaces.d/*

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
#allow-hotplug enp0s3
#iface enp0s3 inet dhcp

auto enp0s3
iface enp0s3 inet static

# This is an autoconfigured IPv6 interface
#iface enp0s3 inet6 auto

Finally, restart the network:

systemctl restart networking.service

Connect using SSH

From workstation computer:


then become root to perform administrative tasks

su -l root

Perform a full system update

Using apt-get:

apt-get update && apt-get -V upgrade

Update files database

Install the packages (if not installed):

apt-get install locate mlocate



Harden SSH

This is optional in a LAN machine. Anyway, edit SSH configuration:

nano /etc/ssh/sshd_config

Make the following changes

PermitRootLogin no
X11Forwarding no
AllowUsers your_user_name ...

Restart SSH

systemctl restart ssh.service

SSH key based authentication

First, generate a new SSH key

cd ~/.ssh
ssh-keygen -t rsa -b 4096 -C "your_email_here"

To connect from workstation to server machine, add your public key to server.

ssh-copy-id -i ~/.ssh/

Color Bash Prompt

To add color to common user prompt:

cd /home/pontikis
nano .bashrc

uncomment #force_color_prompt=yes


To add red color to root prompt:

cd /root
nano .bashrc

Set PS1 as follows:

PS1='${debian_chroot:+($debian_chroot)}\[\033[01;31m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '

Also, find # You may uncomment the following lines if you want `ls’ to be colorized: and uncomment the following lines

To see the changes you have to logoff and login again, or go to home and give

. .bashrc

Set default text editor

nano in my case:

update-alternatives --config editor


There are 4 choices for the alternative editor (providing /usr/bin/editor).

  Selection    Path                Priority   Status
* 0            /bin/nano            40        auto mode
  1            /bin/nano            40        manual mode
  2            /usr/bin/mcedit      25        manual mode
  3            /usr/bin/vim.basic   30        manual mode
  4            /usr/bin/vim.tiny    10        manual mode

Press <enter> to keep the current choice[*], or type selection number:

Customize nano text editor

To dislpay line numbers, uncomment # set constantshow

nano /etc/nanorc

## Constantly display the cursor position in the statusbar.  Note that
## this overrides "quickblank".
# set constantshow
set constantshow
## (The old form, 'const', is deprecated.)

Install ntp (Network Time Protocol)

Using apt-get

apt-get install ntp

Install webmin

You have to know the original Linux commands to perform all administrative tasks from command line. However, a control panel makes things easier sometimes. Webmin is a free and Open Source control panel basically for Linux. Webmin is a very powerful tool, but I use it mainly for the following tasks:

  • users management
  • iptables firewall
  • scheduled cron jobs

So, create a file like

nano /etc/apt/sources.d/webmin.list

and add the following lines

deb sarge contrib

Add apt key:

cd /root
apt-key add jcameron-key.asc


apt-get update
apt-get install apt-transport-https
apt-get install webmin

Install exim4 MTA

Using apt-get:

apt-get install exim4

Configure exim

This is a local machine, so you must use “smarthost”. See Gmail smarthost with Exim4 on Debian for details.

Forward root mail

It is important as various software and services send mail to inform root for results or errors (cron for example).

nano /etc/aliases


Then, rebuild aliases:


Install git (optional)

Using apt-get:

apt-get install git

Display basic configuration

git config --list

Set basic settings

git config --global 'Your Name'
git config --global
git config --global core.editor "nano"

Configure Git to properly handle line endings:

git config --global core.autocrlf input

Various tools (optional)

Using apt-get:

apt-get install mc p7zip-full htop

Wipe is useful to secure delete files.

apt-get install wipe

Get email notifications for updates

Install apticron to get email notifications for updates

apt-get install apticron

Check which services need restart after an update

apt-get install needrestart

READ DETAILS in this post: When to Restart Services or Reboot after Update on Debian or Ubuntu

Next part is LAMP (Linux, Apache, MySQL, PHP) setup. Additionally I describe Postgresql setup (optional) and memcached setup (optional).

MariaDB database server

Using apt-get:

apt-get install mariadb-server

(this will also install mariadb-client)

After installation, run:


mysql_secure_installation sets a root password (if not exists), removes anonymous users, disables non-local root access, removes the test database and access rules related to it and finally reloads privileges.

Restart MariaDB

systemctl restart mariadb.service

Configure connection mode – IMPORTANT

At this time, when you will try to connect to MariaDB (or MySQL) you will note something “strange”:

  • If you are root on your server, you may connect DIRECTLY to MariaDB (or MySQL) root account without any password, even you have defined a password. The command mariadb (or mysql) is enough:
    root@stretch-rc3:~# mariadb
    Welcome to the MariaDB monitor.  Commands end with ; or \g.
    Your MariaDB connection id is 10
    Server version: 10.1.22-MariaDB- Debian 9.0
    Copyright (c) 2000, 2016, Oracle, MariaDB Corporation Ab and others.
    Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
    MariaDB [(none)]>
  • A common user in your server cannot connect to MariaDB (or MySQL) root account using the root password. The command mariadb -uroot -p (or mysql -uroot -p) will fail:
    pontikis@stretch-rc3:~$ mariadb -uroot -p
    Enter password:
    ERROR 1698 (28000): Access denied for user 'root'@'localhost'

    Remark that this error is NOT the error you get when you give a wrong password:

    ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)

The reason for this is: the UNIX_SOCKET plugin (AUTH_SOCKET in MySQL) is installed by default in new installs of Ubuntu 15.10 and later, and Debian 9 Stretch.

Ream more for MariaDB here and for MySQL here.

You have two options in this situation:

  • either to modify your php code to connect to MariaDB/MySQL using Operating System user
  • or to revert to classic password authentication:

    Become root and login to MariaDB/MySQL. Then, execute the query:

    update mysql.user set plugin = '' where User='root';
    flush privileges;

    or (actually the same)

    update mysql.user set plugin = 'mysql_native_password' where User='root';
    flush privileges;

    personally, I chose this solution.

Postgresql database server (optional)


apt-get install postgresql

(this will also install postgresql-contrib)


Set postgres password and configure postgresql.conf and pg_hba.conf

I prefer md5 authentication.

Restart postgres

systemctl restart postgresql.service

Apache web server


apt-get install apache2

Configuration principles

Default document root: /var/www/html/

Configuration file: /etc/apache2/apache2.conf. DO NOT EDIT this file. Add your configuration to /etc/apache2/conf-available/. Example:

nano /etc/apache2/conf-available/my-config.conf
a2enconf my-config
systemctl restart apache2.service

Apache modules

Enable the modules you need. In my case

a2enmod rewrite


root@stretch-rc3:~# a2enmod rewrite
Enabling module rewrite.
To activate the new configuration, you need to run:
systemctl restart apache2
root@stretch-rc3:~# systemctl restart apache2.service

Configure Virtual Hosts

First modify “default host”. Remember to remove <VirtualHost *:80>

nano /etc/apache2/sites-available/000-default.conf




    DocumentRoot /var/www/html
    <Directory />
        Options FollowSymLinks
        AllowOverride None
    <Directory /var/www/html/>
        Options -Indexes +FollowSymLinks +MultiViews
        AllowOverride All
                Require all granted

    <Directory /var/www/html/webadmin>
        Options +Indexes +FollowSymLinks +MultiViews
        AllowOverride All
        Require all granted

    ErrorLog ${APACHE_LOG_DIR}/error.log

    # Possible values include: debug, info, notice, warn, error, crit,
    # alert, emerg.
    LogLevel warn

    CustomLog ${APACHE_LOG_DIR}/access.log combined


Here is another example (with Gzip Compression):

nano /etc/apache2/sites-available/




    DocumentRoot /var/www/html/

    <Directory /var/www/html/>
        Options -Indexes +FollowSymLinks +MultiViews
        AllowOverride All
        Require all granted

    ErrorLog ${APACHE_LOG_DIR}/pontikis.net_error.log

    # Possible values include: debug, info, notice, warn, error, crit,
    # alert, emerg.
    LogLevel warn

    CustomLog ${APACHE_LOG_DIR}/pontikis.net_access.log combined

    ErrorDocument 404 /404/

    SetOutputFilter DEFLATE
    SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|ico|png)$ \ no-gzip dont-vary
    SetEnvIfNoCase Request_URI \.(?:exe|t?gz|zip|bz2|sit|rar)$ \no-gzip dont-vary
    SetEnvIfNoCase Request_URI \.pdf$ no-gzip dont-vary

    BrowserMatch ^Mozilla/4 gzip-only-text/html
    BrowserMatch ^Mozilla/4\.0[678] no-gzip
    BrowserMatch \bMSIE !no-gzip !gzip-only-text/html


enable site:

systemctl restart apache2.service

Check Apache configuration

apachectl configtest


AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using Set the 'ServerName' directive globally to suppress this message
Syntax OK

To avoid this warning

nano /etc/apache2/conf-available/fqdn.conf

add ServerName directive:



a2enconf fdqn
systemctl restart apache2.service

Local domains from your workstation

To use local domains from your workstation, add records to file /etc/hosts. In my case:

sudo nano /etc/hosts

here are some examples:   localhost   athena

# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

# Local domains   dev.lo

Restart Apache

systemctl restart apache2.service



Using apt-get:

apt-get install php7.0

Configuration principles

Main configuration file (as Apache module): /etc/php/7.0/apache2/php.ini. DO NOT EDIT this file. Add your configuration to /etc/php/7.0/apache2/conf.d/. Example:

nano /etc/php/7.0/apache2/conf.d/my-config.ini
systemctl restart apache2.service

Main configuration file (CLI command line interface): /etc/php/7.0/cli/php.ini. DO NOT EDIT this file. Add your configuration to /etc/php/7.0/cli/conf.d/.


Create a file phpinfo.php in your web server (NOT public available for production servers) like this example:

nano /var/www/html/webadmin/phpinfo.php


<?php phpinfo() ?>

Use this file to check php configuration (as Apache module). Example:

Error log

Enable php error log. Log file must be writable from Apache. So:

mkdir /var/log/php
chown www-data /var/log/php

Create configuration file:

nano /etc/php/7.0/apache2/conf.d/99_error_log.ini


error_log = /var/log/php/php_errors.log

Remember to rotate /var/log/php/php_errors.log:

nano /etc/logrotate.d/php

add the following:

/var/log/php/php_errors.log {
        rotate 4

Php extensions

Install the php extensions/modules you need. This is a testing server, so I installed many extensions for various projects.

Find the full list here.

After installing an extension and restarting Apache, you will see the relevant changes to phpinfo.

To check installed php extensions from command line, use:

php -m


apt-get install php7.0-mysql


apt-get install php7.0-pgsql


apt-get install php7.0-intl


apt-get install php7.0-mbstring


apt-get install php7.0-curl


apt-get install php7.0-zip


apt-get install php7.0-xml


apt-get install php7.0-gd


apt-get install php7.0-mcrypt


apt-get install php-gettext


apt-get install php-memcached

Harden php

Create a configuration file

nano /etc/php/7.0/apache2/conf.d/99_security.ini

with contents

allow_url_include = Off
allow_url_fopen = Off
session.use_only_cookies = 1
session.cookie_httponly = 1
expose_php = Off
display_errors = Off
register_globals = Off
disable_functions = shell_exec, escapeshellarg, escapeshellcmd, passthru, proc_close, proc_get_status, proc_nice, proc_open,proc_terminate

(settings may vary according to your needs, especially for “disable_functions”).

Restart Apache

systemctl restart apache2.service

Install database manager

phpMyAdmin and adminer are popular. I prefer adminer:

You may use apt-get install adminer, but I prefer to download the latest package

mkdir /var/www/html/wedamin/adminer
cd /var/www/html/wedamin/adminer

In production servers restrict access to this directory using .htaccess

Install memcached (optional)

Using apt-get:

apt-get install memcached

Read more at Memcached Installation and Configuration with PHP on Debian Server

Install phpMemcachedAdmin (optional):

cd /var/www/html/webadmin/
tar xvzf phpmemcachedadmin-1.3.0.tar.gz
mv phpmemcachedadmin-1.3.0 phpMemcachedAdmin
cd phpMemcachedAdmin/Config
cp Memcache.sample.php Memcache.php
chmod g+w Memcache.php
chmod o+w Memcache.php
cd ..
chmod 777 Temp

In production servers restrict access to this directory using .htaccess

Restart Apache

systemctl restart apache2.service

Almost ready...

Perform (again) a full system update

Using apt-get:

apt-get update && apt-get -V upgrade

Update files database (again)



Enjoy Debian 9 Stretch!

DebianArt Themes Nonagons

Summary of important changes concerning php7 and MariaDB

PHP7 incompatibilities to 5.6 (and solutions)

Problems I encountered in the various webapps I manage

  1. php-gettext does not translate correctly (returns the en_US translation for any language)
  2. SwiftMailer errors
    2017-04-17 15:26:35: [ErrNo=16384 (UNKNOWN ERROR), File=/path/to/SwiftMailer_v5.4.6/lib/classes/Swift/Transport/MailTransport.php, Line=45] The Swift_Transport_MailTransport class is deprecated since version 5.4.5 and will be removed in 6.0. Use the Sendmail or SMTP transport instead.
    2017-04-17 15:26:35: [ErrNo=2 (WARNING), File=/path/to/SwiftMailer_v5.4.6/lib/classes/Swift/Transport/MailTransport.php, Line=259] escapeshellcmd() has been disabled for security reasons
  3. phpass errors
    [17-Apr-2017 17:05:26 UTC] PHP Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; PasswordHash has a deprecated constructor in /path/to/phpass-0.3/PasswordHash.php on line 27

Solutions, working in my case

  1. I replaced



    see more at this post

  2. I replaced in my code
    $transport = Swift_MailTransport::newInstance();


    $transport = Swift_SendmailTransport::newInstance('/usr/sbin/sendmail -bs');
  3. I replaced in class PasswordHash
    function PasswordHash($iteration_count_log2, $portable_hashes)


    function __construct($iteration_count_log2, $portable_hashes)

Moving from MySQL to MariaDB

MariaDB is a drop-in replacement for MySQL (so far, at least). You will not notice remarkable differences in everyday work. The commands are actullay the same. The SQL code absolutely compatible.

In Debian 9 Stretch, I prefer to revert the default authentication with Operating System user (unix_plugin) to classic authentication using password.

Related Posts

You may also be interested in