Virtual Proxmox part 3: Port Forwarding to a Virtual Proxmox KVM
Introduction
In Part 1 of this series, you installed a
Virtual Proxmox server in a libvirt virtual machine (with the GUI tool
virt-manager
), and you chose the network selection of type Virtual Network 'default': NAT
. This type of network only allows traffic from another
(virtual) machine on the same network ('default'
), including from your host
workstation (libvirt has created a virtual network device, on the host
workstation, with an IP address in the same subnet as the VM running Proxmox).
No external traffic is allowed to this network (ie. from your LAN), because, by
default, there are no external routes created for it.
The NAT network type provides pretty good default security for a development environment, where you only want access from your workstation. However, you may soon wish to deliberately expose some services to other machines on your LAN, or even to the Internet.
When exposing the Proxmox dashboard, it is important to install a valid TLS certificate, and stop using the default self-signed certificate created on first install. (Remember how you had to tell your browser that the certificate was OK?) Proxmox has the ability to generate a valid certificate, using Let’s Encrypt with ACME DNS-01 challenge type. This allows you to create a valid browser-trusted TLS certificate, even if your host system itself is behind another NAT firewall (which is the typical home Interet configuration, with no external ports opened, which excludes the use of ACME HTTP or TLS challenge types).
If you follow the suggestions in this post for exposing services, you are changing the role of your workstation: it is now a a hybrid workstation and server (for your LAN and/or the Internet).
Setup firewall and routes on host
Create the libvirt hooks directory on the native libvirt host:
# This directory didn't exist for me, so I had to create it:
sudo mkdir -p /etc/libvirt/hooks
Create a new libvirt hooks file, /etc/libvirt/hooks/qemu
:
#!/bin/bash
# /etc/libvirt/hooks/qemu
# Forward ports for Proxmox
# See https://wiki.libvirt.org/page/Networking
# Find your actual Proxmox VM IP address and put it here:
PROXMOX_IP=192.168.122.X
# Associative array of TCP host ports to TCP proxmox ports:
PROXMOX_TCP_PORTS=([8006]=8006 [2222]=22)
# Port forwarding for the Proxmox VM
if [ "${1}" = "Proxmox" ]; then
for key in "${!PROXMOX_TCP_PORTS[@]}";
do
host_port=${key}
proxmox_port=${PROXMOX_TCP_PORTS[key]}
if [ "${2}" = "stopped" ] || [ "${2}" = "reconnect" ]; then
/sbin/iptables -D FORWARD -o virbr0 -p tcp -d $PROXMOX_IP \
--dport $proxmox_port -j ACCEPT
/sbin/iptables -t nat -D PREROUTING -p tcp \
--dport $host_port -j DNAT --to $PROXMOX_IP:$proxmox_port
fi
if [ "${2}" = "start" ] || [ "${2}" = "reconnect" ]; then
/sbin/iptables -I FORWARD -o virbr0 -p tcp -d $PROXMOX_IP \
--dport $proxmox_port -j ACCEPT
/sbin/iptables -t nat -I PREROUTING -p tcp \
--dport $host_port -j DNAT --to $PROXMOX_IP:$proxmox_port
fi
done
fi
Edit the new hooks file, change the following:
-
PROXMOX_IP
the value of this variable should be the IP address of your Proxmox Server VM. (The same as theHostname
forproxmox
in your~/.ssh/config
) -
PROXMOX_TCP_PORTS
is a translation map of TCP ports between your host and Proxmox. The example does the following:- Pass TCP host port
8006
directly to Proxmox TCP port8006
. This is for the Proxmox dashboard. - Translate TCP host port
2222
to Proxmox TCP port22
. This is for SSH access to the Proxmox server.
- Pass TCP host port
-
Note that this hook configures the host firewall, and only forwards packets, it does not do any filtering. Filtering is the role of the Proxmox firewall, which will be configured next.
Now restart the libvirtd
service and the hook will automatically run. (You do
not need to restart the Proxmox VM).
Configure the Proxmox firewall
You already turned on the Proxmox firewall in part 1 of this series, now you need to add additional rules to allow access from outside your workstation:
- Go to the Proxmox dashboard, click on the
Datacenter
in theServer View
list. - Click on
Firewall
in theDatacenter
view. - Click on
Add
to add a new firewall rule:- Click the
Enable
checkbox. - Click the
Macro
dropdown, and selectSSH
. - Optional: Enter a
Source
to filter by IP/Subnet range. (Note that Proxmox already allows the private virbr0 network by default [anti-lockout rule for your workstation], so you only need to filter the outside network.) - Click the
Add
button to add the new rule.
- Click the
- Click on
Add
to add another new firewall rule:- Click the
Enable
checkbox. - Click the
Protocol
dropdown, and selecttcp
. - Enter the
Dest. port
as8006
. - Optional: Enter a
Source
to filter by IP/Subnet range. (Note that Proxmox already allows the private virbr0 network by default [anti-lockout rule for your workstation], so you only need to filter the outside network.) - Click the
Add
button to add the new rule.
- Click the
Test the firewall
Use a second computer on the same LAN as your workstation (ie. your home WiFi):
# Test access to the proxmox dashboard port forwarded from the workstation.
# Enter the LAN IP address of the workstation:
curl -k https://X.X.X.X:8006
# Test SSH access to port 2222 which forwards to the Proxmox port 22:
# Enter the LAN IP address of the workstation:
ssh -p 2222 root@X.X.X.X
Assuming it works, you should get an HTML response back from curl
and the
ssh
connection should connect and not hang (it is OK if it says Permission denied (publickey)
, because this shows that the connection itself is working.)
Generate a valid TLS certificate
In order to generate a certificate from a private LAN, you need to use the ACME DNS-01 challenge type, which requires you to control the DNS server for the Internet domain the certificate is to be issued for. You can use a DNS host like DigitalOcean, which offers an API that Proxmox can use to update DNS automatically to satisfy the requirements of the ACME DNS-01 challenge. This example will use DigitalOcean DNS.
Setup DigitalOcean DNS
- Go to cloud.digitalocean.com and go to your
project’s
Networking
page in the main sidebar menu. - Click on the
Domains
tab. - Add your domain if you haven’t already.
- Go to the
API
page in the main sidebar menu. - Click on the
Tokens/Keys
tab. - Click
Generate New Token
. - Enter
Proxmox ACME on [hostname]
for the name. - Select the
Write
scope. - Click
Generate Token
. - Copy the new
Personal access token
, it is only shown once. This is to be kept safe, as it can control your entire DigitalOcean (sub-)account.
Setup Proxmox ACME
Configure the Proxmox Datacenter:
- Go to the Proxmox dashboard, look under the
Server View
, click on theDatacenter
. - Click on the
ACME
tab. - Under
Accounts
click theAdd
button. - Use the account name:
default
- Enter your real
E-Mail
address. - Select the
ACME Directory
: chooseLet's Encrypt V2
for the production certificate service. - Check the
Accept TOS
checkbox. - Click
Register
. - Under
Challenge Plugins
, click theAdd
button. - Enter the
Plugin ID
:digitalocean
(or the name for your provider). - Select the
DNS API
:DigitalOcean DNS
. - Enter the
DO_API_KEY
: (This is to be pasted from thePersonal access token
you copied from the DigitalOcean dashboard.)
Configure the Proxmox server node:
- Look under the
Server View
, click on the Proxmox server node (underneathDatacenter
). - Under
System
, click onCertificates
. - Under
ACME
, click theAdd
button. - Change the
Challenge Type
toDNS
. - Choose the
Plugin
:digitalocean
- Enter the sub domain name you want to use for the Proxmox dashboard
certificate (eg.
proxmox.example.com
if you ownexample.com
) - Click the
Order Certificates Now
button.
Configure DNS to use the hostname of the certificate
In order to use the new certificate, you must access the Proxmox dashboard from the domain name that you generated the certificate for. To do that, you need to edit your DNS.
You can edit your local DNS by adding the domain to /etc/hosts
:
# snippet of /etc/hosts on the workstation:
# Enter the IP address of Proxmox VM :
X.X.X.X proxmox proxmox.example.com
# snippet of /etc/hosts on another LAN machine:
# Enter the LAN IP address of the workstation :
X.X.X.X proxmox proxmox.example.com
Or you may add this to the DNS server on DigitalOcean:
- Go to cloud.digitalocean.com and go to your
project’s
Networking
page in the main sidebar menu. - Click on
Domains
- Click on your domain name from the list.
- Create a new type
A
record:- Enter the hostname:
proxmox.example.com
ifexample.com
is the main domain. - Enter the local LAN IP address of the workstation. (this will not be routable outside your LAN, but DNS is cool with that.)
- Click
Create Record
- Enter the hostname:
Now you should be able to go to https://proxmox.example.com:8006 from anywhere on your LAN (unless you added an IP filter in the firewall rule), and you can access the Proxmox dashboard. Your web browser should now automatically trust the certificate, issued by Let’s Encrypt. Bookmark the dashboard, so that you always access it using this full domain name.
Exposing services to the Internet
After you have exposed the port to the LAN, you can configure your Internet router to port forward certain port ranges to the workstation IP address, thus exposing them to the Internet.
If you don’t want to open your Internet router ports, you can use a VPN or do something a bit fancier like sish using only SSH to tunnel traffic through another public bastion host.
You can discuss this blog on Matrix (Element): #blog-rymcg-tech:enigmacurry.com
This blog is copyright EnigmaCurry and dual-licensed CC-BY-SA and MIT. The source is on github: enigmacurry/blog.rymcg.tech and PRs are welcome. ❤️