rtmp streaming to multiple platforms at once using nginx with docker

juni 27th, 2020 No comments

It’s been while since I posted here, and since I recently did something that is worth to put on here, I’ll have another go 😉

I’m part of the hamradio YOTA project, and with the epidemic thingie we wanted to do some live sessions on Youtube, Facebook and twitch at once.

To capture/broadcast I’m using OBS on my desktop PC, however, this software can only push to one streaming service at once, unless I open up multiple OBS’s and try to set things up that way, but that could lag your computer, and if you have bandwidth limitations, this can also create issues.

So, I wanted to push the stream to one of my datacenter servers, and transcode(where needed)/redistribute to the streaming platforms from there.
This makes it so I only have to upload once from a “home” connection
In my tests, my rtmp stream +-6 Mbit up from home, +-17 Mbit up from datacenter to the services.
Optionally people can also pull from that service, or you can distribute it to more servers for other people to look live, if you want to have your own mini rtmp setup.

Since I like to use docker, I’ve created a Dockerfile that builds nginx with this rtmp module.
I’ve also created a docker-compose so it’s easy for you to get started an try it out yourself.
(Requires some experience with servers and docker)
You can find it here:

Note, if your home router overheats and restarts during the stream, cause of heatwave (yeah I need to get an airco in that tech room), you might have to stop the broadcast and start it again, cause it doesn’t handle disconnects that well.. if facebook is disconnected too long they stop and you might need to reset that stream key.. Youtube nicely waits, for twitch it doesn’t matter

73 de ON1GPS

Docker Service Discovery (aka resolv the IP’s of your running containers)

september 30th, 2015 No comments

Note: In this blogpost I expect that you are aware of docker, it’s basics and how to use it. Also, don’t blame me if this doesn’t work, cause PEBKAC

I’ve been experimenting with docker for the last year in a hobby project, which is running a small Minecraft server network for a Youtuber called Xisumavoid

docker came to my attention some time last year (2014), heard people talking and praising it, so I checked it out, I’ve been hooked ever since.

One feature of docker is a lot of fun, the –link feature, this puts the hostname of the certain container to it’s proper IP.
However, this doesn’t update when the container you linked to restarts.. which is annoying.. also your container doesn’t start when that container isn’t up.

Also, if you want to connect to the containers from your host, or another host, say through a different docker container on a different host, yeah.. issues..

What I have found to work is this combination:

It’s a strange combination, but it works for me just fine.

This is how it works:

dnsdock is connected to the docker API, using the socket, Yes there is some security related discussion that discourages this practice… but for this one app, which is open source.. and has no direct incoming connection to the outside world.. I don’t worry that much.

The powerdns part, is basically a recursive dns server, which will combine the queries for all the docker instances, powerdns is quiet the powerfull dns server.. so that way I’m sure resolving doesn’t crash that easy.

Now, how do i make all of this work, like this:

docker pull tonistiigi/dnsdock
docker pull urelx/pdns-recursor

docker run -d -v /var/run/docker.sock:/var/run/docker.sock --name dnsdock -p tonistiigi/dnsdock -environment="servername"
docker run -d --name powerdns \
-p -p \
urelx/pdns-recursor --forward-zones="servername.docker=, otherservername.docker=" --forward-zones-recurse=".="

In this example I also added a 2nd baremetal server, with ip

I’m aware this is not the most advanced thing, and could be expanded in lots of ways, but this just a simple proof of concept that does the basics you need in order to resolv containers.
More info you’ll find on the dnsdock repo.

However, how does this basically work

the hostname looks something like this:

so if you run a mysql server, name mysql1 (assuming you use the official mysql image) it looks like this:

Interesting fact, if you have mysql1, mysql2, etc, you can dns loadbalance:
mysql.servername.docker. will give back all the ip’s of the running containers, using that image.


Catacomb Snatch

november 21st, 2012 No comments

End February Mojang (if you are from an other planet: the makers of Minecraft) participated on a charity event called “The Humble Bundle“.

For this charity they developed in 60 hours a game called Catacomb Snatch, but what you could expect, 60 hours is not much time.

After the charity event was done (they raised over $352.000), the source-code (java) of the game was released into the wild.

