Geuni/ April 28, 2020/ Englisch/ 0 comments


In the previous articles, we have built up two services that we provide on the Internet. These should be offered once via port 80 (HTTP) and port 443 (HTTPS). We don’t need a ReverseProxy now, in terms of numbers, but in perspective we want to build more services and that’s where this thing will help us! That’s why we deal quite early on with how we build something like this and, above all, what it is.

1) What is our goal?

We want to be able to offer all our services safely, ideally on port 443 (only), uniformly and centrally controlled.

2) What requirements do we have?

We want to:

  • all our services are offered safely and uniformly on the Internet,
  • manage our certificates only in one place,
  • offer all services uniformly secure.

3) What is a ReverseProxy?

A ReverseProxy is a server or service that accepts requests (usually from the Internet), then (simply) processes them to its defined destination (a server or server or services). Sounds simple at first. It is practically a middleman. The topic can be complicated as desired.

Using the ReverseProxy, we can “hide” our services from the Internet. Hiding means here, the ip for all services will give a server that occurs on the Internet for us and not as many as you want. This helps us to control the “entry” into our LAN. Furthermore, with a little trick (use of DNS subdomains) we can offer all services via port 443 with HTTPS, no matter which port the service actually uses in the background.

This “containment” of all ports on 443 makes the input into our LAN as small as possible. Furthermore, we are always on a standard port that can be reached from almost any network. Port 443 is essential to today’s internet standard and can therefore be accessed from almost any network.

Ultimately, we have the advantage that we can control our SSL parameter independently and centrally from the service (this unfortunately only comes in part 2). In my example, I’ll set up an Apache-ReverseProxy Docker container.

4) Why Apache and not Nginx? Or something else?

This section is one of the few that won’t be really rational, because I chose Apache, because I used to do something with Apache, but didn’t understand it all and wanted to keep going with it. Whether that was a good decision, I cannot say. It definitely works and very well.

I once, on a test basis, set up an NGINX Docker container and tried it. I also did the first steps like with Apache, some things went even better with NGINX, but I didn’t exactly test all this and then stayed with Apache.

In my opinion, only the fact that NGINX was purchased by F5 speaks against NGINX at the moment. I compare this to Oracle’s purchase of MySQL. This hasn’t been bad for MySQL, but there are also reasons why forks came from MySQL. I am therefore sceptical about NGINX and not only for this reason I am tenandishing to Apache. But that wasn’t the reason Why, I chose Apache.

This does not mean that I am opposed to commercial solutions per se. On the contrary, I come from large infrastructure environments and have learned to appreciate some “enterprise features” in some applications. Enterprise environments simply need different features than SMEs, and here, in the blog, we work in very small environments for home use, so we certainly don’t need enterprise features.

5) What does our network architecture look like?

Since we are at home here in our own LAN, I assume that we do not have so-called internal offenders. We also do not rely on us to secure our LAN internally (with a DMZ, for example). If you have a lot of devices, e.g. A home control that goes beyond the radiators and controls something like a water pump, air conditioning, boilers and the like, I would recommend segmenting your network, because not everything has to be able to communicate with all devices in the network. However, this is all really dependent on the personal use case and cannot really be described as a general one.

But because we work here in a very small environment, we limit ourselves to a so-called ” Class-C network (allows up to 254 devices, IPs change only in the fourth octet). Within this network, we define for ourselves that all IPs are 2-20 “infrastructures” and from 20 a DHCP rage applies. In the DHCP range, we only try to have “clients”; like a smart TV, smartphones or laptops. All infrastructures always get a fixed IP (this is really recommended, except for a few exceptions).

When I write something, we are always in my network at home and that has a Fritz.Box as a router, there you can define the DHCP range in place (network -> network settings -> IPv4 addresses):

Fritz.Box setting for the local IP range and DHCP range.
Fritz.Box setting for the local IP range and DHCP range.

If you have navigated into it, then you should come into the following dialog. Here you can see some IPs. I’m not going to explain all of them, because our goal is just to see that for DHCP servers in the lines “from” and “to” the fourth field (so-called “from” and “to” fourth Octet) from 20 to e.g. 201. The “up” must not be greater than 254.

