Zurück zum Blog

Deployment mit Git: Automatisch auf den Server veröffentlichen

Deployment mit Git: Deploy Key einrichten, Deploy-Skript schreiben, automatisches Deployment mit GitHub Actions, eigener Benutzer, Secrets und Rollback.

Nodesty-Team6 Min. LesezeitServer
Der Schriftzug Git Deploy mit SSH, Actions und Rollback auf dunklem Nodesty-Hintergrund

Deployment mit Git bedeutet, den Code Ihrer Anwendung nicht von Hand per FTP auf den Server hochzuladen, sondern ihn aus einem Git-Repository zu holen und so zu veröffentlichen. Im einfachsten Fall führen Sie auf dem Server git pull aus und starten die Anwendung neu; einen Schritt weiter erledigt ein Werkzeug wie GitHub Actions das für Sie, sobald Sie Code in den Hauptbranch pushen. Da jede Veröffentlichung einem Commit entspricht, wissen Sie jederzeit, was auf dem Server läuft, und kehren bei einem Problem in Sekunden zurück.

In dieser Anleitung zeigen wir, wie Sie dem Server einen Deploy Key hinzufügen, ein Deploy-Skript schreiben, automatisches Deployment mit GitHub Actions einrichten, welche Sicherheitsmaßnahmen sinnvoll sind und wie ein Rollback funktioniert.

Warum Deployment mit Git?

  • Reproduzierbarkeit: Jede Veröffentlichung läuft mit denselben Schritten ab; das Problem „Diesmal habe ich diese Datei vergessen“ gibt es nicht mehr.
  • Nachvollziehbarkeit: Welcher Commit auf dem Server läuft, sehen Sie mit git log -1.
  • Einfacher Rollback: Nach einer fehlerhaften Veröffentlichung kehren Sie mit einem einzigen Befehl zur vorherigen Version zurück.
  • Teamarbeit: Alle pushen ihren Code ins Repository; den Server fasst nur der Deployment-Prozess an.

Schritt 1: Ein eigener Deploy-Benutzer

Führen Sie Anwendung und Deployment-Prozess nicht als root aus, sondern mit einem eigenen Benutzer. Nachdem Sie sich per SSH mit Ihrem Server verbunden haben:

sudo adduser deploy
sudo mkdir -p /var/www/app
sudo chown deploy:deploy /var/www/app
sudo su - deploy

Schritt 2: Deploy Key

Damit der Server Code aus dem Repository holen kann, erzeugen Sie einen Deploy Key, der nur auf dieses eine Repository zugreifen kann:

ssh-keygen -t ed25519 -f ~/.ssh/deploy_key -N "" -C "deploy@server"
cat ~/.ssh/deploy_key.pub

Fügen Sie den öffentlichen Schlüssel auf GitHub im Repository unter Settings → Deploy keys → Add deploy key hinzu und lassen Sie den Schreibzugriff deaktiviert. Weisen Sie SSH anschließend an, diesen Schlüssel für GitHub zu verwenden; ergänzen Sie dazu die Datei ~/.ssh/config:

Host github.com
    IdentityFile ~/.ssh/deploy_key
    IdentitiesOnly yes

Klonen Sie das Repository auf den Server:

git clone git@github.com:benutzer/projekt.git /var/www/app

Da der Deploy Key nur ein einziges Repository lesen kann, gelangt ein Angreifer selbst bei einem kompromittierten Server nicht an Ihre anderen Repositorys und Ihr Konto.

Schritt 3: Deploy-Skript

Fassen Sie die Schritte, die bei jeder Veröffentlichung laufen sollen, in einem Skript zusammen, zum Beispiel /home/deploy/deploy.sh. Für eine Node.js-Anwendung:

#!/bin/bash
set -euo pipefail

cd /var/www/app
git fetch origin
git reset --hard origin/main

npm ci
npm run build

pm2 reload app
echo "Veröffentlicht: $(git log -1 --oneline)"
  • set -euo pipefail: Schlägt ein Schritt fehl, bricht das Skript ab; ein halb fertiger Build geht nicht live.
  • git reset --hard origin/main: Gleicht den Code auf dem Server exakt mit dem Hauptbranch des Repositorys ab. Von Hand auf dem Server vorgenommene Änderungen werden dabei gelöscht; deshalb ist es wichtig, Code grundsätzlich nur über das Repository zu ändern.
  • npm ci: Installiert exakt die Versionen aus der Datei package-lock.json.
  • pm2 reload: Startet die Anwendung ohne Unterbrechung neu. Wie Sie Anwendungen mit pm2 und systemd betreiben, erklären wir in unserer Anleitung Discord-Bot hosten.

Bei PHP-Projekten tritt an die Stelle der npm-Zeilen composer install --no-dev --optimize-autoloader, bei Laravel kommen zusätzlich php artisan migrate --force und die Cache-Befehle hinzu. Machen Sie das Skript ausführbar:

chmod +x ~/deploy.sh

Für eine Veröffentlichung genügt es nun, auf dem Server ~/deploy.sh auszuführen.

Schritt 4: Automatisches Deployment mit GitHub Actions

Einen Schritt weiter können Sie dafür sorgen, dass das Skript bei jedem Push in den Hauptbranch automatisch läuft.

  1. Erzeugen Sie einen eigenen SSH-Schlüssel für Actions (auf Ihrem eigenen Computer):
    ssh-keygen -t ed25519 -f actions_key -N "" -C "github-actions"
    

    Fügen Sie den Inhalt von actions_key.pub auf dem Server in die Datei ~/.ssh/authorized_keys des Benutzers deploy ein.
  2. Legen Sie auf GitHub die Secrets an. Fügen Sie im Repository unter Settings → Secrets and variables → Actions die Secrets DEPLOY_SSH_KEY (Inhalt der Datei actions_key) und SERVER_HOST (IP-Adresse Ihres Servers) hinzu.
  3. Erstellen Sie die Workflow-Datei: .github/workflows/deploy.yml
    name: Deploy
    on:
        push:
            branches: [main]
    
    jobs:
        deploy:
            runs-on: ubuntu-latest
            steps:
                - name: Auf Server deployen
                  env:
                      SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
                      HOST: ${{ secrets.SERVER_HOST }}
                  run: |
                      mkdir -p ~/.ssh
                      echo "$SSH_KEY" > ~/.ssh/id_ed25519
                      chmod 600 ~/.ssh/id_ed25519
                      ssh-keyscan -H "$HOST" >> ~/.ssh/known_hosts
                      ssh deploy@"$HOST" '~/deploy.sh'
    

Ab jetzt verbindet sich GitHub bei jedem Push in den Branch main mit Ihrem Server und führt das Deploy-Skript aus. Das Ergebnis verfolgen Sie im Reiter Actions des Repositorys. Wenn Sie möchten, fügen Sie vor dem Deployment einen Schritt hinzu, der Ihre Tests ausführt; so wird nur Code veröffentlicht, der die Tests besteht.

Sicherheitsempfehlungen

  • Legen Sie keine Geheimnisse ins Repository. Tragen Sie die Datei .env in die .gitignore ein, legen Sie sie auf dem Server von Hand an und führen Sie im Repository nur eine .env.example mit leeren Werten.
  • Schränken Sie die Rechte des Deploy-Benutzers ein. Muss der Benutzer per sudo nur den Dienst der Anwendung neu starten können, erlauben Sie mit sudo visudo genau diesen einen Befehl:
    deploy ALL=(root) NOPASSWD: /bin/systemctl restart app
    
  • Verwenden Sie den Actions-Schlüssel nur für das Deployment. Gelangt dieser Schlüssel nach außen, genügt es, ihn aus der Datei authorized_keys zu löschen.
  • Schützen Sie SSH. Deaktivieren Sie die Anmeldung per Passwort und installieren Sie Fail2ban gegen automatisierte Angriffe.

Rollback

Haben Sie eine fehlerhafte Version veröffentlicht, kehren Sie auf dem Server zum vorherigen Commit zurück:

cd /var/www/app
git log --oneline -5
git reset --hard <vorheriger-commit>
npm ci && npm run build && pm2 reload app

Sauberer ist es, den fehlerhaften Commit auf Ihrem eigenen Computer mit git revert rückgängig zu machen und in den Hauptbranch zu pushen; der automatische Deployment-Prozess veröffentlicht die korrigierte Version dann selbst, und die Historie des Repositorys bleibt mit dem Server konsistent. Machen Sie es sich zur Gewohnheit, vor Veröffentlichungen mit Datenbankänderungen (Migrationen) ein Backup der Datenbank anzulegen; wenn Sie den Code zurücksetzen, wird die Datenbank nicht mit zurückgesetzt.

Nodesty-Server für Deployment mit Git

Die AMD Ryzen 9 9950X vServer von Nodesty beschleunigen mit ihrer hohen Single-Core-Leistung die Build-Schritte und sorgen für kurze Antwortzeiten Ihrer Anwendung; die AMD EPYC 7763 vServer bieten reichlich RAM, um mehrere Anwendungen und Datenbanken auf demselben Server zu betreiben. Mit vollem Root-Zugriff installieren Sie Git, Node.js, PHP und Docker ganz nach Bedarf und schützen Ihre Projekte mit NVMe-Speicher und kostenlosen täglichen Backups, die 7 Tage lang aufbewahrt werden.

Häufig gestellte Fragen

Warum sollte ich Git verwenden, statt Dateien per FTP hochzuladen?

Mit Git entspricht jede Veröffentlichung einem Commit; Sie wissen jederzeit, welche Version auf dem Server läuft, und kehren bei einem Problem mit einem einzigen Befehl zur vorherigen Version zurück. Wer Dateien von Hand hochlädt, hat dagegen schnell fehlende oder veraltete Dateien auf dem Server und weiß nicht mehr, wer was geändert hat.

Was ist der Unterschied zwischen einem Deploy Key und einem persönlichen SSH-Schlüssel?

Ein Deploy Key ist ein Schlüssel, der nur auf ein einziges Repository zugreifen kann und meist nur Leserechte hat. Selbst wenn der Server kompromittiert wird, kann ein Angreifer nur dieses eine Repository lesen; an Ihr Konto und alle Repositorys, auf die Ihr persönlicher Schlüssel zugreifen kann, kommt er nicht heran.

Sollte ich die .env-Datei in Git aufnehmen?

Nein. Sind Passwörter, API-Schlüssel und Datenbank-Zugangsdaten einmal in der Git-Historie gelandet, lassen sie sich nur schwer wieder vollständig entfernen. Tragen Sie die .env-Datei in die .gitignore ein, legen Sie sie auf dem Server von Hand an und führen Sie im Repository nur eine .env.example mit leeren Werten.

Ist die Website während des Deployments nicht erreichbar?

Ein einfaches git pull mit anschließendem Neustart kann zu einer Unterbrechung von einigen Sekunden führen. Werkzeuge wie pm2 reload starten die Anwendung schrittweise neu und vermeiden so eine Unterbrechung. Bei Projekten, die überhaupt keine Ausfallzeit vertragen, ist es üblich, jede Veröffentlichung in einem eigenen Ordner aufzubauen und erst dann per symbolischem Link auf die neue Version umzuschalten, wenn sie bereit ist.

Kann ich statt GitHub auch GitLab oder meinen eigenen Git-Server verwenden?

Ja. Das Prinzip mit Deploy Key und git pull ist bei jedem Git-Anbieter gleich; auch GitLab bietet Deploy Keys in den Repository-Einstellungen. Für automatische Deployments können Sie statt GitHub Actions GitLab CI/CD oder auf Ihrem eigenen Git-Server einen post-receive-Hook verwenden.

Ich habe eine fehlerhafte Version veröffentlicht. Wie kehre ich zurück?

Suchen Sie im Projektordner auf dem Server mit git log den vorherigen Commit, kehren Sie mit git reset --hard zu diesem Commit zurück und bauen und starten Sie die Anwendung neu. Sauberer ist es, den fehlerhaften Commit mit git revert rückgängig zu machen, in den Hauptbranch zu pushen und den normalen Deployment-Prozess laufen zu lassen.

Nodesty

Über den Autor

Nodesty-Team · Infrastruktur und Support

Das Nodesty-Team betreibt unsere Server, unser Netzwerk und unseren DDoS-Schutz im Alltag und beantwortet Support-Anfragen rund um die Uhr. Diese Ratgeber entstehen aus dieser Arbeit.

Verwandte Artikel

Starte deinen Server jetzt.

Erstellen, wachsen und skalieren Sie Ihre Projekte grenzenlos auf der Premium-Infrastruktur von Nodesty.

                                                                                                                                                                                                                            
                                                                                                                                                                                                                            
                                                                                                                                                                                                                            
                                                                                                                             ············································                                                   
                                                ··································································································..........···························                                     
                                       ················..........................................................................................................................··············                             
                                  ·············.................::::::::::::::::::::::::::::::::::::::::::::::....................:::::::::::::::::::::::::::::::::::::::................···········                        
                             ············................:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::............·········                     
                         ············.................:::::::::::::::::::::::::::::::::::::::::::::::::::------------::::::::::::::::::::::::::::::----------------:::::::::::::::::::::..........········                  
                    ············......................::::::::::::::::::::::::::::::::::::------------------------------------------------------------------------------------:::::::::::::.........········                
                ··········.............................................::::::::::::::::::-------------==========================================-----------------------------------:::::::::::........·······               
             ········..................:.....................................::::::::::--------=======+++++++++++++++++++++++++++++++++++++=========================------------------::::::::::.......·······              
           ······.........::::::::::::::::::::................................:::::::-----=====++++xxxxxx**************************xxxxxxxxx++++++++++++++===================------------::::::::.......·······             
          ·····.......:::::::::::::::::::::::::::.............................:::::----===+++xxx****%%%%&&&&&&#############&&&&&&&%%%%%*******xxxxxxxx++++++++++++++==============----------:::::::......······             
         ····......::::::::-------------:::::::::::..........................::::---===+++xx***%%%&&&####@@@@@@@@@@@@@@@@@@@@@@@@####&&&&&%%%%*******xxxxxxxxx+++++++++++++===========--------::::::......·····             
        ····.....:::::::--------------------:::::::::.......................::::---===++xxx**%%&&&###@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@###&&&&%%%%%********xxxxxxxxxxx++++++++++++========------::::::.....······            
        ····.....:::::--------------------------::::::::....................::::---===++xx***%%&&&####@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@###&&&&&%%%%%**********xxxxxxxxxxxxx+++++++++=======------:::::.....·····            
        ····....::::::-------=============---------:::::::::................:::::---===+++xx***%%%&&&#####@@@@@@@@@@@@@@@@@@@@@@@@@#####&&&&&%%%%%%*************xxxxxxxxxxxxxx+++++++++======-----:::::....·····            
         ····....:::::-------================---------:::::::::...............:::::----===++++xxx***%%%%&&&&&&#################&&&&&&%%%%%%%*******************xxxxxxxxxxxxxxxxx++++++++======----:::::....·····            
         ·····....:::::--------=================---------::::::::::..............:::::::-----====+++++xxxxxx**************************xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx++++++++=====-----::::....·····            
          ·····.....:::::--------=================----------:::::::::::.................:::::::::-------=============++++++++++++++++++++++++++++++++++++xxxxxxxxxxxxxxxxxxxxxxx++++++++======-----::::....·····            
            ·····.....:::::::----------===========-------------::::::::::::.........................::::::::::::::::::------------------=============+++++++++++++++++++++++++++++++++=======-----::::.....·····            
              ······......:::::::---------------------------------:::::::::::::........................................:::::::::::::::-----------============+++++++++++++++++++++========------:::::.....·····             
                 ······........:::::::::---------------------------:::::::::::::::::...........................................:::::::::::::------------=============================--------::::::.....······              
                    ·········.........:::::::::::::::-------------::::::::::::::::::::::::.......................................::::::::::::::::--------------------------------------::::::::......·······                
                          ··········............::::::::::::::::::::::::::::::::::::::::::::::::::................................::::::::::::::::::::::::::-------------:::::::::::::::.........········                   
                                  ············..................:::::::::::::::::::::::::::::::::::::::::::.........................:::::::::::::::::::::::::::::::::::::................···········                        
                                             ················.............................................................................................................·················                                 
                                                           ······················................................................................···························                                                
                                                                               ·········································································