Configuring HTTP/2 with Apache on Fedora

HTTP/2 is the new version of the well known HTTP protocol which has been at the venerable 1.1 since late last century. Version 2 was derived out of Google’s SPDY protocol and it’s a binary protocol over the text based 1.1. It introduces a bunch of improvements including reducing latency, multiplexing, and server push. There’s some useful improvements that will be great for things like apps that use WebSockets. The Apache httpd daemon has included complete support for HTTP/2 since the 2.4.17 release in the form of mod_http2.

First you should configure your site with SSL, I suggest using LetsEncrypt/certbot as documented in this Fedora Magazine article.

Then you need to make sure the module is loaded, at least in Fedora 25 this is enabled in /etc/httpd/conf.modules.d/00-base.conf by default:

LoadModule http2_module modules/

Then you just need to enable the protocol in either the general configuration or in specific VirtualHost directives for specific sites:

# for a https server
Protocols h2 http/1.1

# for a http server
Protocols h2c http/1.1

Then it’s just a systemctl restart httpd to make the changes take effect.

To test whether you’re serving over HTTP/2 you can test using this HTTP/2 testing site or with the OpenSSL client (check for “ALPN protocol: h2” in the output) with the following command:

openssl s_client -alpn h2 -connect HOSTNAME:443

Note: HTTP/2 is not currently supported in the httpd shipped in RHEL.

Connect to a wireless network using command line nmcli

I use a lot of minimal installs on various ARM devices. They’re good because they’re quick to download and you can test most of the functionality of the device to ensure it’s working or to quickly test specific functionality but of course it doesn’t have a GUI to use the nice graphical tools which are useful to quickly connect to a wifi network or other things.

This where nmcli comes in handy to quickly do anything you can do with the GUI. To connect to a wireless network I do:

Check you can see the wireless NIC and that the radio is enabled (basically “Airplane” mode):

# nmcli radio
enabled  enabled  enabled  enabled 
# nmcli device
wlan0   wifi      disconnected  --         
eth0    ethernet  unavailable   --         
lo      loopback  unmanaged     --         

Then to actually connect to a wireless AP:

# nmcli device wifi rescan
# nmcli device wifi list
# nmcli device wifi connect SSID-Name password wireless-password

And that should be enough to get you connected. You can list the connection with nmcli connection and various other options. It’s pretty straight forward. The only complaint I have is that it doesn’t prompt for a password if you leave it out so it means the AP password is stored on the command line history. Not a major given it’s quite easy to find where it’s stored anyway on the system but it would be a useful addition.

When creating updates remember to build for rawhide and Fedora 25 (devel)

When ever we branch for a new release of Fedora I, and others, end up spending a non trivial amount of time ensuring that there’s a clean upgrade path for packages. From the moment we branch you need to build new versions and bug fixes of packages for rawhide (currently what will become Fedora 26), for the current stabilising release (what will become Fedora 25) as well as what ever stable releases you need to push the fix for. For rawhide you don’t need to submit it as an update but for the current release that’s stabilising you do need to submit it as an update as it won’t just automagically get tagged into the release.

As a packager you should know this, it’s been like it for a VERY LONG TIME! Yet each cycle from the moment of branching right through to when a new release goes GA I still end up having to fix packages that “get downgraded” when people upgrade between releases!!

So far this cycle I’ve fixed about 20 odd with the latest being bash-completion (built but not submitted as an update for F-25) and certmonger (numerous fixes missing from F-25 and master branch).

The other silly packaging bug I end up having to fix quite a bit is NVR downgrades where even though it’s a newer package the way the NVR is handled makes rpm/dnf/yum think the newer package is a lesser version than the current version and hence you’re new shiny fix won’t actually make it to end users. I see this a lot where people push a beta/RC package to a devel (F-25/rawhide) release. Just something to be aware of, there’s lots of good docs around the way rpm/dnf/yum handles eNVR upgrades.

Changing ssh ports on Fedora or RHEL

