docker web dev

To simplify the development I tried docker for building the runtime environment. Here are the major steps to get it running.

Prerequisites

The docker installation is straight forward as described on the docker home page:

un-install old version

aptitude remove docker docker-engine docker.io

add reporitory

aptitude update

aptitude install apt-transport-https ca-certificates curl gnupg2 software-properties-common

add docker official key

curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -

check fingerprint

apt-key fingerprint 0EBFCD88

add repository

add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable"

aptitude update

install docker from repo

aptitude install docker-ce

check if everything works

docker run hello-world

install docker compose

curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose

chmod +x /usr/local/bin/docker-compose

and check everything works

docker-compose --version

Docker Cheat Sheet

## List Docker CLI commands
docker
docker container –help

## Display Docker version and info
docker –version
docker version
docker info

## Execute Docker image
docker run hello-world

## List Docker images
docker image ls

## List Docker containers (running, all, all in quiet mode)
docker container ls
docker container ls –all
docker container ls -aq

Development Environment

create folder for docker environment

mkdir dockerproject

create yaml file for docker compose

vi docker-compose.yaml

At least the following sections should be available:

  • app
  • main application configuration

  • web
  • Webserver configuration is required

  • database
  • database configuration is required

and here comes an exmaple


version: '3'
services:
app:
build:
context: ./
dockerfile: app.dockerfile
working_dir: /var/www
volumes:
- ./../laravel:/var/www
environment:
- "DB_PORT=3306"
- "DB_HOST=database"
web:
build:
context: ./
dockerfile: web.dockerfile
working_dir: /var/www
volumes:
- ./../laravel:/var/www
ports:
- 8080:80
database:
image: mysql:5.6
volumes:
- dbdata:/var/lib/mysql
environment:
- "MYSQL_DATABASE=homestead"
- "MYSQL_USER=homestead"
- "MYSQL_PASSWORD=secret"
- "MYSQL_ROOT_PASSWORD=secret"
ports:
- "33061:3306"
volumes:
dbdata:

and now the app configuration


FROM php:7.1.3-fpm

RUN apt-get update
RUN apt-get install -y libmcrypt-dev
RUN apt-get install -y mysql-client
RUN apt-get install -y libmagickwand-dev --no-install-recommends
RUN pecl install imagick
RUN docker-php-ext-enable imagick
RUN docker-php-ext-install mcrypt pdo_mysql
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
RUN php -r "if (hash_file('SHA384', 'composer-setup.php') === '544e09ee996cdf60ece3804abc52599c22b1f40f4323403c44d44fdfdd586475ca9813a858088ffbc1f233e9b180f061') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
RUN php composer-setup.php
RUN php -r "unlink('composer-setup.php');"
RUN mv composer.phar /usr/local/bin/composer
RUN apt-get install -y git
RUN apt-get update && apt-get install -y zlib1g-dev
RUN docker-php-ext-install zip

the web configuration


FROM nginx:1.10

ADD vhost.conf /etc/nginx/conf.d/default.conf

Mirror – semi-transparent mirror info panel

I recently started building my own version of a semi-transparent mirror info panel. The server inside is running as a main service station for basically everything.
The server is hosting an external hard disk to serve videos, music and hard disk space via minidlna, nfs, appletalk and samba. Further the server is hosting my mail, imap, icinga, etc services.

A web front end is showing the basic information on an LCD behind the semi-transparent screen and here comes the PHP behind:

<?php ############# HEAD  ############################
$refresh_period = "3600";# refresh once in an hour only
$PHP_SELF = htmlspecialchars($_SERVER['PHP_SELF']); # use one file only which will be reload with new parameters all the time
header("Refresh: $refresh_period; url=$PHP_SELF");
echo "<!DOCTYPE html>\n";
echo "<html>\n<head>\n <meta http-equiv='refresh' content='.".$refresh_period."'><meta charset='utf-8'><meta name='viewport' content='width=device-width, initial-scale=1.0'>\n";
require_once('simpleCalDAV/SimpleCalDAVClient.php');
$client = new SimpleCalDAVClient();
$zeiger = array("Stunde", "Minute", "Sekunde");
############# Configuration ##########################
$numberClocks = array("Shenzen" => 2, "Saarbruecken" => 0);
$calendar_config = array('server' => '<server adress>/remote.php/dav/calendars/olkn/personal/', 
						'login' => '<login>', 
						'password' => '<password>',
						'calendar' => 'personal');
