DIY Super Secure WordPress on a VPS


Want secure wordpress for next to nothing…? (except a bit of work and understanding of course…) Read on!

I highly reccomend any tech minded website owner get familiar with how to run their own vps for hosting. As a musician I’ve noticed that the skills are the same as for building custom synths/recording appliances etc with single board computers (ie knowing your way around a linux OS). And with a vps you can do all your email marketing, automate a ton of stuff and handle your security far more effectively than you could under standard shared hosting.

It’s the security aspect that I’m going to focus on here in this article. WordPress sites used to be so simple – you just install it – blog stuff – maybe do your own custom theme if you’re clever. And you really could just leave it on one version of wordpress for the entire lifecycle of the site. You’d probably build another one before you needed to upgrade it!

Not so anymore. On the positive side, more features become available very rapidly these days. On the negative side security has become a running battle. There are teams of coders out there it seems writing robots that trawl the net for sites with security vulnerabilities. Once found these sites are infiltrated and usually end up posting up links to spam sites trying to sell you the usual viagra, debt consolidation, even (hilariously I think) seo…

Hence there are now expensive pieces of software like wordfence, ithemes security, securi… the list goes on. I have my opinions on which I would choose right now if I didn’t have a vps – but over time their different approaches and levels of effectiveness wax and wane according to conditions. If you have a vps/cloud server for your wordpress for some of the other reasons above then it seems to me logical that you should use that power to mimick their functionality and hence take control of your own security.

Essentially there are four main areas of security in a wordpress site:
1) Keep your site as up to date as possible both in wordpress, theme and plugin versions. This is a topic for another article…
2) Log in security – if someone wants to log in, ideally there should be some kind of two factor protection – also for another article (simple to achieve by the way)
3) Some kind of firewall – The open source approach is to use mod_security php module. This is also a subject for another article!
4) Intelligent File Permissions – this is what we’re going to focus on here today – and honestly if I could only have one out of these 4 it’d definitely be this one….

If your file permissions are set up right then wordpress literally CANNOT modify itself without your consent as the system admin (ie to install plugins/alter core/plugin files/do upgrades etc). If this is the case then one VERY major way that virusses/malware can infiltrate your site has been completely neutralised by design.

The concept is simple in the abstract but can be a little tricky to actually apply. Broadly we divide wordpress files into two types:

  • Everyday usage files Mainly this means images/videos and other media files. Note that this also includes files plugins create as part of their daily processing.
  • Site code files – basically this means the wordpress core files and the plugins/themes of your site.

We’re going to use the advanced permissions of a vps to create a situation where the first category can be modified as normal (ie you can upload media to your site and plugins can manipulate their own files as needed) but where your site can literally NEVER modify anything that comes into the second category UNLESS you personally as admin enter a password (or supply a private RSA key if you prefer).

We’re going to achieve this by having php run as one user for php (ie running the actual site) and have another user for handling the actual files via sftp. This user will also have read/write access to files created by the php user since it will belong to its group.

Therefore to begin with we’re going to set our vps to:

  sudo umask 002

This means that group write permissions are set for newly created files. So our sftp user (site code files from group 2 remember from above) will be able to read/write the php files from group 1 since the sftp user is a member of the php user’s group. (notice that vice versa is NOT the case so the php user cannot do anything with the sftp user’s files apart from read them.

Then you will need to set up the two users: (mysite-sftp for the sftp one and mysite-fpm for the php one)

  mkdir -p /media/mydisk/
  mkdir -p /media/mydisk/
  chmod 700 /media/mydisk/
  touch /media/mydisk/
  chmod 644 /media/mydisk/
  mkdir -p /media/mydisk/
  chmod 700 /media/mydisk/
  touch /media/mydisk/
  chmod 644 /media/mydisk/
  useradd -d /media/mydisk/ -s /bin/bash mysite-fpm
  useradd -d /media/mydisk/ -s /bin/bash mysite-sftp
  passwd mysite-sftp

make sftp user member of php user group

  usermod -aG mysite-php mysite-sftp

We will need apache/mysql/php-fpm set up so:

  ### Installing LAMP and other utilities
  apt update
  apt install -y apache2 mariadb-client mariadb-server php7.3-fpm php7.3-curl php7.3-gd php7.3-mbstring php7.3-mysql php7.3-xml php7.3-zip pwgen certbot zip unzip exim4
  ### Apache mods
  a2enmod proxy_fcgi setenvif ssl rewrite
  a2dismod -f autoindex
  systemctl restart apache2
  apache2ctl configtest
  # MySQL
  echo <mysql root pass enter one here!> > /root/mysql.pass

Add php-fpm config:

  touch /etc/apache2/sites-available/
  cat > /etc/apache2/sites-available/ << EOF
  <VirtualHost *:80>
  	DocumentRoot /media/mydisk/
         <Directory /media/mydisk/>
          Options Indexes FollowSymLinks MultiViews
  	AllowOverride All
  	Require all granted
          CustomLog /var/log/apache2/mydisk.access.log combined
  	        ErrorLog /var/log/apache2/mydisk.error.log
  <FilesMatch \.php$>
         SetHandler "proxy:unix:/var/run/php7.3-mysite-fpm.sock|fcgi://localhost"

It’s a bit more complicated for SSL… Ping me if you’ve got an https site and I’ll try to post something…

And restart your php:

  /etc/init.d/apache2 reload
  /etc/init.d/php7.3-fpm reload

Then to get this sucker over the line we’re also gonna need wp cli:

  curl -O
  chmod +x wp-cli.phar
  sudo mv wp-cli.phar /usr/local/bin/wp

Get wp core and set up your db with mysql then set wp to use that db:

  su -u mysite-sftp
  cd ../public/
  wp core download --path=/media/mydisk/ --locale=en_GB
  mysql -u root -p<Rootpassword>
  CREATE USER mysite@'localhost' IDENTIFIED BY '<mypass>';
  GRANT ALL PRIVILEGES ON `mysite_%`.* TO  `mysite`@`localhost`;
  CREATE DATABASE `mysite_wpdev`;
  wp config create --dbname=mysite_wpdev --dbuser=mysite --dbpass=mypass --path=/media/mydisk/
  wp core install --title=SITE_TITLE --admin_user=myuser --admin_password=mypassword --path=/media/mydisk/

Then run this permissions script:

  #### Script is used after setting up the environment via script
  ### change the path to the disk as appropriate
  umask 002
  #### INPUT
  echo "Enter website (domain) for which you want to edit permissions and ownership  (example:"
  read website
  echo "Enter handle/prefix for existing SFTP user who has ownership over $website files: (eg mysite)"
  read user
  #### Ownership and permisssions set
  ## Basic ownership
  chown -R $user-sftp:$user-sftp $diskpath/$website/
  chown -R $user-fpm:$user-fpm $diskpath/$website/$user-fpm/
  ## wp-content ownership (sftp languages, mu-plugins, plugins, themes, upgrade)
  chown -R $user-fpm:$user-fpm  $diskpath/$website/public/wp-content/
  chown -R $user-sftp:$user-sftp $diskpath/$website/public/wp-content/languages/
  chown -R $user-sftp:$user-sftp $diskpath/$website/public/wp-content/mu-plugins/
  chown -R $user-sftp:$user-sftp $diskpath/$website/public/wp-content/plugins/
  chown -R $user-sftp:$user-sftp $diskpath/$website/public/wp-content/themes/
  chown -R $user-sftp:$user-sftp $diskpath/$website/public/wp-content/upgrade/
  ## Permissions on folders and files
  find $diskpath/$website/public/ -type d -exec chmod 755 {} \;
  find $diskpath/$website/public/ -type f -exec chmod 644 {} \;
  find $diskpath/$website/public/wp-content/ -type d -exec chmod 775 {} \;
  find $diskpath/$website/public/wp-content/ -type f -exec chmod 664 {} \;
  chmod 775  $diskpath/$website/public/wp-content/
  echo "Finished."

In a nutshell this makes wp core files and the plugin/theme files sftp user files and the wp-content’s immediate contents plus the uploads folder php user files. If something goes wrong – use this script and it’ll put it right.

Lastly use wp-cli to install this plugin:

  su mysite-sftp
  wp plugin install ssh-sftp-updater-support --activate

Total genius! This thing is an absolute godsend. Had it not existed I’d probly have written it eventually.

Phew – still with me?:) Now the fun part – usage cases:

  • media uploads – try it! when you ls -ltr your uploads/2020/01 directory (or whatever the date of your upload was) you should see something like this:
      -rw-rw-rw- 1 mllorg-fpm mllorg-fpm 674870 Mar  1 09:43 preamp.jpg
      -rw-rw-rw- 1 mllorg-fpm mllorg-fpm  11597 Mar  1 09:43 preamp-225x300.jpg
      -rw-rw-rw- 1 mllorg-fpm mllorg-fpm   5426 Mar  1 09:43 preamp-150x150.jpg
      -rw-rw-rw- 1 mllorg-fpm mllorg-fpm  89359 Mar  1 09:43 preamp-768x1024.jpg
      -rw-rw-rw- 1 mllorg-fpm mllorg-fpm 202460 Mar  1 09:43 preamp-1152x1536.jpg

    …which means your files are created by the php user (mllorg-fpm) but modifiable by both the php user and the sftp user (mllorg-sftp) because the sftp user is a member of the php user group

    On the other hand if you were to ls -ltr in theregular site root dir you’d see this:

      -rw-r--r--  1 mllorg-sftp mllorg-sftp  4764 Mar 21  2020 wp-trackback.php
      -rw-r--r--  1 mllorg-sftp mllorg-sftp 19120 Mar 21  2020 wp-settings.php
      drwxr-xr-x 20 mllorg-sftp mllorg-sftp 12288 Mar 21  2020 wp-includes
      -rw-r--r--  1 mllorg-sftp mllorg-sftp  2898 Mar 21  2020 wp-config-sample.php
      drwxr-xr-x  9 mllorg-sftp mllorg-sftp  4096 Mar 21  2020 wp-admin
      -rw-r--r--  1 mllorg-sftp mllorg-sftp 19935 Mar 21  2020 license.txt
      -rw-r--r--  1 mllorg-sftp mllorg-sftp  3150 Mar 21  2020 xmlrpc.php
      -rw-r--r--  1 mllorg-sftp mllorg-sftp 31112 Mar 21  2020 wp-signup.php
      -rw-r--r--  1 mllorg-sftp mllorg-sftp  8483 Mar 21  2020 wp-mail.php
      -rw-r--r--  1 mllorg-sftp mllorg-sftp 47597 Mar 21  2020 wp-login.php
      -rw-r--r--  1 mllorg-sftp mllorg-sftp  3326 Mar 21  2020 wp-load.php
      -rw-r--r--  1 mllorg-sftp mllorg-sftp  2504 Mar 21  2020 wp-links-opml.php
      -rw-r--r--  1 mllorg-sftp mllorg-sftp  3955 Mar 21  2020 wp-cron.php
      -rw-r--r--  1 mllorg-sftp mllorg-sftp  2283 Mar 21  2020 wp-comments-post.php
      -rw-r--r--  1 mllorg-sftp mllorg-sftp   369 Mar 21  2020 wp-blog-header.php
      -rw-r--r--  1 mllorg-sftp mllorg-sftp  6939 Mar 21  2020 wp-activate.php
      -rw-r--r--  1 mllorg-sftp mllorg-sftp  7368 Mar 21  2020 readme.html
      -rw-r--r--  1 mllorg-sftp mllorg-sftp   420 Mar 21  2020 index.php
      -rw-r--r--  1 mllorg-sftp mllorg-sftp  2888 Jan 12 13:23 wp-config.php
      drwxrwxr-x  6 mllorg-fpm  mllorg-fpm   4096 Mar  1 09:37 wp-content

    These files are *only* modifiable by the mllorg-sftp (SFTP) user and NOT the mllorg-fpm (PHP) user since mllorg-fpm is NOT a member of the mllorg-sftp (SFTP) group! In fact the permissions script sets files so that they are not group writeable when they are SFTP files – but even if your sftp app does something different or some plugin (with your permission…) does something different while modifying files it won’t be a problem. You could set all those group write flags to true and the mllorg-fpm (PHP) user that your plugins and theme and wordpress use in execution would never be able to write to those files as that user does not belong to the right group. And no-one and nothing is stupid enough to set global write permissions:)

  • plugin/theme/core update – use that genius sftp-ssh-updator plugin we installed earlier to install plugins/update etc – literally just enter in your sftp user’s name/password and it’ll get on with it! Cool huh? I’d like to see a piece of malware do that…
  • File changes for custom editing – use the sftp user
  • WP CLI – Use the sftp user if its a core/plugin/theme related command. Use the php user if its media related. Use either if its just doing db queries. If you get tangled up just use the initial permissions script again to reset everything
  • er… that’s it… Your site is now uber-secure!

Actually there’s one more thing you can do… You can set the .htaccess of the wp-content and uploads directories so that it cannot ever execute php files. Just in case someone puts a php file somewhere (your php user can modify stuff there remember):

  <Files *.php>
  deny from all

You could even add a .htaccess permission set to your permissions script so that no one could modify it then exectute php:

  chown mysite-sftp:mysite-sftp wp-content/uploads/.htaccess
  chown mysite-sftp:mysite-sftp wp-content/.htaccess

This article, for a few hrs work if you know what you’re doing, has just given you top notch security included in the price of your VPS. A bit crazy this is on a musician’s site and not a general webdev one right? But why shouldn’t us musicians have top notch systems?

Fact is I went through hell being hacked finding this out so feels good to share…

Let me know how you get on. My web development business uses a system similar to this in production and we and our clients love it!

Next artile I’ll get back to something more musical – my raspberry pi based sample player!


DIY Audio Preamp for a few euros

Well it took a bit of research for a newbie like me but I eventually found a nice looking circuit diagram in this book:100 circuits audio circuit bench

Basically I was trying to get my cahon mic’ed up and into my live Twitch broadcasts so I could stomp it with my right foot whil I sing and play. The issue was I was using a small amp as a mixer – it worked nicely with the headphone socket as output. However, with the mic and instrument inputs taken, the only one left was a kind of CD/backing track level minijack. And my little dynamic mic didn’t have enough juice to make any noise through it.

After looking at a bunch of checp preamps/mixers (I didn’t want another mixer – I only needed 3 channels and was happy with my lil’ battery amp!) I realised that no matter how cheap behringer made something it always had a bunch of features that I didn’t want and probably sounded a lot worse than something I could build for less than half the price…

Therefore I went looking for circuit diagrams and found the aformentioned one to do the job.

Here are a few pointers that might help someone move from the circuit diagram to getting the right components and soldering them on a board.

  • I found this circuit happily worked on 12V instead of 9V – I used 8 1.2V rechargeable 1.2V AA batteries to power it & it seemingly lasts forever….
  • I put the circuit on a prototyping board first to make sure I’d arranged the components right. Then I just copied that to solder onto my main board.
  • I doubled the mono signal in order to output to the stereo minijack input on my amp/mixer.
  • Film capacitors are apparently better than ceramic for this sort of thing so that’s what I used
  • I used cheap carbon resistors and so far they sound fine – some day I’ll try some real expensive ones.
  • I taped it all up liberally. Much prettier than moulded plastic in a rugged DIY sorta way;)

I’ve tried it on some vocals since building and it really does sound better than any of the cheap built in preamps I’ve found on gear over the years. I think you’d have to start spending proper money on a really well made one to do better. Very impressed…

Now to go back to my DIY mic project and finally get that into usage:)

Cloud Raspberry Pi

Podcasts at the Command Line with Ecasound

Recently I’ve been tasked with mixing a few podcasts – and me being me (in other words reluctant to bother using a mouse if I don’t have to… and only possessing 50usd raspberry pi computers) I decided to try using command line utils. Really a raspberry pi 3 is easily up to the task – haven’t tried it on my zero, I’m not that much of a masochist!

Happily, a combination of ffmpeg and ecasound has seemed to do a pretty good job. It was fiddly to set up but as tends to be the case with CLI setups, it holds the potential for mixing future episodes to be very fast indeed to mix.

Recording and File Prep

The two ladies recording the podcast are situated on opposite sides of the Atlantic. Therefore each has a mic and recording device and also a phone. That way the call is conducted over the phone and two pristine recordings are made locally so we get the highest possible quality.

Then I need to mix the two recordings at a later date. One of the recordings actually gets saved as m4a (odn’t ask why:) and at 48khz while the other is a wav at 44.1khz. Seeing as I like to mix at 44.1 and ecasound can only really seek effectively with wavs, I used ffmpeg to convert the m4a to a wav at the correct frequency.

  ffmpeg -i input.m4a -ar 44100 output.wav

Synch and Volume

Then I need to synch the two files from the two podcast participants. I’ve used ecasound’s simple cli syntax for this:

  ecasound -c \
  -a:1 -chcopy:1,2 -ea:70 -i:playat,$1,input_A.wav \
  -a:2 -chcopy:1,2 -ea:100 -i:input_B.wav \
  -a:1,2 -o alsahw,1,0

Let’s break that down.

  • ‘-c’ means to go into interactive mode – more on that in a moment…
  • The ‘-a:x’ bits mean an effect chain (ie input followed by a load of cables, followed by output). In this case we’re specifying multiple chains going to the same output so we have to put them in one line (ie the last one). I couldn’t really tell you why, but as long as you only mention any input or output once in the file then it seems happy connecting them to as few or many chains as you like!
  • The ‘-chcopy:1,2’ bits are simply there because the input files are mono and I have headphones and two ears! Therefore I want to be able to hear the mono channel through both sides of my headphones.
  • ‘-ea:’ is an amplifier. The value is a percentage of the natural amplitude of the file.
  • The ‘-i’ part means specifying an input. ‘playat’ means we’ve got an offset for one of the files to get them in synch. It also happens that I’ve made the offset a parameter for the bash script. In this way I can do ‘bash ./ 4’ to start input_A.wav after 4 seconds.
  • The ‘-o alsahw,1,0’ is to play through alsa to my soundcard.

But wait, what if my guess of 4 seconds turns out to be wrong??!:-)

Well if we run our command we’ll have ecasound’s interactive mode which serves as a control surface and more. Unfortunately, pretty much the only thing it can’t edit easily is that little parameter in ‘playat’ that tells it at what point to play the sample.

Therefore we press ‘t’ to start ecasound playing – then probably a whole lot of ‘fw 30’, ‘rw 10’ etc to send the transport back and forward to understand if our guess of 4 seconds to synchronise was close or not. If so then cool… If not then we simply press ‘q’ and start our script with 5.5 seconds etc…

The other thing you’ll want to do is balance the volumes between the files. This is easy interactive mode.

Just type:


You should see something like this:

  ecasound ('h' for help)> cop-status
  ### Chain operator status (chainsetup 'untitled-chainsetup') ###
  Chain "1":
          1. Channel copy: [1] from-channel 1.000, [2] to-channel 2.000
  	2. Amplify: [1] amp-% 70.000
  Chain "2":
          1. Channel copy: [1] from-channel 1.000, [2] to-channel 2.000
  	2. Amplify: [1] amp-% 100.000

Volumes are a percentage – so to change that volume from 70 to 90:

  c-iselect 1
  cop-set 2,1,90

In other words, select chain 1, then set chain-operator 2, parameter 1 to 90.

The beauty of this is you can press the up arrow and change the 90 to 95 etc then press return and execute the command again with a different value.

In this instance you’ll have to note down the two volumes you used as ecasound doesn’t edit the ‘playat’ command interactively unfortunately. When they’re noted down just press ‘q’, edit the two vols in the original script and start up ecasound again (by pressing up arrow a couple of times and return given were in bash…)

Then when you’re done just note down the number you used to synchronise and edit the last line of your script so that the output is ‘output.wav’ instead of alsa.


Everyone’s human and I’ve been asked to cut bits out…

Here I tend to fire up jack so I can have multiple outputs. (something like this: jackstart -d alsa -p 128 -n 2 -r 44100) and set up a screen or tmux session with one terminal showing:

  ecasound -c -i podcast.wav -o jack,system,notransport

This way I can whizz back and forth in playing the file and find the places I want. The ‘notransport’ bit means it doesn’t impact the whizzing back and forth I’ll be doing on the editted copy…

Then I have another tab with an sh script open which will look something like this:

  ecasound -c \
  -a:1 -i:playat,0,select,0,30,podcast.wav
  -a:2 -i:playat,30,select,35,60,podcast.wav
  -a:1,2,<and more...> -o jack,system,notransport

Above I just removed a 5 second gap.

Again, when I’m done I just replace the output for ‘podcast_edited.wav’.