What i saw happening (mostly on the minecraft forum’s) was people patching the game up, not looking at each others fixes, others patched the game closed-source and were asking for donations, yes they did!

So i decided to start a Github project for this game, i merged all the patches i could find on the interwebs, builded them, and a guy named Zorro300 (on the minecraft forum) started to advertise my github project on the forums, that it has a merge of all the fixes, it’s open-source and everybody could contribute.
That made it boom so hard, i couldn’t keep up..
over 30 people started committing a load of fixes, new features, new sprites, etc

The same week I registered catacombsnatch.net, installed a jenkins build-server, created an irc-channel on freenode
2 guys made the website and installed the forums.

So this project has been silent for the last couple of months, sometimes i did some patching, but mostly, people don’t have time 😉
An other reason why I’m not that active, my java skills are not that great, i do have basic understanding of programming, this game is quite the challenge.

We do have a lot of idea’s, for example an improved multiplayer system with lobby, where you also can add friends, some kind of ranking system.. etc..
this also requires gameserver system etc..
We also want to port the game to the OUYA game console.

But for these features, we need some people who are better in java, and have some spare time 😉
+ one of the priorities now is abstracting the “rendering” system, so we can add a better system, also that will make it more easy to port to android.

Anyway, this post was long overdue 😉 I’ll see if i can keep this blog a bit more up-to-date.

Categories: Development Tags:

EDPnet goes IPV6

april 5th, 2012 4 comments

So, about one year after the first announcement, The Belgian DSL provider EDPnet has started a test-group for native ipv6.

Their ipv6 does not work on the standard (by Belgacom issued) Sagem modems.
You will need to place a router behind the Sagem, which bridges PPPoE perfectly through.

I placed a Mikrotik RB1200 firmware version 5.12.

The IPV6 is enabled through DHCPv6 and you are given an /48 or /56 range, depending if you have static or dynamic ip contract.

I will post here how to have a basic setup to get ipv6 working on your MikroTik.

I assume you already have set up PPPoE. If you don’t know how to initially use the router, please read the documentation first.

The configuration example here is done over the MikroTik terminal.

/ipv6 dhcp-client
add disabled=no interface=pppoe-edpnet-v6 pool-name=DSL pool-prefix-length=48

The interface is the PPPoE interface you created to connect.
The pool-prefix-length is depending on what kind of contract you have, dynamic ip’s = 56, static = 48
Now for the lan-side:

/ipv6 address add from-pool=DSL interface=BR-LAN advertise=yes

The pool was defined in the DHCP-Client
the interface is the LAN interface you have.
advertise will make sure the devices on the lan get router advertisement, so they will obtain a IPV6 IP.
Now the firewall settings

/ipv6 firewall filter
add action=accept chain=input comment="Router - Allow IPv6 ICMP Traffic" disabled=no protocol=icmpv6
add action=accept chain=input comment="Router - Accept established connections" connection-state=established \
add action=accept chain=input comment="Router - Accept related connections" connection-state=related disabled=\
add action=drop chain=input comment="Router - Drop invalid connections" connection-state=invalid disabled=no
add action=accept chain=input comment="Router- UDP" disabled=no protocol=udp
add action=accept chain=input comment="Router - From our LAN" disabled=no in-interface=BR-LAN
add action=log chain=input comment="Router - Log everything else" disabled=no log-prefix="DROP IP6 INPUT"
add action=drop chain=input comment="Router - Drop everything else" disabled=no
add action=drop chain=forward comment="Lan - Drop invalid Connections" connection-state=invalid disabled=no
add action=accept chain=forward comment="Lan - Accept UDP" disabled=no protocol=udp
add action=accept chain=forward comment="LAN - Accept ICMPv6 " disabled=no protocol=icmpv6
add action=accept chain=forward comment="Lan - Accept established Connections" connection-state=established \
add action=accept chain=forward comment="Lan - Accept related connections" connection-state=related disabled=\
add action=accept chain=forward comment="Lan - From our Lan" disabled=no in-interface=BR-LAN
add action=log chain=forward comment="Lan - Log everything else" disabled=no log-prefix="Log IPv6"
add action=reject chain=forward comment="Lan - Drop everything else" connection-state=new disabled=no \
 in-interface=pppoe-edpnet-v6 reject-with=icmp-no-route

