Veilig doorsluizen van je internetverkeer via een Reverse proxy

Wil je bepaalde webdiensten die binnen je netwerk draaien op een veilige manier beschikbaar maken van buitenaf, zodat je ze bijvoorbeeld onderweg of op reis kunt gebruiken? Dan is een reverse proxy een ideale oplossing. We laten in dit artikel zien hoe je dit opzet met Nginx en hoe je dit vervolgens optimaal kunt beveiligen.

Code downloaden

In deze masterclass worden wat voorbeelden van stukken code gegeven. Omdat overtikken van code erg foutgevoelig is, kun je die code ook downloaden en daarna bekijken of kopiëren. Zie het bestand code-reverseproxy.txt, beschikbaar via www.pcmweb.nl/download.

Het is vaak erg praktisch om de webinterface van apparaten zoals je NAS beschikbaar te maken voor toegang van buitenaf. Hetzelfde valt te zeggen voor webdiensten die in je netwerk draaien. Denk aan toepassingen als Nextcloud, Airsonic, een WordPress-blog of software voor thuisautomatisering zoals Home Assistant en Domoticz. Het geeft vaak geen goed gevoel om deze toepassingen publiek toegankelijk te maken door een poort in de router open te zetten. De toepassingen zijn immers standaard niet altijd (goed) beveiligd. 

Het kan ook zijn dat je de beveiliging niet voldoende kent of vertrouwt. Veel veiliger is het gebruik van een reverse proxy die al het verkeer afvangt. Daarmee kun je ook meteen de toegang beveiligen en eventueel toegangsbeperkingen instellen. Zo kun je bijvoorbeeld alleen bepaalde ip-adressen toelaten of alleen lokale netwerkgebruikers. Ook een extra beveiliging met gebruikersnaam en wachtwoord is mogelijk. In dit artikel laten we zien hoe je een reverse proxy kunt gebruiken en hoe je extra toegangsbeperkingen instelt!

Werking een reverse proxy

Een reverse proxy is (bij voorkeur) een aparte server in je netwerk die verzoeken doorsluist naar de doelserver en daardoor als een soort schild werkt. Geen enkele gebruiker communiceert immers rechtstreeks met de doelserver. De reverse proxy mag een lichte server zijn, er worden geen zware eisen aan gesteld. Zelfs een Raspberry Pi is geschikt. Op basis van een domeinnaam kan de reverse proxy beslissen voor welke webdienst het verkeer is bedoeld. Je kunt deze server dus flexibel voor uiteenlopende toepassingen inzetten. 

Bovendien kun je ook direct een https-certificaat van bijvoorbeeld Let’s Encrypt gebruiken om verkeer via een versleutelde verbinding mogelijk te maken. Dat is met name belangrijk voor toegang van buitenaf, om te voorkomen dat bijvoorbeeld inloggegevens onderschept kunnen worden. Het https-adres kun je behalve voor toegang vanaf internet ook – zonder de bekende certificaatfouten – vanuit je lokale netwerk gebruiken. Dit wordt steeds vaker aanbevolen, ook met het oog op ransomware.

Als extra beveiliging kun je op het niveau van de reverse proxy allerlei toegangsbeperkingen instellen. Denk aan autorisatie of het uitsluiten van ip-adressen. Een reverse proxy kan overigens niet alleen de veiligheid verbeteren, maar ook de prestaties of betrouwbaarheid. Al richten we ons in deze masterclass op het beveiligingsaspect.

Router instellen

Je zou een reverse proxy op dezelfde server kunnen draaien als de webdienst(en) die je daarmee wilt benaderen, zolang er geen poortconflicten zijn. Een apart systeem is echter veiliger, bij voorkeur met Linux als besturingssysteem. Als proxyserver gebruiken we het bekende Nginx, wat voor dit doel ook een van de populairste opties is. Je zou datzelfde systeem met Nginx overigens ook prima voor het hosten van een blog kunnen gebruiken, het één sluit het ander niet uit. We gaan zowel poort 80 (http-verkeer) als 443 (https-verkeer) doorsturen vanaf de router naar de proxyserver, middels portforwarding. Beide poorten zijn nodig voor het aanvragen van certificaten en afhandelen van http- en https-verkeer. 