Add the Intro and Outro

The last thing you’ll need to do is stick an intro and outro on it:

  ecasound -c \
  -a:1 -ea:60 -i intro.wav
  -a:2 -ea:130 -i playat,30,podcast_edited.wav
  -a:3 -ea:190 -i playat,5030,outro.wav
  -a:1,2,3 -o final.wav

And we’re done!


Multicasting Livestreams to Twitch, Twitter and More with a VPS

I’ve had a couple of people ask me how I do my multicast to both Twitch and Twitter at the same time. If you stream to periscope currently your broadcasts appear in your twitter feed therefore for twitter you need a periscope account linked to your twitter account – probly a good idea to do this soon as Periscope is closing soon.

My solution actually applies to Facebook and Youtube also – though not instagram (for reasons I’ll explain later…). Re periscope closing – according to twitter’s docs we’ll continue to be able to use the periscope api to broadcast direct to twitter until the api is migrated to twitter – so in theory come march 31st we’re still in business…

Anyway… In summary – what I’m doing is broadcasting an RTMP stream of video and audio to a VPS I rent. Then I’m using an NGINX web server on that VPS to multiply that stream to post to more than one source. Then I have the chat feed from both services open in front of me.

Another quick note re twitter – It shows your broadcast live in your feed v but then all that is left aft’r you finish is a seemingly random 30s excerpt. So probably good to then repost another link from twitch/fb/youtube etc…

1. Generating an RTMP Stream

You can do this with a number of apps on Android or iOS or if you have a desktop device then OBS can do it. I use a raspberry pi 4 with installed, a standard pi camera, and a usb interface to grab the audio.

Something like this: should work on Android – probably there is something similar on iOS. You can use a USB audio device to input audio on android and iOS if you have a fairly modern version of the OS. So in theory you can have a mixer going into your tablet pc and balance your mic etc to record a whole band!

More detail is beyond the scope of this article or though at some point I’m likely to post set up instructions for the camera etc on a pi…

2. The VPS

I use for vps’s ‘cos they’re a great company with a reliable service. But you can use digitalocean etc there are a ton of good providers.

Only need a half a gig of RAM and one CPU to do the job so we’re talking no more than a tenner a month. Note also you could conceivably only turn it on when you use it and pay next to nothing – it’s just one button to click in gandi’s dashbaord. I use mine for a ton of other things hence leave it turned on…

Steps are Debian because that’s what I use but probly ubuntu is almost identical and no doubt others can be adapted.

To Install NGinx:

  apt-get install build-essential libpcre3 libpcre3-dev libssl-dev
  tar -zxvf nginx-1.16.1.tar.gz
  cd nginx-1.16.1

You *should* be able to type this line. However with my debian 10 I found two issues.

  ./configure –-with_http_ssl_module –-add-module=../nginx-rtmp-module-master

Firstly the with_http_ssl_module option did not work. My solution was to edit /nginx-1.16.1/auto/options and search for HTTP_SSL=NO and change it to ‘YES’ (without quotes…)

Secondly the add module option syntax was insanely picky… I ended up typing it like this:

  ./configure –-add-module="../nginx-rtmp-module-master"

Then I also found my gcc was set with a different kind of error reporting so I needed to do:

  grep -r 'Werror' 

…in the nginx directory and remove all instances of that option in compile commands otherwise the compilation would break… sigh… linux how I love you…

Anyway, At that point I had a working nginx installation and could edit my /usr/local/nginx/conf/nginx.conf