$tokens = array('SUMMA', 'DESCR', 'DTSTA', 'LOCAT', 'DTEND');// tokens to check for in calendar entry
############# style sheets ########################
echo "<link rel='stylesheet' type='text/css' href='stylesheet.css'>\n";
echo "<style>\n";
foreach ($numberClocks as $ort => $zeitzone){
	$rotation["Stunde"] = (date("h") + $zeitzone) * 30 + round(date("i")/2);# define hour rotation including timezone and minute part
	$rotation["Minute"] = date("i") * 6;# define minute rotation and
	$rotation["Sekunde"] = date("s") * 6;# second rotation
	foreach ($zeiger as $zeigername){
		$rotstart = $rotation[$zeigername];$rotstop = $rotation[$zeigername]+360;
		$temp = $zeigername.$ort;# CSS class name is StundeShenzen, etc
		echo ".".$temp." { \n\t-moz-animation-name: drehen".$temp.";\n\t-webkit-animation-name: drehen".$temp." ;\n\t";
		echo "-o-animation-name: drehen".$temp.";\n\t-ms-animation-name: drehen".$temp.";\n\tanimation-name: drehen".$temp.";\n\t";
		echo "-moz-animation-iteration-count: infinite;\n\t-webkit-animation-iteration-count: infinite;\n\t";
		echo "-o-animation-iteration-count: infinite;\n\t-ms-animation-iteration-count: infinite;\n\t";
		echo "animation-iteration-count: infinite;\n\t-moz-animation-direction: normal;\n\t-webkit-animation-direction: normal;\n\t";
		echo "-o-animation-direction: normal;\n\t-ms-animation-direction: normal;\n\tanimation-direction: normal;\n\t";
		if ($zeigername == "Sekunde"){# second hand will go in steps rather than continously
			echo "-moz-animation-timing-function: steps(60);\n\t-webkit-animation-timing-function: steps(60);\n\t";
			echo "-o-animation-timing-function: steps(60);\n\t-ms-animation-timing-function: steps(60);\n\tanimation-timing-function: steps(60);\n\t}\n";
		} else {
			echo "-moz-animation-timing-function: linear;\n\t-webkit-animation-timing-function: linear;\n\t";
			echo "-o-animation-timing-function: linear;\n\t-ms-animation-timing-function: linear;\n\tanimation-timing-function: linear;\n\t}\n";
		}
		echo "@-moz-keyframes drehen".$temp." { \n\tfrom { -moz-transform: rotate(".$rotstart."deg); } \n\tto { -moz-transform: rotate(".$rotstop."deg); } \n}\n";
		echo "@-webkit-keyframes drehen".$temp." { \n\tfrom { -moz-transform: rotate(".$rotstart."deg); } \n\tto { -moz-transform: rotate(".$rotstop."deg); } \n}\n";
		echo "@-o-keyframes drehen".$temp." { \n\tfrom { -moz-transform: rotate(".$rotstart."deg); } \n\tto { -moz-transform: rotate(".$rotstop."deg); } \n}\n";
		echo "@-ms-keyframes drehen".$temp." { \n\tfrom { -moz-transform: rotate(".$rotstart."deg); } \n\tto { -moz-transform: rotate(".$rotstop."deg); } \n}\n";
		echo "@keyframes drehen".$temp." { \n\tfrom { -moz-transform: rotate(".$rotstart."deg); } \n\tto { -moz-transform: rotate(".$rotstop."deg); } \n}\n";
	}
}
echo "</style>\n";
echo "<title>Mirror</title>\n</head>\n<body>\n\n";
############################## MAIN ##################################
date_default_timezone_set('Europe/Berlin');# set time zone
############## show weather on top right #############################
echo "<a href='second.php'><div class='header'>\n";
echo "<div id='cont_29118c24cbd1fe3b37edea315a92451d'><span id='h_29118c24cbd1fe3b37edea315a92451d'>";
echo "</span><script type='text/javascript' async src='https://www.daswetter.com/wid_loader/29118c24cbd1fe3b37edea315a92451d'>";
echo "</script></div>";
echo "</div>\n";# header
############### show calender and clock on bottom ####################
echo "<div class='footer'>\n";
echo "<div class='calendar'>\n";
try {
	$client->connect($calendar_config['server'], $calendar_config['login'], $calendar_config['password']);
	$arrayOfCalendars = $client->findCalendars();# get all available calendars
	$client->setCalendar($arrayOfCalendars[$calendar_config['calendar']]);# choose specific calendar
	$events = $client->getEvents(date('Ymd')."T000000Z", date('Ymd')."T240000Z"); # get list of events for today
	echo "<div class='calendar_header'>".date("l d.F Y")."</div>\n";# show current date
	foreach ($events as $event){
		$results = array();
		$event_data = explode("\n", $event->getData());
		foreach ($event_data as $line){
			list($key, $value) = explode(":", $line);
			if ($key == "BEGIN" && $value == "VEVENT") $trigger = true;// only check VEVENT entries
			elseif ($key == "END") $trigger = false;// other entries will be ignored
			if ($trigger){
				$key = substr($key, 0, 5);// DTSTART and END use complexe format, so the beginning of the word is enough
				if (in_array($key, $tokens)){// we found a relevant token, so store it in array for this event
					$results[$key] = $value;
				}
			}//end of triggering
		}//mext line of ICALENDAR Event
		echo "<div class='calendar_contents'>\n";
		if (strstr($results['DTSTA'], 'T') && strstr($results['DTEND'], 'T')){//we have a specific time (no whole day entry)
			echo "<div class='calendar_time'>".str_split(substr($results['DTSTA'], -6), 2)[0].":".str_split(substr($results['DTSTA'], -6), 2)[1];
			echo " - ".str_split(substr($results['DTEND'], -6), 2)[0].":".str_split(substr($results['DTEND'], -6), 2)[1];
			echo "</div>\n";//calendar_time
		}//event time processing
		echo $results['SUMMA']."\n<div class='calendar_entry'>".$results['DESCR']."</div>\n";//calendar_entry
		if (isset($results['LOCAT'])) echo "<div class='calendar_location'>".$results['LOCAT']."</div>\n";//calendar_location
		echo "</div>\n";//calender_contents
	}// next event
}
catch (Exception $e) {
	echo $e->__toString();
	echo "Error during catching calendar entries from Server<br>";
}
echo "</div>\n";# calender
############### show two clocks for worldtime ########################
echo "<div class='clock'>\n";
foreach ($numberClocks as $ort => $zeitzone){
	echo "<div class='clock_inner'>\n";
	echo "\t<div class='uhr'>\n";
	echo "\t<ul class='markierungen'>\n<li id='mark01'><div></div></li><li id='mark02'><div></div></li>\n";
	echo "\t<li id='mark03'><div></div></li><li id='mark04'><div></div></li>\n<li id='mark05'><div></div></li>";
	echo "\t<li id='mark06'><div></div></li>\n<li id='mark07'><div></div></li><li id='mark08'><div></div></li>\n";
	echo "\t<li id='mark09'><div></div></li><li id='mark10'><div></div></li>\n<li id='mark11'><div></div></li>";
	echo "\t<li id='mark12'><div></div></li>\n</ul>\n";
	foreach ($zeiger as $zeigername){
		echo "\t<div class='".$zeigername.$ort."' id='".$zeigername."'></div>";
	}
	echo "\t</div><div class='clock_location'>".$ort."</div>\n";
	echo "</div>\n";# clock_inner
}
echo "</div>\n";# clock
echo "</div>\n</a>";# footer
############### close ####################################################
echo "</body>\n</HTML>\n";
########### END ###################################?>

