Automatically pull updated Docker images and restart containers with docker-puller

If you use docker.io (or any similar service) to build your Docker containers, it may be possible that, once the new image is generated, you want your Docker host to automatically pull it and restart the container.

Docker.io gives you the possibility to set a web hook after a successful build. Basically it does a POST on a defined URL and send some informations in JSON format.

docker-puller listens to these web hooks and can be configured to run a particular script, given a specific hook. It’s a very simple service I wrote using Python/Flask. It’s also my first Flask application, so if you want to improve it, feel free to send me a pull request on GitHub.

Note: this is not the only existing service that is able to do this task. I took inspiration from this article http://nathanleclaire.com/blog/2014/08/17/automagical-deploys-from-docker-hub/ and I really tried to customize https://github.com/cpuguy83/dockerhub-webhook-listener for my own needs, but the problem is that dockerhub-webhook-listener is not ready to be used as is (you have to customize it) and I’m not very good with Golang (yet) to be able to do it in little time. This is why I rewrote the service in Python (that is my daily language). I want to thank Brian Goff for the idea and all the people in #docker @ FreeNode for the support.

How to use docker-puller

Setting up the service should be quite easy. After you clone the repository from https://github.com/glowdigitalmedia/docker-puller there is a config.json file where you define the host, port, a token and a list of hooks you want to react to. For example:

{
    "host": "localhost",
    "port": 8000,
    "token": "abc123",
    "hooks": {
        "hello": "scripts/hello.sh"
    }
}

Create a bash script (in this case it was called hello.sh) and put it under script folder and write the instructions to be executed to pull the new image and restart the container (example):

docker pull andreagrandi/test:latest
docker stop test
docker rm test
docker run --name test -d -p 8000:80 andreagrandi/test:latest

Once configured, I suggest you to setup a Nginx entry (instructions not covered here) that for example redirect yourhost.com/dockerpuller to localhost:8000 (I would advise to enable SSL too, or people could be able to sniff your token). The service can be started with: “python app.py” (or you can setup a Supervisor script).

At this point docker-puller is up and running. Go to docker.io automatic build settings and setup a webhook like this: http://yourhost.com/dockerpuller?token=abc123&hook=hello

Every time docker.io finishes building and pushing your image to the docker registry, it will POST on that URL. docker-puller will catch the POST, check for a valid token, get the hook name and will execute the relative script.

That’s all! I hope this very simple service can be useful to other people and once again, if you want to improve it, I will be glad to accept your pull requests on GitHub.

Create an EncFS volume compatible with BoxCryptor Classic

If you are planning to share an encrypted volume between Linux/OSX and Windows (I will assume you are sharing it on Dropbox, but you could use any similar service) and you are using EncFS under Linux/OSX and BoxCryptor under Windows, there are some specifig settings to use when you create the EncFS volume. Infact even if BoxCryptor claims to be “encfs compatible”, it’s not 100%.

Suppose you want to create an encrypted volume located at $HOME/.TestTmpEncrypted and mounted at $HOME/TestTmp you need the following command:

andrea-Inspiron-660:~ andrea $ encfs ~/.TestTmpEncrypted ~/TestTmp

answer “Y” when you are asked if you want to create the folders:

The directory "/home/andrea/.TestTmpEncrypted/" does not exist. Should it be created? (y,n) y
The directory "/home/andrea/TestTmp" does not exist. Should it be created? (y,n) y

At this point you will need to select between default paranoia mode or advanced mode. Please choose the advanced one (x):

Creating new encrypted volume.
Please choose from one of the following options:
 enter "x" for expert configuration mode,
 enter "p" for pre-configured paranoia mode,
 anything else, or an empty line will select standard mode.
?> x

Manual configuration mode selected.

Select <strong>AES</strong> as cypher algorithm:

The following cypher algorithms are available:
1. AES : 16 byte block cipher
-- Supports key lengths of 128 to 256 bits
-- Supports block sizes of 64 to 4096 bytes
2. Blowfish : 8 byte block cypher
-- Supports key lengths of 128 to 256 bits
-- Supports block sizes of 64 to 4096 bytes