I always forget the exact commands to change the port ssh (or any default service in the case of the selinux bits) runs on. It’s nicely simple though!

Edit /etc/ssh/sshd_config to change the port number:

Port 2022

You can add a second line if you wish to initially leave it running on Port 22 too in case something goes wrong, obviously don’t forget to remove it once the new port is working!

To add port 2022 to port contexts, enter:
# semanage port -a -t ssh_port_t -p tcp 2022

You can verify new settings, enter:

# semanage port -l | grep ssh
Sample outputs:
ssh_port_t tcp 2022,22

Reload the sshd service to pick up the new config:
#systemctl reload sshd.service

And of course don’t forget to update your firewall to allow the new port through.

network bridge for libvirt host with a single live IP

The default network config for libvirt is simple and works for most basic use cases but there’s a number of use cases where you need more complex config like Adam outlined for a local bridged config.

I run a number of VMs on a hosted server on the internet and I’ve had on my ToDo list for some time to add a IPSEC site to site VPN but the default network doesn’t make that easy because libvirtd deals with the iptables networking including the NAT automagically.

The network config looks like this:

                    *-----*  --| Hyp |-(eth0)- internet
 (br0) VM net       *-----*

Create non routed network bridge
Initially create a basic network bridge and disable STP (spanning tree protocol). Note we don’t bind it with eth0 which is a public internet facing interface.

nmcli con add type bridge ifname br0
nmcli con modify bridge-br0 bridge.stp no

I then edited the /etc/sysconfig/network-scripts/ifcfg-bridge-br0 file and to add IP network config and adjust a few bits to get the following:


Once we’ve done that we can bring the bridge online and check the config looks OK:

ifup br0
nmcli c show
nmcli -f bridge con show bridge-br0
ip addr