There is also a second page, which is showing some statistics about the server:

<?php ############# HEAD  ############################
echo "<!DOCTYPE html>\n";
echo "<html>\n<head>\n <meta charset='utf-8'><meta name='viewport' content='width=device-width, initial-scale=1.0'>\n";
############# style sheets ########################
echo "<link rel='stylesheet' type='text/css' href='stylesheet.css'>";
echo "<title>Mirror</title>\n</head>\n<body>\n\n";
############# Configuration ##########################
$PHP_SELF = htmlspecialchars($_SERVER['PHP_SELF']); # use one file only which will be reload with new parameters all the time
$display_size = array(1024, 768);
###### debug output of POST
function debug_output(){
        echo "<pre><br><h1>Hier kommt der schamass!</h1>";
        print_r($_POST);
        echo "</pre>"; return ;
}
######################################################################
############################## MAIN ##################################
######################################################################
echo "<body><form method='POST' action='$PHP_SELF'>\n";# page header with headline and table headers
echo "<a href='index.php'><section class='contents'>";
############## show weather on top right #############################
echo "<table width='100%' border=1><tr>";
echo "<td><img src='<cacti-server-adress>/graph_image.php?local_graph_id=12&rra_id=1&graph_width=500&graph_height=120&graph_nolegend=true'></td>";
echo "<td><img src='<cacti-server-adress>/graph_image.php?local_graph_id=24&rra_id=1&graph_width=500&graph_height=120&graph_nolegend=true'></td>";
echo "</tr><tr>";
echo "<td><img src='<cacti-server-adress>/graph_image.php?local_graph_id=20&rra_id=1&graph_width=500&graph_height=120&graph_nolegend=true'></td>";
echo "<td><img src='<cacti-server-adress>/graph_image.php?local_graph_id=38&rra_id=1&graph_width=500&graph_height=120&graph_nolegend=true'></td>";
echo "</tr><tr>";
echo "<td><img src='<cacti-server-adress>/graph_image.php?local_graph_id=40&rra_id=1&graph_width=500&graph_height=120&graph_nolegend=true'></td>";
echo "<td><img src='<cacti-server-adress>/graph_image.php?local_graph_id=9&rra_id=1&graph_width=500&graph_height=120&graph_nolegend=true'></td>";
echo "</tr><tr>";
echo "<td><img src='<cacti-server-adress>/graph_image.php?local_graph_id=23&rra_id=1&graph_width=500&graph_height=120&graph_nolegend=true'></td>";
echo "<td><img src='<cacti-server-adress>/graph_image.php?local_graph_id=9&rra_id=1&graph_width=500&graph_height=120&graph_nolegend=true'></td>";
echo "</tr></table>";
echo "Nagios Entries!";
echo "</section>";
############# cleanup and end ########################################
#debug_output();
echo "</form>\n<footer id='footer'>My personal page hosted on my own server &copy; olkn</footer></a></body></HTML>\n";
########### END ###################################?>

