Skip to content

Instantly share code, notes, and snippets.

@c4y
Last active January 4, 2024 16:50
Show Gist options
  • Save c4y/3f2dafc30c6f3b12beddef00417dd738 to your computer and use it in GitHub Desktop.
Save c4y/3f2dafc30c6f3b12beddef00417dd738 to your computer and use it in GitHub Desktop.
Entwicklungsumgebung

Allgemeines

Auf der Suche nach der "perfekten" Entwicklungsumgebung für die Webentwicklung habe ich mir meine eigene Lösung gebaut.

Folgende Ziele waren mir dabei wichtig:

  • Nutzung eines Linux-Servers
  • Einsatz von Docker (Compose)
  • keine manuelle Änderung an DNS Einträgen
  • keine manuelle Konfiguration von vHost Einträgen
  • mehrere PHP Versionen parallel (über Port-Angaben)
  • MailHog als E-Mail-Server
  • lokales Entwickeln (Remote SSH per VS Code)
  • "Freischalten" der Seiten, um sie öffentlich erreichbar zu machen
  • schnell muss es sein :-)
  • automatische Backups

Mein aktueller Workflow:

  • mit VS Code Remote/SSH auf den Server verbinden
  • Ordner erstellen, z.B. contao-test
  • im Terminal composer create-project contao/managed-edition . 4.13 ausführen
  • 2 Sekunden!! warten
  • fertig :-)
  • Contao ist nun schon unter contao.local.contao4you.de erreichbar (nur lokal)
    bzw. für PHP 7.4 unter contao.dev.contao4you.de:8074

Da ich mit drei verschiedenen Endgeräten arbeite (Macbook, Windows-Notebook und ein Windows-Desktop) habe ich jetzt überall den gleichen Entwicklungsstand. Ich muss keine "Zwischenversionen" auf einem Entwicklungsserver deployen, etc.

Homeserver

Im Prinzip reicht jede x-beliebige Linux-Kiste. Um das ganze komfortabel (und schnell) zu gestalten, habe ich mich für einen "fetten" i5 mit 64 GB RAM und einer SSD mit 8 GB/s entschieden. Ist so ein netter Cube und steht im Regal :-) Eingesetzt habe ich Ubuntu und darauf Proxmox. In Proxmox habe ich dann für die Entwicklung einen Ubuntu-Container erstellt mit Docker, Portainer und SMB. In einem zweiten Container habe ich per Docker den nginx Proxy Manager installiert. Und nur mal so nebenbei: ich wüsste gar nicht, wie ich früher ohne Proxmox leben konnte.

Verzeichnisstruktur

Ich nutze die folgende Verzeichnisstruktur, um ein paar Configs abzulegen bzw. mit docker-compose einzubinden:

/var/www/bin/backup.sh
/var/www/database_backups
/var/www/html
/var/www/mysql/config.cnf
/var/www/nginx/nginx-conf/nginx.conf
/var/www/php/74/php.ini
/var/www/php/74/www.conf
/var/www/php/74/xdebug.ini
/var/www/php/81/php.ini
/var/www/php/81/www.conf
/var/www/php/81/xdebug.ini
/var/www/php/php81-fpm-docker
/var/www/docker-compose.yml
/var/www/rsync-excludes

(beim nächsten Mal würde ich vermutlich einiges unter /var/www/configs zusammenfassen...)

docker-compose

In meinem Fall habe ich alle Dateien (Configs) in /var/www angelegt. Mit docker-compose up -d werden die Container gestartet.

Die PHP Images baue ich selbst.

DNS

Um nicht für jede Domain einen Eintrag in eine hosts-Datei vornehmen zu müssen, habe ich zwei Wildcard-Domains zu meiner Domain eingerichtet:

*.local.contao4you.de => 192.168.1.7 (Homeserver) *.dev.contao4you.de => IP-Adresse meiner FritzBox (Portweiterleitung auf die 192.168.1.8)

Das erspart mit die manuelle Konfiguration eines DNS Servers sowie die Anpassung von DNS Einträgen an meinen Notebooks bzw. der FritzBox.