If more details are needed how to set up mikrotik for DSL, leave a comment, i’ll try to update this post then to help out.

Note this is an example and will not guarantee to work with everybody.

I’m not responsible if you fail miserably.

Categories: ipv6 Tags:

semi-native ipv6 on telenet line for linux

december 26th, 2010 2 comments

Deze post is in het engels omdat dit toch internationaal mag gelezen worden.

So a friend of my send me a little howto how to setup semi-native ipv6 on my internet connection to my cable provider (Telenet).
Although Telenet has Docsis 3, they haven’t yet implemented the native ipv6 support.

So, the solution Thomas gave me was quick, dirty, but it works!

We’ll setup an 6to4 tunnel.
Wait would you think, isn’t this another tutorial to install an tunnel-broker like siXXs?


You’ll have to generate an ipv6 ip adress based on your ipv4 ipadress with the 2002: prefix
This prefix defines it’s an 6to4 semi-native ip.

So this is the script to enable ipv6 on your machine (connected to direct wan connection, so to the modem, not an router)

I got some commands from Thomas how to get 2002 ip, the rest i wrote myself.

Note: wan side needs to be on eth0 for this script, you should be able to change the script if your connection is different.


ipv4=$(ifconfig eth0 | grep inet | cut -d : -f 2 | cut -d \  -f 1)
ipv6=$(printf "2002:%02x%02x:%02x%02x::$id\n" `echo $ipv4 | tr "." " "`)
ip tunnel add tun6to4 mode sit remote any local $ipv4
ip link set dev tun6to4 up
ip -6 addr add $ipv6/16 dev tun6to4
ip -6 route add 2000::/3 via :: dev tun6to4 metric 1

So, why the ip?
This is the ip of 6TO4-RELAY-ANYCAST this means, any 6to4 provider in the neighborhood of the network of your provider can give you ipv6 connectivity.
So this ip is reserved by default for this functionality.

He also send me an config example for cisco routers + to have an subnet.
I did some tuning on it to make it work dynamically.

Note: Outside (WAN) is FastEthernet0/0, inside (LAN) is FastEthernet0/1 in this example.

ipv6 unicast-routing
ipv6 general-prefix 6TO4PREFIX 6to4 FastEthernet0/0
ipv6 cef

interface Tunnel6
 description 6TO4-TUNNEL
 no ip address
 no ip redirects
 ipv6 address 6TO4PREFIX ::0:0:0:0:1/128
 ipv6 enable
 ipv6 mtu 1472
 tunnel source FastEthernet0/0 tunnel mode ipv6ip 6to4

interface FastEthernet0/1
 ipv6 address 6TO4PREFIX ::1:0:0:0:1/64
 ipv6 nd ra-interval 10
 ipv6 nd ra-lifetime 180
 ipv6 nd prefix default 180 120
 ipv6 enable
ipv6 route 2002::/16 Tunnel6
ipv6 route ::/0 2002:C058:6301::

in this case 2002:C058:6301:: is the 6to4 relay anycast ip.

Some interesting links:

http://wiki.nil.com/IPv6_over_IPv4_tunneling (some help i found to optimize cisco script)
http://www.coris.org.uk/cgi-bin/ip6addr (ipv6 adress calculator)

UPDATE: I’ve seen a lot of video’s on youtube this week of conferences, google techtalks, etc and i’ve learned a lot.

http://www.youtube.com/watch?v=AmjlptEva4Y&feature=channel they state that this 6to4 tunneling method is not the best, cause of major latency issue’s non-correct routing etc.
With this in mind, i’ll recommend, if your provider doesn’t have native v6, the time is now to start bugging them, since ip’s will run out by february 2011 and they probably just have an reserve for about 6 month’s.

Extra note: i have router-advertised both sixxs and 6to4 on my lan, and since i added the 6to4, my mac refuses to prefer ipv6 to connect, so that is an other reason to get back to brockers or get native v6.

Categories: ipv6, linux Tags: , , , , , ,


oktober 23rd, 2010 No comments

So i wanted to run sixxs IPV6 on my mac through aiccu but i had a lot of work making it work..
Therefor i post this on my blog to help people enjoy the ipv6  provided by in my case sixxs