mirror – setup

Software Installations for Min Server

  • fetchmail
  • postfix
  • cups
  • dnsmasq
  • logwatch
  • smartmontools
  • ClamAV
  • fail2ban
  • dovecot
  • shellInABox
  • nagios
  • cacti
  • rsyslog
  • Mysql
  • netsnmp
  • spamassassin
  • git
  • apache
  • webalizer
  • wordpress
  • nextcloud
  • glype
  • gitlist
  • roundcube
  • gitlist
  • libreoffice
  • php
  • imagemagick
  • amavis
  • spamd
  • managesieve
  • VPN Tunnel
  • ntpd
  • nfs
  • samba
  • music streamer
  • video streamer

Nagios Components

  • postfix
  • dovecot
  • apache
  • dnsmasq
  • cups
  • mysql
  • clamav
  • nextclou
  • wordpress
  • rsyslog
  • ntpd
  • git
  • smartd
  • shellinanbox
  • spamd
  • nfs
  • minidlna
  • samba
  • timemachine
  • afpd
  • cups

actual to do:

  • shinken als nagios Ersatz
  • samba/timemaschine
  • shellinabox

apache config – wordpress

    wordpress

##############################################
ServerAdmin olkn@gmx.net
DocumentRoot /var/www/wordpress/
DirectoryIndex index.php
ProxyRequests off
SSLProxyEngine On
# ProxyHTMLLogVerbose On
ProxyPreserveHost On
##############################################

# problem with wordpress image upload
Options FollowSymlinks
Order Deny,Allow
Allow from all
AllowOverride All

apache config – squirrel

    squirrelmail

##############################################
# squirrel webmail
##############################################
Alias /squirrelmail /usr/share/squirrelmail

Options FollowSymLinks

php_flag register_globals off


DirectoryIndex index.php

# access to configtest is limited by default to prevent information leak

order deny,allow
deny from all
allow from 127.0.0.1

apache config – owncloud

    owncloud

##############################################
# owncloud
##############################################
Alias /owncloud /var/www/owncloud

Options +FollowSymLinks
AllowOverride None
order deny,allow
allow from all
# AuthType Basic
# AuthName “owncloud”
# AuthUserFile /etc/apache2/htpasswd
# Require user olkn

apache config – acidbase

    acidbase

############################################################
# acidbase config
##############################################

Alias /acidbase “/var/www/acidbase”


Options +FollowSymLinks
AllowOverride None
order deny,allow
deny from all
allow from 192.168.4.0/255.255.255.0
AuthType Basic
AuthName “acidbase”
AuthUserFile /etc/apache2/htpasswd
Require user olkn

php_flag magic_quotes_gpc Off
php_flag track_vars On
php_value include_path .:/usr/share/php

apache config – cacti

    cacti

##############################################
# cacti website for traffic graphing
##############################################
Alias /cacti /var/www/cacti/site

Options +FollowSymLinks
AllowOverride None
order allow,deny
allow from all
AddType application/x-httpd-php .php

php_flag magic_quotes_gpc Off
php_flag short_open_tag On
php_flag register_globals Off
php_flag register_argc_argv On
php_flag track_vars On
# this setting is necessary for some locales
php_value mbstring.func_overload 0
php_value include_path .

DirectoryIndex index.php

apache config – anyterm

    anyterm

##############################################
# anyterm proxy
##############################################

ProxyPass http://192.168.4.200:5000/
ProxyPassReverse http://192.168.4.200:5000/
AuthType Basic
AuthName “anyterm”
AuthUserFile /etc/apache2/htpasswd
Require user olkn