Just add this to the end:

  server {
  listen 1935;
  chunk_size 4096;
  buflen 4s;
  application <whatever_you_want_as_a_password> {
  live on;
  record off;
  push rtmp:// ;
  push rtmp:// ;

Then the two commands you need (as root) are:


…to start… and…

  /usr/local/nginx/sbin/nginx -s stop

…to stop…

3. Putting it together

The stream url for your rtmp app/pi/OBS whatever will be:

…where ‘this-stream’ is just a random name you gave to this stream… And you’ll get streaming to however many services you’ve listed!

The only thing that is driving me up the wall right now is the quality settings. The command I’m using right now to go live is:

  screen -d -m bash -c "ffmpeg -i tcp:// -c:v copy -b:v 1.5M -maxrate 1.5M -bufsize 500k -x264-params "keyint=48:min-keyint=48" -c:a aac -ar 44100 -ab 112k -ac 2 -strict -2 -flags +global_header -bsf:a aac_adtstoasc -f flv 'rtmp://'" &&
  sleep 5 &&
  /home/pi/picam/picam --alsadev hw:1,0 --tcpout tcp://

Whatever the quality settings are they need to work on all the services you are using… Hopefully you can grab the relavent numbers out of the above to fit into whatever app you are using to stream!

Happy streaming!

Raspberry Pi

A twitch chatroom display that appears on an e-ink screen at the press of a button.

I’ve been trying recently to get a twitch video broadcast system that I can just push a button and we’re go. As usual I’m working with a raspberry pi and its basic (but more than adequate) camera.

One of the annoying things I’m running into is firing up my twitch chat server on my phone and picking it up between songs etc. I don’t like having to press/swipe a load more things and I don’t honestly like an lcd screen flashing away at me or a mobile phone/wifi device right next to me while I’m playing (yes I’m sensitive to them – both the blue light and the wifi – I know you probably think I’m crazy but no amount of the government/manufacturers telling me this stuff is safe is ever going to stop me feeling like sh*t when I’m exposed to them too much!).

My pi gives me the potential to eliminate all this and have a wifi/mobile/lcd free device where I literally just have to press one button and the chat server appears on the screen! Cool huh!

Problem is… Twitch lets you into its chatroom with oauth tokens. This means when you disconnect from the chatroom you have to get another token! Really annoying if you do not have a permanent internet connection. Therefore I’ve got a VPS that is permanently logged into my twitch chatroom:-)

So what do we do? Well… Step number one is to actually get twitch to accept me into its chatroom. I’m using weechat as my irc.

Steps are:

  • Log into twitch in your browser
  • Go here: and press to generate a token, then copy it.
  • then ssh into your vps and run ‘screen’ – this way it’ll stay even if you disconnect
  • then run ‘weechat’ in your screen session
  • then in weechat: server add twitch -password=<pasted oauth token> -nicks=<username> -username=<username>
  • then connect to twitch with: /connect twitch
  • then join your channel with: /join #<username>
  • save your settings: /save

Now if you ssh back into your VPS you can type ‘screen -r -d’ and your twitch chat server will appear again!

Oh and I find Ctrl A – F really useful if I’ve used it on the wrong screen size and now it looks silly – it’ll have a good look at wherever you’re ssh’ing from and figure out what size screen you’re using now and modify itself…

Great, but what happens when your vps host has to reboot to do some security updates? (happened to me recently…) or you manage to completely gum up your vps with zombie processes to the point where you have to reboot from the hosting panel (ah… I errr… once heard a friend of mine did that…) Well then, here’s your set of instructions to sort out your chat screen if it disconnects:

  • go back here and get a new token: Didn’t you know there is an infinite supply!
  • start screen again then weechat
  • back in weechat: /set irc.server.twitch.password <paste it here!>
  • /connect twitch
  • join #<username> and you’re back in!

But what about the e-ink screen I told you about? It’s a waveshare 800*450 one. Terrible refresh rate (we’re talking seemingly endless thumb-twiddling seconds…) But really cheap, good enough for displaying chat messages and has this excellent software for it:

Essentially what I’ve done is set up my old pi3 (aw I love the lil’ thing – I actually used it as my main work machine for the best part of a year – no kidding… Recorded a load of music on it too…) ummm where was I? Ah yes I set up the pi with the PaperTTY terminal command loading at startup.

In fact I messed with the config of the tty1 systemd process so that instead of coming up with a login screen, it shows tmux right from boot.

And then… And here’s the cool bit – I’ve got a script on my main machine (a pi4 in case you were wondering) that is triggered by xbindkeys so I press one keypress to:

  • log into the pi3 via ssh
  • trigger a local script on the pi3 that does a ‘writevt /dev/tty1 bash’

And does exactly that. It has an RSA key to log in so no password and it autoloads shell from the .bashrc on login.

Voila! One keypress and I’ve got a twich chat server on a reasonably sized e-ink screen.


Hello world!

Welcome to WordPress. This is your first post. Edit or delete it, then start writing!