Projects & Blog | PORTFOLIO

The Anatomy of this Website

Table of Contents

  1. Introduction
  2. Services
  3. Docker
  4. HTTPS with letsencrypt
  5. Python content generator

Introduction

In this article I will show how this website has been created and how I maintain / update it. It's nothing really special, but maybe interesting to know for some of you. Have fun!

Services

Lets dive right into it. Figure 1 shows an overview of the most important services and components running on this server. Most needed services are containerized and run inside a docker-network which expose all of their services only to the localhost. Then an apache2 instance is using a reverse proxy to expose the services to the web. Of course a nginx instance would also do the trick. We will get into the details later. I use docker-compose to start and maintain the docker containers.

Also the server runs a gitlab-runner instace, which I use to fetch new updates from the git repository. After fetching the updates the runner will invoke a deployment script which automatically deploys the new updates. This is very cool, just a few seconds after a push to my gitlab instance the new website content will be automatically updated in production.

Figure 1. Services and deployment

The layout of the main site (portfolio content) is based on the portfolio of Navendu. Thanks for that: https://github.com/navendu-pottekkat/navendu-pottekkat.github.io, I just made some minor changes to it. The commenting feature is provide by integrating ISSO, take a look: https://github.com/posativ/isso/. A self written python service is dealing with analytics, it is deployed in a flask app. Finally my resume, it is based on a markdown layout which gets converted to html and pdf by pandoc, its very cool to have a single source to provide a web base and a pdf CV: https://mszep.github.io/pandoc_resume/.

Docker

Following listing shows the structure of the docker-network and how it is deployed. The first service "apache" contains all of the content for this portfolio, all the styles, pages, images, etc. The second one "isso", contains the commenting feature. The third one "visitor" is the analytics service. Consider that all services are only exposed to the localhost.

Listing 1. docker-compose.yml

version: '2'

services:
    apache:
        image: 'bitnami/apache:latest'
        ports:
            - '127.0.0.1:81:8080'
        volumes:
            - ./main_site/:/app
            - ./vhost.conf:/vhosts/my_vhost.conf:ro
        networks:
            testing_net:
                ipv4_address: 172.28.1.1

    isso:
        build:
            context: ./isso
            dockerfile: ./Dockerfile
        image: 'isso'
        ports:
            - '127.0.0.1:8080:8080'
        volumes:
            - ./isso.cfg:/config/isso.cfg 
            - ./isso:/db
        networks:
            testing_net:
                ipv4_address: 172.28.1.2

    visitor:
        build:
            context: ./visitor
            dockerfile: ./Dockerfile
        image: 'visitor'
        volumes:
            - ./vis:/db
        ports:
            - '127.0.0.1:8081:80'    
        networks:
            testing_net:
                ipv4_address: 172.28.1.3

networks:
    testing_net:
        ipam:
            driver: default
            config:
                - subnet: 172.28.0.0/16

HTTPS with letsencrypt

Lets take a look at the configuration of the main apache2 instance running outside of the docker-network and lets see how we can setup a https only connection via letsencrypt. Lets assume that initially you do not have any ssl-certificates. Just start up all the services and start with a very simple apache configuration which simply states all of your ServerNames (subdomains for which you want to generate certificates), see Listing 2. Now you can use "certbot", a simple python application provided by letsencrypt to get your certificates. You can run the bot with "certbot --apache". Then certbot will autmatically parse your apache configuration and generate the suitable certificates for all of your subdomains. Awesome!

Listing 2. apache2 configuration before certificate generation

<VirtualHost *:80>
    ServerName site.mark-geiger.de
</VirtualHost>

<VirtualHost *:80>
    ServerName comments.mark-geiger.de
</VirtualHost>

<VirtualHost *:80>
    ServerName api.mark-geiger.de
</VirtualHost>

Now we got our certificates and not only this! Certbot has also created an additional apache configuration file which should contain something like this:

Listing 3. apache2 configuration generated by certbot

<IfModule mod_ssl.c>
<VirtualHost *:443>
    ServerName api.mark-geiger.de
    ProxyRequests Off
    ProxyPass "/" "http://127.0.0.1:8081/"
    ProxyPassReverse "/" "http://127.0.0.1:8081/"

    SSLCertificateFile /etc/letsencrypt/live/api.dev.mark-geiger.de/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/api.dev.mark-geiger.de/privkey.pem
    Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>

This configuration will activate our ssl-certificates additionally I entered the needed reverse proxies to the fitting services running inside the docker-network. Listing 4 shows how we adjust our previous apache configuration to force a redirect to https.

Listing 4. apache2 configuration after certificate generation

<VirtualHost *:80>
    ServerName mark-geiger.de
    RewriteEngine on
    RewriteCond %{SERVER_NAME} =mark-geiger.de
    RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

<VirtualHost *:80>
    ServerName comments.mark-geiger.de
    RewriteEngine on
    RewriteCond %{SERVER_NAME} =comments.mark-geiger.de
    RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

<VirtualHost *:80>
    ServerName api.mark-geiger.de
    RewriteEngine on
    RewriteCond %{SERVER_NAME} =api.mark-geiger.de
    RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

Python content generator

I use a small set of python scripts to generate the content for my portfolio site. For this purpose two libs are very important, jinja2 and markdown. I write my content in markdown, the python script converts the markdown input to html and also generates some meta information. Then I use "jinja" to put this content into template files, which will then result in a functional website.

For example the beginning of this article looks like this:

Listing 5. Markdown Project page

badges:badge-primary|Webdev,badge-info|DevOps
link:PORTFOLIO.html
media:<img class="card-img-top" src="./assets/img/projects/portfolio/cover.png">
title: The Anatomy of this Website
description: Quick description of the setup of this website. Uses docker containers, apache2, markdown, pandoc and python generators.
site-name:PORTFOLIO

markdown-content-starts-below
# Table of Contents
1. [Introduction](#introduction)
2. [Services](#services)
3. [Docker](#docker)
4. [HTTPS with letsencrypt](#https-with-letsencrypt)
5. [Python content generator](#python-content-generator)


<a class="anchor" name="#introduction"></a>
# Introduction #

In this article I will show how this website has been created and how I maintain / update it. It's nothing really special, but maybe interesting to know for some of you. Have fun!

The python script will parse this file and merge it into the template files.

Well this was just a very quick catch up. Theres a lot more needed for a complete pictures. Anyway, feel free to ask for more!