Nginx, PHP-FPM und Let’s Encrypt per Docker-Compose aufsetzen
Um einen LAMDA Server einfach aufzusetzen, wie in meinem Fall auf Amazon EC2, geht es am Einfachsten mit Docker-Compose. Damit lassen sich die einzelnen Container schnell aktualisieren und System unabhängig betreiben.
Als Erstes installieren wir auf der neuen EC2 Instanz (ich verwende ein Ubuntu 18.4) gewisse Dinge:
apt update && apt upgrade apt install -y mysql-client curl python unzip
Ich installiere alles in das /opt Verzeichnis und erstelle dazu diverse weitere Verzeichnisse die benötigt werden:
mkdir -p /opt/www/cache /root/.aws /opt/www/log/certbot /opt/www/log/nginx /opt/www/log/php /opt/www/certbot/conf /opt/www/certbot/www
Jetzt installieren wir Docker und Docker-Compose.
apt-get install -y apt-transport-https ca-certificates gnupg-agent software-properties-common curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" apt-get update apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose
Als nächstes benötigen wir je nach gewünschten Diensten die Dockerfiles:
/opt/docker/php/Dockerfile:
FROM php:fpm-alpine RUN apk update && apk add --no-cache python sudo && docker-php-ext-install mysqli &&\ mkdir -p /var/log/php /etc/nginx/cache /root/scripts
/opt/docker/nginx/Dockerfile:
FROM nginx:alpine RUN apk update && apk add --no-cache logrotate &&\ mkdir -p /var/log/nginx /etc/nginx/cache /var/www/certbot
Die beiden Container müssen wir nun erstellen:
cd /opt/docker/nginx/ docker build --progress=plain -t my-nginx --force-rm -f Dockerfile . cd /opt/docker/php/ docker build --progress=plain -t my-php --force-rm -f Dockerfile .
Nun können bereits die Webdateien in das Verzeichnis /opt/www kopiert werden.
Leider startet der Nginx nicht ohne Zertifikate. Let’s Encrypt kann aber Zertifikate nur ausstellen bei lauffähigem Nginx. Daher erstellen wir einmalige Wegwerf-Self-Signed-Zertifikate für jede Domain die wir nutzen wollen:
openssl rand -writerand /root/.rnd mkdir -p /opt/www/certbot/conf/live/FULLDOMAINNAME openssl req -x509 -nodes -newkey rsa:1024 -days 90 -keyout '/opt/www/certbot/conf/live/FULLDOMAINNAME/privkey.pem' -out '/opt/www/certbot/conf/live/FULLDOMAINNAME/fullchain.pem' -subj '/CN=localhost' rm /root/.rnd
Wir erstellen folgendes Script /opt/www/certbot/conf/start.sh und ersetzen FULLDOMAINNAME wieder überall
if [ ! -d "/opt/www/certbot/conf/accounts" ]; then echo "No Lets Encrypt Account found, wait 5s and start getting Certifications..." sleep 5s mv /etc/letsencrypt/live/FULLDOMAINNAME /etc/letsencrypt/live/FULLDOMAINNAME-tmp certbot certonly --webroot -w /var/www/certbot --email marketing@sintratec.com --no-eff-email -d FULLDOMAINNAME --cert-name FULLDOMAINNAME --rsa-key-size 4096 --agree-tos --force-renewal --expand --allow-subset-of-names if [ ! -d "/etc/letsencrypt/live/staging.sintratec.com" ]; then mv /etc/letsencrypt/live/FULLDOMAINNAME-tmp /etc/letsencrypt/live/FULLDOMAINNAME.com else rm -R /etc/letsencrypt/live/FULLDOMAINNAME-tmp fi fi
Und geben ihm Ausführrechte:
chmod 740 /opt/www/certbot/conf/start.sh
Was nun noch fehlt, sind die Konfigurationsdateien, welche man hier für PHP und Nginx runterladen kann: etc.zip, was ins /opt Verzeichnis entpackt werden kann. Im Nginx sites/ Ordner, müssen noch die entsprechenden Domains eingetragen werden, welche ausgeliefert werden sollten (siehe FULLDOMAINNAME).
Jetzt erstellen wir noch die Datei /opt/docker-compose.yml mit folgendem Inhalt:
version: '3.2' services: php: container_name: php image: my-php:latest restart: always volumes: - type: bind source: /opt/www target: /var/www bind-propagation: rshared - type: bind source: /opt/etc/php target: /usr/local/etc bind-propagation: rshared - type: bind source: /opt/www/cache target: /etc/nginx/cache bind-propagation: rshared - type: bind source: /opt/www/log/php target: /var/log/php bind-propagation: rshared - type: bind source: /opt/scripts/client target: /root/scripts bind-propagation: rshared - type: bind source: /opt/git/etc/aws target: /root/.aws bind-propagation: private nginx: container_name: nginx image: my-nginx:latest ports: - "80:80" - "443:443" command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'" restart: always depends_on: - php volumes: - type: bind source: /opt/www target: /var/www bind-propagation: rshared - type: bind source: /opt/etc/nginx/conf.d target: /etc/nginx/conf.d bind-propagation: rshared - type: bind source: /opt/etc/nginx/sites target: /etc/nginx/sites bind-propagation: rshared - type: bind source: /opt/etc/nginx/cert target: /etc/nginx/cert bind-propagation: rshared - type: bind source: /opt/etc/nginx/nginx.conf target: /etc/nginx/nginx.conf bind-propagation: rshared - type: bind source: /opt/www/cache target: /etc/nginx/cache bind-propagation: rshared - type: bind source: /opt/www/log/nginx target: /var/log/nginx bind-propagation: rshared - type: bind source: /opt/www/certbot/conf target: /etc/letsencrypt bind-propagation: rshared - type: bind source: /opt/www/certbot/www target: /var/www/certbot bind-propagation: rshared certbot: container_name: certbot image: certbot/certbot restart: always depends_on: - nginx entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'" volumes: - type: bind source: /opt/www/certbot/conf target: /etc/letsencrypt bind-propagation: rshared - type: bind source: /opt/www/certbot/www target: /var/www/certbot bind-propagation: rshared - type: bind source: /opt/www/log/certbot target: /var/log/letsencrypt bind-propagation: rshared
Achtung, MySQL wird nicht mitgeliefert, kann aber einfach eingebaut werden.
Das Docker Konstrukt wird mit folgendem Befehl gestartet:
docker-compose -f /opt/docker-compose.yml up --force-recreate -d ; Startet Docker Container docker exec `docker ps -a -f name=certbot -q` /etc/letsencrypt/start.sh ; Let's Encrypt soll Zertifikate requesten docker exec `docker ps -a -f name=nginx -q` nginx -s reload ; Neue Zertifikate im Nginx laden
oder gestoppt:
docker-compose -f /opt/docker-compose.yml down ; Docker beenden docker ps -a | grep Exit | cut -d ' ' -f 1 | xargs sudo docker rm ; Falls Docker nicht sauber beenden, kann man sie damit löschen
Fehlerdateien sind im /opt/log der Container zu finden.