Guide v5.12 / Updated 2020-07-19 / First published 2020-01-21 / echo (at) screaming (dot) computer

Preface

Over the years while working on various projects, I've often wished for a fully-featured web development environment confined to my local network. This would allow for offline development (before uploading to a public server), and also allow hosting of local projects that are never meant to be online.

After a few unsatisfactory experiments with running a WAMP stack on my laptop, I decided to dive in and configure a proper LAMP server on a Linux virtual machine. This approach was ideal since I already had a home server running UnRAID, which has great VM support.

This guide was written primarily for myself as I set up the VM and configured Linux, and installed/configured all the various features and settings that are important for my needs. There was a lot of trial-and-error to get everything working, so I wanted to ensure the “correct” procedures were captured somewhere. The guide grew to the point where it seemed sensible to share publicly in the hopes that others might find it helpful. Here it is.

Please Note: The choice of software and settings are entirely based on what I imagine my personal needs to be, and depend upon my current (possibly flawed) understanding of the software involved. This guide might not be suitable for you, and even if it is, it might contain errors. Proceed at your own discretion.

Content may be updated and expanded over time... take note of the “Updated” date, above.

Overview

Platform:

  • Linux Mint Xfce 19.3

Server:

  • Apache 2.4
  • MySQL 5
  • PHP 7.2

Additional features:

  • phpMyAdmin 4.6
  • ImageMagick 6.9 PHP plugin
  • Samba network file sharing
  • Virtual hosts

* version numbers as of this writing

1. User accounts

Once you have completed all steps in this guide, a variety of accounts and users will exist.

Anywhere you see a VARIABLE in this document, substitute your chosen value. To change passwords later, refer to appendix A.

1.1 Linux Users

Linux Mint does not have a separate user named root. The first user you create during installation gets root privileges; in this guide the primary admin user is VMUSER.

root VMPASS Virtual root user; not a true account
VMUSER VMPASS Primary admin user; has root privileges; member of the www-data usergroup

1.2 SQL Users

root SQLPASS MySQL administrator; requires local superuser privileges to use
SQLUSER SQLPASS MySQL administrator; used to access phpMyAdmin
DBUSER DBPASS Limited user with permission to manage only the DBNAME database

You should create separate low-privilege users for accessing your databases from PHP projects, such as DBUSER, above; refer to phpMyAdmin user management, and section 8 of this guide.

1.3 Samba User

SMBUSER SMBPASS Used to connect to the network share \\mint-vm\www; member of the www-data usergroup

1.4 Linux Usergroups

www-data Any member of this group has full R/W access to web files, locally via /var/www or remotely via \\mint-vm\www

2. UnRAID VM setup

Download Mint Xfce 64-bit ISO from https://www.linuxmint.com/download.php
Place the ISO file in UnRAID /mnt/user/isos

UnRAID [VMs] tab → [Add VM] → [Linux]

Name: Linux Mint Xfce
Initial Memory: 1024 MB
Max Memory: 1024 MB
OS Install ISO: [select downloaded ISO file]
Primary vDisk Size: 16G
[Create]

Launch [VNC Remote] from “Linux Mint Xfce” VM dropdown menu

3. Linux installation

From the boot menu, run [Start Linux Mint]
From the desktop, run [Install Linux Mint]
Accept all defaults, then [Install Now]

Your name: Administrator
Your computer's name: mint-vm
Pick a username: VMUSER
Choose a password: VMPASS
Confirm your password: VMPASS
Log in automatically: yes
[Continue]

Wait for installation, then [Restart Now]
“Please remove the installation medium then press enter” → just press enter
Wait for restart
Uncheck [Show this dialog at startup] on Welcome screen, then close it

Open [Update Manager] from the tray
Install all available updates

Open [System Reports] from the tray (warning icon with exclamation mark)
[Ignore this problem] for each detected issue

Open [Power Manager] from the tray (lightning bolt icon)
[Display] tab → uncheck [Display power management], set [Blank after] to never
[Security] tab → [Automatically lock the session] → [Never]

4. LAN configuration

These instructions apply to routers running Tomato firmware; tested on FreshTomato v2018.4

STATIC-IP is an IP address suitable for your LAN; ex: 192.168.0.55
HOSTNAME is a local hostname for your server; using an unassigned TLD such as .home or .lan is recommended (avoid .local as it is reserved for use with mDNS); ex: mint-vm.home

Log in to your router

4.1 Set a static IP address

[Status] → [Device List] → (your VM) → [static]
Set a STATIC-IP address, [Add], [Save]

[Status] → [Device List] → (your VM)(click on lease time to delete current lease)
Deleting the lease will expire the existing IP allocation

Reboot the Mint VM, then verify the static IP address is in use

4.2 Set a local hostname for the server

[Advanced] → [DHCP/DNS] → [Dnsmasq Custom Configuration]

local-ttl=1
address=/.HOSTNAME/STATIC-IP

[Save]

This allows any computer on your LAN to access the Mint VM via the host name HOSTNAME or any subdomain *.HOSTNAME

5. Install server software

Inside the Mint VM, open terminal and run these commands

5.1 Install LAMP

sudo apt-get update && sudo apt-get dist-upgrade -y
sudo reboot
sudo apt-get install lamp-server^ -y

Test Apache: Open Firefox, view http://localhost

5.2 Test PHP

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

<?php phpinfo(); ?>

Ctrl+O, Enter (to save)
Ctrl+X (to exit nano)

sudo service apache2 restart

Open Firefox, view http://localhost/phpinfo.php

5.3 Install phpMyAdmin and configure SQL user

sudo apt-get install phpmyadmin -y

when prompted for a webserver, press space to tick the box selecting apache2
when prompted to configure database, select yes
when prompted for MySQL password, enter SQLPASS

sudo mysql -uroot -pSQLPASS

DROP USER 'root'@'localhost';
DROP USER 'phpmyadmin'@'localhost';
CREATE USER 'SQLUSER'@'%' IDENTIFIED BY '';
GRANT ALL PRIVILEGES ON *.* TO 'SQLUSER'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
SELECT User,Host FROM mysql.user;

Ctrl+Z (to exit)

mysqladmin --user=SQLUSER password "SQLPASS"

sudo nano -w /etc/dbconfig-common/phpmyadmin.conf

Edit the line containing dbc_dbuser:

dbc_dbuser='SQLUSER'

Ctrl+O, Enter (to save)
Ctrl+X (to exit nano)

sudo nano -w /etc/phpmyadmin/config-db.php

Edit the line containing $dbuser:

$dbuser='SQLUSER';

Ctrl+O, Enter (to save)
Ctrl+X (to exit nano)

sudo service mysql restart
sudo service apache2 restart

Open Firefox, view http://localhost/phpmyadmin
Username: SQLUSER
Password: SQLPASS

5.4 Enable “nologin” user accounts

sudo nano /etc/shells

Append this line to the end of the file (no trailing newline):

/usr/sbin/nologin

Ctrl+O, Enter (to save)
Ctrl+X (to exit nano)

5.5 Set permissions on web folder