Fritz.Box setting for the local IP range and DHCP range.
Fritz.Box setting for the local IP range and DHCP range.

This means that we now have a DHCP range (if we didn’t already have it) for all clients. All devices will first receive an IP from this area. All “infrastructures” that we will set up can be manually set to an IP below the DHCP range and should never cause an IP conflict.

6) Docker or VM?

This is now a possible one. philosophical question, or a question of available resources. In any larger environment, I would always recommend a dedicated server for a ReverseProxy. In our small environment, I recommend a Docker container for resource reasons and operational effort. Let’s compare technical figures of the two options in the table below.

Ram200 MB1 GB
Hdd200 MB5 GB
Operation (subj. Up)littlemedium

The CPU load of both options is the same. Therefore, this is not in the table. The RAM load in the Docker is very low. We are talking about approx. 200 MB. I do all this on a Qnap and it uses the so-called. “Virtualisation Station” for VMs and unfortunately, this is independent of the VM, the “Virtualization Station” already consumes min 1GB of RAM, which we have to add here, because I have nothing else in a VM.

After that, we have the HDD property, which is to be considered as disk consumption, a Docker container needs approx. 200 MB again, the VM, because of the OS, at least 5GB. On our NAS, I assume we don’t have any problems with disk space, but it’s a trait that should be used in comparison when it’s different for someone.

The last two features are an “expert assessment” of mine. With company I talk about the amount of work that the solution in everyday life costs me. Is it crashing? Do patches often come? Do I often have to adjust something? I rate the container with very little effort, a VM with significantly more, because OS patches come out almost monthly and 3rd party patches as well, which you have to install regularly.

Documentation is always such a thing. Docker, if you say so. Using YML files, then the documentation is great, because it describes everything that is infrastructural. Unfortunately, this is not the case with an OS, so the documentation point goes to the Docker solution. We don’t have to compare Apache-ReverseProxy here, because both solutions are identical.

So for me, for home, the Docker solution is an option.

7) What is our name concept?

I have already mentioned this above, we will be able to use so-called ” sub-domains. On the one hand, we can do this very easily with FreeDNS, because we can set up as many sub-domains as we like. Furthermore, the handling in the ReverseProxy is very easy! Why this is so, I will explain later that has something with so-called. “Rewrites” on the ReverseProxy. These are more complicated than using subdomains.

Let’s start with the explanation of what a sub-domain is, what I recognize it by and how I set it up on FreeDNS.

FreeDNS Admin-Ui to manage your own domains
FreeDNS Admin-Ui to manage your own domains

A sub-domain is always prefix.domain.tld. You have a domain that ends on “DE”, “COM” or something else. If you write a “Prefix.” in front of your domain, it will be called a sub-domain and we can create it in the FreeDNS admin web ui. Since we have only 2 services so far, our Qnap web UI and our Card/CalDav server, I will put the Qnap UI on the “root” of the domain, i.e. on “domain.tld” and our Card/CalDav server, because the software is called Radicale, we can e.g. call the sub-domain “radicale.domain.tld”. For every further service we will build, we follow this scheme, we always create one sub-domain per service.

Subdomain view in FreeDNS admin UI with stored IP or dynamic IP
Subdomain view in FreeDNS admin UI with stored IP or dynamic IP
Dialog for creating new subdomains or so-called Records
Dialog for creating new subdomains or so-called Records

If we now use FreeDNS, we can create a sub-domain simply by clicking on “Subdomain” in the navigation menu on the left. There we should then see a list of our domains and its subdomains, if any. By clicking on “add” (top right of the domain) we can create a subdomain. We set a subdomain as so-called A-Record. In the “SubDomain” field, “radicale” comes in for our example. In the “Destination” field, if your Dyn DNS is set up correctly, your IP should already be. You may not be able to select stealth (as in the picture) with the “Domain” drop-down, but that’s not bad. Just leave the default.

8) How do I set up the container? – Network requirement

As I described above, the Cointainer should have its own IP. For this to work, we first have to check via SSH on the NAS whether our container station has already configured a network correctly, so that we can really give the container its own IP. As mentioned, we need SSH and we check this in the Qnap under “Control Panel -> Netzerk and File Services -> Telnet/SSH”. There we have to set a catch for “allow SSH connections (…)” and determine the port for it. Standard is 22, but you should change it, because if you ever release port 22 on the Internet, you will quickly find that a lot of people are looking for it and will try to bruteforce you (try to guess username and password to gain access) or similar (we will not share port 22, or your defined port, on the Internet here!).

Qnap Control Panel for configuring the SSH service
Qnap Control Panel for configuring the SSH service

If we have that, we should still look at which user we want to make SSH accesses with. To do this, we check this under “Edit access rights”. Only those users who are in the Administrators user group appear there. Therefore, if a user is in this group, they should also appear here for “Edit Access Rights”. I will always work with the “admin” user on SSH, so I have to change as few permissions as possible to leave the NAS as far as possible in the “standard”. This means that for all those who want to do it differently, you have to adjust your permissions for some files again and again so that you can work with the data, or you have to put the “sudo” command in front of a command so that you can execute it.

Now let’s take a tool like Putty to connect to the NAS via SSH (use internal IP and then the configured port).

Username and password, logged in.

We now have to see if we already have a suitable network in the container station, which we can use for ip allocation for a container. It is important to know that the container station is only the QNap own implementation of Docker. So everything we do here should be applied in pretty much every other Docker environment. We type the following command into our SSH console and get a small table as output:

docker network ls

What does that mean now? The first line is the names of the properties that are quite speaking. We don’t care about the “Network ID”, the names are important to us, because we will use them later for the so-called ” YML file. The driver “cryptically” refers to the basic configuration and function of the virtual network.

Driver “bridge” means that the NAS creates a so-called NAT and hides your container behind it in its own network. “host” means that the container as part of the NAS (IP is seen) and all ports that the container opens are placed directly on the IP of the NAS (can cause problems with port overlaps because a port can only be used once by an application). “zero” means that it does nothing.

This is like no network have. “qnet” is what we need, because this is what is called. Spanning-Tree protocol applied and thus we can give the container its own IP without the need for several NETWORK cards (although this would be possible with the Qnap, of course, depending on the model). But right here, you may lack this network, which has the parameter “qnet”! So that we can now create the whole thing as easily as possible, we use a detour.

We go into our web UI of the Qnap and start the container station (of course you should have installed before). Now we simply create a container there, with me in the example I take the Apache-ReverseProxy docker from Bitnami and click on Create.

Qnap Container Station Docker Implementation, Installation of New Container with Static IP
Qnap Container Station Docker Implementation, Installation of New Container with Static IP

Now comes another dialogue that looks different from the picture! But now we click on “Advanced Settings” and go to “Network” on the left, then it looks like in the picture! As “Network Mode” we select “Bridge” in the drop down menu (not surprisingly, the names “Bridge, NAT and host” are used differently between the Qnap-Web-Ui/Container Station and Docker!). Then we can choose our network interface. We take the adapter, which also has a network cable on it, and then say “Use static IP”. There we now enter a local IP according to our mini IP concept from before.

Important: We only do this so that the NAS now automatically creates a network for Docker/Container Station after your configurations, which we can address and use quite easily via SSH. We could have done it all now via SSH and Docker orders. This is a bit more complicated and so it should be the easiest for everyone. We can delete the container as soon as it is created. Once we’ve done that, we’ll go back to the SSH console and tap the Docker Network command again, and then have an entry in the table that has “qnet” as “Drive.” As is already the case with me at the top of the picture.

9) How do I set up the container? – File structure

Unfortunately, we are still not ready to put the container in a way that would be in line with our requirements! But it’s not much anymore. We now need to create the file structure/folder structure in which we will store the container’s persistent data. Ideally, we do this via SMB via Windows File Explorer. We are accessing our NAS and should see a shared folder named “Container”. This is created by the container station and has already stored all the data of the containers there by default and since we also put our data in and in. define where we want our data to be in there.

If you don’t see the folder, check the NAS’s web ui under “Control Panel -> Rights -> Shared Folder” to see if your user using sMB also has write permissions to the “Container” shared folder. If not, you should give it to yourself by clicking on the second icon on the far right at “Container” (as in the picture), and giving your user write rights to the directory.

Qnap Web UI Control Panel for granting rights to shared folders
Qnap Web UI Control Panel for granting rights to shared folders

