Nginx reverse proxy and Webmin

Before going into “How” you may wonder “Why” I need a reverse proxy in front of Webmin.

First, and most important, is laziness. Yes, you read it right. I have in my home lab a one page html listing all http(s) resources I have in my IT lab. Instead of typing numerous URLs I just type one and click the needed link. You may argue that I can use browser bookmarks, true, but I use the one html landing page to access various resources.

Second is a bit more realistic (at least professional realistic).

I’m using Sophos XG (home version) to access my home lab and other in-house smart devices when on the road. This product has a very nice User Portal feature where you can add various “bookmarks” to resources accessible via various protocols (rdp, vnc, ssh, http(s)…)

Recently Sophos decided to retire the http(s) bookmark feature “in order to improve security and reduce the potential for cross-site scripting (XSS) exploits”

In my opinion you work on features to improve security and fix issues, you just don’t retire them. If this would be the way, then let’s shutdown electrical grid, stop cars or terminate Internet and we’re all be more secure. But that’s just my opinion…

Anyway, this action leaves a gap in my happiness accessing my home IT resources. Sophos recommend using WAF, which is a good advice from security perspective, but I don’t plan to have 50 redirections (as in DNAT) from my public facing IP address / router to LAN just to access the various URLs I have in my home lab.

I plan to use one port redirection from Internet to a LAN hosted webserver (protected with WAF) and, you guessed, hosting page lisingt my home lab resources (in form of Webpage Links)