sudo adduser $USER www-data
sudo chown $USER:www-data -R /var/www
sudo chmod u=rwX,g=srwX,o=rX -R /var/www
sudo chmod 0664 /var/www/html/*

5.6 Allow .htaccess configuration in web folder

sudo nano -w /etc/apache2/apache2.conf

Inside configuration block <Directory /var/www/>, alter the AllowOverride line:

AllowOverride All

Ctrl+O, Enter (to save)
Ctrl+X (to exit nano)

sudo service apache2 restart

5.7 Enable mod_rewrite Apache module

sudo a2enmod rewrite
sudo service apache2 restart

5.8 Install ImageMagick plugin for PHP

sudo apt-get install php-imagick
sudo service apache2 restart

5.9 Increase PHP upload and POST size limits

PHP defaults to 8 megabytes max POST size and 2 megabytes max file upload size. Changing these limits so they match can make debugging easier. Select a limit MAXUPLOAD megabytes that is suitable for your projects.

Note: the path below may require updating to match the installed PHP version.

sudo nano -w /etc/php/7.2/apache2/php.ini

Alter the line containing post_max_size:

post_max_size = MAXUPLOADM

Alter the line containing upload_max_filesize:

upload_max_filesize = MAXUPLOADM

Ctrl+O, Enter (to save)
Ctrl+X (to exit nano)

sudo service apache2 restart

5.10 Enable PHP error reporting

If you're using this server for development purposes, you will want to allow PHP to display errors. The display_errors setting should be On for development, and Off for production/live servers.

Note: the path below may require updating to match the installed PHP version.

sudo nano -w /etc/php/7.2/apache2/php.ini

Alter the line containing display_errors:

display_errors = On

Ctrl+O, Enter (to save)
Ctrl+X (to exit nano)

sudo service apache2 restart

Alternately, you can control this setting on a script-by-script basis by calling the PHP ini_set() function:

ini_set ('display_errors', 'On');

Error reporting can be further controlled by the error_reporting setting in php.ini or the corresponding error_reporting() function in your PHP script. For production I use a value of 0, or (E_ALL | E_STRICT) for development.

5.11 Reboot

sudo reboot

6. Install and configure Samba

6.1 Install Samba

sudo apt-get update
sudo apt-get install samba

6.2 Create Samba user

sudo useradd -s /usr/sbin/nologin SMBUSER
sudo passwd SMBUSER

when prompted for password, enter SMBPASS

sudo adduser SMBUSER www-data

sudo smbpasswd -a SMBUSER

when prompted for password, enter SMBPASS

sudo smbpasswd -e SMBUSER

6.3 Add network share

sudo nano -w /etc/samba/smb.conf

Append these configuration lines to the end of the file:

[www]
  comment = Web Data
  path = /var/www
  guest ok = no
  read only = no
  writeable = yes
  browseable = yes
  valid users = +www-data
  create mask = 0664
  directory mask = 0775

Ctrl+O, Enter (to save)
Ctrl+X (to exit nano)

sudo service smbd restart

Validate your Samba configuration:

testparm -s /etc/samba/smb.conf

normalized configuration file is printed; look for error messages

6.4 Test network share

Validate your network share:

smbtree

look for \\MINT-VM\www

From a Windows PC, connect to the Samba share:
Start Menu → Run → "\\mint-vm\www"
Username: SMBUSER
Password: SMBPASS

7. Configure Apache virtual hosts

* Configuration tested on Apache v2.4

* For detailed reference, refer to the Apache documentation:

* Refer to section 4 in this guide to define a local hostname

Enable multi-project hosting using Apache virtual hosts; this example configures 4 hosts: delta, gamma, phpmyadmin, and a default host:

delta.HOSTNAME /var/www/delta
gamma.HOSTNAME /var/www/gamma
phpmyadmin.HOSTNAME /usr/share/phpmyadmin
HOSTNAME /var/www/www

Note that in this configuration the default host is served for any request by IP address and any request to an unknown hostname. This behaviour has security implications: if your server becomes publicly-accessible, your default host might be served. Therefore we remove all admin-related content (such as phpMyAdmin) from this area.

In this example we keep no content on the default host; all real content is served from specific subdomains.

7.1 Remove default host access to phpMyAdmin

Since phpMyAdmin will be accessed under its own subdomain, we should remove it from the default host; this allows us to explicitly control who can access it:

sudo nano -w /etc/phpmyadmin/apache.conf

Comment out (prepend a # character) this Alias line:

#Alias /phpmyadmin /usr/share/phpmyadmin

Ctrl+O, Enter (to save)
Ctrl+X (to exit nano)

sudo service apache2 restart

phpMyAdmin can no longer be accessed from http://localhost/phpmyadmin

7.2 Change the default host's server name and document root

By default Apache serves web files from /var/www/html; we change this directory to better integrate with a multi-host setup:

sudo nano -w /etc/apache2/sites-enabled/000-default.conf

Insert the following line at the top of the file:

ServerName HOSTNAME

This comment may be worth adding inside the <VirtualHost> configuration block:

# This first virtual host definition becomes the default.
# Default is served for all requests not matching hosts below,
# including requests by IP and requests for undefined hosts.

Add a ServerAlias line inside the <VirtualHost> configuration block:

ServerAlias www.HOSTNAME

Change the DocumentRoot line:

DocumentRoot "/var/www/www"

Ctrl+O, Enter (to save)
Ctrl+X (to exit nano)

Delete the previous html directory and create a new www directory
WARNING: all files in /var/www/html will be deleted!

rm -r /var/www/html
mkdir /var/www/www

Validate your configuration and restart the server:

apache2ctl configtest
sudo service apache2 restart

You may implement a website on the default host, however in this example setup we prefer to respond “404 Not Found” to all requests that don't match an expected virtual host subdomain:

nano /var/www/www/index.php

<?php
  http_response_code (404);
  header ('Content-Type: text/plain');
  echo '404 Not Found';
  die();
?>

Ctrl+O, Enter (to save)
Ctrl+X (to exit nano)

Visiting any address that resolves to this server should now yield a 404 error, generated from /var/www/www/index.php; for example:

7.3 Reenable phpMyAdmin under a virtual host

sudo nano -w /etc/apache2/sites-enabled/000-default.conf

Append the following configuration block to the end of the file:

<VirtualHost *:80>
  DocumentRoot "/usr/share/phpmyadmin"
  ServerName phpmyadmin.HOSTNAME
  ServerAlias *.phpmyadmin.HOSTNAME
</VirtualHost>

Ctrl+O, Enter (to save)
Ctrl+X (to exit nano)

Validate your configuration and restart the server:

apache2ctl configtest
sudo service apache2 restart

Visiting http://phpmyadmin.HOSTNAME now accesses phpMyAdmin

7.4 Add additional virtual hosts, as desired

This example sets up two projects, delta and gamma, each with their own hostname and server directory. In your configuration, you would instead use these placeholders as examples to configure your own projects.

mkdir /var/www/delta
mkdir /var/www/gamma

sudo nano -w /etc/apache2/sites-enabled/000-default.conf

Append the following configuration blocks to the end of the file:

<VirtualHost *:80>
  DocumentRoot "/var/www/delta"
  ServerName delta.HOSTNAME
  ServerAlias *.delta.HOSTNAME
</VirtualHost>

<VirtualHost *:80>
  DocumentRoot "/var/www/gamma"
  ServerName gamma.HOSTNAME
  ServerAlias *.gamma.HOSTNAME
</VirtualHost>

Ctrl+O, Enter (to save)
Ctrl+X (to exit nano)

Validate your configuration and restart the server:

apache2ctl configtest
sudo service apache2 restart

Access these sites via http://delta.HOSTNAME and http://gamma.HOSTNAME

8. Create a database and limited SQL user

Tip: Match the database name, username, and password of the database from your online hosting provider when configuring this local database. Migrating projects between the two then involves only changing the host name of the database server.

Execute this SQL code from the phpMyAdmin [SQL] tab to create a database:

CREATE DATABASE `DBNAME` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Create a limited user who can only control this database:

CREATE USER 'DBUSER'@'%' IDENTIFIED WITH mysql_native_password AS '';

GRANT USAGE ON *.* TO 'DBUSER'@'%' REQUIRE NONE;

GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER,
CREATE TEMPORARY TABLES, CREATE VIEW, EVENT, TRIGGER, SHOW VIEW,
CREATE ROUTINE, ALTER ROUTINE, EXECUTE ON `DBNAME`.* TO 'DBUSER'@'%';

phpMyAdmin → [Home] → [User accounts] → (DBUSER) → [Edit privileges] → [Change password]
Assign a password DBPASS to the database user

From PHP, this database can now be accessed through mysqli or equivalent:

$db = new mysqli ('localhost', 'DBUSER', 'DBPASS', 'DBNAME');

Appendix A: Changing passwords

If you need to change an account password after initial setup, use the following procedures:

A.1 Linux User

sudo passwd VMUSER

sudo may ask for a password; use OLD-VMPASS
when prompted for new UNIX password, enter NEW-VMPASS

sudo reboot

A.2 SQL User

mysqladmin --user=SQLUSER --password=OLD-SQLPASS password "NEW-SQLPASS"

sudo nano -w /etc/dbconfig-common/phpmyadmin.conf

Edit the line containing dbc_dbpass:

dbc_dbpass='NEW-SQLPASS'

Ctrl+O, Enter (to save)
Ctrl+X (to exit nano)

sudo nano -w /etc/phpmyadmin/config-db.php

Edit the line containing $dbpass:

$dbpass='NEW-SQLPASS';

Ctrl+O, Enter (to save)
Ctrl+X (to exit nano)

sudo service mysql restart
sudo service apache2 restart

A.3 Samba User

sudo passwd SMBUSER

sudo may ask for a password; use VMPASS
when prompted for new UNIX password, enter NEW-SMBPASS

sudo smbpasswd SMBUSER

when prompted for password, enter NEW-SMBPASS

sudo service smbd restart

On Windows you may need to flush all open network connections to use new credentials; run this from a command prompt:

net use * /delete

Appendix B: Add a USB expansion card & connect a thermal printer

Connect a thermal receipt printer to a Linux VM in UnRAID: this guide provides troubleshooting suggestions and solutions for connecting a USB printer to the VM. It also outlines how to add a USB expansion card for exclusive use of the virtual machine.

Appendix C: Install the escpos-php receipt printer library

Install and test the escpos-php library: used for communicating with thermal receipt printers via the ESC/POS protocol.

Additionally, if your printer does not natively support printing QR codes, you can add image-based QR code support to the escpos-php library by integrating the PhpQrCode library.

Appendix D: Install the PHP Simple HTML DOM Parser

Install the SimpleHtmlDom library: This PHP library allows for exceptionally-easy web scraping and parsing of arbitrary HTML pages.

Appendix E: Mount a network share for read/write access

Mount a network share in Linux: This allows your VM to read from and write to shared folders on your network.

[end of guide]