Ok. In our example, I’ll now specify what the folder structure will be like. You create a folder on your NAS in the Container shared folder with the name “apache” and a folder named “letsencrypt”. In the folder “apache” you create a folder with the name “logs”. In the folder “letsencrypt” you create a folder with the name “data”. IMPORTANT: Ultimately, we always work on a Linux OS, which means that case-insensitive makes a difference! So always make sure that’s a mistake!

Done with the folders. Now we continue to work in the SSH console and use everything we have just prepared.

10) How do I set up the container? – The YML file for Docker Compose

We have finished our foundation. Now we write our so-called . YML file. YML stands for “Yet another Markup Language” and is used within Docker to describe and install containers. I would always recommend using this, because with this file you can always rebuild your containers in any docker environment with a command. This file also helps us if we want to update the containers.

Below is my YML file for Apache-ReverseProxy! You probably can’t just take them over like that, you’re going to have to change a little bit to make it happen to you. That’s why I explain below the code what it’s all about the lines. IMPORTANT: YML works with indentas as block marking.

Would you now, for example, in the config below, push the word “apache:” to the far left on line 4, the Docker compose (the tool that processes the file) would spit out an error while processing the file, because this line defines a service and thus belongs to “in” (i.e. at least one spaces) the “services:” block and not on the same level! In other markup or programming languages, such a thing is usually solved by parentheses ( , (, ) .

First of all, I always link my YML files to services, then volumes, and then networks. I always try to clearly mark this with comments. A YML file always starts with the “version” tag. We use version 2, even if version 3 is already available.

version: '2'
# ---------------------------
# ---------------------------
        container_name: apache
        hostname: apache
        mac_address: xx:xx:xx:xx:xx:xx
        restart: always
        image: bitnami/apache:latest
            - apache_data:/bitnami
            - apache_logs:/logs
            - apache_letsencrypt:/letsencrypt

# ---------------------------
# ---------------------------
            type: none
            device: /share/Container/letsencrypt/
            o: bind
            type: none
            device: /share/Container/apache/
            o: bind
            type: none
            device: /share/Container/apache/logs/
            o: bind
# ---------------------------
# ---------------------------
        external: true

11) How do I set up the container? – Explanation of the Services Block

Let’s start with the Services block. On the first level, the name of the service is indented (the line “apache:” in the example above). I’m still commenting on the name above it (comments start with a diamond, because the name of the container isn’t always the same as the service you want to run in it. This is followed by the “container_name” and the “hostname”, both properties that define the name of the container.

I therefore enter the “mac_address” (fictitious value, 6x hexadecimal values separated with a colon) so that a router like a Fritz.Box does not recognize a new device every time a container is restarted (provides for not nice long lists of unknown devices in the Fritz.Box), because otherwise the containers will always receive a random Mac at the start. The next “Restart” parameter is the behavior when the container should crash or the NAS goes out, in which case, always restart. “Image” is the reference of the container image to be used from the Docker hub. The naming convention is Provider/Application:Version. Just googling for something as a container, most of you will find a link from a provider on Docker Hub since you see the notation, but further in the YML.

Volumes are ultimately drive mappings from the NAS or the host running on the Docker itself into the container. The notation in YML is possible once I do this, where you first give a name for the volume on the NAS and then, after a colon, specify the path in the container, which folder should be that. This is used to keep data persisting for a container, such as Configuration files for the Apache-ReverseProxy server. That’s why we’re tying three volumes here. The first is the Bitnami folder, which is specific to the Bitnami image we use and there are all Apache configs in it. The second volume is one for Apache logs and the third is a volume through which we will include our SSL certificate (as already mentioned, this comes only in part 2).

Now comes the last section for the container, namely “networks:”. Here we define the network of the Docker container and its IP. We want to use static IPs, so here in my sample YML we need to use the name of the “qnet-…” Network change! For you, this is called differently. As it is, you have to scroll up and in the section “How do I set up the container? – Network Prerequisite” by the name of your network, which has the parameter “qnet” and enter it here. You should adjust the IP according to your wishes.

12) How do I set up the container? – Explanation of the volume block