nginx Proxy Manager

Auf 192.168.1.8 (bei mir) läuft ein nginx Proxy Manager (Proxmox Container bzw. Portainer). Sobald ich die Domain hier eintrage, ist sie öffentlich erreichbar:

contao.dev.contao4you.de (Standard PHP Version) oder contao.dev.contao4you.de:8074 (für z.B. PHP 7.4)

Und mit einem Klick sind alle Domains per Lets-Encrypt per SSL abgesichert.

Und mit Visual Studio Code lässt es sich per SSH Remote so entwickeln, als wäre alles lokal installiert.

MailHog

Ist in meinem Beispiel unter 192.168.1.7:8025 erreichbar.

Backup

Für mein Backup nutze ich einen herkömmlichen Cron-Job und rsync. Als Speicher nutze ich eine Storagebox von Hetzner. Einfach die bin/backup.sh z.B. alle vier Stunden ausführen.

In der Storagebox können tägliche Snapshots aktiviert werden. Somit sind auch die letzten 7 Tage kein Problem.

#bin/backup.sh
```
#!/bin/bash
set -e
# SSH_SERVER=
WEB_FOLDER=/var/www/html
DB_FOLDER=/var/www/database_backups
MYSQL_USER=root
MYSQL_PASSWORD=olli
MYSQLDUMP=/usr/bin/mysqldump
MYSQL=/usr/bin/mysql
# Sichern der Datenbanken
backup_db() {
if [ -d "$DB_FOLDER" ]; then
rm -R $DB_FOLDER
fi
mkdir $DB_FOLDER
databases=`$MYSQL --defaults-extra-file=/var/www/mysql/config.cnf -e "SHOW DATABASES;" | grep -Ev "(Database|information_schema|performance_schema|mysql)"`
for db in $databases; do
$MYSQLDUMP --defaults-extra-file=/var/www/mysql/config.cnf --force --opt --column-statistics=0 --databases $db | gzip > "$DB_FOLDER/$db.sql.gz"
done
}
catch() {
# echo -e "Subject: Backup-Fehler\nFehler in Zeile $1" #| msmtp [email protected]
if [ "$1" != "0" ]; then
echo "Error $1 occurred on $2"
fi
}
echo `date +"%y%m%d-%H%M%S Datenbank Dumps werden erzeugt"` > /var/www/backup.log 2>&1
backup_db
echo `date +"%y%m%d-%H%M%S Die Webseiten werden gesichert"` >> /var/www/backup.log 2>&1
rsync -avz -e 'ssh -p23' --delete --exclude-from=/var/www/rsync-excludes /var/www/html/ [email protected]:/home/backups/html
echo `date +"%y%m%d-%H%M%S Die Datenbanken werden gesichert"` >> /var/www/backup.log 2>&1
rsync -avz -e 'ssh -p23' --delete /var/www/database_backups/ [email protected]:/home/backups/databases/
echo `date +"%y%m%d-%H%M%S Sicherung erfolgreich beendet"` >> /var/www/backup.log 2>&1
```
```yml
version: '3.8'
services:
# Nginx Service
nginx:
image: nginx:latest
ports:
- 80:80
- 8074:8074
links:
- 'php81'
- 'php74'
volumes:
- ./html:/var/www/html
- ./nginx/nginx-conf/nginx.conf:/etc/nginx/conf.d/nginx.conf
depends_on:
- php81
restart: always
# PHP Service
php81:
build:
context: ./php
dockerfile: php81-fpm-docker
volumes:
- './html:/var/www/html'
- './php/81/php.ini:/usr/local/etc/php/php.ini'
- './php/81/www.conf:/usr/local/etc/php-fpm.d/www.conf'
- './php/81/xdebug.ini:/usr/local/etc/php/conf.d/xdebug.ini'
depends_on:
- mariadb
restart: always
# PHP Service
php74:
build:
context: ./php
dockerfile: php74-fpm-docker
volumes:
- './html:/var/www/html'
- './php/74/php.ini:/usr/local/etc/php/php.ini'
- './php/74/www.conf:/usr/local/etc/php-fpm.d/www.conf'
- './php/74/xdebug.ini:/usr/local/etc/php/conf.d/xdebug.ini'
#expose:
#- 9003
depends_on:
- mariadb
restart: always
# MariaDB Service
mariadb:
image: mariadb:10.9
ports:
- 3306:3306
environment:
MYSQL_ROOT_PASSWORD: olli
volumes:
- mysqldata:/var/lib/mysql
restart: always
# Mailhog
mailhog:
image: mailhog/mailhog
ports:
- 1025:1025
- 8025:8025
restart: always
# Volumes
volumes:
mysqldata:
```
#nginx/nginx-conf/nginx.conf
```
#user olli olli
server {
listen 80;
server_name ~^(?<projekt>.+)\..*\.contao4you.de$;
root /var/www/html/$projekt/public;
index index.php index.html;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
client_max_body_size 64M;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ ^/(preview|contao-manager\.phar)\.php(/|$) {
fastcgi_pass php81:9000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
include fastcgi_params;
}
location ~ \.php$ {
fastcgi_pass php81:9000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
include fastcgi_params;
#internal;
}
location = /favicon.ico {
log_not_found off;
access_log off;
try_files $uri /index.php$is_args$args;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
log_not_found off;
try_files $uri /index.php$is_args$args;
}
#error_log /var/www/logs/nginx_error.log;
#access_log /var/www/logs/nginx_access.log;
}
server {
listen 8074;
server_name ~^(?<projekt>.+)\..*\.contao4you.de$;
root /var/www/html/$projekt/public;
index index.php index.html;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
client_max_body_size 64M;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ ^/(preview|contao-manager\.phar)\.php(/|$) {
fastcgi_pass php74:9000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
include fastcgi_params;
}
location ~ \.php$ {
fastcgi_pass php74:9000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
include fastcgi_params;
#internal;
}
location = /favicon.ico {
log_not_found off;
access_log off;
try_files $uri /index.php$is_args$args;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
log_not_found off;
try_files $uri /index.php$is_args$args;
}
}
```
#php/81/php.ini
```
[www]
user = olli
listen .owner = olli
```
#php/php81-fpm-docker
```
FROM php:8.1-fpm
RUN groupadd -g 1000 olli
RUN useradd -d /home/olli -s /bin/bash -u 1000 -g 1000 olli
RUN mkdir /home/olli
RUN chown -R olli /var/www/html
# Installing dependencies for the PHP modules
RUN apt-get update && \
apt-get install -y zip gettext openssl libzip-dev libpng-dev libicu-dev libjpeg-dev libjpeg62-turbo-dev libxml2-dev libwebp-dev libfreetype6-dev libgd-dev
# Installing additional PHP modules
RUN docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp
RUN docker-php-ext-install gd
RUN docker-php-ext-install mysqli pdo pdo_mysql zip
RUN docker-php-ext-configure intl
RUN docker-php-ext-install intl
RUN pecl install xdebug-3.1.6 && docker-php-ext-enable xdebug
```
```
.git
assets
public
system/cache
system/themes
system/logs
system/tmp
var
vendor
web
node_modules
```
#php/81/www.conf
```
[www]
user = olli
group = olli
listen = 9000
listen.owner = olli
listen.group = olli
```
#php/81/xdebug.ini
```
zend_extension=xdebug
[xdebug]
xdebug.mode = debug
xdebug.start_with_request=yes
xdebug.client_port=9003
xdebug.remote_autostart = 0
xdebug.client_host = 192.168.1.7
```
@Moongazer
Copy link

Was DDEV not an option? For development everything works just out-of-the-box in <60 seconds.

@c4y
Copy link
Author

c4y commented Jan 4, 2024

I have to ddev start for each project? And a new Database (and so on) Container for each Project? I don't like that. In my Environment i have to setup everything once. Ok, that's a bit of work. But it's worth the work (in my opinion). After that, you doesn't to configure anything. Everything works out of the box. And you have ONE Database, ONE PHP 8.1 Container and so on.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment