A guide for a simple web site

There is a famous proverb in my homeland “Et sartor non potest cadere cœperat vestimenta sua” meaning “The tailor cannot mend his own clothes” which is actually similar to British proverb “The shoemaker’s son always goes barefoot”. Today I will be trying to prove the opposite and apply my years of experience in building medium and large scale web applications into this simple web site that I need for my own company.

The Web Template

The company that I am promoting is a software development consultancy company. I need a clean and one page web site which would be enough as a start. Remember what we have been taught: “Start simple and enhance with iterations”, i.e. “you’ll always have the chance to mess it up down the road” 🙂

I started by selecting a free template from bootstrapmade.com. There are dozens of really nice alternatives from which you can select by filtering according to the type of business, colour, single page or multi pages, etc. I selected a on page web site and customised it by filling in the information regarding my business.

Source Code Versioning

Although what I am doing here is a single page web application and I am the only developer that is making updates here I am pretty sure that I need a source code versioning system. You see, according to a hard learned principle of mine the necessity for a versioning system starts just after you have ONE developer in your team. 😉

I chose git as my versioning system and went on with gitlab in accordance with my experience in my latest projects. With gitlab it’s fairly easy to create a new project and keep it for yourself (i.e. without a requirement to make it open source or paying a regular fee, etc.)  I created an account in gitlab and uploaded my public SSH key through the web user interface. If you haven’t created an SSH key for yourself yet, there are instructions on the Settings->SSH Keys section of which you can access by clicking your user icon.

The Server

There are lots of alternatives when it comes to selecting a server for hosting your application. The one I needed was to be cheap and easily manageable. Scaleway is a nice alternative here: it allows getting up a server ready within a minute and nice set of ready to launch server images.

I must admit that I was tempted by the ARM64 server and initially started with an Ubuntu Xenial image deployed on ARM64 processors. However I quickly reverted to X86 servers when I started getting error messages while installing Docker on this architecture. X86 architecture also lets you to select a set of ready images including Docker, LEMP, node.js, python, etc. I chose Docker image for my purpose.

It would be practical to add your public SSH key to the account credentials via the admin user interface of scaleway.com. I also added a local user and set a new password for the user.

$ useradd -m -d /home/fatiho -s /bin/bash -U fatiho
$ passwd fatiho

to the server and performed all my operations with this user after adding the user to the sudoers.

$sudo visudo
# User privilege specification
root        ALL=(ALL:ALL) ALL
fatiho    ALL=(ALL:ALL) ALL

Then I installed git on the server using apt-get:

$ sudo apt-get update
$ sudo apt-get install git

Docker and nginx Configuration

Docker is already installed on the server that I created however the user that I added is not in the docker group so when I tried to run docker commands I get an error complaining about connecting docker daemon. So I added my user to the docker (which is actually controversial due to the amount of rights it gives to my user, but for now I’ll move forward)

$ sudo usermod -aG docker fatiho

For the web server, I will use nginx to serve my web site. So once I got my Docker image ready and running on scaleway, I prepared a docker configuration file which start with latest version of nginx server and applies the my nginx configuration to the docker image.

FROM nginx
COPY . /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf

The nginx configuration for my case is actually trivial, the only change I made was for redirecting the requests made for the root directory to the index.html page as default. For this I only added the last line.

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
    index index.html;


Once everything is set up, I checked out  the latest version of codebenders project from gitlab into my home directory (this step requires your gitlab password)

git clone https://fatihozceylan@gitlab.com/fatihozceylan/codebenders.git

Then in the codebenders directory where the Dockerfile exists I started the docker build command:

docker build -t codebenders .

Once the build is done I started the docker image with nginx

$ docker run -d -p 80:80 --name codebenders.io codebenders

fatiho@codebenders:~/codebenders$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
adf4e7618329        codebenders         "nginx -g 'daemon off"   5 seconds ago       Up 5 seconds>80/tcp   codebenders.io

You can check the access logs of the nginx server by accessing the vm running on docker by the following commands:

fatiho@codebendersWeb:~/codebenders$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
0a6382d65de0        codebenders         "nginx -g 'daemon off"   5 minutes ago       Up 5 minutes>80/tcp   codebenders.io
fatiho@codebendersWeb:~/codebenders$ docker exec -it 0a6382d65de0 /bin/bash
root@0a6382d65de0:/# tail -f /var/log/nginx/access.log

Refreshing the Deployment

As you have new updates on the site, you need to refresh the sorce code by pulling the latest version from git. Then remove old images, build the new image an run the docker container with the changes applied.

fatiho@codebenders:~/codebenders$ git pull
Password for 'https://fatihozceylan@gitlab.com':
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 2), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From https://gitlab.com/fatihozceylan/codebenders
   7f6e144..9ec7aaf  master     -> origin/master
Updating 7f6e144..9ec7aaf
 README.md | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)
fatiho@codebenders:~/codebenders$ docker stop codebenders.io
fatiho@codebenders:~/codebenders$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
codebenders         latest              45de0a9bdcc6        29 seconds ago      113.9 MB
nginx               latest              3448f27c273f        2 weeks ago         109.4 MB
hello-world         latest              48b5124b2768        4 months ago        1.84 kB
fatiho@codebenders:~/codebenders$ docker rmi -f 45de0a9bdcc6 
Deleted: sha256:26411437b7444fbf2f89741edf9ba312fe3ec1a5873a2da0de36249248890104
Deleted: sha256:b6266e3dd6c1ea552438771c8608aeb0df2e69cd0ee5fb4178eba648044463f3
fatiho@codebenders:~/codebenders$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
codebenders         latest              45de0a9bdcc6        47 seconds ago      113.9 MB
nginx               latest              3448f27c273f        2 weeks ago         109.4 MB
hello-world         latest              48b5124b2768        4 months ago        1.84 kB
fatiho@codebendersWeb:~/codebenders$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                          PORTS               NAMES
32498c005552        6b94de50f43e        "nginx -g 'daemon off"   13 minutes ago      Exited (0) About a minute ago                       codebenders.io
fatiho@codebendersWeb:~/codebenders$ docker rm -f 32498c005552
32498c005552fatiho@codebenders:~/codebenders$ docker build -t codebenders .
Sending build context to Docker daemon 4.599 MB
Step 1 : FROM nginx
 ---> 3448f27c273f
Step 2 : COPY . /usr/share/nginx/html
 ---> fda503c7e5b0
Removing intermediate container 3f7da193f5af
Step 3 : COPY nginx.conf /etc/nginx/nginx.conf
 ---> 6c5ef6fb6acd
Removing intermediate container 8dbcecd2be3e
Successfully built 6c5ef6fb6acd
fatiho@codebenders:~/codebenders$ docker run -d -p 80:80 --name codebenders.io codebenders

What’s Next?

As you might have noticed by now, everything that I explained here leaves the automated/ continuous deployment out of scope. Although I went for easy setup and easy deployment still the missing piece is to get rid of the manual deployment as a whole. Given the amount of change and frequency of change for my target web site, I hereby release myself from the burden of setting up a continuous build. However, I promise to cover that topic in my other posts.

It would have been another important target to minimise the down time during the deployment, I’ll also leave how this can be handled for a future post.

Fatih is an experienced software development expert with excellent communication skills. He is skilled at intercepting client’s needs, translating them into technical terms and coming up with a solid solution. He is committed to taking ownership in all aspects of solution development lifecycle. He is a great team maker and team player with plenty of analysis, design, solution development and implementation experience in both small scale and large scale development and integration projects. His experience and confidence keeps the team highly motivated. Currently he is interested with cloud computing, big data, machine learning algorithms and DevOps in general.