Redirect a subdomain to a VM with HAproxy

19th Jul 2015 Karibu

HAPorxy logoI use a dedicated server to host multiple websites. Because I only have one public IP and each website runs in a different VM, I needed a solution to redirect web traffic to a VM depending on the domain name.

HAProxy is a lightweight load-balancer that can be configured to act as a reverse proxy in front of any website. It can deal with HTTP / HTTPs connections and redirect traffic to the VM that corresponds to the domain the end user wants to access. It can handle SSL connections which means you don’t have to bother with certificates on your web servers. I have been using HAProxy for several months in front of my Seafile, Owncloud, Piwigo and Proxmox websites. It runs very well even in a small VM (1 vCPU, 128 MB of RAM and 4 GB of storage) and is simple to configure.

In this tutorial, I will explain how to configure a HAProxy server on Debian with a SSL wildcard certificate that will redirect HTTP / HTTPs traffic to VMs.

Installation

 

**1) Install HAProxy

**

On Debian Wheezy, you need to enable backports repositoy

echo deb http://httpredir.debian.org/debian wheezy-backports main | \
sudo tee /etc/apt/sources.list.d/backports

Then install HAproxy

apt-get install haproxy
**2) Generate self-signed certificates

**

A wildcard certificate is a certificate valid for every subdomain of a domain,. E.g. a certificate for *.freedif.org will be valid for blog.freedif.org, owndcloud.freedif.org, etc. Use the commands below to generate such certificate. On the third command, you will be asked for “Common Name (e.g. server FQDN or YOUR name)” and enter *.your.domain to create a wildcard certificate for your.domain.

cd /etc/ssl/private

openssl req -x509 -nodes -sha256 -days 365 -newkey rsa:2048 -keyout your.domain.key -out your.domain.pem

cat your.domain.pem your.domain.key | tee /etc/ssl/certs/your.domain.pem
rm your.domain.pem
**3) Create HAProxy configuration file

**

This is when we tell HAProxy to redirect traffic to a particular VM depending on the domain. I based this example with two websites:

  • a WordPress server: - Web server listens on port 80 (http)
  • IP address 10.10.10.10
  • Domain name: blog.freedif.org
  • an Owncloud server: - Web server listens on port 443 (https)
  • IP address 10.10.10.11
  • Domain name: owncloud.freedif.org

We will tell HAProxy to handle the SSL connections (which is why we created a wildcard certificate in step 2) so their is no need to encrypt the traffic internally (from HAProxy to the VMs).  However, sometimes softwares are configured to listen on HTTPs only and you need to tell HAProxy to use SSL to communicate with the VM (which is why in my example Owncloud server listens on port 443).

 

Use the configuration file below:

<pre class="lang:default highlight:0 decode:true  ">global
        log /dev/log    local0
        log /dev/log    local1 notice
        chroot /var/lib/haproxy
        stats socket /run/haproxy/admin.sock mode 660 level admin
        stats timeout 30s
        user haproxy
        group haproxy
        daemon

        # Default SSL material locations
        ca-base /etc/ssl/certs
        crt-base /etc/ssl/private

        # Default ciphers to use on SSL-enabled listening sockets.
        # For more information, see ciphers(1SSL).
        ssl-default-bind-ciphers EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH:+CAMELLIA256:+AES256:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!ECDSA:CAMELLIA256-SHA:AES256-SHA:CAMELLIA128-SHA:AES128-SHA
ssl-default-bind-options no-sslv3 no-tls-tickets #disable SSLv3
        tune.ssl.default-dh-param 2048 #tune DH to 2048
        
defaults
        log     global
        mode    http
        option  httplog
        option  dontlognull
        timeout connect 5000
        timeout client  50000
        timeout server  50000
        errorfile 400 /etc/haproxy/errors/400.http
        errorfile 403 /etc/haproxy/errors/403.http
        errorfile 408 /etc/haproxy/errors/408.http
        errorfile 500 /etc/haproxy/errors/500.http
        errorfile 502 /etc/haproxy/errors/502.http
        errorfile 503 /etc/haproxy/errors/503.http
        errorfile 504 /etc/haproxy/errors/504.http

frontend public

        # Listen on port 80
        bind *:80

        # Listen on port 443
        bind *:443 ssl crt /etc/ssl/private/your.domain.pem
        
        mode http

        # Define ACLs for each domain
        acl blog hdr(host) -i blog.freedif.org
        acl owncloud hdr(host) -i owncloud.freedif.org

        # Figure out which backend (= VM) to use
        use_backend blog_server if blog
        use_backend owncloud_server if owncloud

backend blog_server

        http-request set-header X-Forwarded-Port %[dst_port]
        http-request add-header X-Forwarded-Proto https if { ssl_fc }
        rspadd Strict-Transport-Security:\ max-age=15768000;\ includeSubDomains #enable HSTS header for this backend
        rspadd X-XSS-Protection:\ 1;\ mode=block #enable XSS protection for this backend

        balance leastconn
        option httpclose
        option forwardfor
        cookie JSESSIONID prefix
        
        # Redirect to WordPress VM on port 80
        server srv01 10.10.10.10:80 cookie A check
        
backend owncloud_server

        http-request set-header X-Forwarded-Port %[dst_port]
        http-request add-header X-Forwarded-Proto https if { ssl_fc }
        rspadd Strict-Transport-Security:\ max-age=15768000;\ includeSubDomains #enable HSTS header for this backend
        rspadd X-XSS-Protection:\ 1;\ mode=block #enable XSS protection for this backend
        
        balance leastconn
        option httpclose
        option forwardfor
        cookie JSESSIONID prefix
        
        # Redirect to Owncloud VM on port 443 with SSL
        server srv01 10.10.10.11:443 weight 1 maxconn 100 check ssl verify none

and edit the relevant sections:

  • frontend public: defines what to do for http and https connections. You need to customize ACLs and backends with your own servers
  • backend abc: put here the properties of your VM(s)

Based on this example, you can redirect any domain to a VM with little customization. Copy the content above, edit it for your needs and save it to /etc/haproxy.cfg. Finally, reload haproxy configuration (service haproxy reload) to apply configuration, create a NAT to HAProxy server on port 80 and 443 (+ firewall rules) and you are all set !

0 Comments:

Add a comment