Now we come to the second block, “Volumes”. Here we define our previously named volumes. We have three volumes, as explained. What is important for you here is the path you have identified as the Absolute Path on your NAS, where the volume is to be stored. We save the other features in the explanation. The structure in the YML is always, name of the volume, colon, paragraph, indentation, options, colon, paragraph, indentation, properties (after a colon, the value of the property).

13) How do I set up the container? – Explanation of the network block

Last block “Network”. Here you have to use your name for the “qnet-…” network and the parameter “external: true”, which simply means that the network already exists and we therefore want to take the existing network for the container. You could define the network completely here, if you like, but we have done this in a different way and whites before and therefore do not need it for the use case.

14) How do I set up the container? – Use Docker Compose

So, now our YML is ready and can be executed! It is best to store this file on our NAS in the Container shared folder. There I simply store all my data that has to do with my containers and so I find this easiest again. I call the file “apache.yml”. Now we log in to our NAS via SSH, navigate to the share “container” and execute a “docker-compose” commands as follows (we will navigate to the folder where our YML file is located beforehand):

cd /share/Container/
docker-compose -f apache.yml -p apache up

Once you’ve done that, Docker should download and install the Bitnami Apache image directly on your NAS. Short explanation, while your NAS downloads what you’ve done: “docker-compose” simply calls the application, which says parameter “-f” which YML file to use to know what to do. Here we only specify the relative path to the YML file, because we have previously navigated into the directory. The parameter “-p” is only a name for the project to be compiled and we simply call this “apache”, but you can enter everything you want. The last parameter “up” then says that we build it all up.

After this has been done, the view in the shell goes directly into the container and you should now see all the outputs that happen in the container directly as running text in the SSH console. If you want to get out of there without finishing the container, press Ctrl+Z. If you try to go out with CTRL+C, you end the container, which we don’t want at first.

A browser test on the internal IP of the container should now bring a website with the text “It Works!”.

15) How do I configure my ReverseProxy container? – httpd.conf #1

Unfortunately, it is not done with installing the container yet. We need to start by editing a few files that are so-called ” httpd.conf; This is the basic configuration of the Apache-ReverseProxy server. Then we remove, I call them test websites of Bitnami, so that we don’t have unnecessary configurations and then we create our so-called . virtual hosts, these are the settings that then take over the work, so to speak. We do this at the beginning of everything in HTTP and thus unencrypted, SSL we add after we have made it.

So let’s start with HTTPD.conf. We find these as we defined it in the YML file in the volume named “apache_data” which we have set to “/share/Container/apache/”. We should be able to open this via SMB via our Windows File Explorer on our NAS in the “Container” shared folder. The file should now be in the folder “.. “Container” “apache”apache-conf”.

Unfortunately, Qnap sometimes has a weird behavior in my eyes regarding permissions, so let’s test if we can edit the file first. Simply open with an editor/notepad, make a small change and save. If that works, wonderful if not we need to log in via SSH to the NAS and change the owner of the file. This way, we don’t have to change the basic permission structure of the file and still get write rights. If the permission is not a problem, then just skip the small excursion.

16) Excursion: Understand, check and change Linux permissions

When we have opened an SSH session, let’s first look at the authorization structure, with the following command (the path may differ with you if you haven’t set it up as described):

ls -al /share/Container/apache/apache/conf/

This should bring output across all files and folders in this folder and show us the permission structure, as well as the owner and permission group. For me, for example, i can see that. as if:

-rw-rw-r-- 1 admin administrators 19147 2019-05-26 21:58 httpd.conf

Now we should first understand how the line is structured. Importantly, properties are separated by a space. Thus, the first “block” is the permission structure, the subsequent block an ID then the owner comes to the permission group, the file size in bytes, the last modified date and the name.

It is important to understand what is at the beginning of the line, the permission structure. The first “-” here means that it is a file, because if it were a directory there would be a “d”. Below are 9 characters, always to be seen as a block of 3 with the values “r”=read, “w”=write, “x”=execute. The first block says what rights the owner has. Here “rw”, i.e. write and read rights. The second block refers to the group, here “administrators” also with “rw”. The last block refers to all users of the system and they only have read rights “r”. Now, if we want to change the owner to access the user we use via SMB, we type the following command:

