Blog posts

Setting up Secure MPD Control from Android

This post documents setting up secure MPD control. You will be able to control MPD running on your host Linux system via an MPD client on your Android device. By using firejail, the client connection will be restricted to only accessing MPD, and cannot access the internet through the ssh connection.

Note that sshd configuration is not covered in this post, and it is expected for you to know how to.


Note it is expected that your system is using systemd.

Setting up the Host

Securing access

Creating the user to log into

Create a new user that uses firejail as its default shell:

sudo useradd -m -s /bin/firejail jailuser

Note we created the user that will accept ssh connections as jailuser. If you use a different username, be sure to keep track of that as later parts in this post refer to jailuser.

Creating the bridge interface

Create a systemd service that will start a bridge interface that the firejail instance of the new user will use:

Place the following snippet in /etc/systemd/system/jailuser_br.service

Description=Set up bridge interface for jailuser

ExecStart=/usr/bin/brctl addbr jailuser_br
ExecStart=/usr/bin/ip addr add dev jailuser_br
ExecStart=/usr/bin/ip link set jailuser_br up
ExecStop=/usr/bin/ip link set jailuser_br down
ExecStop=/usr/bin/brctl delbr jailuser_br


This oneshot service will create a new interface for the jail to connect to. Note that we are using the subnet, and assigned to the host system. You will need to sudo systemctl daemon-reload after creating the file to make systemd aware of it (unless you choose to reboot first), then sudo systemctl enable jailuser_br to make systemd execute it on every boot. If you want to create the interface now, do sudo systemctl start jailuser_br.

Restricting the new user

Create the directory in jailuser's home that will have the firejail config for the login shell (note jailuser by default cannot access this file).

sudo mkdir -p /home/jailuser/.config/firejail

Place the following snippet in /home/jailuser/.config/firejail/default.profile:

# Firejail profile for default
# This file is overwritten after every install/update
# Persistent local customizations
include default.local
# Persistent global definitions
include globals.local

# generic gui profile
# depending on your usage, you can enable some of the commands below:

# include
# include
# include
# include

# apparmor
caps.drop all
# ipc-namespace
# machine-id
# net none
net jailuser_br
netfilter /etc/firejail/
# no3d
# nodbus
# nodvd
# nogroups
# nosound
# notv
# nou2f
# novideo
protocol unix,inet,inet6
# shell none
shell /bin/bash
# tracelog

# disable-mnt
# private
# private-bin program
# private-cache
# private-dev
# private-etc alternatives
# private-lib
# private-tmp

# memory-deny-write-execute

Note this snippet is a copy of /etc/firejail/default.profile except with a few changes:

Restricting the network in which the user has access to

Place the following snippet in /etc/firejail/


#allow all loopback traffic
-A INPUT -i lo -j ACCEPT

# allow ping etc.
-A INPUT -p icmp --icmp-type destination-unreachable -j ACCEPT
-A INPUT -p icmp --icmp-type time-exceeded -j ACCEPT
-A INPUT -p icmp --icmp-type echo-request -j ACCEPT

# allow access to mpd
-A INPUT -p tcp --sport 6600 -s -m state --state ESTABLISHED -j ACCEPT
-A OUTPUT -p tcp --dport 6600 -d -m state --state NEW,ESTABLISHED -j ACCEPT


The file will enforce dropping of all connections except to the host's MPD (at port 6600). If your MPD is listening on a port other than 6600, you will have to change that in the previous snippet. You may also have to change the if you are using a different local subnet and address for the host. Right now, those two entries refer to the host's ip address in the bridge interface.

Other configuration

Finally, if you have a firewall configured, you will need to allow connections from to the host at port 6600 over tcp. For example, configuration for ufw can be used as follows:

ufw allow in proto tcp from to any port 6600

Setting up the Client

As mentioned before, sshd configuration is not covered in this post, but you are expected to have set up a key set up for an ssh client to connect to the host with. The ssh client must be set up to forward local connections at 6600 to, which is equivalent to something like ssh -L 6600:

Prior to using your MPD client, you will need to access your host system with the ssh client and have port 6600 forwarded to the host. It is kind of inconvenient, but it is the price we must pay to secure the connection.

You will need to install an MPD client on your Android device. I've gotten this setup to work with M.A.L.P., which is available on the F-Droid app repository.

Make sure your MPD client has set up a connection to localhost:6600, including the password that your MPD has been set up with if it is set.

Using the setup

Your host should have the jailuser user created, have configuration for that user's firejail shell set up in /home/jailuser/.config/firejail/default.profile, sshd should be configured for that user, /etc/firejail/ should exist and enforce the restricted network, and the jailuser_br interface should be up.

All that's left is to connect to the host's sshd with the ssh client on your Android device, and then open the MPD client to interface with the host's MPD.

