Using Letsencrypt with Wowza Media Server

As part of a work project, I needed to set up Wowza Media Server to do video streaming. As the webapp (which I wrote using the excellent ionic 3 framework) is running under https, it won’t accept video traffic coming from non-encrypted sources. Wowza has some pricey solutions for automatically installing SSL certificates for you, you can also purchase ones however these days I don’t see why everyone doesn’t just use the free and easily automated letsencrypt system. Unfortunately however, letsencrypt doesn’t let you run servers on different ports particularly easily, although it does have some hooks to stop/start services that may already be listening on port 443 (ssl). I happen to be using a redhat/centos distro, although I’m pretty sure the exact same instructions will work on ubuntu and other distros.

Firstly, you need to download the wowza-letsencrypt-converter java program which will convert letsencrypt certificates to the Java format that Wowza can use. Install that prebuild jar under /usr/bin.

Now, create a directory under the Wowza conf directory called ssl and create a file called jksmap.txt (so for example full path is /usr/local/WowzaStreamingEngine/conf/ssl/jksmap.txt) which lists all the domains the Wowza server will be listening on like:

video-1.example.org={"keyStorePath":"/usr/local/WowzaStreamingEngine/conf/ssl/video-1.example.org.jks", "keyStorePassword":"secret", "keyStoreType":"JKS"}

‘secret’ is not actually a placeholder; it’s the password that the wowza-letsencrypt-converter program sets up automatically so keep it as it is.

Configure SSL on the Wowza server by editing the VHost.xml configuration file (find out more about this process in the wowza documentation). Find the 443/SSL section which is commented out by default and change the following sections:

<HostPort>
        <Name>Default SSL Streaming</Name>
        <Type>Streaming</Type>
        <ProcessorCount>${com.wowza.wms.TuningAuto}</ProcessorCount>
        <IpAddress>*</IpAddress>
        <Port>443</Port>
        <HTTPIdent2Response></HTTPIdent2Response>
        <SSLConfig>
                <KeyStorePath>foo</KeyStorePath>
                <KeyStorePassword></KeyStorePassword>
                <KeyStoreType>JKS</KeyStoreType>
                <DomainToKeyStoreMapPath>${com.wowza.wms.context.VHostConfigHome}/conf/ssl/jksmap.txt</DomainToKeyStoreMapPath>
                <SSLProtocol>TLS</SSLProtocol>
                <Algorithm>SunX509</Algorithm>
                <CipherSuites></CipherSuites>
                <Protocols></Protocols>
        </SSLConfig>
        ...

Note the <KeyStorePath>foo</KeyStorePath> line – the value foo is ignored when using jksmap.txt, however if this is empty the server refuses to start or crashes.

Next, install letsencrypt using the instructions on the certbot website.

Once you’ve done all this, run the following command to temporarily stop the server, fetch the certificate, convert it and start the server again:

certbot certonly --standalone \
    -d video-1.example.org \
    --register-unsafely-without-email \
    --pre-hook 'systemctl stop WowzaStreamingEngine' \
    --post-hook '/usr/local/WowzaStreamingEngine/java/bin/java -jar /usr/bin/wowza-letsencrypt-converter-0.1.jar /usr/local/WowzaStreamingEngine/conf/ssl/ /etc/letsencrypt/live/; systemctl start WowzaStreamingEngine'

Then, in order to ensure that the certificate continues to be valid you need to set up a cron entry to run this command daily which will automatically renew the cert when it gets close to its default 3 month expiry time. Simply create /etc/cron.d/wowza-cert-renewal with the following content:

0 5 * * * root /usr/bin/certbot renew --standalone --pre-hook 'systemctl stop WowzaStreamingEngine' --post-hook '/usr/local/WowzaStreamingEngine/java/bin/java -jar /usr/bin/wowza-letsencrypt-converter-0.1.jar /usr/local/WowzaStreamingEngine/conf/ssl/ /etc/letsencrypt/live/; systemctl start WowzaStreamingEngine'