chown admin:administrators /share/Container/apache/apache/conf/httpd.conf

The syntax: chown -> “Change Owner” a space and then the new owner, after the colon the group and after a space the path to the file. Here in the text, admin is back in it as the owner, you may change that. your user. Now we should be able to change the file in Windows File Explorer if it didn’t work before!

17) How do I configure my ReverseProxy container? – httpd.conf #2

We insert these two lines in the httpd.conf under “ServerRoot/opt/bitnami/apache”:

ServerSignature Off
ServerTokens Prod

These two lines harden our apache ReverseProxy server a little. The first line causes the server to never tell the user its version number for error pages. The second line ensures that the server always only pretends to be “Apache” and does not disclose any further information.

Next, we define which ports our server should listen on. Bitnami has defined port 80 by default and 443 (that’s standard ports for HTTP and HTTPs), which we change from my personal interest to 8181 and 8443. To do this, we replace the line with “Listen 80” with:

Lists 8181
Lists 8443

Each can change these values according to his or her preference, it should only be taken into account later then the change uniformly in the so-called . virtual host configurations.

Now we come to the list of modules to load when Apache ReverseProxy is started. We’ll need a few more than are enabled by default in the Bitnami container. All of the modules mentioned below should be marked with a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . The points are meant to mean that there are between some other modules, mentioned to me are only those who are active with me in deviation from the standard.

LoadModule cache_module modules/
LoadModule cache_disk_module modules/
LoadModule cache_socache_module modules/
LoadModule socache_shmcb_module modules/
LoadModule deflate_module modules/
LoadModule logio_module modules/
LoadModule unique_id_module modules/
LoadModule proxy_module modules/
LoadModule proxy_connect_module modules/
LoadModule proxy_http_module modules/
LoadModule proxy_fcgi_module modules/
LoadModule proxy_wstunnel_module modules/
LoadModule slotmem_shm_module modules/
LoadModule ssl_module modules/
LoadModule dav_module modules/
LoadModule dav_fs_module modules/
LoadModule negotiation_module modules/
LoadModule rewrite_module modules/

I don’t explain every single module. That would be too much. I’m just saying that we’re going to use some of these modules now, others just a little later in subsequent posts. But it’s not bad that we’re already loading the modules.

Now we look for a line called “ServerAdmin” below and enter our e-mail address. This allows others to find out who to turn to if they find problems with your server.

ServerAdmin user@mail.tld

The server name defines, oh wonder, the name of your server. However, you should make sure that the name of the website is the name to be accessed. So your domain.

ServerName domain.tld

The last change we make is to change the “ErrorLogFormat”. We will have Apache logged into a Graylog later. To do this, we are already making ourselves live by changing the format of the errors to a standard JSON format. To do this, you search for the line that starts with “ErrorLogFormat” and replace it with the following:

ErrorLogFormat " "Timestamp": "%"cu-t"","Module"":"%-m"","LogLevel": "%-l", "ClientIP": "%-a", "ID": "%-L","Message": "%M"

Now we just need to restart the container with:

docker restart apache

And check, as I find easiest, in the Qnap web UI whether the container starts without errors. If there were errors, the container would not start and indicate where there are black bars in the “Console” where the syntax error (usually in the configuration) is located. Unfortunately, you cannot restart the containers you create via SSH via the UI or otherwise modify them. This can only be done by SSH. unfortunately. I said yes, QNap’s own integration of Docker.

QNap Wen-Ui View of the containers and their consoles
QNap Wen-Ui View of the containers and their consoles

18) How do I configure my ReverseProxy container? – Remove ballast

Bitnami brings two vHosts as the default, which we remove, because we don’t use them. To do this, let’s remove the file, . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

We’ll completely empty the file, “”container” “apache” “apache” “conf” 00_status-vhost.conf” because we’ll rewrite it now!

It is important to note that a change to the configuration will not take effect until you restart the container.

19) How do I configure my ReverseProxy container? – virtual host for the NAS #1

Ok, we’ll start with a quickwin here. We directly build the HTTP virtual host for our NAS. To do this, as described earlier, we go to the 00_status-vhost.conf (you could also rename them, all *.conf files in the folder will be loaded).