When the client logs in as jailuser on your host, the session will log in with the /bin/firejail shell (which isn't actually a shell but ends up running a restricted /bin/bash session by default), which will automatically load the profile in /home/jailuser/.config/firejail/default.profile and enforce the restricted network for the session. The internet will be unavailable in the session, and only connections to the host's ip ( at port 6600 will be available, which should be what your MPD on the host is listening on.

EDIT 2021-05-15

I discovered a better streaming solution, you can check it out here:


Using OBS-Studio (for streaming), VLC (client to view the stream), NGINX (RTMP server to serve the stream), and Vagrant (for easy setup of the server), anyone can stream from their computer for anyone to see.
Maybe you are paranoid about third-party screen-sharing services and want to roll your own screen-sharing service, or maybe you want to present something to a bunch of colleagues. Whatever the case, this setup should work well since a client only needs a program that can view an RTMP stream (in this case, VLC).


Setting up the server

Server files from git repository

Grab the config with git:

git clone
# also get the required submodules
cd StreamingServer
git submodule update --init --recursive

Note that in the freshly created StreamingServer directory you will be using commands like vagrant up.

Server files from packaged zip/tar.xz

Grab the config here (zip) or here (tar.xz) and put it on the machine you want to host the RTMP server to serve streams.

Note if you don't trust the NGINX files in the config, you can grab the nginx source here and grab the RTMP module for NGINX here. After placing these files in the DebianRTMP directory containing the Vagrantfile and scripts, you may need to modify as the versions of NGINX and NGINX RTMP module may be different (and may extract to differently named directories).

unzip/untar the config and it should create a DebianRTMP directory with all the necessary config. You can place this directory anywhere, just note this is where we'll be using commands like vagrant up.

Notes about config

Note: The config (namely Vagrantfile) will set up the local network. If this is already being used by something else, you will have to change it in the Vagrantfile and, and use the different ip address in later steps in this guide.

# Using instead of
sed -i 's/' Vagrantfile
sed -i 's/'

First time running the server

Go into the StreamingServer (server files from git) or DebianRTMP (server files from zip/tar.xz) directory and run vagrant up.

This may take some time as it will grab a Debian stretch64 box if it isn't already downloaded by vagrant. Afterwards it will download several pacakges necessary to build a custom NGINX. Then it will build a custom NGINX (so that is is compiled with the RTMP module necessary for this to work) and install it. Some config will be overwritten by the script that will setup the RTMP server. Finally NGINX will be started as the last step of the provisioning process.

When done using the server, use vagrant halt and not vagrant destroy to retain what was downloaded on the server.

Not first time running the server

Go into the StreamingServer (server files from git) or DebianRTMP (server files from zip/tar.xz) directory and run vagrant up && vagrant provision.

The script was designed to not reinstall things already installed and to not compile NGINX again if it was already installed, so running the provision step again will just skip to running the NGINX server without need of ssh-ing into it.

Other notes regarding the server

Note that the server should have the 1935 port forwarded to allow incoming connections to view the stream.

Streaming to the server

Streaming to a server that is on the same machine as the streamer

Note that the server has been set up such that a local network is whitelisted such that streams pushed through that network will only be accepted.

In OBS-Studio, click on the settings button, click on the Stream tab, and set the "Stream Type" to Custom Streaming Server. Then set the URL to rtmp:// The stream key can be anything, but you will need to know the stream key when connecting to view the stream.


Streaming to a server that is on a different machine than the streamer

The easiest way to be able to send a stream to the server is to port forward using ssh.

ssh -L1935: <server_hostname>

Then instead of setting the URL to rtmp:// in OBS-Studio, you will need to set it to rtmp://

It is possible to use port forwarding and/or firewall rules to allow access to the internal network, but this is discouraged. If this is done, anyone could stream to your server, thus using ssh is more secure.

Viewing the stream

Open up VLC and in the menu bar under "Media", click on "Open Network Stream" (or use the shortcut Ctrl + N).

The network URL should be set to rtmp://<server-ip>/live/<stream-key>.

If the server is on the same machine and if the stream-key is test, then the URL would be rtmp://

Note that the server should have the 1935 port forwarded to allow incoming connections to view the stream.


For the hoster, setting up the server and stream is a little complicated but is easier due to the use of Vagrant.
For the viewer, the only config needed is the URL of the stream.

If there are any questions, please feel free to comment and I will provide answers as another comment.

Thanks for reading, and remember to vagrant halt the server when it is no longer in use.

EDIT (as of September 2019)

I recently visited this area, and found that many of the restaurants have closed, including the one mentioned here. Thus, this post is no longer accurate regarding availability.

So there's this place called "On The Table" in Gyunggi-do, Seongnam-Si, Bundang-gu, South Korea.

(It's in a building called "First Tower". I'm sure if you Naver search First Tower in Korean you'll find it.)

It's got a wide selection of restaurants (that seem more like "booths") to choose from. My favorite "restaurant" is TomaTillo.

This place satisifies my hunger for Mexican food as they have a good selection of dishes.

However, I usually get the burrito set/combo.

A spicy burrito plus chili-cheese-nachos sure hits the spot!

When I first started this website, I was using a simple webhost that was friendly and easy to use.

A Small Orange logo

This blog post is simply an appreciation of the service provided by, which was provided really cheap simple webhosting services that I used for a while.

Just got this website up and running on a new host.

And wow what a pain it was.

At the moment, Arch Linux images at are broken. Updating forces you to first manually update package-query and yaourt or nothing can be updated. And even if you get that far, you're still unable to update because pacman isn't able to add new keys to pgp/gpg for some reason, which breaks the update system.

So this baby is running on Debian 8 and hopefully will remain secure and up to date.

Good to be here at last!