Setting up Laravel with Docker - Part 1

Laravel is by far one of the most popular PHP framework. In this post we will set up laravel application using Docker.

By Subash Adhikari · · 5 min read

Updated . Written in 2017. Commands, prices, and links in this piece may be out of date.

Share on X


Rows of shipping containers in a container yard, seen from above

Laravel is one of the most popular PHP frameworks around right now. In this post we'll set up a Laravel application using Docker. Docker containerizes the platform, which keeps your application independent of the infrastructure it runs on.

Docker is available on most operating systems. Download and install the right version for yours from the Docker Store. To check the install, open a terminal and type docker -v. It should print the version of Docker on your machine.

text
Docker version 17.09.0-ce, build afdb6d4

Here's what the project structure will look like. The application lives in the app folder and the Docker files live in the docker folder.

text
+-- laravel
|   +-- app
|   +-- docker
|   |   +-- Dockerfile
|   |   +-- supervisord.conf
|   |   +-- default

Create the directory structure by running this in the terminal.

bash
cd ~
mkdir -p laravel/app laravel/docker
touch laravel/docker/Dockerfile

Building docker container#

A Dockerfile defines all the commands that run to assemble the container image. Add the following to your Dockerfile.

markup--code
FROM php:7.0-fpm
 
LABEL maintainer="Subash Adhikari <me@subash.tech>"
 
RUN apt-get update \
    && apt-get install -y nginx curl zip unzip git supervisor sqlite3 \
    && php -r "readfile('http://getcomposer.org/installer');" | \
      php -- --install-dir=/usr/bin/ --filename=composer \
    && echo "daemon off;" >> /etc/nginx/nginx.conf \
    && ln -sf /dev/stdout /var/log/nginx/access.log \
    && ln -sf /dev/stderr /var/log/nginx/error.log \
    && apt-get -y autoremove && apt-get clean \
    && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /var/www/html/*
 
COPY default /etc/nginx/sites-available/default
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
 
EXPOSE 80
 
CMD ["/usr/bin/supervisord"]

Don't be overwhelmed by all of that. We'll go through the Dockerfile step by step, and by the end of this section every line should make sense.

We use the php-fpm7 Docker image as the base image for the container.

dockerfile
FROM php:7.0-fpm

This adds metadata to the image saying who maintains it. Replace it with your own details.

markup--code
LABEL maintainer="Subash Adhikari <me@subash.tech>"

Docker caches each command while building an image, and it won't run a command again on the next build if it hasn't changed. So it's a good idea to group together commands that aren't likely to change often. That makes later builds faster.

The RUN command runs the given commands inside the container while it's being built. Let's break ours down.

First we update the apt repositories and install the dependencies the Laravel application needs.

dockerfile
apt-get update \
&& apt-get install -y nginx curl zip unzip git supervisor sqlite3 \

Next we install Composer. We need it to install Laravel and manage its PHP dependencies.

dockerfile
&& php -r "readfile('http://getcomposer.org/installer');" | \
php -- --install-dir=/usr/bin/ --filename=composer \

By default Nginx runs as a daemon in the background. We turn that off so we can run it with supervisord.

dockerfile
&& echo "daemon off;" >> /etc/nginx/nginx.conf \

We symlink the nginx access and error logs to stdout and stderr so we can see them from Docker.

dockerfile
&& ln -sf /dev/stdout /var/log/nginx/access.log \
&& ln -sf /dev/stderr /var/log/nginx/error.log \

Finally we clean up everything we don't need. This matters for keeping the image small.

dockerfile
&& apt-get -y autoremove && apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /var/www/html/*

The COPY command copies a local file into the container at the given path. Here we copy in the config templates for nginx and supervisord.

dockerfile
COPY default /etc/nginx/sites-available/default
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf

Then we tell Docker the container should listen on port 80 at runtime.

dockerfile
EXPOSE 80

Last, we set the default command to run when the container starts.

dockerfile
CMD ["/usr/bin/supervisord"]

Next up is the configuration for nginx and supervisord.

Create a file called ~/laravel/docker/default and add this nginx configuration to it.

Nginx config

nginx
server {
  root /var/www/html/public;
 
  index index.html index.htm index.php;
 
  server_name _;
  charset utf-8;
 
  location = /favicon.ico { log_not_found off; access_log off; }
  location = /robots.txt { log_not_found off; access_log off; }
 
  location / {
    try_files $uri $uri/ /index.php$is_args$args;
  }
 
  location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass 127.0.0.1:9000;
  }
 
  error_page 404 /index.php;
 
  location ~ /\.ht {
    deny all;
  }
}

supervisord config

Create another file called ~/laravel/docker/supervisord.conf and add this configuration to it.

markup--code
[supervisord]
nodaemon=true
 
[program:nginx]
command=nginx
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
 
[program:php-fpm]
command=php-fpm
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0

Building the image#

Now that the Dockerfile is ready, let's build the image. The docker build command builds an image from a Dockerfile.

bash
docker build -t subashcom/laravel ~/laravel/docker

The -t flag tags the image. subashcom is the namespace and laravel is the name, and you can change both to whatever you like. The last argument is the path to the directory that holds the Dockerfile.

You can check the image built correctly by listing all your images with docker images.

Installing laravel#

With the Laravel Docker image ready, we can install Laravel by running this command.

bash
docker run -it --rm \
    -w /var/www \
    -v ~/laravel/app:/var/www/html \
    subashcom/laravel \
    composer create-project --prefer-dist laravel/laravel html

The -it flag runs the container interactively. --rm removes the container once the command finishes. -w sets the working directory for the command. We mount the app directory to /var/www/html inside the container, and subashcom/laravel is the image we want to run. Whatever comes after the image name is the command that runs inside the container, in the working directory we set. Here that command installs the Laravel application into the html directory inside the container.

Running the application#

At this point Laravel is installed inside our Docker container. Next we'll run the application and open it in a web browser. Notice that this time we don't pass any command after the image name, so the container runs the default command we set in the Dockerfile.

We share ports 80 and 9000 of the container with the host machine. Nginx serves the application on port 80, and port 9000 is used by php-fpm. The -d flag runs the container in detached mode in the background, so it doesn't block your terminal window.

bash
docker run -d --rm \
    --name=laravel \
    -p 80:80 -p 9000:9000 \
    -w /var/www \
    -v ~/laravel/app:/var/www/html \
    subashcom/laravel

Now you can open the site by going to localhost or 127.0.0.1 in your browser. To stop the running container, type docker stop laravel.

Conclusion#

We've installed a Laravel application in a Docker container that's easy to ship around. The Docker commands we used were pretty long and complex, though. docker-compose can simplify that. In part 2 of this series we'll use docker-compose to build the container and update the application to use redis and mysql.

Setting up laravel with docker: Part 2

Setting up laravel with docker: Part 3


Thanks for reading. You can also follow along on X or with RSS.