There we insert the following lines:

    <VirtualHost *:8181=""></VirtualHost>
        Server name domain.tld
        ServerAlias www.domain.tld

        <Location "/"=""></Location>

Everything else from the file should be removed for the time being, especially if you don’t know what the commands mean. This single vHost now has only two functions. The first function is, if requests on port 8181 ( )<VirtualHost *:8181=””>arrive with the domain “domain.tld” (server name …) or the alias with the prefix www, the requests should return to the back (from the ReverseProxy) to the address “ forwarded (ProxyPass, ProxyPassReverse; Usage: “Protocol://IP:Port/”).</VirtualHost> A example for NAS port 8080 is specified, which may of course differ for your NAS if you have changed this setting. Answers are also expected from the same body. The “<Location “/”=””>parameter ” says that all requests for the server name (starting from the root URL) will be forwarded to the back.</Location> The trick here is that the ReverseProxy for the Benuzter (e.g. user who comes via a browser) does not reveal that it forwards the requests to another server at the back. A user believes that it addresses a server such as the NAS directly. This is a security boost for our infrastructure.

Now we need to test whether our domain works with the ReverseProxy. For this purpose we create a port release on our Fritz.Box, outwardly ideal white on port 80 and inwards (in my case) on port 8181 (this is what the ReverseProxy listens to). That would look like this in the Fritz.Box.

Port Acces Translation in the fritz. Configure Box
Port Access Translation (PAT) in the fritz. Configure Box

Restart the Docker container with the SSH command:

docker restart apache

If we go to our domain now, with a browser, we should find the UI of the NAS.

If the NAS UI is not accessible on our domain now, please check your NAS under Control Panel if you have prevented access to the NAS with HTTP! For QNAP-Nas, this can be defined in two places (Control Panel -> General; Control Panel -> Applications -> WebServer) and should be issued in both places, because this is exactly the security function we will now take over on the ReverseProxy ourselves. In addition, if your ReverseProxy works, you could issue the NAS web server, which has no added value.

20) Excursion: Our new IT architecture

Schematically, we now have the following structure:

Schematic representation of the architecture that we built with a ReverseProxy
Schematic representation of the architecture that we built with a ReverseProxy

Looks a bit oversized at first glance. But it’s not. Because we don’t need any further changes to the FritBox in the future, because we can now map everything on the basis of subdomains on the reverse proxy, regardless of which server in the background actually offers the service. End with the small excursion of THE IT architecture.

Why don’t we use encryption from ReverseProxy to NAS? This has something to do with the effort in daily operation. If you want to do this properly, you have to renew the HTTPS certificate regularly, but since we are here in the internal network, we can not just use Lets-Encrypt with so-called . Auto-Renewals. So it’s just too much effort for us at home to do that. You can do this naturally, communicate encrypted in the internal network, only then you have to be aware of what this means in terms of effort. For me at home, it just doesn’t make sense. Here, keywords such as an on-premise PKI would be used if one seriously strives for such a solution with full encryption.

21) How do I configure my ReverseProxy container? – virtual host for Radicale

Now we come to our contacts and calendars based on Radicals. The goal we have is to make Radicals securely accessible via the ReverseProxy. To do this, we will add a new vHost to our vHost configuration of the Apache-ReverseProxy container (we build so-called htaccess collateral), radicals easily adapt and find that we can also use it in some places. behaved in a comical manner.

We are now collecting data for the time being. For this purpose, we go to our NAS via LAN-IP and start Radicale from there in order to log in to the Radicale UI with the previously created user. Now we see again an image like the following one and there is all the information that will be needed for the vHost (later in the text). We will therefore use this information later.

Radical Web-Ui view if you are in an account and can see the URLs of the created contacts and calendars
Radical Web-Ui view if you are in an account and can see the URLs of the created contacts and calendars

Now we’re changing the form of authentication of Radicale so that we can authenticate to our ReverseProxy. This helps us at the point that we can map everything in perspective via a central active directory and otherwise we have it first centrally on a server and not distributed in every application.

To do this, we search for the Config file of Radicale, which is located in the hidden “.qpkg” directory on the NAS for usual under “/share/CACHEDEV1_DATA/.qpkg/Radicale/config/config” and change the lines below as described.