Ook laten we straks het http-verkeer omleiden naar https (door de proxyserver). Het instellen van portforwarding verschilt per router. Op www.portforward.com vind je eventueel instructies per merk en model router. De principes zijn wel steeds gelijk. Je stuurt het externe inkomende verkeer naar een bepaald poortnummer door naar een bepaald ip-adres en poort binnen je lokale netwerk. Extern kiezen we poort 80. Dit verkeer sturen we door naar het ip-adres van de proxyserver en eveneens poort 80. We maken ook zo’n regel voor poort 443. Vergeet niet om de configuratie in je router te bewaren voordat je verdergaat.

We sturen in de router de poorten 80 en 443 door naar de proxyserver.

Subdomeinen instellen

We kiezen ervoor om de proxyserver steeds op basis van de domeinnaam te laten beslissen steeds voor welke dienst verkeer bestemd is. In deze masterclass gebruiken we één domeinnaam met voor elke webdienst een aparte subdomein. Een domeinnaam kost afhankelijk van je provider vanaf zo’n 8 euro per jaar. De gewenste subdomeinen kun je gratis en onbeperkt toevoegen zolang je zelf de DNS-instellingen beheert. Stel dat je bijvoorbeeld domein.nl hebt gekozen als domeinnaam, dan kun je nextcloud.domein.nl gebruiken voor Nextcloud en nas.domein.nl voor je NAS.

We zorgen er op de proxyserver voor dat de subdomeinen via een geautomatiseerd proces een Let’s Encrypt-certificaat krijgen. De eerste stap is het instellen van de subdomeinen bij de provider. Als voorbeeld gebruiken we het domein xda.nl bij provider TransIP. Voor de DNS-instellingen kun je terecht in het controlepaneel. Als naam vullen we bijvoorbeeld nextcloud in, zodat de Nextcloud-installatie straks bereikbaar is via nextcloud.xda.nl. We kiezen voor een zogeheten A-record waardoor we als waarde direct het ip-adres van de internetverbinding thuis kunnen invullen. Je voegt op vergelijkbare wijze subdomeinen toe voor andere webdiensten die je hebt draaien. Let op dat het na een DNS-wijziging tot 24 uur kan duren voordat de wijzigingen merkbaar zijn, door caches van onder meer je internetprovider.

In dit voorbeeld voegen we een subdomein voor Nextcloud toe aan de DNS-instellingen.

Installatie reverse proxy

Zoals gezegd gebruiken we Nginx als reverse proxy. Er worden geen hoge eisen gesteld aan het systeem. Je kunt zelfs een Raspberry Pi gebruiken. Wij kiezen hier voor een kleine server met Ubuntu, maar je zou eventueel ook een virtualisatieplatform kunnen gebruiken zoals Proxmox VE of kunnen werken met Docker. Zorg dat je toegang hebt tot de opdrachtregel, bijvoorbeeld via ssh. Vervolgens installeer je Nginx met het commando:

sudo apt install nginx

Start hierna de webserver met:

service nginx start

Bezoek vervolgens het ip-adres van de server en controleer of de welkomstpagina van Nginx verschijnt. We gaan vervolgens Certbot installeren voor het maken van Let’s Encrypt-certificaten. We kiezen ervoor om de versie uit de pakketbronnen van Ubuntu te installeren. Hiervoor geef je de opdracht:

sudo apt install certbot python3-certbot-nginx

Voor instructies voor andere besturingssystemen kun je ook altijd kijken op https://certbot.eff.org/instructions.

Via de website van Certbot vind je eventueel instructies voor de installatie per platform.

Configuratie voor Nextcloud

In Nginx gaan we voor elke clouddienst een apart configuratiebestand maken met daarin alle vereiste details. Je zou eventueel ook alles in één configuratiebestand kunnen zetten, maar aparte bestanden zijn overzichtelijker, zeker als je veel extra opties gaat gebruiken. Op basis van de (sub)domeinnaam zijn diensten van elkaar te onderscheiden. We noemen dat ook wel de hostnaam. Je kunt één configuratie als zogeheten default gebruiken. Die configuratie wordt dan altijd gebruikt als de hostnaam niet wordt herkend. Als voorbeeld maken we een configuratiebestand voor Nextcloud. De locatie van configuratiebestanden is standaard /etc/nginx/conf.d. Blader naar deze map met het commando:

cd /etc/nginx/conf.d

Maak daarna het configuratiebestand met:

nano nextcloud.conf

In eerste instantie hoef je hier alleen onderstaande regels in te zetten:

server {

listen 80;

server_name nextcloud.xda.nl;

}

Controleer de configuratie op eventuele fouten met:

nginx -t

Certificaat maken

We kunnen nu het Let’s Encrypt-certificaat maken met de opdracht certbot. De eerste keer wordt om een e-mailadres gevraagd en moet je akkoord gaan met de gebruiksvoorwaarden. Hierna kun je steeds kiezen voor welke naam je het certificaat wilt maken. We drukken in dit voorbeeld op 1 voor nextcloud.xda.nl. Als laatste kies je of http-verkeer moet worden omgeleid naar https. Dat betekent dat iemand die de http-pagina (http://nextcloud.xda.nl) bezoekt, wordt doorgezet naar de https-pagina (https://nextcloud.xda.nl). We raden aan dit te gebruiken. Certbot zal de configuratie hierop aanpassen. Open vervolgens het configuratiebestand met teksteditor nano en bekijk wat er is veranderd:

nano nextcloud.conf

De inhoud van het configuratiebestand behandelen we in de volgende paragraaf. Ook voegen we een blok toe voor de reverse proxy.

Door enkele vragen te beantwoorden, kun je het certificaat voor Nextcloud maken.

Blok voor reverse proxy

In de aangepaste configuratie zie je twee blokken, elk omsloten door server {}. Een van deze blokken bevat maar enkele regels, waaronder deze:

server {

listen 80;

server_name nextcloud.xda.nl;

return 301 https://$server_name$request_uri;

}

Dit blok ‘luistert’ naar poort 80 voor http-verkeer, zoals aangeven achter listen, en dan specifiek naar de domeinnaam nextcloud.xda.nl, zoals aangeven achter server_name. Het blok bevat vervolgens alleen de doorverwijzing naar https achter return met een 301 response-code (‘moved permanently’). Het andere blok is voor de https-configuratie. Aan dat blok zijn verwijzingen naar de ssl-certificaten toegevoegd, zodat we daar niets meer aan hoeven te doen. Wel moeten we de regels voor de reverse proxy nog toevoegen binnen een blok location. Deze configuratie kan per webdienst soms wat afwijken. Enkele keren zijn aanvullende parameters nodig of gewenst. De configuratie voor Nextcloud is zoals in het volgende codeblok.

Parameters voor proxyserver

De cruciale parameter is proxy_pass. Hierachter zet je het adres van Nextcloud waar de verzoeken naar doorgestuurd moeten worden. Dat kan een ip-adres zijn, maar ook een domeinnaam. In ons voorbeeld is dat http://10.0.10.230. Je kunt er ook een poortnummer in opnemen, zoals http://10.0.10.230:8000. De andere opties, zoals de regels met proxy_set_header, kunnen verschillen per webdienst en zijn niet altijd nodig. De hier getoonde regels zijn optimaal voor Nextcloud. De headers informeren de doelserver onder meer over het originele ip-adres en de originele hostnaam van de bezoeker. Controleer na het maken van de aanpassing de configuratie met:

nginx -t

Herstart vervolgens de webserver met:

service nginx reload

Controleer daarna of je de Nextcloud-installatie via https://nextcloud.xda.nl kunt bereiken en of de browser het certificaat accepteert. Deze domeinnaam is slechts ons eigen experimentele domein, dus als jij als lezer dit letterlijk in je browser intikt, dan werkt dat natuurlijk niet.

De volledige configuratie voor de reverse proxy voor Nextcloud.

Toegang via een niet-vertrouwd domein

Bij toegang tot Nextcloud via je ingestelde domein zal, als je geen actie onderneemt, een waarschuwing verschijnen over een niet-vertrouwd domein. Standaard accepteert Nextcloud het ip-adres, maar niet de domeinnaam. Met een kleine en eenvoudige aanpassing aan de configuratie van Nextcloud los je dat op. Het komt er op neer dat je elk domein dat je voor toegang tot Nextcloud gebruikt, moet instellen als zijnde vertrouwd. Dit pas je aan in het bestand config.php, dat je vind in de map /var/www/nextcloud/config. Zoek naar onderstaande regels:

array (

0 => '10.0.10.230',

),

Hier zie je dat op dit moment 10.0.10.230 wordt vertrouwd. Je kunt dit adres vervangen door nextcloud.xda.nl. De configuratie wordt dan als volgt:

array (

0 => 'nextcloud.xda.nl',

),

Let goed op de plaatsing van komma’s. Eventueel kun je de domeinnaam ook toevoegen naast het ip-adres, zodat beide worden geaccepteerd. De configuratie wordt dan als volgt:

array (

0 => '10.0.10.230',

1 => 'nextcloud.xda.nl',

),

Het is veiliger om de eerdere configuratie te gebruiken, waarbij alleen toegang via de domeinnaam wordt toegestaan. Zo voorkom je rechtstreeks verkeer naar Nextcloud binnen je lokale netwerk.

Nextcloud komt standaard met een waarschuwing over een niet-vertrouwd domein.

Alleen lokale netwerktoegang?

Wil je de toegang om veiligheidsredenen beperken tot enkele ip-adressen of gewoon alle gebruikers op het lokale netwerk? Je zou dat eventueel in de configuratie van Nextcloud kunnen regelen. Maar het is veel handiger om dit gewoon op het niveau van de reverse proxy in te stellen. Je hoeft maar enkele regels aan de configuratie toe te voegen. En je kunt dezelfde regels gemakkelijk in andere configuratiebestanden gebruiken. Je kunt ook, zoals we hierna toelichten, de regels in een apart bestand zetten waar je in je configuratiebestand(en) naar verwijst. Met de aanpassing die we gaan maken, is toegang alleen mogelijk via het lokale netwerk. Evengoed kan nog steeds https://nextcloud.xda.nl worden gebruikt. Je profiteert dus van een veilige https-verbinding met een geldig https-certificaat en een eenvoudig te onthouden adres. We voegen hiervoor enkele blokkades op ip-adres toe.

Whitelisten gebruiken

Via allow- en deny-regels kun je individuele ip-adressen blokkeren of toegang geven. Ook kun je via één regel een compleet adresbereik toegang geven, bijvoorbeeld alle gebruikers op je lokale netwerk. De aanpassingen maken we in het blok location. De regels zet je bovenaan, zodat ze direct van kracht zijn en je deze ook direct herkent. Wil je een bepaald ip-adres toegang geven, dan voeg je een regel allow toe met daarachter het ip-adres. Dat werkt echter alleen voor internetadressen. Het probleem is namelijk dat verzoeken vanuit je lokale netwerk worden omgeleid in je router, waardoor ze altijd van je router afkomstig lijken te zijn. Er wordt in dat geval dus niet naar het werkelijke ip-adres gekeken van de gebruiker. Dat kun je in het logbestand controleren met de opdracht:

cat /var/log/nginx/access.log

Hier zie je voor elk verzoek steeds een regel die begint met het geregistreerde ip-adres. Hier gebruiken we allow en deny daarom alleen om bepaalde gebruikers vanaf internet toe te laten en daarnaast álle gebruikers op het lokale netwerk. Eventueel stel je met de geo-module wat flexibeler toegangsrestricties in, maar in deze masterclass gebruiken we die niet.

Via het logbestand kun je controleren wie er toegang kregen.

Regels maken

Om individuele gebruikers op basis van het ip-adres toegang te geven, vul je gewoon het ip-adres in achter de aanduiding allow. Als voorbeeld geven we de gebruiker met ip-adres 80.70.123.50 toegang. Daarnaast geven we alle gebruikers op het lokale netwerk toegang. Je kunt zo’n adresbereik in de zogenoemde CIDR-notatie invullen. Dat is in dit voorbeeld 10.0.10.0/24, maar in jouw situatie kan het ook bijvoorbeeld iets zijn als 192.168.1.0/24. Sluit af met een deny all om het andere verkeer te blokkeren. De configuratie is dan als volgt:

allow 80.70.123.50;

allow 10.0.10.0/24;

deny all;

Zulke regels worden stap voor stap doorlopen, totdat er een passende regel is. In dit voorbeeld zal de gebruiker met ip-adres 80.70.123.50 toegang krijgen. Ook zullen alle gebruikers in het lokale netwerk 10.0.10.0/24 toegang krijgen. Dat zijn alle adressen van 10.0.10.1 tot en met 10.0.10.255. Als er nog geen match is, zal de volgende regel met deny all ervoor zorgen dat alle andere ip-adressen worden geblokkeerd. Vergeet niet om de configuratie weer actief te maken met:

service nginx reload

Als je het handig vindt kun je dit soort regels ook in een apart bestand zetten (zie het kader ‘Whitelist via configuratiebestand’) waar je vervolgens naar verwijst.

Whitelist via configuratiebestand

Als je het handig vindt, kun je allow- en deny-regels ook opnemen in een apart bestand. Je verwijst er dan in je configuratie naar, door het bewuste bestand toe te voegen aan de configuratie. Maak dit bestand bijvoorbeeld in een nieuwe map die je aanmaakt met:

mkdir /etc/nginx/includes

Bewerk dan de whitelist met:

nano /etc/nginx/whitelist

En zet hier de volgende regels in:

allow 80.70.123.50;

allow 10.0.10.0/24;

deny all;

Vervolgens verwijs je hier als volgt naar in het location-blok:

include includes/whitelist;

Toegang via wachtwoord

Wil je de toegang nog wat beter beveiligen, dan gebruik je http-authenticatie. Er zijn dan een gebruikersnaam en wachtwoord nodig om in te loggen. We hebben een kleine tool nodig om een wachtwoordbestand te maken. Als voorbeeld gebruiken we apache2-utils. Let wel, we gaan de webserver (Apache) waar deze tool voor is ontwikkeld niet installeren op dit systeem, omdat het zou conflicteren met Nginx. Maar deze losse tool kunnen we prima installeren en gebruiken. De apache2-utils-tool installeer je met de opdracht:

sudo apt install apache2-utils

Maak hierna een map aan waarin het wachtwoordbestand wordt bewaard met:

mkdir /etc/apache2

Met de volgende opdracht voeg je een gebruiker toe (hier: gertjan):

sudo htpasswd -c /etc/apache2/.htpasswd gertjan

Er wordt daarbij twee keer om het wachtwoord gevraagd. De optie -c zorgt ervoor dat het wachtwoordbestand wordt aangemaakt. Voor elke volgende gebruiker die je toevoegt, moet je deze optie daarom weglaten, zoals:

sudo htpasswd /etc/apache2/.htpasswd peter

In het blok location voor je reverse proxy maak je de authenticatie actief door de volgende twee regels toe te voegen:

auth_basic "Toegang beperkt";

auth_basic_user_file /etc/apache2/.htpasswd;

Op basis van een wachtwoordbestand beperk je toegang tot een locatie.

Methodes combineren

Je kunt toegangsrestricties voor ip-adressen en authenticatie combineren. Zo kun je er bijvoorbeeld voor kiezen om gebruikers alleen toegang te geven als ze een geldig ip-adres hebben én zijn geautoriseerd. Je begint in het blok location dan met een regel satisfy all, gevolgd door de regels met allow en deny om bepaalde ip-adressen of adresreeksen toe te laten dan wel te blokkeren. Daarna volgen dan de regels voor authenticatie. Dit ziet er bijvoorbeeld als volgt uit:

satisfy all;

allow 10.0.10.0/24;

deny all;

auth_basic "Toegang beperkt";

auth_basic_user_file /etc/apache2/.htpasswd;

Een andere optie is het gebruik van satisfy any in plaats van satisfy all. Met deze kleine aanpassing wordt verkeer toegelaten als de gebruiker aan één van de condities daaronder voldoet. Dat betekent dat deze ofwel een geldig ip-adres moet hebben óf een geldige authenticatie. Dat komt er in de praktijk op neer, dat alleen om authenticatie wordt gevraagd vanaf een niet-toegelaten ip-adres.

Automatisch vernieuwen certificaten

Certificaten bij Let’s Encrypt verlopen automatisch na drie maanden. Dat is geen probleem, maar je moet er wel voor zorgen dat ze op tijd worden vernieuwd. Als ze (dreigen te) verlopen, krijg je hiervan overigens een bericht per e-mail. Om vernieuwingen technisch mogelijk te maken, is het nodig om poorten 80 en 443 steeds open te hebben staan naar de reverse proxy. Er is namelijk een zogeheten challenge nodig, niet alleen om de certificaten te maken, maar ook om deze te vernieuwen. Het vernieuwen van certificaten kun je gelukkig eenvoudig automatiseren. Je hebt er dan eigenlijk geen omkijken meer naar. Onder Linux gebruik je daarvoor cron. Open via de opdrachtregel deze tool met:

crontab -e

En voeg deze regel toe:

0 12 * * * /usr/bin/certbot renew --quiet

Nu worden alle certificaten op je systeem automatisch vernieuwd. Elke twaalf uur wordt gekeken welke certificaten hiervoor in aanmerking komen.

Geschreven door: Gertjan Groen op

Category: Workshop, Netwerk

Tags: internetverkeer, nginx, doorsluizen, reverse proxy