Now we have a network bridge with an IP address you can now edit any VM configuration and reassign the virtual NICs to the new bridge and adjust the VM network config to the new subnet and assign static IPs to each VM, or configure dhcpd to assign IPs on the br0 interface. Once that’s done you should be able to ping the gateway ( and have local network connectivity.

Once you’ve moved everything over you can delete the original libvirtd network config.

Outbound NATed networking
Using the traditional iptables.service (firewalld investigation is on my todo list) you can add a basic outbound NAT configuration which restores the last of the missing functionality with the following basic rule set which will NAT by masquerading the br0 network out through the public IP on eth0:

iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -p icmp -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m state --state NEW -p tcp -m tcp --dport 22 -j ACCEPT
iptables -A INPUT -j REJECT --reject-with icmp-host-prohibited
iptables -A FORWARD -i eth0 -o br0 -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i br0 -o eth0 -j ACCEPT
iptables -A FORWARD -j REJECT --reject-with icmp-host-prohibited
iptables-save > /etc/sysconfig/iptables
systemctl enable iptables.service
systemctl start iptables.service

With the network now under complete control of NetworkManager and a IP firewall/NAT configuration under control from a single point it now makes it easier to add things like IPSEC connections and IPv6 configuration both of which are next on the list.

using ssh keys with screen

It always annoyed me I couldn’t use my ssh key in a screen session. Every now and again I would try and work it out with google and some trial and error. Eventually with the help of a couple of good bits off the net I worked out what I thought to be the easiest way to achieve it consistently.

Firstly the ssh config bits:

Add the following to your ~/.ssh/config file, creating it if you don’t already have one:

host *
  ControlMaster auto
  ControlPath ~/.ssh/master-%r@%h:p

And create the ~/.ssh/rc file:

if test "$SSH_AUTH_SOCK" ; then
    ln -sfv $SSH_AUTH_SOCK ~/.ssh/ssh_auth_sock

And make sure they have the correct permissions for ssh:

chmod 600 ~/.ssh/config ~/.ssh/rc

Finally add the following to your ~/.screenrc file:

setenv SSH_AUTH_SOCK $HOME/.ssh/ssh_auth_sock

I’m not sure it’s the best and most effective way but it’s nice and simple and to date it’s been working well for me, I’ve not had issues with it. Any suggestions for improvement feel free to comment.

Disable SSLv3 in Dovecot

Disabling SSLv3 in Dovecot is nice and straight forward.

In the /etc/dovecot/conf.d/10-ssl.conf file edit the ssl_cipher_list line to look as below (or adjust to suit your specific requirements):

ssl_cipher_list = ALL:!ADH:!LOW:!SSLv2:!SSLv3:!EXP:!aNULL:+HIGH:+MEDIUM

To test the option to ensure it’ll work you can run the following command before you restart dovecot and the output should look something like below:

$ openssl ciphers -v 'ALL:!ADH:!LOW:!SSLv2:!SSLv3:!EXP:!aNULL:+HIGH:+MEDIUM'
ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AES(256)  Mac=SHA384
ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AES(256)  Mac=SHA384
DHE-DSS-AES256-GCM-SHA384 TLSv1.2 Kx=DH       Au=DSS  Enc=AESGCM(256) Mac=AEAD
DHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=DH       Au=RSA  Enc=AESGCM(256) Mac=AEAD
DHE-RSA-AES256-SHA256   TLSv1.2 Kx=DH       Au=RSA  Enc=AES(256)  Mac=SHA256
DHE-DSS-AES256-SHA256   TLSv1.2 Kx=DH       Au=DSS  Enc=AES(256)  Mac=SHA256
ECDH-RSA-AES256-SHA384  TLSv1.2 Kx=ECDH/RSA Au=ECDH Enc=AES(256)  Mac=SHA384
AES256-GCM-SHA384       TLSv1.2 Kx=RSA      Au=RSA  Enc=AESGCM(256) Mac=AEAD
AES256-SHA256           TLSv1.2 Kx=RSA      Au=RSA  Enc=AES(256)  Mac=SHA256
ECDHE-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AES(128)  Mac=SHA256
ECDHE-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AES(128)  Mac=SHA256
DHE-DSS-AES128-GCM-SHA256 TLSv1.2 Kx=DH       Au=DSS  Enc=AESGCM(128) Mac=AEAD
DHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=DH       Au=RSA  Enc=AESGCM(128) Mac=AEAD
DHE-RSA-AES128-SHA256   TLSv1.2 Kx=DH       Au=RSA  Enc=AES(128)  Mac=SHA256
DHE-DSS-AES128-SHA256   TLSv1.2 Kx=DH       Au=DSS  Enc=AES(128)  Mac=SHA256
ECDH-RSA-AES128-SHA256  TLSv1.2 Kx=ECDH/RSA Au=ECDH Enc=AES(128)  Mac=SHA256
AES128-GCM-SHA256       TLSv1.2 Kx=RSA      Au=RSA  Enc=AESGCM(128) Mac=AEAD
AES128-SHA256           TLSv1.2 Kx=RSA      Au=RSA  Enc=AES(128)  Mac=SHA256

Finally to test it from client side you can run the following command to ensure it’s not enabled. If it’s configured as expected the negotiation should fail and it’ll return you straight to the command prompt:

openssl s_client -connect -ssl3

Configure Firefox for Kerberos SSO on Fedora or RHEL

Single Sign On (SSO) is one of those nirvana things that rarely happens and a lot of people don’t understand (a central single username/password is not SSO people if you have to keep entering the password!!) but it’s very useful when it does work. With Firefox on Fedora or RHEL it works but it does take a little bit of config to do so efficiently.

  1. In the Firefox address bar type about:config to display the list of current configuration options.
  2. Filter the options with ‘negotiate’ to reduce the list of options.
  3. Double-click the network.negotiate-auth.trusted-uris entry and add the kerberos auth domain, eg: “” and click OK.
  4. Repeat the process for the network.negotiate-auth.delegation-uris entry, using the same domain.

Now you need to ensure you have a kerberos ticket. If you’ve configured an “Enterprise Login” using the GNOME Online Accounts check you have a ticket with the ‘klist’ command from a terminal window. If you don’t have a valid ticket run ‘kinit’ and from there you should be able to visit SSO enable sites and be auto logged in. Magic!

Simple WOL with RHEL and Fedora

I have a number of systems I use at home, they run a combination of RHEL and Fedora and are a variety of architectures (well x86 and ARM). Travelling a lot for $dayjob I don’t always want them on needlessly chewing power but on the flip side if I’m away for two weeks and I’d like to remotely use one and it’s off it’s a little tough to power it up if you’re 12 hours travel away!

So the obvious solution to this problem to get the best of both worlds is to use Wake On LAN (WOL) for supported hardware which means I can leave devices off or suspended and then just bring them up to full power when I actually want to use them from where ever I happen to be at the time, whether it be on the couch across the room or the other side of the world.

There’s a few places where you need to configure the device you wish to wake up. If you want to wake from power off you need to configure the BIOS/Firmware to have WOL enabled, this differs from device to device so this bit is an exercise for the reader. The quickest way to determine if your hardware supports WOL and its enabled in the BIOS/Firmware is to check to see if when the device is turned off and cabled up to a switch is if there’s a link light on the NIC is still lit.

Once you’ve got the HW and BIOS/Firmware sorted the next bit is pretty straight forward. First enable WOL on boot for the NIC in /etc/sysconfig/network-scripts/ifcfg- by adding the following line to the end of the file:


Then run

# ethtool -s  wol g

to enable it now. Finally record the ether address from the output from the “ip link” command so you know what MAC address you need to use to wake it up.

On your gateway make sure you have the appropriate tool to initiate the remote wakeup. On Fedora and RHEL this is ether-wake and it’s in the net-tools package. It’s then as simple as running

# ether-wake -i local-interface mac-address

puppetmaster on apache with passenger in 5 mins

Config management, DevOPs and all those sorts of time saving things are all well and good for readily repeatable tasks that happen on the same systems on a regular basis. But as a consultant my tasks are rarely the same and change from day to day depending on the customer, their mood or the phase of the moon. So while I’ve used puppet a lot I’ve only deployed a puppet platform once or twice and every time I do I end up digging around trying to work out the latest best practice.

So primarily to remind myself so I have a quick guide for the next time here’s my quick puppetmaster in five minutes using just rpm packages (so they’re easily upgraded and checked for security issues etc) on RHEL-6 or Fedora.

First ensure you have proper forward and reverse DNS records for the puppet master server and all puppet clients.

  1. Set SELinux to Permissive. This is a FIXME as there appears to be an issue running puppetmaster on rails on apache. A quick check it seems to be related to comms between httpd and rails. RHBZ 730837 has more info but I need to investigate but it should be straight forward .
    sed 's/SELINUX=enforcing/SELINUX=permissive/' /etc/sysconfig/selinux
    setenforce permissve
  2. On Fedora you already have all the repos required out of the box. On RHEL I’m using the upstream PuppetLabs repos so I used the following:
    rhn-channel -a -c rhel-x86_64-server-optional-6
    rpm -ivh
    rpm -ivh
    yum-config-manager --enable epel puppetlabs-products puppetlabs-deps
  3. Install the needed packages
    yum install puppet-server httpd mod_ssl rubygem-rack mod_passenger
  4. Start the puppetmaster and set it to run on startup. While we won’t be using WEBrick we start it initially so it will initialise the default puppet config and setup things like certificates.
    service puppetmaster start
    puppet resource service puppetmaster ensure=running enable=true
  5. Configure the puppetmaster Rails app
    mkdir -p /usr/share/puppet/rack/puppetmasterd
    mkdir /usr/share/puppet/rack/puppetmasterd/public /usr/share/puppet/rack/puppetmasterd/tmp
    cp /usr/share/puppet/ext/rack/ /usr/share/puppet/rack/puppetmasterd/
    chown -R puppet.puppet /usr/share/puppet/rack
    restorecon -Rv /usr/share/puppet
    mkdir /var/run/passenger
    restorecon -Rv /var/run/passenger
  6. Configure apache by adding the config below and updating FQDN.pem to your local certificate name.
    vim /etc/httpd/conf.d/puppetmaster.conf

    # RHEL/CentOS:
    # And the passenger performance tuning settings:
    PassengerHighPerformance On
    PassengerUseGlobalQueue On
    # Set this to about 1.5 times the number of CPU cores in your master:
    PassengerMaxPoolSize 6
    # Recycle master processes after they service 1000 requests
    PassengerMaxRequests 1000
    # Stop processes if they sit idle for 10 minutes
    PassengerPoolIdleTime 600
    PassengerTempDir /var/run/passenger
    Listen 8140
    <VirtualHost *:8140>
        SSLEngine On
        # Only allow high security cryptography. Alter if needed for compatibility.
        SSLProtocol             All -SSLv2
        SSLCipherSuite          HIGH:!ADH:RC4+RSA:-MEDIUM:-LOW:-EXP
        SSLCertificateFile      /var/lib/puppet/ssl/certs/FQDN.pem
        SSLCertificateKeyFile   /var/lib/puppet/ssl/private_keys/FQDN.pem
        SSLCertificateChainFile /var/lib/puppet/ssl/ca/ca_crt.pem
        SSLCACertificateFile    /var/lib/puppet/ssl/ca/ca_crt.pem
        SSLCARevocationFile     /var/lib/puppet/ssl/ca/ca_crl.pem
        SSLVerifyClient         optional
        SSLVerifyDepth          1
        SSLOptions              +StdEnvVars +ExportCertData
        # These request headers are used to pass the client certificate
        # authentication information on to the puppet master process
        RequestHeader set X-SSL-Subject %{SSL_CLIENT_S_DN}e
        RequestHeader set X-Client-DN %{SSL_CLIENT_S_DN}e
        RequestHeader set X-Client-Verify %{SSL_CLIENT_VERIFY}e
        RackAutoDetect On
        DocumentRoot /usr/share/puppet/rack/puppetmasterd/public/
        <Directory /usr/share/puppet/rack/puppetmasterd/>
            Options None
            AllowOverride None
            Order Allow,Deny
            Allow from All

    restorecon -Rv /etc/httpd/conf.d

  7. Disable the puppetmaster so it runs via Rails on Apache
    chkconfig puppetmaster off; service puppetmaster stop
    chkconfig httpd on; service httpd restart
  8. Setup a basic puppet config files:
    • autosign.conf

      vim /etc/puppet/autosign.conf

    • site.pp
      vim /etc/puppet/manifests/site.pp

      # /etc/puppet/manifests/site.pp
      import "nodes"
      # The filebucket option allows for file backups to the server
      filebucket { main: server => '' }
      # Set global defaults - including backing up all files to the main filebucket and adds a global path
      File { backup => main }
      Exec { path => "/usr/bin:/usr/sbin:/bin:/sbin" }
    • modules.pp
      vim /etc/puppet/manifests/modules.pp

      # /etc/puppet/manifests/modules.pp
      import "dns-client"
      import "ntp-client"
    • nodes.pp
      vim /etc/puppet/manifests/nodes.pp

      # /etc/puppet/manifests/nodes.pp
      node 'common' {
              include dns-client
              include ntp-client
      node default inherits common {
      node '' inherits common {

    With the above you obviously need to have the dns-client and ntp-client modules in place in /etc/puppet/modules/ or update the config files to reflect the modules you have installed!

  9. Relabel all the various puppet directories to ensure we’re good with selinux:
    restorecon -Rv /etc/puppet
  10. Reboot to ensure it all works when it comes back online 😉

P.S. I’ll update this post once I’ve had time to work out the SELinux issues, pointers welcome in the comments below 🙂