For this to properly work I need one just one domain / subdomain with various URI resources (e.g. https://mydomain.com/resouce1 , https://mydomain.com/resource2, etc…), hence the use of a reverse proxy.

Nginx reverse proxy is not something new and it works great in a lot of situations, but it gave me some headache with Webmin. After quite some research, I said let me put together a quick and dirty how-to in case somebody else needed it.

My scenario involves one server with Nginx as reverse proxy (https://mypage.local.lan) and one Webmin server (https://webmin01.local.lan:10000) for this example.

Http protocol is secured with SSL certificates issues by a LAN CA. In case you don’t have secure http, just make sure to replace https with http in the example below.

My Nginx SSL config is very basic at this point:

server {
server_name mypage.local.lan;
listen 443;

root /var/www/html;

ssl on;
ssl_certificate /etc/ssl/private/mypage.local.lan.crt;
ssl_certificate_key /etc/ssl/private/mypage.local.lan.key;
access_log off;
error_log off;
}

Next part is to add the reverse proxy configuration for https://webmin01.local.lan:10000 so it can be access via https://mypage.local.lan/webmin01

  location /webmin01/ {
    proxy_pass      https://webmin01.local.lan:10000/;

    #Proxy Settings
    proxy_set_header   Host             $http_host;
    proxy_set_header   X-Real-IP        $remote_addr;
    proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;

  }

Add the part above just before the closing } in the first Nginx configuration part.

Very important, don’t forget the trailing / after webmin01 in the location /webmin01/ line

This should satisfy the majority of scenarios where a resource is accessed via reverse proxy. However Webmin needs a bit more fine tuning.

Restart your Nginx service after modifying the configuration files.

On my webmin01 server, I needed to modify the following files part of webmin installation (btw, this is on Ubuntu 20.04).

/etc/webmin/miniserv.conf

Add or modify the following parameters:

cookiepath=/webmin01
trust_real_ip=1
logouttimes=

/etc/webmin/config

Add or modify the following parameters:

referers=mypage.local.lan
webprefix=/webmin01
relative_redir=0

Referers needs to list the URL from where the request comes from. This is par of the Webmin security avoid malicious redirects from untrusted locations.

Webprefix is for proper redirection of the response from webmin pages. A word of advice, once you modify this part, you may not be able to access the webmin installation directly (e.g. https://webmin01.home.lan:10000) since the it will expect a /webmin01 part in the URL which of course is not there on the webmin server.

Restart your Webmin service after modifying the configuration files

After the above configuration, I added on my one html page located on https://mypage.local.lan and link called Webmin01 (pointing to https://mypage.local.lan/webmin01).

Once I access that URL resource, I’ll be redirected to the login page of Webmin01 instance.

In case you give it a try, let me know if it works for you

Last but not least, I’ve did quite some research on this topic, but the best information was from the Github user 1985a and the folks at https://github.com/webmin/webmin/issues/420. Thanks a lot!

How to create your own Docker image

I mentioned in my previous post that I’ll explain how to create your own Docker image and customize it however you’d like. While is great to just use an image from Docker Hub, it can be that you need some customized image to fit your needs. As said before, is not hard at all to create the image and worth knowing how to do it.

I’ll use for this tutorial a fresh Ubuntu 18.04 minimal installation. You can follow the same steps (or almost) using different Linux distro, Microsoft Windows or MacOS. The reason why I chose Ubuntu is simply because is the distro that I’m most familiar and enjoy working with.

For all steps below you need to be root or run the commands via sudo. So you’ll see either # at the begining of the command if you’re root or $ sudo if you pick to run it with elevated rights.

Install Docker

# apt install -y docker.io

A word of advice here. Be sure to have docker.io typed. If you miss the .io, the system will install a docker, but that’s a different package:

docker/bionic 1.5-1build1 amd64
  System tray for KDE3/GNOME2 docklet applications

You’ll end up with something that cannot be used for what we want to achieve, since the docker command isn’t even there.

You can test if the installation completed successfully by using the following command:

# service docker status

You should see something like this in the output:

Docker service successful status

Since this is a new installation, you’ll have no images, no containers, nothing.
You can check, just to be sure.

# docker image ls

The result should be:

Docker image ls return nothing

I’ll add at the end of the post some basic (and most important) Docker commands to get you started.

Pull Ubuntu 18.04 image – Optional step

This step is optional, but I’d advise to do it, just to test that everything is fine with your Docker installation In this case we’re going to use the official Ubuntu 18.04 minimal Docker image. If you want to read more about this image you can check the explanation on Ubuntu 18.04 minimal Docker image and check their repository on Docker Hub – Ubuntu.

# docker pull ubuntu:18.04

If everything goes well you should see a message ending with “Status: Downloaded newer image for ubuntu:18.04” :

Docker successful download of Ubuntu image

Time to run our first container:

# docker run -i -t ubuntu:18.04 /bin/bash

You should be now in container shell:

Docker container

Now that we tested you can type exit to leave the container.

Create Dockerfile

The Dockerfile is nothing more than a text document which contains all the commands a user could call on the command line to create an image.
A detailed explanation is beyond the scope of this post, but if you’d like to learn more, you can check the Docker Documentation – Dockerfile

Here is a sample that’s good to start with:

# My custom Ubuntu 18.04 with 
# various network tools installed
# Build image with:  docker build mycustomlinux01 .


FROM ubuntu:18.04
MAINTAINER Calin C., https://github.com/yotis1982
RUN apt-get update --fix-missing
RUN apt-get upgrade -y
RUN apt-get install -y software-properties-common
RUN apt-get install -y build-essential
RUN apt-get install -y net-tools mtr curl host
RUN apt-get install -y iputils-arping iputils-ping iputils-tracepath
RUN apt-get install -y iproute2
RUN apt-get install -y traceroute
RUN apt-get install -y tcpdump

A short explanation:

# – This is a comment, add here whatever you think is useful. I’ve picked the name “mycustomlinux01”, but you can add whatever you like.
FROM – is always your first instruction, because it names the base image you’re building your new image from.
MAINTAINER – is the creator of the Dockerfile.
RUN – instruction to run the specified command, in this case apt-get to install various packages

There are multiple instructions for setting environment variables like ADD, COPY, ENV, EXPOSE, LABEL, USER, WORKDIR, VOLUME, STOPSIGNAL, and ONBUILD. You can read all about them in the Docker Documentation – Dockerfile

Using RUN you can add whatever package you need in your custom image. The same like you would do on a regular Ubuntu installation.
Yes, all the packages above could have been added in one RUN line, but for the sake of better visibility I would suggest to have separate lines.

Create your custom Docker image

After you save the Dockerfile is time to create your image

# docker build -t mycustomlinux01 .

You’ll see a lot of output, the same like when you’re installing new packages in any Linux distro. When you see the following lines, you’ll know that the image was successful created:

Docker successful image creation

Let’s check if the image is listed using:

# docker image ls

You should see the mycustomlinux01 image listed:

List my Docker image

Since the image is created successful I’d suggest that you run a container using this image following the same steps like in the “Pull Ubuntu 18.04 image”

Basically that’s it, you just created your custom image.

As mentioned above, here is a list of commands that I find useful to have at hand when working with Docker containers.

List images:

# docker image ls

Start a container from an image:

# docker run -i -t ubuntu:12.04 /bin/bash

Using an ID (you get the ID from List image command):

# docker run -i -t 8dbd9e392a96 /bin/bash

List all containers:

# docker ps -a

List running containers:

# docker ps -l

Attach running container:

# docker attach “container ID”

Remove a container:

# docker rm “container ID”

Last but not least. If you liked my Ubuntu 18.04 Docker image customized for network engineers who wants to learn Python and you would like to install additional packages, here is the Dockerfile:

# Ubuntu 18.04 with Python, Paramiko, Netmiko, Ansible
# various other network tools installed and SSH activated
# Build image with:  docker build -t yotis/ubuntu1804-pfne .

FROM ubuntu:18.04
MAINTAINER Calin C., https://github.com/yotis1982
RUN apt-get update --fix-missing
RUN apt-get upgrade -y
RUN apt-get install -y software-properties-common
RUN apt-get install -y build-essential
RUN apt-get install -y openssl libssl-dev libffi-dev
RUN apt-get install -y net-tools mtr curl host socat
RUN apt-get install -y iputils-arping iputils-ping iputils-tracepath
RUN apt-get install -y iproute2
RUN apt-get install -y iptraf-ng traceroute
RUN apt-get install -y tcpdump nmap
RUN apt-get install -y iperf iperf3
RUN apt-get install -y python python-pip python-dev
RUN apt-get install -y python3 python3-pip python3-dev
RUN apt-get install -y openssh-client telnet
RUN apt-get install -y nano
RUN apt-get install -y netcat
RUN apt-get install -y socat
RUN pip install --upgrade pip
RUN pip install cryptography
RUN pip install paramiko
RUN pip install netmiko
RUN pip install pyntc
RUN pip install napalm
RUN apt-add-repository ppa:ansible/ansible
RUN apt-get update
RUN apt-get install -y ansible
RUN apt-get clean
VOLUME [ "/root" ]
WORKDIR [ "/root" ]
CMD [ "sh", "-c", "cd; exec bash -i" ]

Obviously there is more about Docker than is covered on this post. It wasn’t in my scope to make a detailed analyze of Docker, rather a cheatsheet on how to create your custom image. If you want to learn more there are plenty resources out there and a good starting point is the Docker website.

I hope you find this how-to useful. As always, if you need to add something or you have questions about, please use the Comments form to get in contact with me.

Ubuntu image for EVE-NG – Python for network engineers

Lately I’ve started working more and more with EVE-NG to test various network scenarios, automation and in general to try and learn something everyday.

If you’re familiar with EVE-NG, you know where to find various Linux images which you can download and install . Very helpful indeed, however all of them are coming without any pre-installed tools which I need for network oriented tests. I need Python, IPerf, Ansible, various Python libraries for network automation, etc.
Basically every time when I setup a new lab in EVE-NG, I need to make sure that the Linux image has a connection to Internet to download all these tools. Doable, but too much time consuming.

Lately EVE-NG has the Pro version, where you have Docker images which support some of the tools for a network engineer needs to test automation. If you already have EVE-NG Pro, then maybe this is a bit redundant. However if you’re still using the Community version, it may sounds interesting.

I’ve developed the Ubuntu (18.04) image using the same tools that you can find in my Docker image (Ubuntu 16:04 Pfne):
* If you’re not sure what I’m talking about, please read my previous post.

  • Openssl
  • Net-tools (ifconfig..)
  • IPutils (ping, arping, traceroute…)
  • IProute
  • IPerf
  • TCPDump
  • NMAP
  • Python 2
  • Python 3
  • Paramiko (python ssh support)
  • Netmiko (python ssh support)
  • Ansible (automation)
  • Pyntc
  • NAPALM

The image is hosted on my Firstdigest Project at Sourceforge.
If you are in a hurry, download directly using this link: Ubuntu 18.04 Pfne for EVE-NG.

For convenience here are the steps, but if you run into trouble be sure to check the EVE-NG Documentation.

  • Download the image
  • Using favorite SFTP Client (WinSCP, FileZilla) connect to your EVE-NG and upload the image to the location: /opt/unetlab/addons/qemu/
  • Connect via SSH to your EVE-NG machine and go to location:
cd /opt/unetlab/addons/qemu/
  • Unzip your uploaded image file.
tar xzvf linux-ubuntu-server-18.04-pfne.tar.gz
  • Remove the archived image file (be sure to have a copy somewhere to avoid you have to download it again)
rm -f linux-ubuntu-server-18.04-pfne.tar.gz
  • Fix permissions
/opt/unetlab/wrappers/unl_wrapper -a fixpermissions

The image comes with the following predefined username and password (security was not the point here):

User: root
Password: root
User: pfne
Password: pfne

With this image you have everything ready for your tests. You want to test QoS? Just design a network and two (client / server pair) machine using this image and push some packets with IPerf. Or maybe you want to test some automation. Here you have it, just start playing with.

Btw, I assume you have the EVE-NG installed. If not and you’re into learning topics, I’ll advise you to install this great application. You can start with Community version which is free (and honestly has enough features for most of the self-teaching engineers out there) and if you feel like go with the Pro version.

Let me know if you find it useful. In case of problems, please comment and I’ll try to help in my spare time.

Remote desktop, GNS3 crashes when drag and drop topology objects

Couple of days ago I reinstalled my machine that I use as GNS3 server. It was about time as thing started to become a bit unstable after so many patches and updates to bring it up from Ubuntu 8.04.

I picked Xubuntu 14.04 LTS as my distro because I like XFCE and with the new GNS3 installed directly from PPA following https://www.gns3.com/support/docs/linux-installation it seems to be a piece of cake the entire story.

Unfortunately the reality was different. The above machine is sitting in my lab and most of the time I do just remote desktop on it via X2GO or XRDP. The issue that I encounter was that GNS3 was starting fine, everything looked to be working correctly, but when I was trying to drag and drop an object (like router, switch) to the topology the GNS3 would crash and the logs would show a nice segmentation fault.

I spent a lot of hours reading about and it seems I’m not the only one which had this strange behavior. However nobody could actually point out a real solution to this problem.

One workaround that I found to be working is to use Thinlinc, a remote desktop server provided by Cendio. The free version supports for up to 10 concurrent users and in my case this limitation should not pose a problem. One disadvantage can be seen that it’s not open source and you need to install also the client software. Again not a big deal, at least for my scope.

If you arrived to my post looking for a solution, the above workaround can be one and it’s working fine.

However, the engineer in me was not satisfied as why the solution would not work just using the included packages in Ubuntu 14.04 LTS.

Digging more, I found that the problem is not actually related to GNS3, but rather to the Qt version that comes with Ubuntu 14.04. Also it’s seems that not only GNS3 is affected by this issue, which appears to be a Qt Bug, but also other software used via a remote X11 connection – https://bugreports.qt.io/browse/QTBUG-38109

Now if you check the GNS3 Linux manual installation page, you’ll see that python3-pyqt5 must be installed. When you install it from PPA, the same python3-pyqt5 is installed, just that maybe you’ll miss it among the other packets that are added automatically.

Checking the Ubuntu 14.04 packages http://packages.ubuntu.com/trusty/python/ (search for python3-pyqt5 to avoid going via all packages) I noticed that the default version is 5.2.1 I’ve checked for particular Bugs with this version that can be related to my problems, unfortunately my search brought no conclusive result, so I had to assume that this version has a problem. I’m not a developer so this task was even harder for me.

I went to check the next Ubuntu release. 15.04 is out of the marked since January 2016 and the only alternative was 15.10. I’m not very keen on trying non-LTS versions, but desperate times require desperate measures. Searching for the same python3-pyqt5 (http://packages.ubuntu.com/wily/python/) I saw that this version is 5.4.2.

Next I tried to find a way to install the 5.4.2 python3-pyqt5 version on Ubuntu 14.04. No success here. I ran into more problems than solutions. If you have a solution to have these two versions working together, please let me know.

Having nothing to lose I downloaded the Xubuntu 15.10, installed it and…everything is working like a charm so farm. I can open GNS3 and drag and drop successfully via a remote connection (XRDP or X2GO).

As you can see I have no solution to the actual problem, but at least I can suggest 2-3 workarounds that may get you out of the woods. For me an article like this would have been very helpful while doing my research, but there was none out there, beside different community posts usually without any answer. This is the reason for which I wanted to share this story with you.

If you have this issue and found another solution, please let me know as I would like to use the 14.04 LTS version of Ubuntu, otherwise I need to wait for the release of 16.04 LTS scheduled for this year.

SSL Certificate signed by own CA

There are a lot of “how-to” on the Internet explaining the setup procedure. This is mainly a copy / paste example for those in a hurry :)

How to setup your own CA

Generate a key for CA

openssl genrsa -aes256 -out myCA.key 4096

Pick a password and remember it!

Generate a SSL certificate for CA

openssl req -new -x509 -days 3650 -key myCA.key -out myCA.crt

How to create a new SSL certificate signed by your own CA

Request a new key for the new domain that you want to secure

openssl genrsa -aes256 -out MyServerName.key 2048

Pick a password and remember it!

Request a CSR and sign it with the previous created key

openssl req -new -key MyServerName.key -out MyServerName.csr

Request the SSL certificate and sign it against the CA

openssl x509 -req -in MyServerName.csr -out MyServerName.crt -sha1 -CA myCA.crt -CAkey myCA.key -CAcreateserial -days 720

(Optional for Linux) Secure the key on the server

chmod 0400 *.key

To have the SSL working you need to copy on the server side
– MyServerName.key
– MyServerName.crt
– myCA.crt (that’s the CA certificate)

How to view a certificate

openssl x509 -in MyServerName.crt -text -noout

How to check whether a private key matches a certificate or that the certificate matches the certificate signing request (CSR)

openssl x509 -noout -modulus -in MyServerName.crt | openssl md5
openssl rsa -noout -modulus -in MyServerName.key | openssl md5
openssl req -noout -modulus -in MyServerName.csr | openssl md5

Does anybody knows a simple script that can offer the above functionality from web interface? I was looking around for a while now, but either they are enterprise complex or do not work. Let me know in Comments if you have a good suggestion.

Thanks!