Authentication method
Value: none | htpasswd | remote_user | http_x_remote_user
type = http_x_remote_user

Now we are relaunching Radicale by going to the Qnap Club tab in the NAS UI in the App Center, searching for Radicale and clicking on the little arrow. A so-called ” Context menu should go up in which is selectable that we can exit Radicale and then we just start it again. This can sometimes take a little time.

Restart Radicals from the NAS App Center
Restart Radicals from the NAS App Center

Now we need the further vHost in the Apache-ReverseProxy configuration. To do this, we open the vHost file we used before and insert the following lines below.

    <VirtualHost *:8181=""></VirtualHost>
        Server name radicale.domain.tld
        <Location "/"=""></Location>
            AuthType Basic
            AuthName "Radicale - Password Required"
            AuthUserFile "/bitnami/apache/conf/vhosts/htaccess/htpasswd.txt"
            Require valid-user

            ProxyPass retry=0 timeout=60 Keepalive=on
            RequestHeader set X-Script-Name "/"
            RequestHeader set X-Remote-User expr=%-REMOTE_USER

New commands here are:

AuthtypeBasicThe description that we have a so-called htpasswd file for authentication.
Authname“Radicale – Password Required”This is just the display name of the login window in the browser.
Authuserfile“/bitnami/apache/conf/vhosts/htaccess/htpasswd.txt”The path in the container where the htpasswd file should be located. This path differs from the one we will address via SMB for this.
Requirevalid-userStates that when logging in a user must be from the named file with password.
RequestHeaderset X-Script-Name “/”Radicalespetzic’s value used for the correct execution of scripts.
RequestHeaderset X-Remote-User expr=%-REMOTE_USERRadicale-specific parameter that matches Radicale’s Config X header for user propagation

Now we should look at FreeDNS if we have already created a suitable subdomain. Simply go to FreeDNS in the menu item “Subdomains” and then enter a new subdomain as in the picture, on the top right of “add”.

FreeDNS SubDomain view such as a new subdomain can be added
FreeDNS SubDomain view such as a new subdomain can be added

To make authentication work via the ReverseProxy using htaccess, let’s generate the encrypted content on a page like this. We simply generate a username and password here. We copy the encrypted line into our clipboard. Now, we’ll put a file named “htpasswd.txt” in the Apache folder by SMB (you can also change the name in the vHost). We can do all this via Windows File Explorer. Now let’s insert our clipboard here and save that. Here in the code, the user “test” with the password “test” is now specified.


If you now have your clients, such as DavDroid/Davx5 to your domain, you should be able to log in to the htaccess file with the defined user.

What is now a small hindging foot is that if you want to log in to Radicale in the web UI via domain, first comes a username/password query, then you land on the web ui where you are again asked to enter username and password. But this only brings a limited point, because with the X-Header the already entered name is passed on to Radicale, so you can enter nothing or something here and end up in your account. However, if you now enter a valid other username and password, you will again end up in its account. Slightly quirky, but it doesn’t bother us at first, because all clients synchronize, have no problems with it and we still can’t cross-users access URLs after logging in. So just weird in handling.

22) How do my clients access the Services now? LAN vs. Wan.

We now have both ways open for access, the way out of our own LAN and the way over the Internet (WAN) based on our domain. To make it easiest for us to handle it, I would now recommend that we always address our domain via the WAN address. Of course, it doesn’t always make sense to go over your domain address. But we just don’t have much traffic, so we can just go the easiest way. If you are travelling in larger environments, a distinction between LAN and WAN makes sense, because in the LAN we naturally have shorter distances and faster transmission rates.

23) Conclusion

Despite a lot of work, we haven’t managed to secure our connection with HTTPs yet. That’s because it’s not all too easy with containers if you want to understand what’s happening and how it plays together. We will therefore explain this in detail in the following article.

24) Outlook

We build a container with the Certbot software and let it interact with the Apache container and make sure that we will only use HTTPs. We’ll have some so-called so-called. Install SSL parameters that make our connection as secure and backward-compatible as possible (proverb SSL ciphers). We will not achieve the maximum level of security, because we will not do a public key pinning and no “Content Security Policy” (CSP). This is the part two article!

Share this Post

Leave a Comment

Your email address will not be published. Required fields are marked *