Terug naar blog

Hoe een Django-applicatie te beveiligen en schalen met Docker, Nginx en Let’s Encrypt

Hoe een Django-applicatie te beveiligen en schalen met Docker, Nginx en Let’s Encrypt

Miljoenen gebruikers gaan online om informatie te openen voor verschillende doeleinden, waaronder leren, entertainment, nieuws en het delen van de voortgang van hun leven’ met vrienden. Daarom is het bij het implementeren van een app in uw belang dat u een zeer veilige en schaalbare infrastructuur voor uw applicatie opzet. De cloud biedt verschillende manieren om een Django-applicatie te beveiligen en te schalen. Horizontaal schalen is een methode waarmee u meerdere kopieën van uw app kunt uitvoeren. Dit zorgt ervoor dat deze toleranter is voor fouten en zeer beschikbaar is. Het verhoogt ook de prestaties om meerdere verzoeken tegelijkertijd te verwerken.

Een Django-applicatie horizontaal schalen

U kunt een Django-applicatie horizontaal schalen door verschillende app-servers in te richten die de Django-applicatie en de bijbehorende WSGI HTTP-server uitvoeren (zoals Gunicorn of uWSGI). Vervolgens moet u een infrastructuur opzetten om binnenkomende verzoeken over deze app-servers te verdelen. Een load balancer en een reverse proxy zoals Nginx kunnen uw infrastructuur helpen met de distributie van het verkeer. Nginx kan SSL-certificaten implementeren om veilige verbindingen met uw app via HTTPS te garanderen. Ten slotte kan Nginx ook caching van statische inhoud bieden om de belasting van uw server te minimaliseren.

Het afzonderlijk configureren van deze verschillende componenten en ervoor zorgen dat ze communiceren kan een ontmoedigende taak zijn. Gelukkig vereenvoudigt het gebruik van Docker het configuratieproces en zorgt het ervoor dat de verschillende componenten zich op dezelfde manier gedragen, ongeacht waar ze worden geïmplementeerd.

Wat u gaat doen in deze handleiding

In deze handleiding leert u hoe u een gecontaineriseerde Django-applicatie, die wordt bediend met een Gunicorn WSGI HTTP-server, horizontaal kunt schalen. U richt twee applicatieservers in, elk met Docker geïnstalleerd, waarop dezelfde kopie van een Django- en Gunicorn-app-container draait.

U beveiligt uw applicatie ook met een Let’s Encrypt SSL-certificaat door het inrichten en configureren van een derde proxyserver die een Nginx reverse proxy-container en een Certbot-clientcontainer zal uitvoeren. Certbot is een pakket dat helpt bij het beheren van SSL-certificaten van de certificeringsinstantie Let’s Encrypt. Het haalt het certificaat op, configureert Nginx-serverblokken met de locatie van het certificaat en beheert automatische verlengingen. Dit gebeurt door een cron-job te configureren die periodiek controleert of het certificaat bijna verloopt en moet worden vernieuwd. Door uw SSL-certificaat up-to-date te houden, heeft uw website altijd een hoge veiligheidsbeoordeling op SSL Labs.

De derde proxyserver bevindt zich vóór uw gedistribueerde architectuur en ontvangt al het binnenkomende externe verkeer. Vervolgens distribueert deze het verkeer naar uw app-servers. De app-servers bevinden zich achter een firewall, waardoor alleen de proxyserver toegang heeft.

Deze handleiding is de tweede in een reeks van drie handleidingen over het werken met Django, Docker en Kubernetes. U moet eerst de stappen volgen die worden beschreven in de handleiding over Een Django- en Gunicorn-applicatie bouwen met Docker op Ubuntu. In die handleiding hebben we de basisprojectcode en een Dockerfile opgezet, en verbinden we de app met MinIo Simple Storage Service (S3) om onze statische bestanden te serveren.

Vereisten

Om deze handleiding te volgen, heeft u het volgende nodig:

  1. Vier Ubuntu 20.04-servers:

Als u de stappen in de vereiste handleiding heeft gevolgd, Een Django- en Gunicorn-applicatie bouwen met Docker op Ubuntu, heeft u al twee van de vier servers:

  • De eerste server zal de PostgreSQL-database-instantie uitvoeren. Volg stap 1 en 2 van de handleiding: Een Django- en Gunicorn-applicatie bouwen met Docker op Ubuntu om de database in te richten. De Postgres-configuraties moeten worden gewijzigd om externe verbindingen alleen vanaf de IP-adressen van uw app-servers toe te staan.

  • De tweede en derde servers zullen de containers voor uw applicatiecode hosten. U zou de tweede server al draaiende moeten hebben uit de vereiste handleiding. We zullen de firewall hiervan aanpassen om alleen externe verbindingen vanaf het IP-adres van de proxyserver toe te staan. U kunt stappen 1 tot en met 4 van deze stap-voor-stap handleiding volgen om u te helpen uw Ubuntu-server in te richten op CloudSigma.

  • De vierde server zal de proxyserver zijn die de load balancing en distributie van het verkeer naar de twee applicatieservercontainers afhandelt.

  1. Docker moet worden geïnstalleerd op de twee app-servers en de proxyserver.

    Na het volgen van de stappen in de vereiste handleiding, zou Docker al op een van de servers geïnstalleerd moeten zijn. Je kunt stappen 1, 2 en 3 volgen van onze handleiding over het installeren en gebruiken van Docker. Vergeet niet om de hierboven aangemaakte sudo-gebruiker toe te voegen aan de Docker-groep.

  2. Registreer een domeinnaam en stel de DNS-records in om te verwijzen naar het openbare IP-adres van de proxy server. Voor demonstratiedoeleinden gebruiken we example_domain.com.
  1. Stel een S3-objectopslagdienst in. We hebben MinIO gebruikt als opslagdienst in de vereiste handleiding. Volg daarom de uitleg in Stap 5 van de vereiste handleiding om je MinIO storage bucket in te stellen.

Stap 1: Controleren of de eerste Django-applicatieserver werkt

Zoals uitgelegd in de Vereisten, volgt deze handleiding op de handleiding over Een Django- en Gunicorn-applicatie bouwen met Docker op Ubuntu. Als je van die handleiding komt en de stappen al hebt uitgevoerd, zou de eerste server moeten draaien. De code van de applicatie is gebaseerd op de Polls-applicatiehandleiding van de Django-documentatie. Het is belangrijk dat je die stappen doorleest om de initiële installatie te begrijpen. Als je de stappen in de handleiding hebt uitgevoerd, kun je deze eerste stap overslaan.

Anders kun je gewoon de gedockeriseerde branch naar je server clonen. Begin met inloggen op je eerste app-server en voer het volgende git commando uit om de django-polls-docker branch van de django-polls repository:

Next, navigate into the django-polls directory:

cd django-polls

In deze map vind je een Dockerfile die door Docker wordt gebruikt om de applicatie-image te bouwen, de django-polls map die de Python-applicatiecode bevat, en een env bestand met een lijst van omgevingsvariabelen die bij het opstarten aan de container worden doorgegeven om het gedrag ervan aan te passen. In de Dockerfile, we define Django package dependencies through the requirements.txt bestand. Daarnaast moeten we een poort declareren 8000 die wordt gebruikt om inkomend verkeer te accepteren, en deze instellen om een gunicorn server met 3 workers te draaien. Voor meer informatie over de Dockerfile-instructies, zie Stap 7 van de handleiding Building a Django and Gunicorn Application with Docker on Ubuntu.

Je kunt de Docker-image bouwen met het commando:

docker build -t django-polls:v1 .

Nadat Docker de image heeft gebouwd, kun je de beschikbare images op de server weergeven met het volgende commando:

docker images

Hier is de uitvoer toen we het commando uitvoerden:

Django Application scrn 1

Vervolgens moeten we het env bestand aanpassen dat wordt gebruikt voor het configureren van de runtime-omgeving. Dit bestand wordt doorgegeven aan de Docker run-container bij het opstarten van de container. Open het env bestand met de nano-editor:

Het env-bestand bevat wat tijdelijke aanduidingstekst die je moet aanpassen en invullen met je juiste waarden:

  • DJANGO_SECRET_KEY: Genereer een unieke, onvoorspelbare waarde zoals uitgelegd in de Django-documentatie. Je kunt dit commando gebruiken om een willekeurige tekenreeks te genereren en deze in te stellen voor de variabele:  python -c 'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())'.

  • DJANGO_ALLOWED_HOSTS: deze waarde wordt gebruikt om je app te beveiligen tegen HTTP Host Header-aanvallen. Je kunt deze instellen op *, wildcard die overeenkomt met alle hosts in de ontwikkelingsmodus. Wanneer je je app naar productie implementeert, stel dit dan in op je geregistreerde domeinnaam. Voor onze demonstratie is dit example_domain.com.

  • DB_DATABASE: stel dit in op de naam van de PostgreSQL-database die je hebt gemaakt in de Vereisten-sectie, in ons geval is dat polls_db.

  • DB_USERNAME: stel dit in op de gebruikersnaam die je hebt gekozen voor je database.

  • DB_PASSWORD: stel dit in op het wachtwoord dat je hebt gekozen voor je database.

  • DB_HOST: stel dit in op de host waarop je database-instantie draait, zoals je had ingesteld in de Vereisten-sectie. Dit wordt uitgelegd in stap 1 en 2 van de handleiding Een Django- en Gunicorn-applicatie bouwen met Docker op Ubuntu om de database in te richten.

  • DB_PORT: stel dit in op de poort van je database.

Sla het bestand op en sluit het zodra je klaar bent met bewerken. Nu onze database-inloggegevens zijn ingesteld, kunnen we het databaseschema maken door de container uit te voeren en het CMD-commando dat in de Dockerfile is ingesteld te overschrijven. Meer informatie vind je over het Dockerfile-entrypoint in de officiële documentatie. Voer vervolgens het volgende commando uit:

In dit commando voeren we de django-polls:v1-image uit en geven we het eerder gewijzigde env-bestand mee. Het gedeelte: sh -c "python manage.py makemigrations && python manage.py migrate maakt het databaseschema aan dat is gedefinieerd door de app-code. Als je het commando voor de eerste keer uitvoert, zou je een vergelijkbare uitvoer moeten zien die de aanmaak van het databaseschema aangeeft:

Django Application scrn 2

Zodra we het schema hebben gemaakt, kunnen we de Django-superuser aanmaken. Voer het volgende commando uit om de container te starten met een interactieve shell:

Het commando start de container met een shell-prompt die je kunt gebruiken om te communiceren met de Python-shell. Laten we een gebruiker aanmaken met het volgende commando:

Volg de aanwijzingen om een gebruikersnaam, e-mailadres en wachtwoord op te geven. Typ het wachtwoord nogmaals en druk op enter om de gebruiker aan te maken. Verlaat de shell en stop de container door te drukken op CTRL+D.

Vervolgens moeten we de container opnieuw uitvoeren, waarbij we het standaardcommando overschrijven met het collectstatic Django-commando. Het commando genereert de statische bestanden voor de app en uploadt ze naar MinIO Cloud Storage:

Het commando genereert en uploadt het bestand naar je geconfigureerde objectopslagdienst. Hier is de uitvoer:

object storage

Je kunt de applicatie nu uitvoeren zonder een extra commando op te geven om het standaard CMD-commando te overschrijven dat in de Dockerfile is gedefinieerd:

Django Application scrn 3

Docker voert het standaardcommando uit dat is gedefinieerd in de Dockerfile, start de container met de gunicorn-server, stelt containerpoort 8000 bloot en koppelt deze aan de poort 80 van Ubuntu. Je kunt nu de interface van de applicatie in je browser bekijken door het IP-adres van de eerste server in te voeren in je adresbalk: http://FIRST_SERVER_IP.

Je krijgt een 404 Pagina niet gevonden omdat we niets hebben gedefinieerd voor de / pad. Navigeer naar http://FIRST_SERVER_IP/polls om de Polls-interface te bekijken:

Django Application image 1

Bezoek de admin-interface om enkele polls aan te maken: http://FIRST_SERVER_IP/admin:

polls

Voer de inloggegevens in die u hebt ingesteld met het createsuperuser commando hierboven om toegang te krijgen tot de beheerinterface:

polls administration

Als u de broncode van de pagina bekijkt, zult u merken dat de statische bestanden worden opgehaald uit de gedefinieerde storage bucket. Nadat u hebt gecontroleerd of de container de app naar verwachting serveert, kunt u de container stoppen door te drukken op CTRL+C in the terminal.

Vervolgens moeten we de container laten draaien in de detached modus, zodat we de SSH-sessie van de eerste server kunnen afsluiten. Hierdoor blijft de container op de achtergrond draaien. Voer het volgende commando uit:

De -d vlag start de container op in een detached modus zodat deze op de achtergrond kan blijven draaien. De --rm vlag schoont het bestandssysteem van de container op nadat de container is afgesloten. We geven de container een naam, polls, zodat we deze kunnen zien wanneer we de containers oplijsten.

Sluit de SSH-sessie van uw eerste server af en navigeer naar http://FIRST_SERVER_IP/polls in uw browser om te bevestigen dat deze naar verwachting werkt. Als u de polls-interface kunt bekijken, is uw eerste app-server succesvol ingesteld. Laten we in de volgende stap de tweede applicatieserver instellen.

Stap 2: De tweede applicatieserver instellen

We will be cloning the Dockerized branch of the application we created in the Building a Django and Gunicorn Application with Docker on Ubuntu tutorial. You can find more details of the commands we will use here from that tutorial, or the summarized version in Step 1.

U moet de tweede server actief hebben, een non-root sudo-gebruiker hebben toegevoegd en Docker hebben geïnstalleerd zoals uitgelegd in de Prerequisites sectie.

De volgende stap is om deze server te configureren om verbinding te maken met de PostgreSQL-serverinstantie. Zoals uitgelegd in Stap 1 van de handleiding Building a Django and Gunicorn Application with Docker on Ubuntu, moet u het IP-adres van de tweede server toestaan via de ufw en de PostgreSQL-configuraties.

Log eerst in op de PostgreSQL-databaseserverinstantie met uw non-root sudo-gebruiker. Om de ufw-regel toe te voegen, voert u het volgende commando uit:

Voer vervolgens dit commando uit en voeg het IP-adres van de tweede server toe aan het PostgreSQL-clientauthenticatiebestand:

Lees de opmerkingen door om meer te begrijpen over de configuraties. Voeg vervolgens deze regel toe onder de sectie hosts, waarbij u uw IP-adres opgeeft:

Sla het bestand op en sluit het wanneer u klaar bent met bewerken.

Start vervolgens de PostgreSQL-service opnieuw op om de wijzigingen van kracht te laten worden:

Log uit bij de PostgreSQL-databaseserverinstantie en ga verder met het configureren van de tweede app-serverinstantie.

Log in op de tweede app-server met ssh. Kloon vervolgens de django-polls-branch van de django-polls repository met het volgende commando:

Ga naar de django-polls map:

Bouw daarna de image met het volgende commando:

Zodra het bouwproces van de image is voltooid, wijzigt u het env bestand met configuratiewaarden zoals uitgelegd in Step 1. Open het bestand met nano:

Vervang de tijdelijke aanduidingen door de werkelijke waarden die je hebt toegevoegd in Stap 1. Vergeet niet om de DJANGO_ALLOWED_HOSTS -variabele op de juiste manier aan te passen. Sla het bestand op en sluit het wanneer je klaar bent. Werk je MinIO-inloggegevens bij in het env -bestand, net zoals je in de vorige stap hebt gedaan.

Nu kun je de app-container in detached modus uitvoeren met het volgende commando:

Het commando start de container en zorgt ervoor dat deze op de achtergrond blijft draaien. Sluit de ssh-sessie van de tweede app-server af en navigeer naar http://SECOND_SERVER_IP/polls in je browser om te controleren of het naar verwachting werkt. Je zou de polls-interface moeten kunnen zien als alles naar wens is verlopen.

Je hebt nu twee app-servers die dezelfde kopie van je applicatie draaien. In de volgende stap configureer je de Nginx-container om als reverse proxy te dienen.

Stap 3: De Nginx Docker-container instellen

Nginx is een van de meest populaire open-source webserversoftware ter wereld. Het is verantwoordelijk voor het garanderen van de beschikbaarheid en schaalbaarheid van de websites met het meeste verkeer op internet. Het garandeert beveiliging en het is zeer veelzijdig. Je kunt het gebruiken voor reverse proxying, caching en load balancing. We hebben onze applicatie zo ingesteld dat deze een afzonderlijke objectopslagdienst gebruikt om de statische en mediabestanden te verwerken. Daarom zullen we de cachingfunctionaliteiten van Nginx niet gebruiken. In plaats daarvan gebruiken we de reverse proxy- en load balancing-mogelijkheden van Nginx. De front-facing server van Nginx ontvangt inkomend verkeer en distribueert dit naar de backend-applicatieservers. Vervolgens zorgt het voor veilige communicatie tussen client en server door het verkeer te beveiligen met SSL-certificaten die zijn verkregen van Let’s Encrypt.

Er zijn verschillende manieren om Nginx reverse proxying en load balancing te implementeren. Een van de manieren is om de Nginx reverse proxy apart van de backend-applicatieserver in te stellen, zoals we in deze handleiding hebben gedaan. Deze opzet is flexibel en stelt je in staat om zowel de Nginx-proxylaag als de applicatielaag te schalen. Je kunt meerdere Nginx-proxies toevoegen of een cloud load balancer implementeren. Een andere manier om reverse proxying te implementeren is door een van de backend-app-servers als Nginx-proxy te gebruiken. Vervolgens kun je inkomende verzoeken lokaal en naar andere app-servers proxyen. Optioneel kun je op alle backend-app-servers een Nginx-container configureren en een cloud load balancer aan de voorkant instellen om inkomend verkeer te ontvangen en te distribueren naar de backend-app-servers.

Laten we beginnen met het configureren van de proxyserver. Log in op de vierde Ubuntu-server die je had ingesteld om als Nginx-proxy te worden gebruikt en maak een configuratiemap aan:

Open een configuratie met nano in de map:

Voeg vervolgens de volgende configuratie toe aan het bestand:

In dit configuratiebestand specificeren we de server, upstream, en location blokken om Nginx te instrueren om HTTP-verzoeken om te leiden naar HTTPS en de verzoeken te verdelen over de twee app-servers die we hebben ingesteld in Stap 1 en Stap 2. Je kunt algemene informatie vinden over de Nginx-configuratiebestandsstructuur in hun officiële documentatie.

We hebben configuratiebestanden bestudeerd die zijn geleverd door de Docker Hub-Nginx-image-documentatie, Certbot, en Gunicorn om tot dit minimale Nginx-configuratiebestand te komen. Hoewel dit alleen voor demonstratiedoeleinden is en om onze opzet werkend te krijgen, staat het u vrij om te verkennen en te experimenteren met andere configuraties volgens de Nginx-handleidingen.

Het upstream-blok wordt gebruikt om de groep servers te definiëren die inkomende verzoeken zal verwerken. Er wordt een naam aan de groep gegeven en deze wordt aangeroepen door de proxy_pass-richtlijn. We hebben het blok de naam django gegeven en de IP-adressen van de twee backend-app-servers gespecificeerd:

We hebben ook 3 serverblokken gedefinieerd. Het eerste serverblok vangt alle verzoeken op die niet overeenkomen met uw domein en retourneert een 444-code (sluit de verbinding zonder een antwoord naar de client te sturen, waardoor kwaadaardige of misvormde verzoeken worden geweigerd). Een direct HTTP-verzoek naar het IP-adres van uw server wordt door dit blok afgehandeld, omdat het is gedefinieerd als de default_server:

Het tweede serverblok verwerkt inkomende HTTP-verzoeken (poort 80) en stuurt ze door naar HTTPS (poort 443) met behulp van een HTTP 301-omleiding:

Het derde serverblok handelt nu de verzoeken af. Het heeft verschillende richtlijnen, en we zullen het belang ervan hieronder definiëren.

We hebben twee richtlijnen die de paden definiëren naar het TLS-certificaat en de sleutel zoals geleverd door Certbot. De certificaten worden in de Nginx-container gekoppeld wanneer we deze opstarten:

Vervolgens hebben we de standaard SSL-beveiligingsinstellingen zoals aanbevolen door Certbot. U kunt hier meer over lezen in de officiële Nginx-documentatie over de ngx_http_ssl_module. Mozilla biedt ook meer informatie over Server Side-beveiliging. De waarde van ssl_ciphers in het conf-bestand is overgenomen van de pagina van Mozilla:

In de volgende twee richtlijnen definiëren we de maximaal toegestane grootte van de client-verzoekbody en stellen we de time-out in voor keep-alive-verbindingen met de client. Nginx sluit verbindingen met de client na het aantal seconden dat u instelt in de keepalive_timeout-richtlijn. Meer informatie over Nginx-configuraties voor het implementeren van Gunicorn vindt u in de officiële documentatie:

In het configuratiebestand hebben we ook twee location-blokken gedefinieerd. Het eerste blok handelt het proxyen van de verzoeken af zoals gedefinieerd met de proxy-richtlijnen. Inkomende verzoeken worden geproxyed naar de upstream django-servers die eerder zijn gedefinieerd:

Je kunt meer informatie vinden over de proxy-richtlijnen in Nginx Module ngx_http_proxy_module en de documentatie over het implementeren van een Gunicorn-server.

In het tweede location-blok definiëren we een pad: /well-known/acme-challenge/. Dit wordt meestal door Certbot gebruikt om je domeinnaam te verifiëren bij Let’s Encrypt voordat een SSL-certificaat wordt verstrekt of vernieuwd:

Dat is alles voor het Nginx-configuratiebestand. Je kunt het bestand nu opslaan en sluiten zodra je klaar bent met bewerken.

Het configuratiebestand dat je zojuist hebt gedefinieerd, kan worden gebruikt om een Nginx-container uit te voeren. Dit zal echter mislukken omdat we de SSL-certificaten van Let’s Encrypt nog niet hebben verstrekt. In deze handleiding gebruiken we de nginx:1.20.2 Docker-image versie 1.20.2 uit de officiële Nginx-image-repository op Docker Hub.

Je kunt de onderstaande opdracht uitvoeren om de image te downloaden en te controleren of alles correct werkt:

Deze opdracht maakt een container met de naam nginx en koppelt de poorten 80 en 443 tussen het hostsysteem en de container. De --rm-vlag verwijdert alle tussenliggende containers na een succesvolle build. We gebruiken de -v-vlag om het configuratiebestand in de container te koppelen op /etc/nginx/conf.d/nginx.conf, wat de standaard Nginx-configuratiemap is. Deze is gekoppeld in alleen-lezen modus met behulp van de ro-vlag om te voorkomen dat de Nginx-container deze wijzigt. We stellen de standaard webroot-map in en koppelen deze als /var/www/html. We sluiten af door Docker de opdracht te geven om de nginx:1.20.2-image te gebruiken voor deze build. Laten we in de volgende stap het TLS/SSL-certificaat en de sleutel ophalen van Let’s Encrypt.

Stap 4: SSL/TLS-certificaat verstrekken van Let’s Encrypt en automatische verlenging van Certbot configureren

Certbot helpt bij het verstrekken van gratis TLS-certificaten van Let’s Encrypt en beheert ook de automatische verlenging ervan voordat ze verlopen. Dit verbetert de beveiliging van je websites en zorgt ervoor dat ze via HTTPS worden aangeboden. Om onze architectuur gecontaineriseerd te houden, gebruiken we de Certbot Docker-image om de SSL/TLS-certificaten op te halen en automatische verlenging te configureren. Zorg ervoor dat je Docker hebt geïnstalleerd op je proxyserver volgens de Vereisten instructies.

Je moet ook een DNS A-record van je geregistreerde domeinnaam hebben die naar het IP-adres van je proxyserver verwijst. Je kunt dit controleren door de certbot Docker-image uit te voeren en de --staging-vlag mee te geven:

De opdracht downloadt de Certbot-image en voert deze uit in de interactieve modus. Dit betekent dat deze wordt geleverd met een shell, zodat je enkele gegevens kunt invoeren. Het koppelt poort 80 van de host aan poort 80 binnen de container. We gebruiken de -v-vlag om twee hostmappen in de container te koppelen: /etc/letsencrypt/ en /var/lib/letsencrypt/. De --standalone flag geeft aan dat we willen dat de Certbot-image draait zonder Nginx te gebruiken. Ten slotte hebben we de --staging flag die ervoor zorgt dat Certbot wordt uitgevoerd op de staging-servers en uw domeinnaam valideert.

Voer uw e-mailadres in en accepteer de Servicevoorwaarden wanneer daarom wordt gevraagd. Het volgende is de uitvoer van een succesvolle validatie:

VOLGENDE STAPPEN:

Het certificaat moet worden vernieuwd voordat het verloopt. Certbot kan het certificaat automatisch op de achtergrond vernieuwen, maar u moet mogelijk stappen ondernemen om die functionaliteit in te schakelen. Bekijk deze link voor instructies.

U kunt het certificaat bekijken met het cat commando:

Het bovenstaande commando zou uw certificaat in de terminal moeten weergeven. Zodra u heeft bevestigd dat Certbot uw certificaat heeft geleverd, kunt u nu de Nginx-configuratie testen die u had gemaakt in Stap 3. Voer het onderstaande Docker-commando uit om de Nginx-container te starten:

In dit commando hebben we de -v flag gebruikt om de locatie van de Let's Encrypt SSL/TLS-certificaatmappen te koppelen.

Wanneer de container actief is, opent u de webpagina in uw browser: http://example_domain.com. U zult waarschijnlijk een waarschuwing zien dat de website onveilig is:

Dit komt omdat we alleen staging-/testcertificaten hadden geleverd en geen productie-certificaten van Let's Encrypt. Laten we de productiecertificaten ophalen door het volgende Certbot-commando uit te voeren zonder de --staging flag:

Bevestig in de prompt dat u het bestaande certificaat wilt vernieuwen en vervangen door te typen2 en druk op ENTER. Dit zou een productie-klaar certificaat moeten opleveren. U kunt nu de Nginx-container uitvoeren en alles zou goed moeten werken:

Zodra de container actief is, opent u de webpagina opnieuw in uw browser: http://example_domain.com opnieuw. Merk op dat uw browser wordt omgeleid naar HTTPS zelfs als u HTTP invoert. Dit betekent dat onze server in de Nginx-configuratie en de geleverde SSL/TLS-certificaten goed werken. Navigeer naar de polls  route http://example_domain.com/polls aangezien we geen route hebben gedefinieerd voor het hoofdpad /. Je zou de polls-interface moeten zien:

Tot nu toe heb je met succes een productieklare architectuur geconfigureerd. Je hebt twee backend-servers geïmplementeerd die inkomende verzoeken verwerken die worden doorgestuurd vanaf de proxy-server. De proxy-server regelt de load balancing en de beveiliging van het verkeer met behulp van de geleverde TLS-certificaten.

Houd er echter rekening mee dat Let’s Encrypt-certificaten na 90 dagen verlopen. Je moet ze dus vóór de grens van 90 dagen vernieuwen. Omdat de Nginx-container actief zal zijn, moet je de webroot-modus gebruiken in plaats van de standalone-modus wanneer je het certbot-commando uitvoert voor certificaatvernieuwing. Onthoud dat je de /var/www/html/.well-known/acme-challenge/-map had opgegeven in het Nginx-configuratiebestand in Stap 3. Certbot gebruikt dit pad om validatiebestanden op te slaan. Bovendien zal de Let’s Encrypt-client dit pad aanroepen met validatieverzoeken wanneer je de certificaten probeert te vernieuwen. Zodra het vernieuwingscommando is uitgevoerd, kun je Nginx herladen om de wijzigingen door te voeren.

Beëindig de container door te drukken op CTRL+C in je terminal, en laten we deze opnieuw opstarten in de detached modus met de -d-vlag:

Hierdoor blijft de Nginx-container op de achtergrond draaien. Laten we de procedure voor certificaatvernieuwing testen met de --dry-run-vlag door het onderstaande commando uit te voeren:

In dit commando hebben we de --webroot plugin gespecificeerd, evenals het te gebruiken pad voor validatieverzoeken met de -w-vlag. We specificeren ook de --dry-run-vlag om de automatische vernieuwingsprocedure te verifiëren zonder daadwerkelijk een certificaat aan te vragen.

Je zou een vergelijkbare uitvoer moeten zien bij een succesvolle simulatie:

Wanneer je een certificaat voor je actieve applicatie vernieuwt, moet je Nginx herladen zodat de container het nieuwe certificaat gaat gebruiken. Het volgende Docker-commando herlaadt de nginx -container (onthoud dat we de container nginx hebben genoemd):

Het commando stuurt een HUP Unix-signaal naar het Nginx-proces dat in de nginx Docker-container draait. Dit zorgt ervoor dat Nginx de configuraties herlaadt en de vernieuwde certificaten gaat gebruiken.

Aangezien we TLS/SSL op onze proxy-server hebben geïnstalleerd en onze website via HTTPS wordt aangeboden, moeten we nu onze backend-app-servers beveiligen om alleen verzoeken van de proxy-server toe te staan.

Stap 5: De backend Django-servers beveiligen tegen externe toegang

De proxyserver die u in deze handleiding hebt geïmplementeerd, regelt SSL-beëindiging, waarbij de SSL-verbinding wordt ontsleuteld en onversleutelde pakketten worden doorgestuurd naar de backend-appservers. Omdat we de backendservers zullen beveiligen tegen externe toegang, zou dit beveiligingsniveau in de meeste gevallen voldoende moeten zijn. Als u echter applicaties implementeert die gevoelige gegevens verzenden, zoals bankgegevens of gezondheidsgegevens, moet u end-to-end encryptie.

In deze handleiding worden de Gunicorn-servers in de backend beschermd door Nginx, omdat ze niet bedoeld zijn om rechtstreeks met het internet verbonden te zijn. De Nginx-proxyserver is als een poort naar de backend-servers en voorkomt dat externe clients rechtstreeks toegang krijgen tot de backend-appservers. U moet ervoor zorgen dat alle verzoeken via de proxyserver verlopen. Dat gezegd hebbende, heeft Docker toevallig een probleem waarbij het de ufw omzeilt firewallregels en poorten extern opent, wat uw infrastructuur onveilig kan maken. Dit is eigenlijk al duidelijk omdat we onze appservers hebben ingesteld in Stap 1 en Stap 2 zonder poort toe te staan 80 in de ufw regels. U kunt echter nog steeds de webpagina's openen wanneer u een van de openbare IP-adressen van de server in de browser bezoekt. Een manier waarop u dit probleem kunt oplossen, is door iptables rechtstreeks te gebruiken zonder via ufw te gaan. U kunt de Docker en iptables officiële documenten lezen voor meer informatie. Een andere aanbevolen manier is het gebruik van cloud-firewalls.

Laten we de configuraties van UFW aanpassen om externe toegang te blokkeren tot alle poorten die mogelijk door Docker zijn geopend. Toen we de hostpoort 80 koppelden aan de poort van de Docker-container 8000 met de vlag -p 80:8000 in het Docker-commando, hebben we per ongeluk ook poort 80 geopend op de hostmachine. U kunt deze toegang uitschakelen door de configuratie van UFW te wijzigen zoals beschreven in de ufw-docker repository README.

Laten we dit aanpassen voor de eerste Django-appserver. Log in op de server en open het bestand op /etc/ufw/after.rules met nano als een sudo-gebruiker:

Het bestand bevat de volgende ufw regels:

Voeg het volgende blok met UFW-configuratieregels toe aan de onderkant van het bestand:

De regels die u hebt toegevoegd, voorkomen openbare toegang tot poorten die Docker opent. Bovendien staan ze toegang toe vanaf de 10.0.0.0/8, 172.16.0.0/12, en 192.168.0.0/16 privé-IP-bereiken. U kunt meer details over de regels lezen in de ufw-docker README. Sla de bestanden op en sluit ze wanneer u klaar bent met bewerken. Deze installatie zou moeten werken als u een virtueel privé-cloudnetwerk (VPC) had opgezet, met al uw drie servers in de VPC, en u vervolgens de privé-IP's van de Django-servers had opgegeven in de upstream-richtlijn van de Nginx config -bestand.

We hebben echter openbare IP's gebruikt en we hebben mogelijk geen VPC. Daarom moet u een regel toevoegen aan ufw om verkeer van de Nginx-proxyserver toe te staan via poort 80 van beide Django-appservers. U kunt een allow-regel toevoegen aan ufw waarin u het herkomstige server-IP naar poort 80 specificeert met behulp van de volgende opdracht:

Zodra u klaar bent met de wijzigingen, start u uw Django-appserver opnieuw op om de wijzigingen van kracht te laten worden, aangezien het uitvoeren van sudo ufw reload alleen lijkt te mislukken om de wijzigingen door te voeren:

Wanneer de server opnieuw is opgestart, start u de container op zoals u deed in Stap 1 of Stap 2:

Probeer vervolgens het IP-adres van de eerste Django-server in de browser te bezoeken om te zien of deze de Polls-interface weergeeft: http://FIRST_SERVER_IP/polls. Dit zal mislukken. Log nu uit bij de eerste server en herhaal de stappen die u hier hebt gedaan voor de tweede server. Open de /etc/ufw/after.rules met nano als een sudo-gebruiker:

Scroll, net als eerder, naar beneden en voeg het UFW-configuratieblok toe:

Sla het bestand op en sluit het zodra u het bovenstaande blok hebt toegevoegd.

Voeg vervolgens een allow-regel toe aan ufw waarbij u het oorspronkelijke server-IP naar poort 80 specificeert met behulp van de volgende opdracht:

Start uw server opnieuw op om de wijzigingen van kracht te laten worden:

Wanneer de server weer online is, start u de container opnieuw op met de opdracht:

Test of u de polls-interface kunt bekijken door rechtstreeks naar het IP-adres van de tweede server te gaan: http://SECOND_SERVER_IP/polls. Dit zou ook moeten mislukken.

Deze architectuur is nu klaar om te worden getest. U kunt naar https://example_domain_here/polls gaan om de standaard Polls-interface in uw browser te bekijken. Dit betekent dat de Nginx-proxyserver nog steeds toegang heeft tot de Django-backendservers.

Conclusie

In deze handleiding hebben we u laten zien hoe u een schaalbare infrastructuur implementeert met behulp van Docker-containers. De infrastructuur omvat een afzonderlijke PostgreSQL-databaseserver, twee backend-applicatieservers en een Nginx-proxyserver om het verkeer over de twee servers te verdelen en te distribueren. Hoewel we onze applicatie hebben gebaseerd op de Django Polls-applicatie, kunt u deze architectuur aanpassen voor verschillende applicaties met behulp van andere frameworks, zoals Node.js, Laravel, enz.

Dit is een basisrichtlijn om u op weg te helpen. Een paar verbeteringen die u kunt toevoegen, is het hosten van uw image op een image-repository zoals Docker Hub waardoor de image eenvoudig naar meerdere servers kan worden gedistribueerd. U kunt ook pipelines voor continue integratie en implementatie toevoegen om automatisch images te bouwen, te testen en te implementeren op applicatieservers wanneer er een gebeurtenis plaatsvindt. Een gebeurtenis kan bijvoorbeeld het pushen van nieuwe code naar een specifieke branch in een git-repository zijn. Mogelijk wilt u ook automatiseren wat er gebeurt als de container een fout tegenkomt. De officiële documentatie van Docker biedt een goede richtlijn voor het Automatisch starten van containers in het geval van fouten of een herstart van het systeem.

Veel computerplezier!

author

Hark Labs

Auteur · CloudSigma

Preslav Dobrev is een creatief ontwerper bij CloudSigma, met de nadruk op een consistente bedrijfsidentiteit door middel van traditionele en innovatieve marketingkanalen. Hij is bedreven in het samenvoegen van artistieke visie met strategische marketing om impactvolle merkverhalen te creëren.

Reacties

Nog geen reacties. Wees de eerste.