Creating a LEMP development environment on your MAC (OSX) using DOCKER

Colin Bitterfield
5 min readDec 1, 2019

Getting your tooling setup to just get work done is half the battle sometimes. My battle with LEMP started about two weeks ago when I wanted to configure a representative development environment for a small PHP application I am working on. I spent about two weeks developing a well-configured docker image for LEMP. The image is available for those that don’t want to spend the effort rolling their own. I am maintaining it on a regular basis. Part of the challenge and requirements is to have a named server, a database name, and a database user that is configurable and not “root”.

There are a few prerequisites to getting this all working. First, you have to install the DOCKER desktop for MAC OSX. You do not need to install the local MySQL client or Workbench. I included PHPMYADMIN in this build.

For this example, I am using OSX 10.14.6; however, it should work on any modern version of OSX if there is a docker desktop for it. The install for DOCKER is easy and straight forward; therefore, out of the scope for this example.

The configurable parameters are:

  • LOG_LEVEL
  • LOG_STDOUT
  • MYSQL_DATABASE
  • MYSQL_USER
  • MYSQL_USER_PASS
  • MYSQL_ROOT_PASS
  • SITE_PASS
  • SSH_PUBLIC
  • TLS

These are set either by a command-line setting or using the included scripts for easy deployment. I have included scripts for this purpose:

  • set_environment.sh — sets the parameters
  • lemp_service.sh — a start/stop and login utility

For this example, we will use our old friend “example.com”. We will create a new database called “webapp” with a user called “app_user.”

The first step is to create a working directory for our development environment.

Using either finder or terminal create your directory

Last login: Sat Nov 30 15:14:00 on ttys016
HOSTNAME:~ username$ cd Documents
HOSTNAME:Documents username$ mkdir example.com_dev
HOSTNAME:Documents username$

set or use a script to create the following environment variables. I set the website name to .local. It will help avoid DNS/hostname issues later. Anything left set to undefined will be defined automatically by the start script. This file is available on GitHub set_environment.sh. The best way to do this is to use a file and then source it with a “. set_environment.sh” prior to starting the LEMP environment.

# Set Default Environment Variables here
export LOG_STDOUT=/data/logs/nginix/dev_site/access.log
export LOG_LEVEL=info
export WEBSITE=www.example.local
export SSH_PORT=2222
export MYSQL_PORT=6306
export HTTP_PORT=8080
export HTTPS_PORT=8443

# Option Values for security; if not defined they are assigned at run time.
export MYSQL_ROOT_PASS="**notdefined**"
export MYSQL_DATABASE="webapp"
export MYSQL_USER="app_user"
export MYSQL_USER_PASS="**notdefined**"
export SITE_PASS="**notdefined**"
export SSH_PUBLIC=""
export HOST_MOUNT="$HOME/Documents/example.com_dev"
export TLS="yes"

Add these two entries to your MAC’s /etc/hosts file

#add to /etc/hosts
127.0.0.1 www.example.local
127.0.0.1 phpmyadmin.local

Download and copy this file to your working directory. lemp_service.sh

copy lemp_service.sh ~/Documents/example.com_dev
# Make the script executable
chmod +x lemp_service.sh

Start your development environment

$ ~/Documents/example.com_dev/lemp_service.sh start

This will download the latest image from Docker HUB and start running it with the configured parameters. It will also create self-signed certificates for the TLS websites. You can easily replace them with real certificates for free using the provided CERTBOT program.

lemp_service.sh start

HOSTNAME:example.com_dev username$ ./lemp_service.sh start
Starting docker: LEMP
website name set to [www.example.local]
Enabling key access to [dev_site] password
MOUNT_POINT is /Users/username/Documents/example.com_dev:/data
All undefined values are defaulted on startup and presented to sdtout
In the user directory is a copy of all of the passswords, delete after you have downloaded it
Starting a new container LEMP
Unable to find image 'cbitterfield/lemp:latest' locally
latest: Pulling from cbitterfield/lemp
7ddbc47eeb70: Pulling fs layer
c1bbdc448b72: Pulling fs layer
8c3b70e39044: Pulling fs layer
45d437916d57: Pulling fs layer

After a few minutes, the startup script will finish the configuration.

****************************************************************
* *
* Docker image: cbitterfield/lemp *
* GitHub:https://github.com/cbitterfield/lemp *
* *
****************************************************************


CONTAINER SETTINGS
---------------
· Please refer to READ.md for detailed instructions
· Supports changing LOG_LEVEL for NGINX
· Supports TLS on or off
· PHP date timezone [DATE_TIMEZONE]:
· Allows for SSH and SFTP access (and Key based access)
· Allows custom MySQL database and user
· Allow override on NGINX via ./conf.d
files that start with pre_http_* are loaded before that block
files that start with http_* are loaded at the end of the standard block
· Allows for port redirection on 22,80,443, and 3306
· Allows local host volume or docker volume for persistane
· Included service start/stop and other useful choices (see github)



****************************************************************
Configuring passwords on first run
database user set to [app_user]
database password set to [cC8dQ51V]
database root password is set to [nzhne2tj]
Linux user [dev_site] password is set to [U3UU8idR]
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)
Can't load /root/.rnd into RNG
140215469642176:error:2406F079:random number generator:RAND_load_file:Cannot open file:../crypto/rand/randfile.c:88:Filename=/root/.rnd
Generating a RSA private key
.....+++++
....................................+++++
writing new private key to '/data/conf/nginx/tls/phpmyadmin.local.key'
-----

Starting docker: 29cc2adfc06f
website name set to [www.example.local]
database name set to [webapp]
database user set to [app_user]
* Starting Postfix Mail Transport Agent postfix [ OK ]
* Starting OpenBSD Secure Shell server sshd [ OK ]
* php-fpm started [ OK ]
* Starting nginx nginx [ OK ]
* Starting MariaDB database server mysqld

Open your favorite browser and go to https://phpmyadmin.local:8443. The standard error message for self-signed certificates will be displayed. Click on advanced and proceed to the website.

The username and password from the start screen will work here

database user set to [app_user]
database password set to [cC8dQ51V]

Go to the URL https://example.local:8443

Again the self-signed message will be displayed.

example.com (index.php)

The host mount will allow you to use your favorite editor to edit the files directly or if you need to the server will allow ssh and sftp access as well.

The service script has several useful options:

start - Starts or resumes the container
stop - pauses the container
clear - deletes the container
login - will log in with the bash shell

--

--

Colin Bitterfield

NIST certified Security Professional | 10+ years experience in infrastructure security and compliance | Experienced in creating security programs.