Proxmox 4.x, SSL & nginx (how to)

April 17, 2017    proxmox ssl letsencrypt nginx certificates tutorial howto server

What is Proxmox?

Proxmox is an open source server virtualization solution and an alternative to such solutions as VMware’s vSphere, Microsoft’s Hyper-V server or XenServer. It supports container style virtualization (LXC) and also KVM style virtualization. It is based on Debian so if you happen to be familiar with managing a Debian server already, you’re practically good to go. It has a robust web based interface that lets you do most tasks like provisioning a new VM, changing networking settings, doing backups etc. Proxmox also supports using multiple servers as clusters though I have not ever done this myself.

Overall, I’ve been very happy with Proxmox as a virtualization solution in the year or so that I’ve been using it. If you’re interested in getting deeper into the guts of Proxmox, check out their website which has a plethora of information.

What’s this tutorial about?

The Proxmox web based management portal talked about above works right out of the box after installing Proxmox serving said portal on port 8006. It will be accessible to you at https://YOUR.SERVER.IP:8006/. You’ll surely notice that your browser will complain about the SSL certificate. This tutorial is about how I solved the SSL certificate issue without touching Proxmox’s own settings at all. For this I will use nginx which is a super scalable, easy to setup and lightweight web server. I’ve documented everything you need to do in regards to nginx configuration here, but you can read more about it here if you wish here. I found this easier to set up and less cumbersome than messing with Proxmox’s own settings to use a certificate. We will use the freely available certficates from Let’s Encrypt. Let’s get started.

nginx installation

Let’s first set up nginx on our Debian Jessie based Proxmox install. We will use nginx to redirect a domain/subdomain to the Promox web interface and also have nginx use the proper certificate for that domain/subdomain.

To install the latest Nginx mainline version let’s add the nginx mainline Debian repo & then install nginx on our system with the following commands:

sudo echo "deb http://nginx.org/packages/mainline/debian/ jessie nginx" >> /etc/apt/sources.list.d/nginx-mainline.list
sudo echo "deb-src http://nginx.org/packages/mainline/debian/ jessie nginx" >> /etc/apt/sources.list.d/nginx-mainline.list
sudo wget -O- http://nginx.org/keys/nginx_signing.key | apt-key add -apt-get update
sudo apt-get install nginx

At this point, browsing to either http://YOUR.SERVER.IP/ or http://SUB.DOMAIN.POINTED.AT.SERVER.IP/ should successfully show the default nginx index page.

Basic nginx configuration

For ease of use with Let’s Encrypt, we are going to create a fake webroot for the Proxmox web interface (webroot in the sense that we will pretend the Proxmox web interface lives in this directory even though it won’t actually). You will see how this makes it easy to get a certificate and renew it easily soon enough. Let’s call it pveproxy-certbot-webroot and create it with the following (make sure to give proper write permissions to this directory for the account that will acquire the Let’s Encrypt certificate):

mkdir /var/www/pveproxy-certbot-webroot

It is assumed that you’ve root access at this point (for editing the nginx configuration files). Of course, nginx doesn’t yet know about the existence of said webroot or what to do with it. Let’s first change /etc/nginx/conf.d/default.conf to the following since we do not require the default to serve anything at all:

server {
    deny all;
}

Now we can inform nginx about our fake webroot. Create a new configuration for our Proxmox proxy at /etc/nginx/conf.d/pve-proxy.conf and configure it as such:

server {
    listen 80;
    listen [::]:80;
    server_name sub.domain.com;

    root /var/www/pveproxy-certbot-webroot;

    location @proxy {
        index index.html index.htm;
    }

    location / {
        try_files $uri @proxy;
    }
}

The try_files directive is telling nginx to look for files at the webroot and pass it on to @proxy if not found. This will be enough for us to acquire our certficate. The @proxy part will let us redirect this domain or subdomain to the Proxmox web interface living on port 8006 later on. You can now restart nginx to load our new configuration with:

sudo service nginx reload
sudo service nginx restart

Acquiring Let’s Encrypt certificate with certbot

certbot is an utility that works with Let’s Encrypt to acquire and renew certificates. First we must acquire certbot itself. You can run certbot as any user you prefer but it must have write access to the webroot we created in the previous section. Let’s acquire the newest version & run it once with:

cd ~
wget https://dl.eff.org/certbot-auto
chmod a+x certbot-auto
./certbot-auto

Now that cerbot-auto has acquired all dependencies, we can acquire our certificate with:

./certbot-auto certonly --webroot -w /var/www/pveproxy-certbot-webroot -d sub.domain.com

Enter your email address & if you’ve set up everything correctly, you should see a message telling you that a certificate was acquired successfully & where it was placed (note this location though I’ve provided the usual location below).

Configuring nginx to use our newly acquired certificate

The final step is to change our nginx config to redirect http to https & use our brand new certficate. Change /etc/nginx/conf.d/pve-proxy.conf (again with root access) to:

upstream pve {
    server 127.0.0.1:8006 fail_timeout=0;
}

server {
    listen 80;
    listen [::]:80;
    server_name sub.domain.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name sub.domain.com;

    root /var/www/pveproxy-certbot-webroot;

    ssl_certificate /etc/letsencrypt/live/sub.domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/sub.domain.com/privkey.pem;

    proxy_redirect off;

    location @proxy {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_pass https://pve;
        proxy_buffering off;
        client_max_body_size 0;
        proxy_connect_timeout 3600s;
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
        send_timeout 3600s;
    }

    location / {
        try_files $uri @proxy;
    }
}

I’ll explain briefly what we’re doing here. Firstly, we redirect http requests to your domain/subdomain to https using a 301 redirect. The upstream pve block is just pointing to port 8006, i.e. the Proxmox web interface. So, as I said before, the try_files directive is telling all requests that come to our domain/subdomain (since there are no files in our webroot) to be redirected to @proxy. @proxy points to our Promox web inteface. The ssl_certificate & ssl_certficate_key fields should point to the locations we noted down earlier when we acquired our certificate with cerbot. Let’s load these new settings with:

sudo service nginx reload
sudo service nginx restart

At this point, browsing to http://sub.domain.com/ should redirect to https & show that you’re using a valid certificate! Congratulations!

Certificate renewal

I recommend setting up a cron job to auto renew your certificates twice a day (as recommended by certbot documentation). You can edit your cronjobs with:

crontab -e

I chose to add this line to mine:

39 4,16 * * * "/home/USERNAME"/certbot-auto renew --quiet --no-self-upgrade

This will try to renew twice everyday once at 4:39 AM & again at 4:39 PM. The certbot documentation advises us to use strange between the hour times as to not overload Let’s Encrypt’s servers.

Attribution

I compiled this tutorial from the following tutorials which were VERY helpful. Please take a look at them if you get confused as they are very thorough!



comments powered by Disqus