Enter the number corresponding to your choice: 1

Selected algorithm "AES"

Select 256 as key size:

Please select a key size in bits. The cypher you have chosen
supports sizes from 128 to 256 bits in increments of 64 bits.
For example:
128, 192, 256
Selected key size: 256

Using key size of 256 bits

Choose 1024 as block size:

Select a block size in bytes. The cypher you have chosen
supports sizes from 64 to 4096 bytes in increments of 16.
Alternatively, just press enter for the default (1024 bytes)

filesystem block size:

Using filesystem block size of 1024 bytes

Select Stream as filename encoding:

The following filename encoding algorithms are available:
1. Block : Block encoding, hides file name size somewhat
2. Null : No encryption of filenames
3. Stream : Stream encoding, keeps filenames as short as possible

Enter the number corresponding to your choice: 3

Selected algorithm "Stream""

Do NOT enable filename initialization vector chaining:

Enable filename initialization vector chaining?
This makes filename encoding dependent on the complete path,
rather then encoding each path element individually.
The default here is Yes.
Any response that does not begin with 'n' will mean Yes: no

Do NOT enable per-file initialization vectors:

Enable per-file initialization vectors?
This adds about 8 bytes per file to the storage requirements.
It should not affect performance except possibly with applications
which rely on block-aligned file io for performance.
The default here is Yes.
Any response that does not begin with 'n' will mean Yes: no

Do NOT enable external chained IV:

External chained IV disabled, as both 'IV chaining'
and 'unique IV' features are required for this option.
Enable block authentication code headers
on every block in a file? This adds about 12 bytes per block
to the storage requirements for a file, and significantly affects
performance but it also means [almost] any modifications or errors
within a block will be caught and will cause a read error.
The default here is No.
Any response that does not begin with 'y' will mean No: no

Do NOT enable random bytes to each block header:

Add random bytes to each block header?
This adds a performance penalty, but ensures that blocks
have different authentication codes. Note that you can
have the same benefits by enabling per-file initialisation
vectors, which does not come with as great a performance
penalty.
Select a number of bytes, from 0 (no random bytes) to 8: 0

Enable file-hole pass-through:

Enable file-hole pass-through?
This avoids writing encrypted blocks when file holes are created.
The default here is Yes.
Any response that does not begin with 'n' will mean Yes: yes

Finally you will see:

Configuration finished. The filesystem to be created has
the following properties:
Filesystem cypher: "ssl/aes", version 3:0:2
Filename encoding: "nameio/stream", version 2:1:2
Key Size: 256 bits
Block Size: 1024 bytes
File holes passed through to ciphertext.

At this point set a passphrase for your new volume:

Now you will need to enter a password for your filesystem.
You will need to remember this password, as there is absolutely
no recovery mechanism. However, the password can be changed
later using encfsctl.

New Encfs Password:
Verify Encfs Password:

You should be able to mount this volume using BoxCryptor.

How to configure Edimax EW-7811UN Wifi dongle on Raspbian

If you want to connect your RaspberryPi to your home network and you want to avoid cables, I suggest you to use the Edimax wifi adapter. This device is quite cheap (around £8 on Amazon) and it’s very easy to configure on Raspbian (I assume you are using a recent version of Raspbian. I’m using the one released on 20/06/2014).

edimax-pi3

 

Configure the wifi adapter

Edit /etc/network/interfaces and insert these configuration values:

auto lo
iface lo inet loopback
iface eth0 inet dhcp

allow-hotplug wlan0
auto wlan0

iface wlan0 inet dhcp
wpa-ssid YOURESSID
wpa-psk YOURWPAPASSWORD

Power management issue

There is a known “issue” with this adapter default configuration that makes it to turn off if the wlan interface is not in use for some minutes. To avoid this you have to customize the parameters used to load the kernel module. First check that your adapter is using 8192cu module:

sudo lsmod | grep 8192
8192cu 551136 0

Create the file /etc/modprobe.d/8192cu.conf and insert the following lines inside:

# prevent power down of wireless when idle
options 8192cu rtw_power_mgnt=0 rtw_enusbss=0

I also suggest to create a little entry in crontab to make the RaspberryPi ping your router every minute. This will ensure that your wifi connection will stay alive. To edit crontab just type (from pi user, you don’t need to be root):

crontab -e

and insert this line at the end:

*/1 * * * * ping -c 1 192.168.0.1

where 192.168.0.1 is the IP of your router (of course substitute this value with the ip of your router).

Keep Alive Script

I created a further script to keep my WIFI alive. This script will ping the router (change the IP using the one of your router) every 5 minutes and if the ping fails it brings down the wlan0 interface, the kernel module for the wifi and bring them up again.

Just put this script in /root/wifi_recover.sh and then execute from root user:

chmod +x wifi_recover.sh
crontab -e

Insert this line inside the crontab editor:

*/5 * * * * /root/wifi_recover.sh

Conclusion

The configuration is done. Just reboot your RaspberryPi and enjoy your wifi connection.

Configuring ddclient to update your dynamic DNS at noip.com

noip.com is one of the few dynamic DNS free services that are reliable to use. If you have, like in my situation, a RaspberryPi connected to your home DSL and you want it to be always reachable without knowing the current IP address (the IP could change if you have a normal DSL service at home), you need a dynamic DNS service.

To update the noip.com one you just need ddclient, a tool that is available in Raspbian/Debian repository. You can install it with this command:

sudo apt-get install ddclient

then you just need to edit /etc/ddclient.conf

protocol=dyndns2
use=web, web=checkip.dyndns.com/, web-skip='IP Address'
server=dynupdate.no-ip.com
login=yourusername
password=yourpassword
yourhostname.no-ip.org

and restart the client:

sudo /etc/init.d/ddclient restart

That’s all! Please remember that noip.com free accounts have a limitation: they need to be confirmed every 30 days (you will receive an email and you need to click on the link contained to update your DNS).

Getting started with Digital Ocean VPS: configuring DNS and Postfix for email forwarding

I have recently migrated my website from a shared hosting to a dedicated VPS on Digital Ocean. Having a VPS surely gives you unlimited possibilities, compared to a shared hosting, but of course you have to manage some services by yourself.

In my case I only needed: SSH access, LEMP configuration (Nginx + MySQL + PHP) to serve my WordPress blog and Postfix to use email forwarding from my aliases to my personal email.

Configuring DNS on Digital Ocean

Understanding how to properly configure the DNS entries in the panel could be a bit tricky if it’s not your daily bread. In particular there is a Digital Ocean configuration that assumes certain things about your droplet, so it’s better to configure it properly.

For example the droplet name should not be casual, but it should match your domain name: I initially called my host “andreagrandi” and I had to rename it to “andreagrandi.it” to have the proper PTR values.

You will need to create at least a “mail” record, pointing to your IP and an “MX” record pointing to mail.yourdomain.com. (please note the dot at the end of the domain name). Here is the configuration of my own droplet (you will notice also a CNAME record. You need it if you want www.yourdomain.com to correctly point to your ip.

dns_config_digitalocean

 

Configuring Postfix

In my case I only needed some aliases that I use to forward emails to my GMail account, so the configuration is quite easy. First you need to install Postfix:

sudo apt-get install postfix

Then you need to edit /etc/postfix/main.cf customizing myhostname with your domain name and add virtual_alias_maps and virtual_alias_domains parameters. Please also check that mynetworks is configured exactly as I did, or you will make your mail server vulnerable to spam bots. You can see my complete configuration here:

Add your email aliases

Edit /etc/postfix/virtual file and add your aliases, one per line, like in this example:

info@yourdomain.com youremail@gmail.com
sales@yourdomain.com youremail@gmail.com

At this point update the alias map and reload Postfix configuration:

sudo postmap /etc/postfix/virtual
sudo /etc/init.d/postfix reload

Conclusion

As you can see, configuring Postfix is quite easy, you just need to be careful when you configure the DNS records in the control panel. Are you curious to try how Digital Ocean VPS works? Fancy 10$ credit (enough for 2 months if you choose the basic droplet) for free? Use this link and enjoy it https://www.digitalocean.com/?refcode=cc8349e328a5