Note: I posted this before on the sixxs forum

Download and install
pretty easy, is a package

i found a special build (sixxs staff should add this patch to there repo!(ps. 2nd part of patch is wrong/outdated, so DO NOT DO THAT))
the patch: https://fit.nokia.com/lars/software/aiccu.patch
the site i found it: https://fit.nokia.com/lars/appletv-ipv6-router.html
you also can download a build of the patched version from me (md5: 288b553550fc2cd30343766fac481c80)

If you want to be safe for backdores, you want to build it yourself, this is how:

From here if you want to patch yourself

Get XCode free from the macsite:

for the not programmers under us:
download the aiccu tar.gz from this site:
the source:

just unpack it by double clicking on the file
go to the folder: aiccu
go to the folder common
open the file: aiccu_darwin.c
go to line 32
under: /* Bring the interface up */
remove: aiccu_exec(
“ifconfig %s up”,

Add:char tun[256] = “/dev/”;
open(strcat(tun, g_aiccu->ipv6_interface), O_RDONLY);

save and close the file.

open a terminal (applications/some directory i don’t know the name in english/Terminal.app) or (via spotlight)

From here on, if you want to build

go to the map (DONT TYPE THE #):
# cd Downloads/aiccu
then compile it:
# make
you will get some warnings, they can be ignored..
now in the map unix-console there will be the aiccu binary.
copy this binary to a place you need it like /usr/sbin/
then you can run the aiccu from everywhere you want
MAKE SURE YOU CHANGE IPV6_INTERFACE TO tun0 ; that’s tun zero!!!
edit the outher info from the example config found on the site.

you can start from terminal
# sudo aiccu start aiccu.conf
from the directory where the config is, probably your homedir (that’s the dir where your terminal opens in)

your tunnel is working ^^

been 2 hours for me to find out..
in our language there is an saying: (de aanhouder wint!)
dno the decent translation right now 😉

i hope this works for you.. it did for me 😉

PS: you will need to restart you aiccu everytime you reboot your mac, don’t know the fix.. to lazy to find out right now 😉
if you just go to sleep, there is no problem, it will reconnect on wake-up.

Categories: ipv6, Mac Tags: , , , , ,

Velleman Kit K8000 and Linux

september 26th, 2010 5 comments

Dit bericht is in het engels omdat zo iedereen het kan lezen 😉

So for a while I own a Velleman k8000 kit.. and now I had the time to do something with it!
I went on a google hunt and came up with the following sites:

These sites had interesting files, but they were a little outdated.
So i started a little project to combine them and updated them to work on my ubuntu system.

The changes i made are available in github

I’m new in driver and python programming, I’m just a phper who started experimenting with python.
So if you see rookie mistakes, please, don’t flame, help and fix it, i would love to learn of it 🙂

Categories: Development, linux Tags: , , , , ,

What i have learned about Cassandra NoSQL DB

mei 12th, 2010 2 comments


Normally I write in dutch, but because the rest of the world doesn’t understand dutch (you should learn our bastard language!), i’ll have to evolve to english (and more international) blogposting. (So don’t shoot me if i make major grammatical mistakes and don’t be a bitch about it!)

I’ll try to keep this post as up-to-date posible

So Cassandra is an NoSQL Database, that means, no SQL language.

I even dare to call it an improved memcached.

First of all i’ll post a couple of links where i learned a lot from




There is a List of libraries on http://wiki.apache.org/cassandra/ClientOptions

I’m using the phpcassa lib. (yeah i use php, deal with it)

Since there is a lack of advanced beginner documentation, i have made an little example based on the “wtf is a supercolumn datamodel

$GLOBALS['THRIFT_ROOT'] = 'lib/classes/api/phpcassa/thrift/';
require_once $GLOBALS['THRIFT_ROOT'].'/packages/cassandra/Cassandra.php';
require_once $GLOBALS['THRIFT_ROOT'].'/transport/TSocket.php';
require_once $GLOBALS['THRIFT_ROOT'].'/protocol/TBinaryProtocol.php';
require_once $GLOBALS['THRIFT_ROOT'].'/transport/TFramedTransport.php';
require_once $GLOBALS['THRIFT_ROOT'].'/transport/TBufferedTransport.php';


CassandraConn::add_node('', 9160);

 * Example based on the blog example of http://arin.me/blog/wtf-is-a-supercolumn-cassandra-data-model
 * what you see next, you need to add to your storage-conf.xml
<Keyspace Name="BloggyAppy">

	<!-- CF definitions -->
	<ColumnFamily CompareWith="BytesType" Name="Authors"/>
	<ColumnFamily CompareWith="BytesType" Name="BlogEntries"/>
	<ColumnFamily CompareWith="TimeUUIDType" Name="TaggedPosts"/>
	<ColumnFamily CompareWith="TimeUUIDType" Name="Comments"
		CompareSubcolumnsWith="BytesType" ColumnType="Super"/>
	<!-- other keyspace config stuff like replication values -->


 * Load the ColumnFamilies
 * Normally there you should define the consistancy levels, but that depends on the number of nodes/replication factor or what kind of data it is.
echo "Loading ColumnFamilies..";
$authors = new CassandraCF('BloggyAppy', 'Authors', false, 'BytesType');
$blogentries = new CassandraCF('BloggyAppy', 'BlogEntries', false, 'BytesType');
$tagged = new CassandraCF('BloggyAppy', 'TaggedPosts', false, 'TimeUUIDType');
$comments = new CassandraCF('BloggyAppy', 'Comments', true, 'TimeUUIDType', 'BytesType');
echo "Done.\n";

 * Insert example data

echo "Inserting data..";
$authors->insert("Arin Sarkissian", array("numPosts" => 11, "twitter" => "phatduckk", "email" => "[email protected]", "bio" => "bla bla bla"));
$blogentries->insert("i-got-a-new-guitar", array("title" => "This is a blog entry about my new, awesome guitar", "body" => "this is a cool entry. etc etc yada yada", "author" => "Arin Sarkissian", "tags" => "life,guitar,music", "pubDate" => time(), "slug" => "i-got-a-new-guitar"));
$timeuuid_1 = UUID::generate(UUID::UUID_TIME,UUID::FMT_STRING, "i-got-a-new-guitar");
$tagged->insert("guitar", array($timeuuid_1 => "i-got-a-new-guitar"));
$tagged->insert("life", array($timeuuid_1 => "i-got-a-new-guitar"));
$tagged->insert("music", array($timeuuid_1 => "i-got-a-new-guitar"));
$tagged->insert("__notag__", array($timeuuid_1 => "i-got-a-new-guitar"));
$blogentries->insert("another-cool-guitar", array("title" => "This is a blog entry about my other guitar", "body" => "this is a cool entry. etc etc yada yada", "author" => "Arin Sarkissian", "tags" => "guitar", "pubDate" => time(), "slug" => "another-cool-guitar"));
$timeuuid_2 = UUID::generate(UUID::UUID_TIME,UUID::FMT_STRING, "another-cool-guitar");
$tagged->insert("guitar", array($timeuuid_2 => "another-cool-guitar"));
$tagged->insert("__notag__", array($timeuuid_2 => "another-cool-guitar"));
$blogentries->insert("scream-is-the-best-movie-ever", array("title" => "This is a blog entry about my favorite movie Scream!", "body" => "this is a cool movie entry. etc etc yada yada", "author" => "Arin Sarkissian", "tags" => "movie,horror,", "pubDate" => time(), "slug" => "scream-is-the-best-movie-ever"));
$timeuuid_3 = UUID::generate(UUID::UUID_TIME,UUID::FMT_STRING, "scream-is-the-best-movie-ever");
$tagged->insert("movie", array($timeuuid_3 => "scream-is-the-best-movie-ever"));
$tagged->insert("horror", array($timeuuid_3 => "scream-is-the-best-movie-ever"));
$tagged->insert("__notag__", array($timeuuid_3 => "scream-is-the-best-movie-ever"));
$timeuuid_1a = UUID::generate(UUID::UUID_TIME,UUID::FMT_STRING, "Joe Blow");
$comments->insert("scream-is-the-best-movie-ever", array($timeuuid_1a => array("commenter" => "Joe Blow", "email" => "[email protected]", "comment" => "you're a dumb douche, the godfather is the best movie ever", "commentTime" => time())));
$timeuuid_2a = UUID::generate(UUID::UUID_TIME,UUID::FMT_STRING, "Some Dude");
$comments->insert("scream-is-the-best-movie-ever", array($timeuuid_2a => array("commenter" => "Some Dude", "email" => "[email protected]", "comment" => "be nice Joe Blow this isnt youtube", "commentTime" => time())));
$timeuuid_1b = UUID::generate(UUID::UUID_TIME,UUID::FMT_STRING, "Johnny Guitar");
$comments->insert("i-got-a-new-guitar", array($timeuuid_1b => array("commenter" => "Johnny Guitar", "email" => "[email protected]", "comment" => "nice axe dawg...", "commentTime" => time())));
echo "Done.\n";

 * Fetch data

echo "\n##FETCHING DATA##\n";
$taggedposts = $tagged->get("__notag__"); // You can change this value
foreach ($taggedposts as $tpost){
	echo "Fetching post: ".$tpost."\n";
	$blogentry = $blogentries->get($tpost);
	if (!empty($blogentry)){
		echo "Fetching author info: \n";
		$author = $authors->get($blogentry["author"]);
		$numcomments = $comments->get_count($tpost);
		echo "Fetching ".$numcomments." comments for ".$tpost.": \n";
		$commentposts = $comments->get($tpost);
	echo "\n##NEXT##\n";
echo "\n##END FETCHING DATA##\n";

 * Get a range of posts
$blogs = $blogentries->get_range();

echo "\nScript Done.\n";

This is a basic working example for the use of the cassandra Basics.
Later i will post some example’s of what i have done in my own production code, like using timestamps as indexes to get some data.
I’ll also post some stuff where i was stuck etc, it should help other people, so look for my future cassandra posts ^^

Netlog en XMMP (Jabber)

maart 14th, 2010 2 comments

Het is weer even geleden dat ik me aan men posting zou houden.. maar soit.. we hebben weer even tijd 😉

Netlog heeft sinds eind vorig jaar (denk rond november) hun nieuwe chatsysteem gelanceerd..

nu heb ik dat toch even bekeken wat dat was, bleek het een jabber webclient te zijn, dus dacht ik, dit moet ook werken via een jabber client.

En ik had gelijk!

Hoe erop te geraken:

[email protected]

passwoord is dezelfde als die van je account.

Let op dat je client ssl aankan met een fout certificaat (netlog moet hun certificaat nog laten signen)

Er zijn wel nog wat bugs.. zoals users die niet offline gaan, als je bericht stuurt, komt da toe bij de user alsof die user dat zelf heeft gestuurd naar zichtzelf

maar ik denk dat ze daar aan het werken zijn 🙂

Categories: Geen categorie Tags:

Verse blog

oktober 2nd, 2009 No comments

Hoi hoi

Ik heb nog eens verse moed gevonden om aan een blog te starten..

Hoe web1.0 zouden sommige denken/zeggen, maar ik vind dat blogging toch nog past in de 2.0 wereld 🙂

Ik ben van plan om deze blog vooral voor technische zaken die ik tegenkom in deze rare internet wereld te posten zodat mijn bevindingen/problemen/oplossingen toch op het net verschijnen 🙂

Verder heb ik natuurlijk ook twitter, facebook, linked in maar dat is meer voor het alledaags gedoe 🙂

Wat doe ik in het dagelijkse leven:

Goh.. ASLpage.be 🙂 dat is men grootste bezigheid, coding en servers 🙂
Maes Electronics de zaak van men ouders waar ik geregeld ook in meedraai 🙂

Wat kan ik en wat kan ik niet:

Ik kan zeker en vast redelijk wa technische stuff 🙂 ik ben *nix minded, maarja.. uit noodzaak kan ik natuurlijk ook met micisoft werken 🙂

Wat ik _niet_ kan.. dat is simpel.. design/tekenen/grafische shit.. daar gaat bij mij direct het licht uit 🙂
Design’s implementeren lukt me juist net nog wel 🙂

Anyway.. kheb hier al een redelijke introductie.. de langste dak ooit gedaan heb tot nu toe..

Ik hoop dat je interesante zaken tegenkomt op men blog.. zo niet.. c me care 😉

Categories: algemeen Tags: