Ich habe eine skalierbare WordPress-Serverumgebung mit Trellis aufgesetzt, und das können Sie auch.

Avatar of Mat Gargano
Mat Gargano am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Vor ein paar Jahren begann meine aufstrebende Website-Designagentur Gestalt anzunehmen; wir hatten jedoch ein Problem: die Verwaltung der Webserver und Code-Deployments unserer Kunden. Wir konnten keinen optimierten Prozess für die Bereitstellung von Servern und die Wartung von Sicherheitspatches für das Betriebssystem aufbauen. Wir hatten den Entwicklungszyklus im Griff, aber die Serververwaltung wurde zur Plage unserer Arbeit. Wir benötigten auch eine genaue Kontrolle über jeden Server, abhängig von den spezifischen Anforderungen einer Website. Und nein, Shared Hosting war **nicht** die langfristige Lösung.

Ich begann nach einer vorgefertigten Lösung zu suchen, die dieses Problem lösen könnte, aber ohne besonderen Erfolg. Zuerst habe ich Server manuell bereitgestellt. Dieser Prozess erwies sich schnell als sowohl eintönig als auch fehleranfällig. Ich lernte schließlich Ansible und erstellte eine selbst entwickelte Ansammlung von benutzerdefinierten Ansible-Rollen, Bash-Skripten und Ansible Galaxy-Rollen, die den Prozess weiter vereinfachten – aber auch hier gab es noch viele manuelle Schritte, die unternommen werden mussten, bevor der Server zu 100 % einsatzbereit war.

Ich bin kein Server-Typ (und gebe auch nicht vor, einer zu sein), und zu diesem Zeitpunkt wurde offensichtlich, dass dieser Weg auf Dauer nicht gut enden würde. Ich nahm neue Kunden auf und benötigte eine Lösung, sonst riskiere ich unsere Fähigkeit, nachhaltig zu sein, ganz zu schweigen vom Wachstum. Ich verbrachte Unmengen von Zeit damit, willkürliche sudo apt-get update-Befehle in eine Shell einzugeben, während ich Kunden hätte betreuen oder Code schreiben sollen. Ganz zu schweigen davon, dass ich auch fortlaufende Sicherheitsupdates für das zugrunde liegende Betriebssystem und seine Anwendungen durchführte.

Sagen Sie mir, ob Ihnen das bekannt vorkommt.

Seriell, zu diesem Zeitpunkt, hatte das Team von Roots Trellis für die Serverbereitstellung veröffentlicht; nach dem Testen schienen die Dinge an ihren Platz zu fallen. Ein Bonus ist, dass Trellis auch komplexe Code-Deployments handhabt, was sich als etwas herausstellte, das ich ebenfalls benötigte, da die meisten Kunden-Websites und Webanwendungen, die wir bauten, einen *relativ* ausgeklügelten Build-Prozess für WordPress unter Verwendung von Composer, npm, webpack und mehr haben. Noch besser, es dauert nur wenige Minuten, um ein neues Projekt zu starten. Nachdem ich Hunderte von Stunden damit verbracht habe, meinen Bereitstellungsprozess mit Trellis zu perfektionieren, hoffe ich, Ihnen das Gelernte weiterzugeben und Ihnen all die Stunden der Recherche, der Versuche und der manuellen Arbeit zu ersparen, die ich letztendlich aufgewendet habe.

Eine Notiz zu Bedrock

Wir gehen davon aus, dass Ihr WordPress-Projekt Bedrock als Grundlage verwendet. Bedrock wird von denselben Leuten gepflegt, die auch Trellis pflegen, und ist ein "WordPress-Boilerplate mit modernen Entwicklungswerkzeugen, einfacherer Konfiguration und einer verbesserten Ordnerstruktur". Dieser Beitrag erklärt nicht explizit, wie Bedrock verwaltet wird, aber es ist ziemlich einfach einzurichten, worüber Sie in der Dokumentation lesen können. Trellis ist nativ darauf ausgelegt, Bedrock-Projekte bereitzustellen.

Eine Notiz dazu, was in das Repository einer WordPress-Website gehören sollte

Eines, das mir dieses gesamte Projekt gelehrt hat, ist, dass WordPress-Anwendungen typischerweise nur das Theme (oder das Child-Theme im Parent/Child-Theme-Verhältnis) sind. Alles andere, einschließlich Plugins, Bibliotheken, Parent-Themes und sogar WordPress selbst, sind nur Abhängigkeiten. **Das bedeutet, dass unsere Versionskontrollsysteme typischerweise nur das Theme enthalten sollten und wir Composer verwenden können, um alle Abhängigkeiten zu verwalten.** Kurz gesagt, kein Code, der woanders verwaltet wird, sollte jemals versioniert werden. Wir sollten eine Möglichkeit haben, dass Composer ihn während des Bereitstellungsprozesses abruft. Trellis gibt uns eine einfache und unkomplizierte Möglichkeit, dies zu erreichen.

Erste Schritte

Hier sind einige Dinge, die ich zukünftig voraussetze

  • Der Code für die neue Website im Verzeichnis ~/Sites/newsite
  • Die Staging-URL wird https://newsite.statenweb.com sein
  • Die Produktions-URL wird https://newsite.com sein
  • Bedrock dient als Grundlage für Ihre WordPress-Anwendung
  • Git wird für die Versionskontrolle verwendet und GitHub zum Speichern von Code. Das Repository für die Website ist: [email protected]:statenweb/newsite.git

Ich bin in meiner lokalen Entwicklungsumgebung etwas altmodisch und verzichte daher auf Vagrant für die lokale Entwicklung zugunsten von MAMP. Das Einrichten der lokalen Umgebung werden wir in diesem Artikel nicht behandeln.

Ich habe ein schnelles Start-Bash-Skript für MacOS eingerichtet, um dies noch weiter zu automatisieren.

Die beiden Hauptprojekte, die wir benötigen werden, sind Trellis und Bedrock. Wenn Sie dies noch nicht getan haben, erstellen Sie ein Verzeichnis für die Website (mkdir ~/Sites/newsite) und klonen Sie beide Projekte von dort. Ich klone Trellis in ein /trellis-Verzeichnis und Bedrock in das /site-Verzeichnis.

cd ~/Sites/newsite
git clone [email protected]:roots/trellis.git
git clone [email protected]:roots/bedrock.git site
cd trellis
rm -rf .git
cd ../site
rm -rf .git

Die letzten vier Zeilen ermöglichen es uns, alles korrekt zu versionieren. Wenn Sie Ihr Projekt versionieren, sollte das Repository alles in ~/Sites/newsite enthalten.

Gehen Sie nun in trellis und nehmen Sie folgende Änderungen vor

Öffnen Sie zuerst ~/Sites/newsite/trellis/ansible.cfg und fügen Sie diese Zeilen am Ende des Abschnitts [defaults] hinzu

vault_password_file = .vault_pass
host_key_checking = False

Die erste Zeile ermöglicht es uns, eine .vault_pass-Datei zu verwenden, um alle unsere vault.yml-Dateien zu verschlüsseln, die unsere Passwörter, sensiblen Daten und Salts speichern werden.

Die zweite Zeile host_key_checking = False kann aus Sicherheitsgründen weggelassen werden, da sie als etwas gefährlich angesehen werden könnte. Dennoch ist sie hilfreich, da wir die Überprüfung von Host-Schlüsseln nicht verwalten müssen (d.h. yes eingeben müssen, wenn wir dazu aufgefordert werden).

Ansible Vault-Passwort

Foto von Micah Williams auf Unsplash

Als Nächstes erstellen wir die Datei ~/Sites/newsite/trellis/.vault_pass und geben einen zufälligen Hash von 64 Zeichen ein. Wir können dafür einen Hash-Generator verwenden (siehe hier zum Beispiel). Diese Datei wird im Standard-.gitignore explizit ignoriert, sodass sie nicht in die Quellcodeverwaltung gelangt (oder gelangen sollte!). Ich speichere dieses Passwort an einem extrem sicheren Ort. Stellen Sie sicher, dass Sie chmod 600 .vault_pass ausführen, um den Zugriff auf diese Datei einzuschränken.

Der Grund dafür ist, dass wir verschlüsselte Passwörter im Versionskontrollsystem speichern können, ohne uns Gedanken über die Offenlegung von Servergeheimnissen machen zu müssen. Das Wichtigste, was hervorzuheben ist, ist, dass die .vault_pass-Datei nicht in das Repository committet wird (und auch nicht werden sollte) und dass die vault.yml-Datei ordnungsgemäß verschlüsselt ist; mehr dazu im Abschnitt "Verschlüsselung der geheimen Variablen" unten.

Einrichtung der Ziel-Hosts

Foto von N. auf Unsplash

Als Nächstes müssen wir unsere Ziel-Hosts einrichten. Der Ziel-Host ist die Webadresse, an die Trellis unseren Code bereitstellen wird. Für dieses Tutorial werden wir newsite.com als unseren Produktions-Ziel-Host und newsite.statenweb.com als unseren Staging-Ziel-Host konfigurieren. Um dies zu tun, aktualisieren wir zunächst die Produktionsserveradresse in der production-Hostdatei, die in ~/Sites/newsite/trellis/hosts/production gespeichert ist, zu

[production]
newsite.com

[web]
newsite.com

Als Nächstes können wir die Staging-Serveradresse in der staging-Hostdatei, die in ~/Sites/newsite/trellis/hosts/staging gespeichert ist, aktualisieren zu

[staging]
newsite.statenweb.com

[web]
newsite.statenweb.com

Einrichtung von GitHub SSH-Schlüsseln

Damit die Deployments erfolgreich sind, müssen die SSH-Schlüssel funktionieren. Trellis nutzt die Art und Weise, wie GitHub alle öffentlichen (SSH) Schlüssel verfügbar macht, sodass Sie keine Schlüssel manuell hinzufügen müssen. Um dies einzurichten, gehen Sie in group_vars/all/users.yml und aktualisieren Sie den Wert für die keys im web_user und im admin_user-Objekt, um Ihren GitHub-Benutzernamen einzufügen. Zum Beispiel:

users:
  - name: '{{ web_user }}'
        groups:
          - '{{ web_group }}'
        keys:
          - https://github.com/matgargano.keys
  - name: '{{ admin_user }}'
        groups:
          - sudo
        keys:
          - https://github.com/matgargano.keys

Natürlich setzt all dies voraus, dass Sie ein GitHub-Konto mit allen Ihren notwendigen öffentlichen Schlüsseln haben.

Website-Metadaten

Wir speichern wichtige Website-Informationen in

  • ~/Sites/newsite/trellis/group_vars/production/wordpress_sites.yml für die Produktion
  • ~/Sites/newsite/trellis/group_vars/staging/wordpress_sites.yml für Staging.

Aktualisieren wir die folgenden Informationen für unser Staging wordpress_sites.yml

wordpress_sites:
    newsite.statenweb.com:
        site_hosts:
          - canonical: newsite.statenweb.com
        local_path: ../site 
        repo: [email protected]:statenweb/newsite.git
        repo_subtree_path: site 
        branch: staging
        multisite:
            enabled: false
        ssl:
            enabled: true
            provider: letsencrypt
        cache:
            enabled: false

Diese Datei besagt, dass wir

  • die Website-Host-Weiterleitungen entfernt haben, da sie für Staging nicht benötigt werden
  • die kanonische Website-URL (newsite.statenweb.com) für den Website-Schlüssel (newsite.statenweb.com) festgelegt haben
  • die URL für das Repository definiert haben
  • der Git-Repo-Branch, der auf dieses Ziel bereitgestellt wird, ist staging, d.h. wir verwenden einen separaten Branch namens staging für unsere Staging-Website
  • SSL aktiviert haben (auf true gesetzt), was auch ein SSL-Zertifikat installiert, wenn die Box provisioniert wird

Aktualisieren wir die folgenden Informationen für unser Produktions-wordpress_sites.yml

wordpress_sites:
    newsite.com:
        site_hosts:
          - canonical: newsite.com
                redirects:
                  - www.newsite.com
        local_path: ../site # path targeting local Bedrock site directory (relative to Ansible root)
        repo: [email protected]:statenweb/newsite.git
        repo_subtree_path: site 
        branch: master
        multisite:
            enabled: false
        ssl:
            enabled: true
            provider: letsencrypt
        cache:
            enabled: false

Auch hier bedeutet das, dass wir

  • die kanonische Website-URL (newsite.com) für den Website-Schlüssel (newsite.com) festgelegt haben
  • eine Weiterleitung für www.newsite.com eingerichtet haben
  • die URL für das Repository definiert haben
  • der Git-Repo-Branch, der auf dieses Ziel bereitgestellt wird, ist master, d.h. wir verwenden einen separaten Branch namens master für unsere Produktions-Website
  • SSL aktiviert haben (auf true gesetzt), was ein SSL-Zertifikat installiert, wenn Sie die Box provisionieren

In der wordpress_sites.yml können Sie Ihren Server weiter mit Caching konfigurieren, was über den Rahmen dieser Anleitung hinausgeht. Sehen Sie sich die Trellis-Dokumentation zu FastCGI-Caching für weitere Informationen an.

Geheime Variablen

Foto von Kristina Flour auf Unsplash

Es wird mehrere geheime Informationen für unsere Staging- und Produktions-Website geben, darunter das Root-Benutzerpasswort, das MySQL-Root-Passwort, Site-Salts und mehr. Wie bereits erwähnt, erleichtert Ansible Vault und die Verwendung der .vault_pass-Datei dies enorm.

Wir speichern diese geheimen Website-Informationen in

  • ~/Sites/newsite/trellis/group_vars/production/vault.yml für die Produktion
  • ~/Sites/newsite/trellis/group_vars/staging/vault.yml für Staging

Aktualisieren wir die folgenden Informationen für unser Staging vault.yml

vault_mysql_root_password: pK3ygadfPHcLCAVHWMX

vault_users:
    - name: "{{ admin_user }}"
        password: QvtZ7tdasdfzUmJxWr8DCs
        salt: "heFijJasdfQbN8bA3A"

vault_wordpress_sites:
    newsite.statenweb.com:
        env:
            auth_key: "Ab$YTlX%:Qt8ij/99LUadfl1:U]m0ds@N<3@x0LHawBsO$(gdrJQm]@alkr@/sUo.O"
            secure_auth_key: "+>Pbsd:|aiadf50;1Gz;.Z{nt%Qvx.5m0]4n:L:h9AaexLR{1B6.HeMH[w4$>H_"
            logged_in_key: "c3]7HixBkSC%}-fadsfK0yq{HF)D#1S@Rsa`i5aW^jW+W`8`e=&PABU(s&JH5oPE"
            nonce_key: "5$vig.yGqWl3G-.^yXD5.ddf/BsHx|i]>h=mSy;99ex*Saj<@lh;3)85D;#|RC="
            auth_salt: "Wv)[t.xcPsA}&/]rhxldafM;h(FSmvR]+D9gN9c6{*hFiZ{]{,#b%4Um.QzAW+aLz"
            secure_auth_salt: "e4dz}_x)DDg(si/8Ye&U.p@pB}NzHdfQccJSAh;?W)>JZ=8:,i?;j$bwSG)L!JIG"
            logged_in_salt: "DET>c?m1uMAt%hj3`8%_emsz}EDM7R@44c0HpAK(pSnRuzJ*WTQzWnCFTcp;,:44"
            nonce_salt: "oHB]MD%RBla*#x>[UhoE{hm{7j#0MaRA#fdQcdfKe]Y#M0kQ0F/0xe{cb|g,h.-m"

Aktualisieren wir nun die folgenden Informationen für unser Produktions-vault.yml

vault_mysql_root_password: nzUMN4zBoMZXJDJis3WC
vault_users:
    - name: "{{ admin_user }}"
        password: tFxea6ULFM8CBejagwiU
        salt: "9LgzE8phVmNdrdtMDdvR"
vault_wordpress_sites:
    newsite.com:
        env:
            db_password: eFKYefM4hafxCFy3cash
            # Generate your keys here: https://roots.io/salts.html
            auth_key: "|4xA-:Pa=-rT]&!-(%*uKAcdix_Uv,`/(7dk1+;b|ql]42gh&HPFdDZ@&of"
            secure_auth_key: "171KFFX1ztl+1I/P$bJrxi*s;}.>S:{^-=@*2LN9UfalAFX2Nx1/Q&i&LIrI(BQ["
            logged_in_key: "5)F+gFFe}}0;2G:k/S>CI2M*rjCD-mFX?Pw!1o.@>;?85JGu}#(0#)^l}&/W;K&D"
            nonce_key: "5/[Zf[yXFFgsc#`4r[kGgduxVfbn::<+F<$jw!WX,lAi41#D-Dsaho@PVUe=8@iH"
            auth_salt: "388p$c=GFFq&hw6zj+T(rJro|V@S2To&dD|Q9J`wqdWM&j8.KN]y?WZZj$T-PTBa"
            secure_auth_salt: "%Rp09[iM0.n[ozB(t;0vk55QDFuMp1-=+F=f%/Xv&7`_oPur1ma%TytFFy[RTI,j"
            logged_in_salt: "dOcGR-m:%4NpEeSj>?A8%x50(d0=[cvV!2x`.vB|^#G!_D-4Q>.+1K!6FFw8Da7G"
            nonce_salt: "rRIHVyNKD{LQb$uOhZLhz5QX}P)QUUo!Yw]+@!u7WB:INFFYI|Ta5@G,j(-]F.@4"

Die wesentlichen Zeilen für beide sind, dass

  • Der Website-Schlüssel muss mit dem Schlüssel in wordpress_sites.yml übereinstimmen. Wir verwenden newsite.statenweb.com: für Staging und newsite.com: für Produktion.
  • Ich habe vault_mysql_root_password, password, salt, db_password und db_password zufällig generiert. Ich habe Roots' Helfer zur Generierung der Salts verwendet.

Ich verwende typischerweise die SMTP-Server von Gmail mit dem Post SMTP-Plugin, daher muss ich die ~/Sites/newsite/group_vars/all/vault.yml nicht bearbeiten.

Verschlüsselung der geheimen Variablen

Foto von Markus Spiske auf Unsplash

Wie bereits erwähnt, verwenden wir Ansible Vault, um unsere vault.yml-Dateien zu verschlüsseln. Hier erfahren Sie, wie Sie die Dateien verschlüsseln und sie für die Speicherung in unserem Versionskontrollsystem vorbereiten können.

cd ~/Sites/newsite/trellis
ansible-vault encrypt group_vars/staging/vault.yml group_vars/production/vault.yml

Wenn wir nun entweder ~/Sites/newsite/trellis/group_vars/staging/vault.yml oder ~/Sites/newsite/trellis/group_vars/production/vault.yml öffnen, erhalten wir nur wirres Zeug. Dies kann sicher in einem Repository gespeichert werden, da die einzige Möglichkeit, es zu entschlüsseln, die Verwendung der .vault_pass ist. Es versteht sich von selbst, dass Sie sicherstellen müssen, dass die .vault_pass selbst nicht in das Repository committet wird.

Eine Notiz zu Kompilierung, Transpilierung usw.

Eine weitere Sache, die nicht zum Umfang gehört, ist die Einrichtung von Trellis-Deployments zur Handhabung eines Build-Prozesses mit Build-Tools wie npm und webpack. Dies ist ein Beispielcode zur Handhabung eines benutzerdefinierten Builds, der in ~/Sites/newsite/trellis/deploy-hooks/build-before.yml enthalten sein könnte.

---

-
    args:
        chdir: "{{ project.local_path }}/web/app/themes/newsite"
    command: "npm install"
    connection: local
    name: "Run npm install"

-
    args:
        chdir: "{{ project.local_path }}/web/app/themes/newsite"
    command: "npm run build"
    connection: local
    name: "Compile assets for production"

-
    name: "Copy Assets"
    synchronize:
        dest: "{{ deploy_helper.new_release_path }}/web/app/themes/newsite/dist/"
        group: no
        owner: no
        rsync_opts: "--chmod=Du=rwx,--chmod=Dg=rx,--chmod=Do=rx,--chmod=Fu=rw,--chmod=Fg=r,--chmod=Fo=r"
        src: "{{ project.local_path }}/web/app/themes/newsite/dist/"

Dies sind Anweisungen, die Assets erstellen und sie in ein Verzeichnis verschieben, das ich explizit nicht versionieren wollte. Ich hoffe, in einem zukünftigen Beitrag darauf eingehen zu können, der sich speziell damit beschäftigt.

Provisionierung

Foto von Bill Jelen auf Unsplash

Ich werde nicht im Detail auf die Einrichtung der Server selbst eingehen, aber normalerweise gehe ich zu DigitalOcean und starte einen neuen Droplet. Zum Zeitpunkt der Erstellung dieses Artikels ist Trellis auf Ubuntu 18.04 LTS (Bionic Beaver) geschrieben, das als Produktionsserver dient. In diesem Droplet würde ich einen öffentlichen Schlüssel hinzufügen, der auch in meinem GitHub-Konto enthalten ist. Zur Vereinfachung kann ich denselben Server als meinen Staging-Server verwenden. Dieses Szenario ist wahrscheinlich nicht das, was Sie verwenden würden; vielleicht verwenden Sie einen einzelnen Server für all Ihre Staging-Sites. Wenn das der Fall ist, sollten Sie auf die Passwörter achten, die in ~/Sites/newsite/trellis/group_vars/staging/vault.yml konfiguriert sind.

Auf DNS-Ebene würde ich den nackten A-Record für newsite.com auf die IP-Adresse des neu erstellten Droplets abbilden. Dann würde ich den CNAME www auf @ abbilden. Zusätzlich würde der A-Record für newsite.statenweb.com auf die IP-Adresse des Droplets abgebildet werden (oder alternativ könnte ein CNAME-Record für newsite.statenweb.com auf newsite.com erstellt werden, da beide in diesem Beispiel auf derselben Maschine laufen).

Nachdem die DNS-Propagierung, die einige Zeit dauern kann, abgeschlossen ist, kann die Staging-Box mit den folgenden Befehlen provisioniert werden.

Zunächst muss man möglicherweise Folgendes ausführen, bevor etwas anderes geschieht

ansible-galaxy install -r requirements.yml

Installieren Sie dann die erforderlichen Ansible Galaxy-Rollen, bevor Sie fortfahren.

cd ~/Sites/newsite/trellis
ansible-playbook server.yml -e env=staging

Als Nächstes, provisionieren Sie die Produktions-Box.

cd ~/Sites/newsite/trellis
ansible-playbook server.yml -e env=production

Deployment

Wenn alles korrekt eingerichtet ist, können wir um zu Staging zu deployen diese Befehle ausführen.

cd ~/Sites/newsite/trellis
ansible-playbook deploy.yml -e "site=newsite.statenweb.com env=staging" -i hosts/staging

Und nachdem dies abgeschlossen ist, rufen Sie https://newsite.statenweb.com auf. Dies sollte Sie zur WordPress-Installationsaufforderung bringen, die Ihnen die nächsten Schritte zur Vervollständigung der Website-Einrichtung bietet.

Wenn Staging bereit ist, können wir die folgenden Befehle ausführen, um die Produktion zu deployen.

cd ~/Sites/newsite/trellis
ansible-playbook deploy.yml -e "site=newsite.com env=production" -i hosts/production

Und wie bei Staging sollte auch dies Installationsschritte zur Vervollständigung anzeigen, wenn Sie https://newsite.com aufrufen.

Gehen Sie voran und deployen Sie!

Hoffentlich gibt Ihnen dies eine Antwort auf eine Frage, mit der ich mich persönlich auseinandersetzen musste, und spart Ihnen eine Menge Zeit und Kopfzerbrechen. Stabile, sichere und skalierbare Serverumgebungen, die relativ wenig Aufwand zum Hochfahren erfordern, haben einen großen Unterschied in der Arbeitsweise unseres Teams und in der Art und Weise, wie wir die Bedürfnisse unserer Kunden erfüllen können, gemacht.

Obwohl wir technisch gesehen an diesem Punkt fertig sind, gibt es noch weitere Schritte, um Ihre Umgebung vollständig abzuschließen.

  • Fügen Sie Abhängigkeiten wie Plugins, Bibliotheken und Parent-Themes zu ~/Sites/newsite/composer.json hinzu und führen Sie composer update aus, um die neuesten Manifestversionen abzurufen.
  • Platzieren Sie das Theme in ~/Sites/newsite/site/themes/. (Beachten Sie, dass jedes WordPress-Theme verwendet werden kann.)
  • Integrieren Sie alle Build-Prozesse, die Sie benötigen (z. B. Transpilierung von ES6, Kompilierung von SCSS usw.), in einen der Deployment-Hooks. (Siehe die Dokumentation für Trellis Hooks).

Ich konnte mich auch mit Enterprise-Level Continuous Integration und Continuous Delivery sowie mit der Handhabung von Premium-Plugins mit Composer durch den Betrieb eines benutzerdefinierten Composer-Servers beschäftigen, unter anderem, ohne zusätzliche Kosten. Hoffentlich sind das Bereiche, auf die ich in zukünftigen Beiträgen eingehen kann.

Trellis bietet eine sehr einfache Möglichkeit, WordPress-Server bereitzustellen. Dank Trellis sind die Tage des manuellen Erstellens, Patchens und Wartens von Servern längst vorbei!