{"id":586,"date":"2018-03-09T23:39:47","date_gmt":"2018-03-09T23:39:47","guid":{"rendered":"http:\/\/www.45rpmsoftware.com\/wordpress\/?p=586"},"modified":"2018-03-22T14:23:50","modified_gmt":"2018-03-22T14:23:50","slug":"docker-lab-containerising-your-website-part-1","status":"publish","type":"post","link":"https:\/\/www.45rpmsoftware.com\/blog\/?p=586","title":{"rendered":"Docker Lab &#8211; Containerising your website, Part 1 (Nginx)"},"content":{"rendered":"<p>For many years now, 45RPMSoftware has maintained its own webservers (hosted on virtual machines by <a href=\"https:\/\/www.rackspace.com\">Rackspace<\/a>). \u00a0These webservers have been set up in the &#8216;traditional&#8217; manner, with a LAMP (Linux, Apache, MySQL, PHP) stack. \u00a0They&#8217;ve worked well and so I&#8217;ve ignored them, which isn&#8217;t the right way to run a website and especially not one which hosts your business.For many years now, 45RPMSoftware has maintained its own webservers (hosted on virtual machines by Rackspace). \u00a0These webservers have been set up in the &#8216;traditional&#8217; manner, with a LAMP (Linux, Apache, MySQL, PHP) stack. \u00a0They&#8217;ve worked well and so I&#8217;ve ignored them, which isn&#8217;t the right way to run a website and especially not one which hosts your business.<!--more--><\/p>\n<p>The time has come to make a change. \u00a0The first change that I made was to the stack. \u00a0Out goes Apache and MySQL and in comes Nginx and MariaDB &#8211; changing my LAMP stack to a LEMP stack. \u00a0The next change was a decision to containerise all the services required by 45RPMSoftware by using <a href=\"https:\/\/www.docker.com\">Docker<\/a>. \u00a0There are many reasons why I decided to do this, and many hurdles that I had to overcome &#8211; not least caused by my own inexperience with Docker itself.<\/p>\n<p>For my purposes the primary benefits of Docker are:<\/p>\n<ul>\n<li>Security. \u00a0Each service (Nginx, PHP, MariaDB etc) runs in a container which is completely segregated, able to communicate with other services only according to the rules configured in the Docker configuration. \u00a0No Docker container is allowed to look at the processes running in another container.<\/li>\n<li>Maintainability. \u00a0Because each container is self contained, deleting a service when it is no longer required is as simple as deleting its container. \u00a0All temporary files and configuration (barring those configuration files which you have mounted elsewhere (read on for details)) will be removed when you delete the container. \u00a0Similarly, installing a new version of a service is as simple as reinstalling its container.<\/li>\n<li>Portability. In theory (I haven&#8217;t tried it) Docker also improves portability, if I want to move to a different OS or to a different service provider (AWS, for example), all I need is my configuration file &#8211; Docker will handle consistency between these different environments and so the move should be close to seamless.<\/li>\n<\/ul>\n<p>Other people might have other reasons for containerisation and Docker in particular. You might like it for the potential benefits that it brings to CI\/CD, or for rapid deployment. All you need to know is that it is an extraordinarily useful tool.<\/p>\n<p>So how did I get my LEMP stack up and running? \u00a0These steps will, I hope, help you build a containerised environment using Docker. \u00a0This assumes that you&#8217;re starting with a clean sheet of paper, a fresh install of Linux and that you&#8217;ve registered a domain name and pointed it at your server. \u00a0I&#8217;m assuming that you know how to do these steps!<\/p>\n<p>As always, if you have a better way of doing things don&#8217;t keep it to yourself &#8211; share it with me so that I can learn from your experience and share it with everyone else.<\/p>\n<h2>Installing Docker.<\/h2>\n<p>The first step, of course, is to install Docker. \u00a0Do this as follows:<\/p>\n<pre>cd ~ \r\nmkdir installers \r\ncd installers\/ \r\nwget https:\/\/get.docker.com \r\nmv index.html install_docker.sh \r\nchmod +x install_docker.sh\u00a0 \r\n.\/install_docker.sh\u00a0 \r\nsudo usermod -aG docker &lt;your username&gt;<\/pre>\n<h2>Installing Docker Compose.<\/h2>\n<p>Docker Compose takes a lot of the effort out of using Docker. \u00a0With one configuration file, docker-compose.yml, you can set up multiple services with one command. \u00a0You can also stop and delete multiple services with one command. \u00a0Docker makes building software infrastructure easier &#8211; Docker Compose makes Docker easier. Install it as follows:<\/p>\n<pre>cd ~\/installers\/ \r\nsudo curl -L https:\/\/github.com\/docker\/compose\/releases\/download\/1.17.1\/docker-compose-`uname -s`-`uname -m` -o \/usr\/local\/bin\/docker-compose \r\nsudo chmod +x \/usr\/local\/bin\/docker-compose<\/pre>\n<p>At the time of writing, version 1.17.1 was the latest version. \u00a0Check for the latest version here https:\/\/github.com\/docker\/compose\/releases\/ &#8211; looking for versions which are tagged &#8216;Latest Release&#8217; &#8211; and substitute the version number accordingly.<\/p>\n<h2>Configuring your Containers.<\/h2>\n<p>I find that the best way to configure your containers is one at a time. \u00a0Get Nginx working first and then add PHP. \u00a0Get PHP working and then add MariaDB. \u00a0Get MariaDB working &#8211; and then add anything else that you&#8217;d like to add to your setup.<\/p>\n<h3>Creating your directories<\/h3>\n<p>First of all create your root Docker directory in your home folder. \u00a0I called mine lemp-compose because it contains the files necessary to compose LEMP. Replace &lt;your website name&gt; with, surprisingly, the name of your website. \u00a0For www.45rpmsoftware.com I could use www.45rpmsoftware.com, but it isn&#8217;t necessary &#8211; so I just use 45rpmsoftware<\/p>\n<pre>cd ~ \r\nmkdir -p lemp-compose\/nginx\/vhosts\/sites-enabled \r\nmkdir -p lemp-compose\/nginx\/vhosts\/sites-available \r\nmkdir -p lemp-compose\/public\/&lt;your website name&gt;\/htdocs \r\nmkdir -p lemp-compose\/logs<\/pre>\n<h3>Setting up the Nginx Container<\/h3>\n<p>Next create your configuration file &#8211; docker-compose.yml. \u00a0You might use vi or emacs to edit the file, but I prefer the easy life so I&#8217;ll be using nano. \u00a0The important thing is what the yml file contains:<\/p>\n<pre>cd ~\/lemp-compose \r\nnano docker-compose.yml<\/pre>\n<p>Add the following lines to the docker-compose.yml file<\/p>\n<pre>version: '2'\r\n\r\nservices:\r\n  nginx:\r\n  image: 'bitnami\/nginx:latest'\r\n  ports:\r\n    - '80:8080'\r\n    - '443:8443'\r\n  volumes:\r\n    - .\/logs:\/opt\/bitnami\/nginx\/logs\r\n    - .\/nginx\/vhosts:\/bitnami\/nginx\/conf\/vhosts\r\n    - .\/public:\/opt\/bitnami\/nginx\/html<\/pre>\n<p>Quit out of the editor &#8211; and we&#8217;ll start Nginx. \u00a0Initially we don&#8217;t want to use Nginx &#8211; we just want to copy some configuration files out of the container so that we can edit them without fear of losing our changes if the container gets deleted or updated. Docker containers are supposed to be stateless &#8211; so don&#8217;t make changes to any configuration contained within them. \u00a0Use volumes to make sure that all configuration that will change is outside the container.<\/p>\n<p>Start Docker by typing:<\/p>\n<pre>cd ~\/lemp-compose \r\ndocker-compose up -d<\/pre>\n<p>The -d parameter tells Docker to start detached. \u00a0In practical terms this means that it&#8217;ll return you to the command prompt straight away (and your website will stay running even if you log out).<\/p>\n<p>Next find out what the id of your newly started container is.<\/p>\n<pre>docker ps<\/pre>\n<p>This will return a response something like the following. \u00a0If it doesn&#8217;t then Docker isn&#8217;t installed or working properly &#8211; so work your way back through the steps up to this point checking carefully for mistakes or error messages.<\/p>\n<pre>CONTAINER ID \u00a0 \u00a0 \u00a0 \u00a0IMAGE \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0COMMAND \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0CREATED \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 STATUS \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0PORTS \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 NAMES \r\n673b1e25c03a \u00a0 \u00a0 \u00a0 \u00a0bitnami\/nginx:latest \u00a0 \u00a0 \"\/app-entrypoint.s...\" \u00a0 3 hours ago \u00a0 \u00a0 \u00a0 \u00a0 Up 3 hours \u00a0 \u00a0 \u00a0 \u00a0 \u00a00.0.0.0:80-&gt;8080\/tcp, 0.0.0.0:443-&gt;8443\/tcp \u00a0 lempcompose_nginx_1<\/pre>\n<p>You are particularly interested in the container ID. \u00a0You&#8217;ll need this to access the contents of the container &#8211; or even to log into the container. \u00a0In this example the container ID is 673b1e25c03a<\/p>\n<p>Now copy the configuration files out of the container by typing, replacing &lt;containerID&gt; with the container ID:<\/p>\n<pre>cd ~\/lemp-compose \r\ndocker cp &lt;containerId&gt;:\/bitnami\/nginx\/conf\/nginx.conf .\/nginx\/nginx.conf \r\ndocker cp &lt;containerId&gt;:\/bitnami\/nginx\/conf\/fastcgi.conf .\/nginx\/fastcgi.conf<\/pre>\n<p>Now you can stop Docker and edit the docker-compose.yml file to include a couple of extra configuration lines.<\/p>\n<pre>cd ~\/lemp-compose \r\ndocker-compose stop \r\nnano docker-compose.yml<\/pre>\n<p>Edit the docker-compose.yml file so that it looks like this:<\/p>\n<pre>version: '2'\r\n\r\nservices:\r\n  nginx:\r\n  image: 'bitnami\/nginx:latest'\r\n  ports:\r\n    - '80:8080'\r\n    - '443:8443'\r\n  volumes:\r\n    - .\/nginx\/nginx.conf:\/bitnami\/nginx\/conf\/nginx.conf\r\n    - .\/nginx\/fastcgi.conf:\/bitnami\/nginx\/conf\/fastcgi.conf\r\n    - .\/logs:\/opt\/bitnami\/nginx\/logs\r\n    - .\/nginx\/vhosts:\/bitnami\/nginx\/conf\/vhosts\r\n    - .\/public:\/opt\/bitnami\/nginx\/html<\/pre>\n<h2>Configuring your Website<\/h2>\n<h3>Nginx Configuration<\/h3>\n<p>Now edit nginx.conf to include sites-enabled by searching for the vhosts include line (probably by searching for all instances of include and checking to see if they say vhosts\/*.conf) and commenting it out (if necessary). \u00a0Then add the following line to the http section (it should end up looking something like this)<\/p>\n<pre># \u00a0include \"\/opt\/bitnami\/nginx\/conf\/vhosts\/*.conf\"; \r\ninclude \"\/opt\/bitnami\/nginx\/conf\/vhosts\/sites-enabled\/*.conf\";<\/pre>\n<p>It&#8217;s also a good idea, for security purposes, to hide the Nginx version number. \u00a0There&#8217;s no need to make a crackers life any easier than it is already. \u00a0Add the following line to your nginx.conf file in the http section.<\/p>\n<pre># Don\u2019t show the Nginx version number (in error pages \/ headers)\r\nserver_tokens off;<\/pre>\n<h3>Website Configuration<\/h3>\n<p>Now you need to set up the configuration for your website, which is in ~\/nginx\/vhosts\/sites-available<\/p>\n<pre>nano ~\/nginx\/vhosts\/sites-available\/&lt;your website name&gt;.conf<\/pre>\n<p>Edit it as follows, replacing the server_name domain name with the domain name(s) of your website.<\/p>\n<pre>server {\r\n listen 0.0.0.0:8080;\r\n server_name &lt;your domain name&gt;;\r\n server_tokens off;\r\n \r\n error_log \"\/opt\/bitnami\/nginx\/logs\/&lt;your website name&gt;-error.log\";\r\n access_log \"\/opt\/bitnami\/nginx\/logs\/&lt;your website name&gt;-access.log\";\r\n \r\n location \/ {\r\n  root \/opt\/bitnami\/nginx\/html\/&lt;your website name&gt;\/htdocs;\r\n  index index.html index.htm; \r\n }\r\n \r\n location ~* \\.(js|css|png|jpg|jpeg|gif|ico)$ {\r\n  expires max;\r\n  log_not_found off;\r\n }\r\n}<\/pre>\n<p>Having created the configuration for your website in\u00a0<em>sites-available<\/em> you now need to link to it in\u00a0<em>sites-enabled<\/em> in order that nginx can include it at startup.<\/p>\n<pre>cd ~\/nginx\/vhosts\/sites-enabled\r\nln -s ~\/nginx\/vhosts\/sites-available\/&lt;your website name&gt;.conf .<\/pre>\n<p>If you&#8217;ve pulled all of that off correctly, you should be able to put index.html into ~\/lemp-compose\/public\/&lt;your website name&gt;\/htdocs and start Docker:<\/p>\n<pre>cd ~\/lemp-compose \r\ndocker-compose up -d<\/pre>\n<p>Enter your website URL into your browser and (fingers crossed) your index.html will be displayed, served up by your containerised instance of Nginx. \u00a0Go and have a well earned cup of tea before moving onto the next stage &#8211; setting up php (which I&#8217;ll deal with in a future article).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>For many years now, 45RPMSoftware has maintained its own webservers (hosted on virtual machines by Rackspace). \u00a0These webservers have been set up in the &#8216;traditional&#8217; manner, with a LAMP (Linux, Apache, MySQL, PHP) stack. \u00a0They&#8217;ve worked well and so I&#8217;ve ignored them, which isn&#8217;t the right way to run a website and especially not one &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/www.45rpmsoftware.com\/blog\/?p=586\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Docker Lab &#8211; Containerising your website, Part 1 (Nginx)&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[15,18,28,5],"tags":[],"_links":{"self":[{"href":"https:\/\/www.45rpmsoftware.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/586"}],"collection":[{"href":"https:\/\/www.45rpmsoftware.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.45rpmsoftware.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.45rpmsoftware.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.45rpmsoftware.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=586"}],"version-history":[{"count":0,"href":"https:\/\/www.45rpmsoftware.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/586\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.45rpmsoftware.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=586"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.45rpmsoftware.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=586"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.45rpmsoftware.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=586"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}