Introductie
WordPress is een van de meest populaire Content Management Systemen (CMS'en) die er zijn. Statistisch gezien drijft het meer dan 39% van alle websites aan die je op het wereldwijde web ziet. Het is een populaire keuze vanwege de uitbreidbaarheid via plug-ins en het flexibele sjabloonsysteem. Hiermee kun je het uiterlijk in enkele seconden veranderen. Bovendien kan het beheer worden gedaan via de webinterface zonder dat er veel technische kennis voor nodig is.
Daarnaast is WordPress gratis en open-source en is het gebouwd op een MySQL database met PHP-verwerking. Je kunt WordPress implementeren op een LAMP-stack (Linux, Apache, MySQL en PHP) of een LEMP-stack (Linux, Nginx, MySQL en PHP). Het blijkt echter tijdrovend te zijn om de stack elke keer dat je wilt implementeren opnieuw op te zetten.
Gelukkig hebben moderne softwareleveringsmethoden zoals cloud computing, Docker, en Docker Compose de algehele ontwikkelaarservaring soepeler gemaakt. Deze tools vereenvoudigen het proces van het opzetten van elke stack door de overhead van het installeren en configureren van individuele componenten te vermijden telkens wanneer je een applicatie wilt implementeren. In plaats daarvan schrijf je configuratiebestanden die worden gebruikt om images op te halen en te maken en deze in Docker-containers uit te voeren, zodat je je applicatie met slechts één commando kunt implementeren.
Containers zijn lichtgewicht, gevirtualiseerde, draagbare, software-gedefinieerde gestandaardiseerde omgevingen waarmee de software geïsoleerd kan draaien van andere software die op de fysieke hostmachine draait. Met Docker Compose kun je meerdere containers beheren en ervoor zorgen dat ze communiceren. De broncode van een applicatie en een database moeten bijvoorbeeld communiceren.
In deze handleiding gaan we een meervoudig gecontaineriseerde WordPress-applicatie bouwen. Een complete WordPress-app vereist drie containers: MySQL-database, Nginx-server en WordPress-broncode. Omdat beveiliging een prioriteit is bij moderne websites, zullen we een SSL-certificaat verkrijgen van Let’s Encrypt om je installatie te beveiligen. Vervolgens stellen we een cron job in om periodiek certificaten te controleren en te vernieuwen, zodat de beveiliging van je website continu gehandhaafd blijft.
Vereisten
- Aangezien dit een praktische handleiding is, moet je een installatie van Ubuntu 20.04 hebben als je initiële besturingsomgeving. Je moet ook een non-root gebruiker met sudo-privileges hebben. Hier is een stap-voor-stap handleiding om je te helpen je Ubuntu-server in te richten.
- Je moet ook Docker installeren. Je kunt deze handleiding raadplegen over hoe je Docker installeert en bedient op Ubuntu 18.04.
- Een installatie van Docker Compose. Je kunt stap 1 volgen van de handleiding Hoe Docker Compose te installeren en configureren op Ubuntu 20.04.
- Een geregistreerde domeinnaam is vereist om een TLS/SSL-certificaat van Let’s Encrypt te verkrijgen. Voor deze handleiding gebruiken we
example.com. - Stel DNS-records in om verkeer naar je VPS. Je hebt twee DNS-records nodig:
- Een A-record met
example.comdie naar het openbare IP-adres van je server verwijst. - Een A-record met
www.example.comdie naar het openbare IP-adres van je server verwijst.
- Een A-record met
Stap 1: Definieer de configuraties voor de webserver
De webserver bevat je websitebestanden en stelt gebruikers in staat om toegang te krijgen tot je webapplicatie. Het is dan ook passend dat we in de eerste stap de configuratie voor de webserver definiëren. We zullen een Nginx-serverconfiguratie-bestand definiëren dat WordPress-specifieke locatieblokken bevat. We zullen ook locatieblokken opnemen om Let’s Encrypt-verificatieverzoeken naar de Certbot-client te leiden voor automatische verlengingen van het certificaat.
Laten we beginnen met het maken van een map voor het project. Je kunt een mapnaam kiezen die je verkiest. We zullen wordpress_docker gebruiken voor deze handleiding. Voer het volgende commando in om de map aan te maken en er naartoe te navigeren:
|
1 |
mkdir wordpress_docker && cd wordpress_docker |
Maak vervolgens een map aan om de Nginx-configuratiebestanden in op te slaan met het commando:
|
1 |
mkdir nginx-conf |
Gebruik nano om het bestand te openen met het volgende commando:
|
1 |
nano nginx-conf/nginx.conf |
In dit bestand definiëren we de basisrichtlijnen voor een Nginx server block-configuratie. Deze omvatten richtlijnen voor de servernaam, document root en location blocks om Certbot-pluginverzoeken voor certificaten, statische bestanden en PHP-verwerking te sturen. Je kunt onze handleiding lezen over Nginx beveiligen met Let’s Encrypt om meer te leren. Voeg de volgende code toe aan het bestand en vervang example.com door je geregistreerde domeinnaam:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
server { listen 80; listen [::]:80; server_name example.com www.example.com; index index.php index.html index.htm; root /var/www/html; location ~ /.well-known/acme-challenge { allow all; root /var/www/html; } location / { try_files $uri $uri/ /index.php$is_args$args; } location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass app:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; } location ~ /\.ht { deny all; } location = /favicon.ico { log_not_found off; access_log off; } location = /robots.txt { log_not_found off; access_log off; allow all; } location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ { expires max; log_not_found off; } } |
Laten we de secties definiëren die je hebt toegevoegd:
-
Richtlijnen:
listen: dit vertelt Nginx om te luisteren op poort80. Dit maakt het gebruik mogelijk van Certbots webroot-plugin om certificaatverzoeken te doen. Zodra we een SSL-certificaat hebben verkregen, zullen we deze configuratie bijwerken om poort443.server_name: dit definieert de domeinnaam die deze configuratie moet afhandelen. Het verkeer naar de hier gedefinieerde domeinnaam wordt naar dit specifieke serverblok geleid, en dus naar de document-root.root: dit definieert de hoofdmap (root directory) voor verzoeken aan de bovenstaande domeinnaam. Dit is meestal de map die onze daadwerkelijke websitebestanden bevat. We hebben de map ingesteld op/var/www/html. Deze zal worden gemaakt als een Docker-koppelpunt tijdens het bouwen van de container. We zullen de instructies voor dit proces definiëren in de WordPress Dockerfile.index: dit definieert bestanden die zullen worden gebruikt als indexen of het toegangspunt tot uw webserver bij het verwerken van verzoeken. We hebben index.php voor index.html geplaatst, zodat Nginx prioriteit geeft aanindex.php.
-
Location-blokken:
location ~ /.well-known/acme-challenge: verwerkt verzoeken naar de bekende directory waar Certbot een tijdelijk bestand toevoegt om te valideren dat de DNS voor het opgegeven domein verwijst naar de specifieke server waarvan we SSL-certificaten aanvragen. Dit is de reden waarom u voor deze stap een geldig domein moet toevoegen in plaats van deexample.comdie we in deze handleiding gebruiken.location /: pikt URI-verzoeken op en geeft de controle aan WordPressindex.phpom argumenten voor verwerking aan te vragen.location ~ \.php$: verwerkt PHP-verwerking en stuurt het verzoek door naar de WordPress-container (we zullen hiervoor in een latere stap een configuratiebestand definiëren). We hebben hier configuraties gedefinieerd die specifiek zijn voor het FastCGI protocol, omdat de WordPress Docker-image gebaseerd zal zijn op de php:fpm image. Nginx gebruikt een onafhankelijke PHP-processor voor PHP-specifieke verzoeken. We zullen dephp-fpmprocessor gebruiken die wordt geleverd met dephp:fpmDocker-image.location ~ /\.ht: verwerkt.htaccessbestanden die Nginx niet gebruikt. Dedeny allrichtlijn zorgt ervoor dat deze bestanden nooit aan websitebezoekers worden getoond.location = /favicon.ico, location = /robots.txt: zoals te zien is in de definitie, voorkomt dit het loggen van verzoeken naar/favicon.icoen/robots.txtbestanden.location ~* \.(css|gif|ico|jpeg|jpg|js|png)$: schakelt het loggen van verzoeken naar statische bestanden uit en zorgt ervoor dat ze worden gecached om de belasting van de server te verminderen.
U kunt het bestand nu opslaan en sluiten door te drukken op CTRL+X, Y, en dan ENTER. Daarmee is de eerste stap voltooid.
Stap 2: Omgevingsvariabelen definiëren
Omgevingsvariabelen zijn nodig om de communicatie tussen de WordPress-applicatie en de database te vergemakkelijken. Ze zorgen er ook voor dat de applicatiegegevens behouden blijven. De omgevingsvariabelen bevatten gevoelige informatie zoals database-inloggegevens en niet-gevoelige informatie zoals databasenaam en host.
Om veiligheidsredenen is het altijd een goed idee om geen gevoelige informatie toe te voegen aan projectrepositories. Daarom zullen we, in plaats van de gevoelige waarden in het Docker Compose-bestand in te stellen, de MySQL-inloggegevens definiëren in de .env bestanden die niet aan de projectrepository worden toegevoegd en het risico lopen openbaar te worden gemaakt. Open in de project root ~/wordpress_docker de .env bestand:
|
1 |
nano .env |
|
1 2 3 |
MYSQL_ROOT_PASSWORD=jouw_sterke_root_wachtwoord MYSQL_USER=jouw_wordpress_database_gebruiker MYSQL_PASSWORD=sterk_wordpress_database_wachtwoord |
Het volgende dat u moet doen, is het .env bestand toevoegen aan de .gitignore en .dockerignore bestanden om ervoor te zorgen dat het respectievelijk niet aan uw repositories of Docker-images wordt toegevoegd.
Dit is niet nodig voor deze handleiding, maar als u met Git wilt werken voor versiebeheer, voert u de volgende opdracht uit om de huidige directory te initialiseren als een git-repository:
|
1 |
git init |
Open de .gitignore met nano:
|
1 |
nano .gitignore |
Voeg de volgende regel toe:
|
1 |
.env |
Sla het bestand op en sluit het. Open vervolgens de .dockerignore met nano:
|
1 |
nano .dockerignore |
Voeg de volgende regel toe:
|
1 |
.env |
Als u toch bezig bent, kunt u optioneel andere bestanden en directories toevoegen die verband houden met de ontwikkeling van uw applicatie:
|
1 2 3 |
.env .git docker-compose.yml |
Sla het bestand op en sluit het wanneer u klaar bent. Dat is alles voor deze stap. Laten we doorgaan naar de Docker Compose-definitie.
Stap 3: Services configureren met Docker Compose
Docker Compose gebruikt een docker-compose.yml-bestand om images te bouwen. Dit bestand bevat servicedefinities voor de volledige configuratie van een applicatie. Servicedefinities zijn in feite instructies voor hoe een container zal draaien. Een service is een daadwerkelijk draaiende container.
Docker Compose maakt het mogelijk om verschillende services te definiëren voor applicaties met meerdere containers door de verschillende services met elkaar te verbinden via gedeelde netwerken en volumes. Je zult dit in actie zien, aangezien we drie containers voor onze applicatie zullen definiëren: webserver, WordPress-installatie en database. We voegen een vierde container toe om de Certbot-client uit te voeren voor certificaatverlengingen.
Voer het volgende commando in om het docker-compose.yml-bestand aan te maken:
|
1 |
nano docker-compose.yml |
De eerste regel in een docker-compose.yml-bestand is de versiedefinitie-regel. We hebben de onze op 3 ingesteld. Vervolgens kun je beginnen met het definiëren van je services. Voeg het volgende codefragment toe aan het bestand om de db-service te definiëren:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
version: '3' services: #MySQL Service db: image: mysql:8.0 container_name: db restart: unless-stopped env_file: .env environment: - MYSQL_DATABASE=wordpress volumes: - dbdata:/var/lib/mysql command: '--default-authentication-plugin=mysql_native_password' networks: - app-network |
Laten we bespreken wat we hebben in de db-servicedefinities hieronder:
image: bepaalt de image waarop de container gebaseerd zal zijn. Het is altijd beter om een specifieke versie op te geven (mysql:8.0) dan de tag 'latest' te gebruiken (mysql:latest) omdat toekomstige versies van MySQL-images kunnen conflicteren met onze applicatie als we deze image opnieuw bouwen. Meer informatie over Dockerfiles Best practices op de offiziële Dockerfile-documentatie.container_name: hier specificeren we de containernaam.restart: deze richtlijn bepaalt het herstartgedrag van de container. De standaardwaarde isnomaar we hebben deze ingesteld op altijdrestarttenzij deze handmatig wordt gestopt.env_file: deze richtlijn wordt gebruikt om de locatie te specificeren van het bestand met de omgevingsvariabelen (.env) die door onze applicatie worden gebruikt.environment: gebruikt om extra omgevingsvariabelen te specificeren. In deze handleiding hebben we de variabeleMYSQL_DATABASEgespecificeerd om de databasenaam voor onze applicatie te bevatten. De databasenaam kan worden opgenomen in dedocker-compose.yml.volumes: gebruikt voor het specificeren van koppelingslocaties. In ons voorbeeld hebben we een benoemd volume genaamd dbdata gekoppeld aan de map/var/lib/mysqlop de container, wat meestal de standaard datamap is voor MySQL.command: deze richtlijn specificeert een commando dat de standaard CMD-instructie voor de image overschrijft. We hebben een optie toegevoegd aan het standaardmysqld-commando van de Docker-image dat de MySQL-server in de container start. De optie die we hebben toegevoegd is--default-authentication-plugin=mysql_native_password, die de standaard authenticatie-plug-in voor MySQL bijwerkt om wachtwoordauthenticatie te gebruiken (mysql_native_password). Dit is nodig om je PHP (WordPress-applicatie) te laten werken, omdat deze een gebruikersnaam en wachtwoord gebruiken om toegang te krijgen tot de database. In nieuwere MySQL-versies is de standaard authenticatie-plug-in gewijzigd. De meeste applicaties gebruiken echter wachtwoordauthenticatie. Daarom moet je deze instelling wijzigen om de applicatie te laten werken.networks: deze richtlijn wordt gebruikt om aan te geven dat dedb-service zich moet aansluiten bij hetapp-network, dat we in de loop van de handleiding zullen definiëren.
Vervolgens gaan we de serviceconfiguratie voor onze WordPress-applicatie definiëren. We noemen de service en container_name app. Voeg het volgende codefragment toe onder de db service-definitie, rekening houdend met de juiste inspringing:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#WordPress applicatiecode Service app: depends_on: - db image: wordpress:5.1.1-fpm-alpine container_name: app restart: unless-stopped env_file: .env environment: - WORDPRESS_DB_HOST=db:3306 - WORDPRESS_DB_USER=$MYSQL_USER - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD - WORDPRESS_DB_NAME=wordpress volumes: - app:/var/www/html networks: - app-network |
Net zoals we deden met de db service, hebben we onze container een naam gegeven en het herstartbeleid gedefinieerd. Enkele andere opties die we hebben toegevoegd, worden hieronder gedefinieerd:
depends_on: deze richtlijn zorgt ervoor dat containers worden gestart in volgorde van afhankelijkheid. In ons geval is deappcontainer afhankelijk van dedbcontainer. Daarom zal deze starten nadat dedbcontainer is gestart. Dit moet in deze volgorde gebeuren omdat de WordPress-app afhankelijk is van de beschikbaarheid van een MySQL-database om te kunnen functioneren.image: zoals te zien is in het codefragment, zullen we de WordPress versie 5.1.1 fpm alpine image gebruiken. We had al uitleg gegeven over dephp-fpmprocessor die Nginx vereist voor PHP-verwerking. Deze image regelt dat. De alpine image gebaseerd op het Alpine Linux-project helpt de imagegrootte kleiner te houden. Als je meer informatie wilt over image-variaties, kun je deze link volgen voor Docker Hub Wordpress-images.env_file: specificeert de locatie van het.envbestand dat de databasegegevens bevat.environment: deze richtlijn definieert aanvullende omgevingsvariabelen. In ons geval definiëren we de variabelen die WordPress verwacht en wijzen we ze de waarden toe van de variabelen uit ons.envbestand. Dit zijnWORDPRESS_DB_USER,WORDPRESS_DB_PASSWORD, enWORDPRESS_DB_HOSTdie verwijst naar de MySQL-server die draait op dedbcontainer, toegankelijk via de standaardpoort van MySQL3306. Ten slotte zie je deWORDPRESS_DB_NAMEdie we hebben ingesteld op wordpress. Dezelfde waarde is gespecificeerd in de MySQL-service-definitie in de db-container:MYSQL_DATABASE=wordpress.volumes: deze richtlijn koppelt een volume genaamd app aan het/var/www/htmlkoppelpunt, gemaakt door de WordPress-image. Door volumes een naam te geven, kan applicatiecode worden gedeeld met andere containers.networks: ten slotte voegen we de app-container toe aan hetapp-networkom ervoor te zorgen dat deze communiceert met andere containers op het netwerk.
Dat is alles voor de app servicecontainer voor de WordPress-image. Laten we nu de webserver service voor de Nginx-image definiëren. Voeg eerst het volgende codefragment toe onder de app-service-definitie in je docker-compose.yml bestand:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#Webserver Nginx-service webserver: depends_on: - app image: nginx:1.15.12-alpine container_name: webserver restart: unless-stopped ports: - "80:80" volumes: - app:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt networks: - app-network |
We hebben de optie depends_on al uitgelegd. In het geval van deze webserver service zal de container starten nadat de app container is gestart. De webservercontainer is gebaseerd op de alpine Nginx-image. Deze heeft een vergelijkbaar herstartbeleid als de vorige service-definities. De andere opties in de webserver-service-definitie zijn onder andere:
ports: bindt de poorten tussen de hostmachine en de container. In Stap 1, hadden we poort80in hetnginx.confbestand gedefinieerd. Deze poort is gekoppeld aan poort80op de container.volumes: we hebben een combinatie van bind mounts en benoemde volumes onder deze optie:app:/var/www/html: deze volume-definitie koppelt de WordPress-applicatie aan de/var/www/htmlmap die we eerder als root hadden ingesteld in het Nginx-serverblok../nginx-conf:/etc/nginx/conf.d: deze definitie koppelt de Nginx-configuratiemap op de hostmachine aan de Nginx-configuratiemap die we voor de container hebben gedefinieerd. Eventuele wijzigingen op de hostmachine worden dus automatisch doorgevoerd in de container.certbot-etc:/etc/letsencrypt: deze definitie koppelt de Let’s Encrypt-certificaten en -sleutels voor het domein aan de juiste map op de container.
networks: net als in de vorige service-definities voegt denetworksrichtlijn de webserver-service toe aan deapp-networks.
Nu we klaar zijn met de webserver-definitie, gaan we instructies toevoegen voor de Certbot-service. Deze zorgt voor het verkrijgen van je TLS/SSL-certificaten van Let’s Encrypt. Als je meer wilt weten over het beveiligen van een Nginx-server, is deze handleiding over hoe je Nginx beveiligt met Let’s Encrypt een goede bron.
Voeg vervolgens het volgende codefragment toe onder de webserver-service. Vergeet niet je juiste domeinnaam en e-mailadres in te stellen:
|
1 2 3 4 5 6 7 8 9 10 |
#certbot service certbot: depends_on: - webserver image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - app:/var/www/html command: certonly --webroot --webroot-path=/var/www/html --email hackins@cloudsigma.com --agree-tos --no-eff-email --staging -d example.com -d www.example.com |
De certbot image start pas nadat de webserver is gestart, vanwege de depends_on richtlijn. Docker Compose zal de Certbot-image van Docker Hub ophalen zoals gedefinieerd.
Onder de volumes-definitie zal de Certbot-container de domeincertificaten en -sleutel in certbot-etc delen met de Nginx webserver container en de applicatiecode met de app container.
Onder de command definitie hebben we een subcommando opgegeven om het standaard Certbot-certonly-commando van de container uit te voeren met aanvullende opties zoals hieronder vermeld:
-
--webroot: specificeert het gebruik van de webroot-plugin die bestanden in de webroot-map plaatst voor authenticatie.--webroot-path: specificeert het pad van de webroot-map.--agree-tos: specificeert dat je akkoord gaat met de Servicevoorwaarden van ACME.--no-eff-email: specificeert dat je je e-mailadres niet wilt delen met de EFF. Je kunt dit weglaten als je het wel wilt delen.--staging: vertelt Certbot dat je eerst testcertificaten wilt ophalen uit de staging-omgeving van Let’s Encrypt om je configuratie te testen voordat je het daadwerkelijke certificaat aanvraagt. Let’s Encrypt heeft een limiet op het aantal domeinaanvragen (rate limiting). Daarom helpt het eerst testen van je configuratie om te voorkomen dat je domein wordt beperkt.-d: deze optie neemt de domeinnamen voor de certificaataanvraag op. In deze handleiding hebben weexample.comenwww.example.com. Geef je daadwerkelijk geregistreerde domein op.
Ons docker-compose.yml bestand is bijna compleet. Je moet echter ook de netwerk- en volume-definities onder de Certbot-service toevoegen:
|
1 2 3 4 5 6 7 8 9 10 |
#Volumes volumes: certbot-etc: app: dbdata: #Netwerken networks: app-network: driver: bridge |
De volumes sleutel definieert de volumes die gedeeld moeten worden met alle services (containers) die in dit compose-bestand zijn gedefinieerd: certbot-etc, app, en dbdata. De inhoud van de volumes die Docker maakt, wordt opgeslagen in een map die door Docker wordt beheerd op het bestandssysteem van de host: /var/lib/docker/volumes/. De inhoud van elk volume wordt vervolgens gekoppeld aan elke container die het volume gebruikt. Dit maakt het mogelijk om gegevens en code te delen tussen containers.
De networkssleutel definieert het bridge-netwerk dat communicatie tussen containers mogelijk maakt. Containers op hetzelfde bridge-netwerk zoals webserver en db kunnen veilig communiceren via poorten zonder het verkeer bloot te stellen aan het externe netwerk. We stellen alleen poort 80 open om toegang te verlenen tot de front-end websitepagina's.
Het volledige docker-compose.yml bestand zal er als volgt uitzien:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
version: '3' services: #MySQL-service db: image: mysql:8.0 container_name: db restart: unless-stopped env_file: .env environment: - MYSQL_DATABASE=wordpress volumes: - dbdata:/var/lib/mysql command: '--default-authentication-plugin=mysql_native_password' networks: - app-network #WordPress applicatiecode-service app: depends_on: - db image: wordpress:5.1.1-fpm-alpine container_name: app restart: unless-stopped env_file: .env environment: - WORDPRESS_DB_HOST=db:3306 - WORDPRESS_DB_USER=$MYSQL_USER - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD - WORDPRESS_DB_NAME=wordpress volumes: - app:/var/www/html networks: - app-network #Webserver Nginx-service webserver: depends_on: - app image: nginx:1.15.12-alpine container_name: webserver restart: unless-stopped ports: - "80:80" volumes: - app:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt networks: - app-network #certbot-service certbot: depends_on: - webserver image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - app:/var/www/html command: certonly --webroot --webroot-path=/var/www/html --email hackins@cloudsigma.com --agree-tos --no-eff-email --staging -d example.com -d www.example.com #Volumes volumes: certbot-etc: app: dbdata: #Netwerken networks: app-network: driver: bridge |
Je kunt het bestand opslaan en sluiten. In de volgende stap zullen we de container en certificaataanvragen starten en testen.
Stap 4: De containers uitvoeren en SSL-certificaten verkrijgen
Het grootste voordeel van Docker Compose is dat, zodra je al je services hebt gedefinieerd in het docker-compose.yml -bestand kunt u alle containers met slechts één commando starten: docker-compose up. Het commando voert elke opgegeven instructie uit. Als de domeinaanvragen succesvol zijn, zou u de juiste exit-status in uw terminal moeten kunnen zien. Voer het volgende commando in om de containers aan te maken. De -d-vlag is voor het uitvoeren van de containers op de achtergrond:
|
1 |
docker-compose up -d |
Als u de uitvoer ziet zoals in de onderstaande schermafbeelding, dan zijn de services succesvol aangemaakt:
Om de status van de services te bevestigen, voert u het docker-compose ps-commando uit:
|
1 |
docker-compose ps |
De uitvoer van het commando is zoals hieronder weergegeven als alles succesvol was. De app, db, en webserver-containers moeten de status 'up' hebben, en de certbot-container moet de status Exit0 hebben:
Als u iets anders ziet dan Up in de statuskolom voor app, db of webserver, of een Exit-status die niet 0 is voor de certbot-container, dan is er iets misgegaan. U kunt de logs van elke container controleren met het commando docker-compose logs, en specificeer de service_name:
|
1 |
docker-compose logs service_name |
U kunt bijvoorbeeld de logs van de certbot-container controleren door het volgende commando in te voeren:
|
1 |
docker-compose logs certbot |
Om te controleren of de certificaten zijn gekoppeld aan de webserver-container, gebruikt u het docker-compose exec-commando:
|
1 |
docker-compose exec webserver ls -la /etc/letsencrypt/live |
Als u een daadwerkelijk geregistreerde domeinnaam heeft gebruikt in plaats van example.com en de certificaataanvragen succesvol waren, zou u een uitvoer moeten zien die vergelijkbaar is met deze:
Zodra u heeft bevestigd dat de certificaataanvraag succesvol was, kunt u het docker-compose.yml-bestand bewerken en de --staging-vlag verwijderen. Open het bestand met nano:
|
1 |
nano docker-compose.yml |
Scrol omlaag naar de sectie met de Certbot-service-definitie, in de command-optie en vervang de --staging-vlag door de --force-renewal-vlag. Dit vertelt Certbot dat u een certificaatverlenging aanvraagt voor een certificaat van hetzelfde domein. Uw Certbot-service-definitie zou er nu zo uit moeten zien:
|
1 2 3 4 5 6 7 8 9 10 |
#certbot service certbot: depends_on: - webserver image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - app:/var/www/html command: certonly --webroot --webroot-path=/var/www/html --email hackins@cloudsigma.com --agree-tos --no-eff-email --force-renewal -d example.com -d www.example.com |
Sla het bestand op als u klaar bent met bewerken.
Voer het volgende commando in om de certbot-container opnieuw aan te maken. De meegeleverde --no-deps-vlag vertelt Compose om het herstarten van de webserverservice over te slaan, aangezien deze al actief is:
|
1 |
docker-compose up --force-recreate --no-deps Certbot |
Het commando toont de volgende schermafbeelding, waaruit blijkt dat de certificaataanvraag succesvol was:
Dat is alles voor deze stap. In de volgende stap gaat u het Nginx-configuratiebestand aanpassen om het SSL-certificaat op te nemen.
Stap 5: SSL inschakelen in Nginx-configuratie en service-definitie
Om ervoor te zorgen dat Nginx verkeer via beveiligde SSL serveert, past u eerst het Nginx-configuratiebestand aan om een HTTP-omleiding naar HTTPS toe te voegen. Vervolgens moet u de locaties van het certificaat en de sleutel specificeren, en ten slotte beveiligingsparameters en headers toevoegen.
Voordat u het configuratiebestand wijzigt, moet u de aanbevolen Nginx-beveiligingsparameters ophalen uit de GitHub-repository van Certbot met behulp van curl met het volgende commando:
|
1 |
curl -sSLo nginx-conf/options-ssl-nginx.conf |
Het commando wordt uitgevoerd en slaat de parameters die het ophaalt op in een bestand genaamd options-ssl-nginx.conf, in de nginx-conf-map. Verwijder het Nginx-configuratiebestand zodat we een nieuwe kunnen maken met de volgende commando's:
|
1 2 |
rm nginx-conf/nginx.conf nano nginx-conf/nginx.conf |
In het nu lege nginx.conf-bestand voegt u de volgende code toe die een omleiding bevat van HTTP naar HTTPS, SSL-referentieprotocollen en beveiligingsheaders. Vervang, zoals u eerder hebt gedaan, het example.com-domein door uw eigen geregistreerde domein:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
server { listen 80; listen [::]:80; server_name example.com www.example.com; location ~ /.well-known/acme-challenge { allow all; root /var/www/html; } location / { rewrite ^ https://$host$request_uri? permanent; } } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name example.com www.example.com; index index.php index.html index.htm; root /var/www/html; server_tokens off; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; include /etc/nginx/conf.d/options-ssl-nginx.conf; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-XSS-Protection "1; mode=block" always; add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "no-referrer-when-downgrade" always; add_header Content-Beveiliging-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always; # add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; # activeer strict transport security alleen als je de implicaties begrijpt location / { try_files $uri $uri/ /index.php$is_args$args; } location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass app:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; } location ~ /\.ht { deny all; } location = /favicon.ico { log_not_found off; access_log off; } location = /robots.txt { log_not_found off; access_log off; allow all; } location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ { expires max; log_not_found off; } } |
In het eerste serverblok dat onbeveiligde verzoeken afhandelt via poort 80, specificeren we de webroot voor Certbot-verlengingsverzoeken. We voegen ook een redirect-instructie toe die HTTP-verzoeken omleidt naar HTTPS.
Het tweede serverblok handelt beveiligd HTTPS-verkeer af dat binnenkomt op poort 443. Zoals je kunt zien, schakelen we ook SSL en HTTP2 in. HTTP/2 verbetert de prestaties van je server. Je kunt hier meer over lezen in de officiële Nginx-documentatie over HTTP/2.
In dit blok hebben we ook aangegeven dat Nginx de locaties van het SSL-certificaat en de sleutel bevat, evenals de aanbevolen Certbot-beveiligingsparameters die curl heeft opgeslagen in de nginx-conf/options-ssl-nginx.conf-map.
De extra beveiligingsheaders dienen om de beoordelingen van je website te verbeteren op beveiligingstestsites zoals Security Headers en SSL Labs. Je kunt de links op deze headers volgen om meer te leren: X-Frame-Options, Referrer Policy, X-Content-Type-Options, X-XSS-Protection, Content-Security-Policy. We hebben de HTTP Strict Transport Security (HSTS)-header uitgecommentarieerd. Het staat je vrij om te lezen over de preload-functionaliteit ervan en te beslissen of je deze wilt inschakelen.
De rest van de richtlijnen zoals root, index, WordPress-specifieke locatieblokken blijven zoals besproken in Stap 1. Je kunt het bestand nu opslaan en sluiten als je klaar bent met bewerken.
Nu we HTTPS-verkeer hebben ingeschakeld dat poort 443, gebruikt, moeten we de poort ook inschakelen in de servicedefinitie van de webserver. Voer de volgende opdracht uit om het bestand docker-compose.yml te openen met nano:
|
1 |
nano docker-compose.yml |
Voeg in de webserversectie onder de optie ports een koppeling toe voor poort 443 zoals hieronder gemarkeerd:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
webserver: depends_on: - app image: nginx:1.15.12-alpine container_name: webserver restart: unless-stopped ports: - "80:80" - "443:443" volumes: - app:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt networks: - app-network |
Het volledige docker-compose.yml-bestand zou er nu zo uit moeten zien:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
version: '3' services: #MySQL-service db: image: mysql:8.0 container_name: db restart: unless-stopped env_file: .env environment: - MYSQL_DATABASE=wordpress volumes: - dbdata:/var/lib/mysql command: '--default-authentication-plugin=mysql_native_password' networks: - app-network #WordPress applicatiecode-service app: depends_on: - db image: wordpress:5.1.1-fpm-alpine container_name: app restart: unless-stopped env_file: .env environment: - WORDPRESS_DB_HOST=db:3306 - WORDPRESS_DB_USER=$MYSQL_USER - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD - WORDPRESS_DB_NAME=wordpress volumes: - app:/var/www/html networks: - app-network #Webserver Nginx-service webserver: depends_on: - app image: nginx:1.15.12-alpine container_name: webserver restart: unless-stopped ports: - "80:80" - "443:443" volumes: - app:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt networks: - app-network #certbot-service certbot: depends_on: - webserver image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - app:/var/www/html command: certonly --webroot --webroot-path=/var/www/html --email hackins@cloudsigma.com --agree-tos --no-eff-email --force-renewal -d example.com -d www.example.com #Volumes volumes: certbot-etc: app: dbdata: #Netwerken networks: app-network: driver: bridge |
Zodra u heeft gecontroleerd of alles er correct uitziet, slaat u het bestand op en sluit u het. Voer daarna de volgende opdracht uit om de webserver service opnieuw aan te maken:
|
1 |
docker-compose up -d --force-recreate --no-deps webserver |
|
1 |
docker-compose ps |
Nu al uw containers actief zijn, is het mogelijk om door te gaan met de WordPress-configuratie vanuit de webinterface.
Stap 6: Voltooi uw WordPress-configuratie vanuit de webinterface
Navigeer naar de domeinnaam van je server om de installatie voort te zetten. Je zou de WordPress-installatiestartpagina moeten zien. Deze verwelkomt je om je taal te kiezen voordat je verdergaat:
Kies je taal en klik op Doorgaan om naar de volgende pagina te gaan:
Vul op deze pagina de titel van je website in, kies een gedenkwaardige gebruikersnaam en een sterk wachtwoord. Het wordt om veiligheidsredenen aanbevolen om niet Admin als gebruikersnaam te gebruiken. Voer je e-mailadres in en klik op de knop WordPress installeren om de installatie van WordPress te starten.
Zodra de installatie is voltooid, word je naar het inlogscherm geleid waar je de gebruikersnaam en het wachtwoord invoert die je hebt ingesteld. Wanneer je de juiste inloggegevens invoert, zou je je WordPress-dashboard moeten zien:
Je hebt WordPress nu succesvol geïnstalleerd! Vervolgens moet je de stappen nemen om ervoor te zorgen dat de SSL-certificaten automatisch worden vernieuwd.
Stap 7: Automatische verlenging van SSL-certificaten configureren
Let’s Encrypt TLS/SSL-certificaten zijn slechts 90 dagen geldig. Het is aan jou om een automatische verlengingsconfiguratie te maken om ervoor te zorgen dat ze niet verlopen. Je kunt dit bereiken door een script te maken en dit in te plannen met het hulpprogramma cron job. In deze stap laten we je zien hoe je een script maakt dat de certificaten vernieuwt. We zullen dit vervolgens inplannen met het cron job-hulpprogramma om het periodiek uit te voeren en de certificaten te vernieuwen als ze de vervaldatum naderen.
Open in de projectmap wordpress_docker een script genaamd ssl_renewer.sh met nano:
|
1 |
nano ssl_renewer.sh |
Voeg de volgende code toe aan het script om de automatische verlenging en het opnieuw laden van de Nginx-configuratie af te handelen. Vergeet niet om de gemarkeerde gebruikersnaam te vervangen door je niet-root gebruikersnaam:
|
1 2 3 4 5 6 7 8 |
#!/bin/bash COMPOSE="/usr/local/bin/docker-compose –ansi never" DOCKER="/usr/bin/docker" cd /home/hackins/wordpress_docker/ $COMPOSE run certbot renew --dry-run && $COMPOSE kill -s SIGHUP webserver $DOCKER system prune -af |
In dit script wijzen we het docker-compose binaire bestand toe aan een variabele genaamd COMPOSE. We voegen ook de optie –ansi never toe, die het script vertelt om docker-compose-commando's uit te voeren zonder ANSI-besturingstekens. Verder wijzen we het Docker binaire bestand toe aan een variabele genaamd DOCKER.
Het script gaat vervolgens naar onze projectmap wordpress_docker en voert de volgende commando's uit:
docker-compose run: dit start de certbot-container en overschrijft het commando dat we in de certbot-servicedefinitie hadden opgegeven. In plaats van het subcommando certonly uit te voeren, voert het het subcommando renew uit, dat de SSL/TLS-certificaten van Let’s Encrypt zal vernieuwen als ze bijna verlopen.docker-compose kill: stuurt een SIGHUP-signaal naar dewebserver-container om de Nginx-configuraties opnieuw te laden. Misschien wil je deze handleiding van Docker bekijken over hoe je de officiële Nginx Docker-image gebruikt.docker system prune: dit commando verwijdert alle ongebruikte containers en images.
Sla het bestand op en sluit het wanneer je klaar bent met bewerken. Voer vervolgens het volgende commando uit om het uitvoerbaar te maken:
|
1 |
chmod +x ssl_renewer.sh |
Zodra je het uitvoerbaar hebt gemaakt, open je je root-crontab-bestand om het script periodiek uit te voeren met de intervallen die we zullen specificeren:
|
1 |
sudo crontab -e |
De crontab vraagt je om je voorkeurseditor te kiezen als dit de eerste keer is dat je deze gebruikt:
Kies je voorkeurseditor en druk op Enter om het bestand te openen. Voeg onderaan het bestand de volgende regel toe:
|
1 |
*/5 * * * * /home/hackins/wordpress_docker/ssl_renewer.sh >> /var/log/cron_docker.log 2>&1 |
Dit stelt het interval in op vijf minuten, zodat we kunnen testen of ons vernieuwingsscript werkt of niet. We hebben ook een logbestand gespecificeerd dat de uitvoer van de taak zal bevatten: cron_docker.log.
Wacht vijf minuten en controleer de cron.log om te zien of het script succesvol was met het vernieuwingsverzoek:
|
1 |
tail -f /var/log/cron_docker.log |
Je zou iets vergelijkbaars met de onderstaande schermafbeelding moeten zien als de verzoeken succesvol waren:
Nu we dit hebben getest en bevestigd dat het werkt, kun je het crontab-bestand aanpassen om een dagelijkse vernieuwing op te geven. Je wilt bijvoorbeeld opgeven dat het script elke dag om 18:00 uur wordt uitgevoerd. Pas daarvoor de laatste regel van de crontab aan zodat deze er als volgt uitziet:
|
1 |
0 18 * * * /home/hackins/wordpress_docker/ssl_renewer.sh >> /var/log/cron_docker.log 2>&1 |
Daarnaast moet je de –dry-run-vlag verwijderen uit het ssl_renewer.sh-script om ervoor te zorgen dat de daadwerkelijke vernieuwing plaatsvindt wanneer het wordt uitgevoerd. Het zou er als volgt uit moeten zien:
|
1 2 3 4 5 6 7 8 |
#!/bin/bash COMPOSE="/usr/local/bin/docker-compose --ansi never" DOCKER="/usr/bin/docker" cd /home/hackins/wordpress_docker/ $COMPOSE run certbot renew && $COMPOSE kill -s SIGHUP webserver $DOCKER system prune -af |
Sla vervolgens het bestand op en sluit het. Als je dat hebt gedaan, houdt de cron-taak je scripts geldig door ze te vernieuwen voordat de 90 dagen om zijn.
Conclusie
Als je tot hier in de handleiding bent gekomen, mag je jezelf een stap dichter bij een DevOps Engineer beschouwen. Je hebt een Nginx-configuratiescript kunnen maken, een docker-compose.yml-bestand gemaakt en verschillende services gedefinieerd die nodig zijn om een WordPress-applicatie uit te voeren met Docker en Docker Compose. Je hebt SSL/TLS-certificaten verkregen van Let’s Encrypt om ervoor te zorgen dat je webserver veilig is. Ten slotte heb je een cron-taak gemaakt om ervoor te zorgen dat de certificaten niet verlopen. Goed gedaan!
Als je je verder wilt verdiepen in DevOps, bekijk dan meer bronnen over containers van onze blog:
- Kennismaken met Kubernetes
- Hoe je een Node.js (Express.js) app implementeert met Docker op Ubuntu 20.04
- Een PHP-applicatie implementeren op een Kubernetes-cluster met Ubuntu 18.04.
- Laravel, Nginx en MySQL implementeren met Docker Compose
Veel computerplezier!










Reacties
Nog geen reacties. Wees de eerste.