<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ruben Voß</title>
    <description>The latest articles on DEV Community by Ruben Voß (@rubenvoss).</description>
    <link>https://dev.to/rubenvoss</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F909009%2F1958e781-3b2d-406d-a9b6-b889fac542b7.jpeg</url>
      <title>DEV Community: Ruben Voß</title>
      <link>https://dev.to/rubenvoss</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rubenvoss"/>
    <language>en</language>
    <item>
      <title>Wie man Wordpress lokal mit docker compose aufsetzt</title>
      <dc:creator>Ruben Voß</dc:creator>
      <pubDate>Sun, 23 Jun 2024 20:55:00 +0000</pubDate>
      <link>https://dev.to/rubenvoss/wie-man-wordpress-lokal-mit-docker-compose-aufsetzt-3m33</link>
      <guid>https://dev.to/rubenvoss/wie-man-wordpress-lokal-mit-docker-compose-aufsetzt-3m33</guid>
      <description>&lt;h2&gt;
  
  
  Wieso so?
&lt;/h2&gt;

&lt;p&gt;Um eine reproduzierbare Entwicklungs - Umgebung zu haben, ist es gut das Aufsetzen dieser Umgebung automatisch tun zu können. Dazu kann man docker compose benutzen. Hier zeige Ich euch ein docker-compose.yml, welches ein guter Startpunkt ist für eine reproduzierbare Entwicklungsumgebung.&lt;br&gt;
Wir Benutzen hier als Stack&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- wordpress:6.5.4-php8.1-apache
- mariadb:10.6.4-focal
- traefik:v3.0.3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Die &lt;code&gt;docker-compose.yml&lt;/code&gt; können wir mit dem wordpress - Service anfangen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services:
  wordpress:
      # Am Besten die Wordpress - Version festsetzen
    image: wordpress:6.5.4-php8.1-apache
    volumes:
      # Im wp_data Volume liegt der Wordpress - Code,
      # So kannst du ihn mit anderen Containern teilen
      - wp_data:/var/www/html
    restart: always
    environment:
      # Hier kannst du durch deine eigenen Werte ersetzen
      - WORDPRESS_DB_HOST=db
      - WORDPRESS_DB_USER=wordpress
      - WORDPRESS_DB_PASSWORD=wordpress
      - WORDPRESS_DB_NAME=wordpress
    labels:
      # Weiter unten konfigurieren wir dann traefik als Reverse Proxy
      - traefik.enable=true
      - traefik.http.routers.mywordpress.rule=Host(`localhost`)
    networks:
      # Füge dein Wordpress dem proxy Netzwerk hinzu:
      - proxy
    # Optional kannst du dir noch den richtigen Hostname geben, 
    # sonst beschwert sich Wordpress
    hostname: localhost
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Als nächstes kannst du die Datenbank hinzufügen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  db:
    # Das mariadb image unterstützt amd64 &amp;amp; arm64 architecture
    image: mariadb:11.4.2-noble
    command: '--default-authentication-plugin=mysql_native_password'
    volumes:
      # Deine Datenbank ist unter dem db_data Volume gespeichert
      - db_data:/var/lib/mysql
    restart: always
    environment:
      # Hier kannst du durch deine eigenen Werte ersetzen
      - MYSQL_ROOT_PASSWORD=somewordpress
      - MYSQL_DATABASE=wordpress
      - MYSQL_USER=wordpress
      - MYSQL_PASSWORD=wordpress
    expose:
      - 3306
      - 33060
    networks:
      - proxy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Jetzt müssen wir das ganze nur noch um unseren traefik Reverse - Proxy erweitern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  traefik:
    image: traefik:v3.0.3
    ports:
      - "80:80"
      - "8080:8080"
    networks:
      - proxy
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    command:
      # Lokal reicht das http - Setup
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"

  # Mit whoami kannst du traefik debuggen
  whoami:
    image: traefik/whoami:v1.8
    networks:
      - proxy
    labels:
      - traefik.enable=true
      - traefik.http.routers.mywhoami.rule=Host(`whoami.localhost`)

networks:
  proxy:
    name: proxy

volumes:
  letsencrypt:
    name: letsencrypt
  db_data:
  wp_data:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nun musst du nur noch &lt;code&gt;docker compose up&lt;/code&gt; Auf deinem Terminal ausführen, und dein Wordpress wird unter localhost bei dir erreichbar sein!&lt;/p&gt;

&lt;p&gt;Happy Coden!&lt;br&gt;
Dein Ruben&lt;/p&gt;

&lt;p&gt;&lt;a href="https://rubenvoss.de/?p=48"&gt;Mein Blog&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Automatische Backups von PostgreSQL via Cronjob</title>
      <dc:creator>Ruben Voß</dc:creator>
      <pubDate>Wed, 19 Jun 2024 20:16:15 +0000</pubDate>
      <link>https://dev.to/rubenvoss/automatische-backups-von-postgresql-via-cronjob-2ib4</link>
      <guid>https://dev.to/rubenvoss/automatische-backups-von-postgresql-via-cronjob-2ib4</guid>
      <description>&lt;h2&gt;
  
  
  Kontext
&lt;/h2&gt;

&lt;p&gt;Um die Daten deiner Kunden zu sichern müssen diese Regelmäßig auf einem Server abgespeichert werden. Dieser muss unbeeinträchtigt sein, falls die Infrastruktur auf der deine Datenbank läuft kaputtgeht. Also am besten bei einem Anderen Provider, oder in einer anderen Gegend. Ich zeige dir hier wie du das über einen Cronjob einrichten kannst, der von deiner Datenbank im Docker-Container ein Backup erstellt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Befehl Testen
&lt;/h2&gt;

&lt;p&gt;Dein Container braucht einen Namen, damit du in ihm einen Shell-Befehl auslösen kannst. In docker-compose.yml sieht das so aus:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  postgres:
    container_name: postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Jetzt kannst du mit &lt;code&gt;docker exec -it&lt;/code&gt; In deinem Container einen Befehl auslösen. Probiere es mal aus:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker exec -it mein_container_name pg_dumpall -U mein_datenbank_nutzer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mit diesem Befehl sollte sich nun dein Bildschirm mit dem PostgreSQL dump füllen. Wie aber kannst du das ganze nun Speichern?&lt;br&gt;
Durch Piping bringst du den Output vom pg_dumpall Befehl in eine Datei.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# mit gzip kannst du deine Datei komprimieren.
# mit $(date +%Y%m%d-%H%M%S) kriegt deine Datei einen einzigartigen Namen.
# mit dem \ Backslash kannst du deinen Befehl in mehrere Zeilen aufteilen
docker exec -it mein_container_name pg_dumpall -U mein_datenbank_nutzer \
| gzip -9c &amp;gt; db_backup_$(date +%Y%m%d-%H%M%S).sql.gz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nun kannst du selbst dein Backup erstellen. Aber wie geht das ganze automatisch? Dazu kommen wir jetzt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Crontab bearbeiten
&lt;/h2&gt;

&lt;p&gt;Regelmäßige Befehle werden auf deinem System in der Crontab eingestellt. Die crontab deines Nutzers kannst du mit &lt;code&gt;crontab -e&lt;/code&gt; bearbeiten. &lt;br&gt;
Auf &lt;a href="https://crontab.guru/"&gt;https://crontab.guru/&lt;/a&gt; kannst du dir anschauen, was die Zeichen am Anfang deines cronjobs bedeuten. Wir können unser Backup zum Beispiel immer nachts um 03.22 Uhr ausführen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;22 3 * * * docker exec -it postgres pg_dumpall -U ruben | gzip -9c &amp;gt; /backup/location/db-$(date +%Y%m%d-%H%M%S).sql.gz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Um deine Crontab zu Testen aber am besten am Anfang jede Minute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* * * * * /shell/befehl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;/backup/location/&lt;/code&gt; ersetzt du durch einen vorübergehenden Speicherort auf deinem Server für die Backups. Z.B. home-Verzeichnis.&lt;/p&gt;

&lt;p&gt;Jetzt musst du nur noch mit scp dein Backup zu einem anderen Server bringen. Das kannst du zum beispiel eine Stunde später tun...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;22 4 * * * scp /backup/location/db-$(date +%Y%m%d)*.sql.gz mein_user@mein_server:/backup/location/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Und dein ursprüngliches Backup auf deinem Server Löschen damit dein Speicher nicht überfüllt wird...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;22 5 * * * rm /backup/location/db-$(date +%Y%m%d)*.sql.gz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Das sind aber ganz schön viele cronjobs... Was wenn deine Datenbanksicherung länger dauert als eine Stunde? dann wird dein Backup nicht auf den Backupserver kopiert. D.h. es war quasi fehlerhaft.&lt;br&gt;
Also das ganze lieber als bash-skript aufsetzen.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch backup.sh
chmox +x backup.sh
vi backup.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So könnte dein backup.sh aussehen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/bash
DATE=$(date +%Y%m%d-%H%M%S)
BACKUP_FILE=/home/user/db-$DATE.sql.gz
/usr/bin/docker exec -it postgres pg_dumpall -U ruben | gzip -9c &amp;gt; $BACKUP_FILE
echo "Backup $BACKUP_FILE erstellt" &amp;gt;&amp;gt; /home/user/backup.log
scp $BACKUP_FILE mein_user@mein_server:/backup/location/
rm $BACKUP_FILE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Und bei deiner Crontab fügst du es einfach so hinzu:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;22 3 * * * /backup/script/location/backup.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Happy Coden!&lt;br&gt;
Dein Ruben&lt;/p&gt;

&lt;p&gt;&lt;a href="//rubenvoss.de"&gt;Mein Blog&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>run.bash &amp; migrate.bash - Pimpe deine .bashrc auf 🔝🔥</title>
      <dc:creator>Ruben Voß</dc:creator>
      <pubDate>Wed, 12 Jun 2024 21:56:40 +0000</pubDate>
      <link>https://dev.to/rubenvoss/runbash-migratebash-pimpe-deine-bashrc-auf-307h</link>
      <guid>https://dev.to/rubenvoss/runbash-migratebash-pimpe-deine-bashrc-auf-307h</guid>
      <description>&lt;h2&gt;
  
  
  Deine .bashrc
&lt;/h2&gt;

&lt;p&gt;Deine .bashrc Datei ist ein Skript, das jedes mal bei deinem Shellzugriff aufgerufen wird. Hier kannst du verschiedene Werte setzen &amp;amp; Dein Leben dadurch leichter machen. Wir werden am Beispiel django jetzt Skripte für dein Projekt entwickeln, die dir den Start deines Projekts erleichtern. Außerdem werden wir deinen &lt;code&gt;python manage.py migrate&lt;/code&gt; Befehl in einem Container absetzen, das erleichtert dir das Leben bei einem ganz schön langen Befehl.&lt;/p&gt;

&lt;h2&gt;
  
  
  Skripte anlegen
&lt;/h2&gt;

&lt;p&gt;Lege bei dir in der Repository auf dem Level deines &lt;code&gt;docker-compose.yml&lt;/code&gt; folgende Dateien an:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch run.bash migrate.bash
chmod +x run.bash migrate.bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Folgenden Inhalt brauchen deine Skripte:&lt;br&gt;
&lt;code&gt;run.bash&lt;/code&gt;&lt;br&gt;
Hier kannst du deinen Start-Befehl mit allen Optionen einfügenIch nutze -f, wegen dem speziellen Dateinamen mit --build Baue Ich die images neu vor Containerstart&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/bash
docker compose -f docker-compose.development.yml up --build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;migrate.bash&lt;/code&gt;&lt;br&gt;
Mit &lt;code&gt;exec -it container_name sh -c&lt;/code&gt; können wir unseren migrate Befehl absetzen. Alles in Anführungszeichen wird direkt im Container ausgeführt.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker exec -it meine_app sh -c "python manage.py makemigrations &amp;amp;&amp;amp; python manage.py migrate"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Weil wir den container namen in der &lt;code&gt;migrate.bash&lt;/code&gt; nutzen, muss du jetzt noch deine docker-compose Datei anpassen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services:
  meine_app:
    # wir nutzen den Container Namen in migrate.bash
    container_name: meine_app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Skripte in der .bashrc hinzufügen
&lt;/h2&gt;

&lt;p&gt;Füge deine Skripte deiner .bashrc (oder bei mac .zshrc) Hinzu. Die .bashrc / .zshrc befinden sich in deinem home - Verzeichnis.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;code ~/.bashrc
vi ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wenn du nun "run" als App-Startbefehl nutzen willst und "migrate" als migrierbefehl, kannst du Folgendes hinzufügen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# selfmade build and run scripts
alias run="./run.bash"
alias migrate="./migrate.bash"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Du kannst natürlich deine Skripte anders nennen, und den Befehl zum ausführen der Skripte auch... Es macht aber Sinn, wenn du mehrere Projekte starten / migrieren musst, den Befehl einheitlich zu halten.&lt;br&gt;
Jetzt kannst du nämlich in jedem Projekt ein run.bash hinzufügen. Solange der name des Skriptes "run.bash" bleibt, reicht es jetzt &lt;code&gt;run&lt;/code&gt; auszuführen - Deine App startet.&lt;br&gt;
Du kannst den Skriptinhalt auch verändern, wenn du bei unterschiedlichen Projekten deine App verschieden Starten willst. &lt;/p&gt;

&lt;p&gt;Happy Coden!&lt;br&gt;
Dein Ruben&lt;/p&gt;

&lt;p&gt;&lt;a href="//rubenvoss.de"&gt;Mein Blog&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Wie man django in Entwicklung Containerisiert - via docker compose</title>
      <dc:creator>Ruben Voß</dc:creator>
      <pubDate>Sun, 09 Jun 2024 19:45:51 +0000</pubDate>
      <link>https://dev.to/rubenvoss/wie-man-django-in-entwicklung-containerisiert-via-docker-compose-3n0b</link>
      <guid>https://dev.to/rubenvoss/wie-man-django-in-entwicklung-containerisiert-via-docker-compose-3n0b</guid>
      <description>&lt;h2&gt;
  
  
  Kontext
&lt;/h2&gt;

&lt;p&gt;Des öfteren gibt es in der Entwicklung das Problem, dass es einen Fehler gibt, der nur auf einem Gerät auftaucht.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ku0o6d8f3eb4tq4sapw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ku0o6d8f3eb4tq4sapw.jpg" alt="It works on my machine meme" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Häufig liegt das daran, dass in den verschiedenen Entwicklungsumgebungen verschiedene Programmversionen und/oder Libraries installiert sind.&lt;/p&gt;

&lt;p&gt;Entwickler A:&lt;br&gt;
PostgreSQL 14.6&lt;br&gt;
Python 3.7.11&lt;br&gt;
Redis 7.4.2&lt;/p&gt;

&lt;p&gt;Entwickler B:&lt;br&gt;
PostgreSQL 14.6&lt;br&gt;
Python 3.9.11&lt;br&gt;
Redis 7.4.2&lt;/p&gt;

&lt;p&gt;Wenn es jetzt einen Bug gibt, der in Python 3.7.11 Auftaucht, aber in Python 3.9.11 nicht - wird davon nur Entwickler A betroffen sein. &lt;br&gt;
Normalerweise ist es jedoch so, dass es sehr lange dauert herauszufinden dass der Bug aus den Versionsunterschieden stammt. Es ist also nicht sofort ersichtlich, dass wegen der unterschiedlichen Versionen der Bug auftritt. Alle Versionen und Libraries bei allen Entwicklern immer gleich zu halten ist schwierig bis unmöglich / sinnlos.&lt;br&gt;
Außerdem ist es oft auch so, dass immer wieder neue Entwickler technisch aufgestellt werden müssen. Das kann teilweise mehrere Tage Arbeit bedeuten, damit nur eine Person alles in einen 'funktionierenden' Zustand bekommt.&lt;br&gt;
Hier kommt jetzt docker compose &amp;amp; Containerisierung ins Spiel. Um verschiedene Applikations- und Libraryversionen zu vermeiden, und ebenso den Technischen onboarding - Prozess zu vereinfachen ist hier einiges möglich. Mit etwas DevOps wissen kann man &lt;code&gt;docker-compose.yml&lt;/code&gt; &amp;amp; &lt;code&gt;Dockerfile&lt;/code&gt; Dateien aufsetzen und damit die Gesamte Applikation mit allen Versionen einstellen. Jetzt müssen nur noch die einzelnen Entwickler Docker auf ihrem PC/Mac haben, den Rest erledigt dann Docker.&lt;/p&gt;
&lt;h2&gt;
  
  
  Dockerfile &amp;amp; .yml Speicherorte
&lt;/h2&gt;

&lt;p&gt;Am besten legst du dein &lt;code&gt;Dockerfile&lt;/code&gt; und &lt;code&gt;docker-compose.yml&lt;/code&gt; so an, dass es für deine App Sinn macht. Bei mir ist das so, dass das &lt;code&gt;docker-compose.yml&lt;/code&gt; auf dem Repository-Level ist, und das Dockerfile auf dem Django-Projektlevel. So kann ich meine App direkt starten, wenn ich in die Repository gehe. Außerdem können dann weiter Teile der Applikation am Repository-Level hinzugefügt werden. Wie z.B. andere Webapps, oder Datenbanken, etc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- meine_repository
    - docker-compose.yml
    - mein_django_projekt/
        - Dockerfile
        - manage.py
        - ...
    - venv/
    - .env
    - .gitignore
    - README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Dockerfile
&lt;/h2&gt;

&lt;p&gt;Um deine django-App im container zu starten, brauchst du ein Dockerfile. Hier bestimmst du Details deines Applikationsverhaltens im Container. Hier mein Dockerfile für Django mit Erklärungen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Deine Python-Version gibst du mit Doppelpunkt und der Versionsnummer mit 2 Punkten an.
# So verhinderst du mögliche Probleme mit falschen Versionen
FROM python:3.11.9

# Drei nützliche Optionen für die Python runtime im Container. 
# https://stackoverflow.com/questions/59812009/what-is-the-use-of-pythonunbuffered-in-docker-file
ENV PYTHONUNBUFFERED 1
# https://stackoverflow.com/questions/59732335/is-there-any-disadvantage-in-using-pythondontwritebytecode-in-docker
ENV PYTHONDONTWRITEBYTECODE 1
# https://stackoverflow.com/questions/45594707/what-is-pips-no-cache-dir-good-for
ENV PIP_NO_CACHE_DIR=1

# Du kannst als dein 'Hauptverzeichnis' im Container einfach /app nutzen
# Das 'WORKDIR' wirkt sich auf alle weiteren Docker - Befehle aus, wie z.B.
# den COPY Befehl in der nächsten Zeile. Mit . ist jetzt /app gemeint
WORKDIR /app

# Hiermit kopierst du deine requirements.txt nach /app/requirements.txt
# Dazu muss sich dein requirements.txt in deinem Django-Projektverzeichnis befinden
COPY requirements.txt .

# Jetzt installierst du die requirements.txt
RUN pip install -r requirements.txt

# Du kopierst nun dein gesamtes django-Projekt in den Container
COPY . .

# Gebe deinen Port im Docker-Netzwerk frei
EXPOSE 8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Jetzt kannst du dein Container-Image bauen &amp;amp; laufen lassen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd mein_projekt
docker build -t mein_container_image .

# Hier sollte nichts passieren
docker run mein_container_image
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wieso passiert nichts? Dein Container läuft nur ganz kurz, weil du den &lt;code&gt;python manage.py runserver&lt;/code&gt; Befehl noch nicht angegeben hast! Das machen wir jetzt.&lt;/p&gt;

&lt;h2&gt;
  
  
  docker-compose.yml
&lt;/h2&gt;

&lt;p&gt;Die Orchestrierung deines Containers machen wir aus dem &lt;code&gt;docker-compose.yml&lt;/code&gt;. Momentan brauchst du nur den einen Service, aber in Zukunft kannst du auch mehrere weitere Services hinzufügen. Folgendermaßen kannst du dein &lt;code&gt;docker-compose.yml&lt;/code&gt; aufbauen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services:
  meine_app:
    # Automatischer Neustart, falls deine App abstürzt
    restart: always
    # Das Verzeichnis, in dem dein Dockerfile liegt
    build: ./mein_django_projekt
    # Du gibst den Port 8000 frei vom Inneren des Containers zum Äußeren
    ports:
      - "8000:8000"
    # Mit einem Bind-Mount sorgst du dafür, dass der Code deines Projekts
    # Im Container aktualisiert wird, so wie auf deiner Festplatte
    volumes:
      - ./mein_django_projekt/:/app
    # Hier kannst du deine Umgebung angeben:
    env_file: .env
    # Mit diesem Befehl startest du den Server
    # Bei Containern mit 0.0.0.0 starten!
    command: python manage.py runserver 0.0.0.0:8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Jetzt kannst du deine App starten!&lt;br&gt;
Mit &lt;code&gt;docker compose up&lt;/code&gt; wird nun dein Container gebaut &amp;amp; mit dem runserver-Befehl gestartet. Der Befehl muss im gleichen Verzeichnis wie die &lt;code&gt;docker-compose.yml&lt;/code&gt; Datei abgesetzt werden.&lt;br&gt;
Nun kannst du unter &lt;code&gt;localhost:8000&lt;/code&gt; deine App erreichen! &lt;/p&gt;

&lt;p&gt;Happy Coden!&lt;br&gt;
Dein Ruben&lt;/p&gt;

&lt;p&gt;&lt;a href="//rubenvoss.de"&gt;Mein Blog&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>7. Gunicorn als service - Django in Produktion Teil 7</title>
      <dc:creator>Ruben Voß</dc:creator>
      <pubDate>Sun, 02 Jun 2024 19:54:55 +0000</pubDate>
      <link>https://dev.to/rubenvoss/7-gunicorn-als-service-django-in-produktion-teil-7-3jdh</link>
      <guid>https://dev.to/rubenvoss/7-gunicorn-als-service-django-in-produktion-teil-7-3jdh</guid>
      <description>&lt;h2&gt;
  
  
  Vorwort
&lt;/h2&gt;

&lt;p&gt;Mit &lt;code&gt;gunicorn meine_app.wsgi&lt;/code&gt; kannst du seit der letzten Folge deinen Appserver starten. Das ganze wäre aber etwas unpraktisch, wenn du immer eine Shell-Sitzung mit deinem Gunicorn offen haben müsstest, um deine Webapp laufen zu lassen. Außerdem, was passiert wenn die App crasht? Was passiert falls du gerade kein Internet hast, oder wenn du mal deinen Server neu starten willst? Da jedes mal den gleichen Befehl wieder einzugeben macht keinen Sinn. Deswegen gibt es &lt;code&gt;.service&lt;/code&gt; Dateien, die dafür sorgen dass dein Gunicorn automatisch beim Neustart / Anschalten deines Servers gestartet wird.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation von gunicorn.service
&lt;/h2&gt;

&lt;p&gt;Lege entweder eine Datei an, oder verlinke von deiner Repo aus:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo ln -s /srv/www/meine_repo/services/gunicorn.service /etc/systemd/system/gunicorn.service
# oder:
sudo touch /etc/systemd/system/gunicorn.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Diese kannst du mit folgendem Inhalt füllen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Unit]
Description=Gunicorn service that serves meine_app
After=network.target

[Service]
# Hier kannst du das richtige environment laden
Environment="ENV_NAME=production"

# Nutze am besten nicht root, sondern einen eigens erstellten nutzer, z.B. meine_app_gunicorn
User=root
Group=root

# Deine .wsgi - Datei ist in deinem django-Projektverzeichnis
# Hier wird dein Start-Befehl ausgeführt
WorkingDirectory=/srv/www/meine_repository/mein_projekt

# Das hier Startet deine django App
ExecStart=/srv/www/meine_repository/venv/bin/gunicorn --log-file /var/log/gunicorn --workers 1 --bind 127.0.0.1:8000 meine_app.wsgi

ExecReload=/bin/kill -s HUP $MAINPID
KillMode=mixed
TimeoutStopSec=5
PrivateTmp=true

[Install]
WantedBy=multi-user.target
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Jetzt musst du nur noch den service anmachen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Lade deine neue Konfiguration
sudo systemctl daemon-reload
# Schalte gunicorn ein, sodass der Service automatisch bei einem reboot angeht
sudo systemctl enable gunicorn
# Starte gunicorn
sudo systemctl start gunicorn

# Jetzt sollte hier ein grünes 'started' und 'enabled' rauskommen:
sudo systemctl status gunicorn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PS: probiere doch mal ein &lt;code&gt;reboot&lt;/code&gt; aus, danach sollte dein gunicorn auch wieder laufen.&lt;/p&gt;

&lt;p&gt;Viel Spaß beim Coden,&lt;br&gt;
Dein Ruben&lt;/p&gt;

&lt;p&gt;&lt;a href="//rubenvoss.de"&gt;Mein Blog&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>NGINX als Reverse Proxy - Django in Produktion Teil 6</title>
      <dc:creator>Ruben Voß</dc:creator>
      <pubDate>Wed, 29 May 2024 21:22:45 +0000</pubDate>
      <link>https://dev.to/rubenvoss/nginx-als-reverse-proxy-django-in-produktion-teil-6-33b7</link>
      <guid>https://dev.to/rubenvoss/nginx-als-reverse-proxy-django-in-produktion-teil-6-33b7</guid>
      <description>&lt;h2&gt;
  
  
  Vorwort
&lt;/h2&gt;

&lt;p&gt;Jetzt, da unsere App mit Gunicorn als Applikations - Server läuft, müssen wir sie nur noch über nginx in das Öffentliche Internet bringen. nginx wird unsere Statischen Dateien bereitstellen, und alles andere als reverse proxy an Gunicorn weiterleiten. nginx wird von Firmen wie Netflix und Dropbox genutzt um Seiten mit vielen Besuchern online zu halten. Ebenso werden wir unsere https - Verschlüsselung mit certbot aufbauen.&lt;/p&gt;

&lt;h2&gt;
  
  
  nginx Set-Up
&lt;/h2&gt;

&lt;p&gt;Zuerst kannst du nun nginx installieren.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt install nginx
sudo service enable nginx
sudo service start nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hier liegt die Konfigurationsdatei für nginx:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat /etc/nginx/nginx.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dort sind alle wichtigen Einstellungen. Jetzt kannst du auf deine Domain gehen, dort solltest du nun von der Standard nginx - Webseite begrüßt werden. Hurra! dein Server ist nun offiziell im offenen Internet erreichbar.&lt;/p&gt;

&lt;h2&gt;
  
  
  optional - nginx config als softlink
&lt;/h2&gt;

&lt;p&gt;Um die Änderungen in deine Konfiguration zu speichern, kannst du die config - Datei bei dir in deine git - repository einchecken. Bei einer Produktiven Website am besten nicht 'public', also für alle einsehbar machen. Falls deine git - repo public ist, erstelle dir eine neue repo mit deinen Konfigurationsdateien. Nach dem einchecken kannst du einen Softlink von deiner Repo zur config - Datei erstellen. So kann sich nginx immer die Updates von deiner Repository holen.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cp /etc/nginx/nginx.conf srv/www/meine_app/produktion/nginx.conf
git commit -m "nginx.conf" &amp;amp;&amp;amp; git push

rm /etc/nginx/nginx.conf
ln -s /srv/www/meine_app/produktion/nginx.conf /etc/nginx/nginx.conf

# Deine Datei kann nun in deiner repository geupdated werden:
ls -l /etc/nginx/nginx.conf
lrwxrwxrwx 1 root root 40 May 29 20:48 /etc/nginx/nginx.conf -&amp;gt; /srv/www/meine_app/produktion/nginx.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  certbot Set-Up
&lt;/h2&gt;

&lt;p&gt;Um deine Web - App mit https zu verschlüsseln, brauchst du ein Zertifikat. Ein kostenloses Zertifikat bekommst du von Let's encrypt. Diese Zertifikat läuft aber nach 12 Monaten ab, deswegen nutzen wir &lt;code&gt;certbot&lt;/code&gt; um das Zertifikat automatisch alle 12 Monate zu erneuern.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So kannst du certbot auf Debian installieren:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Jetzt sollte certbot deine &lt;code&gt;nginx.conf&lt;/code&gt; angepasst haben. Schau dir die Änderungen mit &lt;code&gt;git status&lt;/code&gt; an&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd /srv/www/meine_app
git status
git add produktion/nginx.conf
git commit -m "certbot setup"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://certbot.eff.org/instructions"&gt;Falls du eine andere Architektur benutzt, kannst du hier auf certbots Webseite mehr Infos bekommen.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Weitere nginx.conf Anpassungen.
&lt;/h2&gt;

&lt;p&gt;Das ganze ist aber noch nicht genug. Jetzt musst du deine .conf für den launch vorbereiten. Das ganze sieht dann etwa so aus:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;worker_processes 1;
user www-data;

# Hier sind deine error logs - für alle Zugriffe gibt es auch ein access.log am gleichen Ort:
error_log  /var/log/nginx/error.log info;
pid /var/run/nginx.pid;

# events kannst du so lassen:
events {
  worker_connections 1024; # increase if you have lots of clients
  accept_mutex off; # set to 'on' if nginx worker_processes &amp;gt; 1
}


# Mehrere Voreinstellungen für django:
http {
  include mime.types;
  # fallback in case we can't determine a type
  default_type application/octet-stream;
  access_log /var/log/nginx/access.log combined;
  sendfile on;

  upstream app_server {
    # fail_timeout=0 means we always retry an upstream even if it failed
    # to return a good HTTP response

    # for UNIX domain socket setups
    server unix:/tmp/gunicorn.sock fail_timeout=0;
  }


# Das ist dein HTTP - Server:
  server {
    listen 80;

    server_name meine_domain.de;

    return 301 https://$server_name$request_uri;
  }

  # Das ist dein HTTPS - Server:
  server {

    listen 443 ssl;
    client_max_body_size 75M;

    server_name meine_domain.de;

    # Hier sind deine ssl - Zertifikate, die du dir mit certbot geholt hast:
    ssl_certificate     /etc/letsencrypt/live/meine_domain.de/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/meine_domain.de/privkey.pem;

    keepalive_timeout 5;

    # Hier sind deine Statischen Dateien. Sie werden in Produktion 
    # direkt von nginx gehosted. In deinen django settings 
    # musst du STATIC_ROOT = "/srv/www/static" hinzufügen
    location /static {
        alias /srv/www/static;
    }

    # Das hier ist deine Proxy - Server Weiterleitung. Dein lokaler 
    # Gunicorn wird so an das offene Internet weitergeleitet. 
    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    # Hier kanst du deine error - Seiten bereitstellen. Da diese 
    # Statisch sind, werden sie direkt von nginx bereitgestellt
    error_page 500 502 503 504 /500.html;
    location = /500.html {
      root /srv/www/meine_repository/meine_app/static;
    }

  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Starte deine Webapp mit Gunicorn
&lt;/h2&gt;

&lt;p&gt;Jetzt fehlt nur noch eine Sache, deine eigene App!&lt;br&gt;
Du kannst sie, wie beim letzten mal - mit Gunicorn starten.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Exportiere dein Produktions - env, damit deine Richtigen Einstellungen geladen werden.
export ENV_NAME=production

# Starte dein Gunicorn - Die Applikation befindet sich im venv in deiner Repository
# Deine .wsgi ist im Verzeichnis deiner App
# und mit -b kannst du deine lokale ip bestimmen - Diese leitest du an nginx weiter.
/srv/www/meine_repository/venv/bin/gunicorn /srv/www/meine_repository/meine_app/meine_app.wsgi -b 127.0.0.1:8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lade deine neue Konfiguration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl daemon-reload
sudo systemctl restart nginx.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Jetzt solltest du deinen Browser öffnen und unter deiner domain deine App sehen können!&lt;/p&gt;

&lt;p&gt;Im nächsten Teil werden wir deine .service Dateien für systemd anlegen, damit auch nach einem &lt;code&gt;reboot&lt;/code&gt; alle deine wichtigen Applikationen laufen.&lt;/p&gt;

&lt;p&gt;PS: Viel Spaß beim Coden,&lt;br&gt;
Dein Ruben&lt;/p&gt;

&lt;p&gt;&lt;a href="//rubenvoss.de"&gt;Mein Blog&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>WSGI als Python runtime - Django in Produktion Teil 5</title>
      <dc:creator>Ruben Voß</dc:creator>
      <pubDate>Sun, 26 May 2024 20:33:06 +0000</pubDate>
      <link>https://dev.to/rubenvoss/wsgi-als-python-runtime-django-in-produktion-teil-5-1701</link>
      <guid>https://dev.to/rubenvoss/wsgi-als-python-runtime-django-in-produktion-teil-5-1701</guid>
      <description>&lt;h2&gt;
  
  
  Vorwort
&lt;/h2&gt;

&lt;p&gt;Nun, da wir auf unserem Produktionsserver alles auf unsere django - Webapp vorbereitet haben, ist als nächstes Gunicorn dran. Gunicorn wird unsere app - so wie &lt;code&gt;python manage.py runserver&lt;/code&gt; in der Entwicklung, in Produktion zum laufen bringen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation in requirements.txt
&lt;/h2&gt;

&lt;p&gt;Jetzt sollte unsere requirements - Datei zumindestens folgendes enthalten:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# django
django==5.0.4

# postgresql database adapter
psycopg2==2.9.9
psycopg2-binary==2.9.9

# webserver in production
gunicorn==21.2.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;in Entwicklung und Produktion mit &lt;code&gt;pip install -r requirements.txt&lt;/code&gt; installieren&lt;/p&gt;

&lt;h2&gt;
  
  
  Erster Start
&lt;/h2&gt;

&lt;p&gt;Jetzt kannst du den WSGI server das erste mal starten, am besten bei dir Lokal in der Entwicklungsumgebung.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd meine_repository/meine_app
gunicorn meine_app.wsgi

# so sollte dein Output ausschauen:
[2024-05-26 22:25:05 +0200] [71525] [INFO] Starting gunicorn 21.2.0
[2024-05-26 22:25:05 +0200] [71525] [INFO] Listening at: http://127.0.0.1:8000 (71525)
[2024-05-26 22:25:05 +0200] [71525] [INFO] Using worker: sync
[2024-05-26 22:25:05 +0200] [71526] [INFO] Booting worker with pid: 71526
--- Using development Settings ---
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nun sollte deine app in der Produktionsversion lokal bei dir laufen. Gehe einfach auf &lt;a href="http://127.0.0.1:8000"&gt;http://127.0.0.1:8000&lt;/a&gt; und du kannst sie dir anschauen.&lt;/p&gt;

&lt;p&gt;Das kannst du nun so auch auf deinem Server ausführen, aber du wirst deine App wahrscheinlich nicht unter deiner Domain / ip erreichen können. Um das zu können musst du mit nginx deinen Webserver als Reverse-Proxy weiterleiten. Damit geht's beim nächsten mal weiter.&lt;br&gt;
&lt;a href="https://docs.gunicorn.org/en/latest/deploy.html"&gt;Hier kannst du mehr über nginx als Reverse Proxy herausfinden.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PS: Viel Spaß beim Coden,&lt;br&gt;
Dein Ruben&lt;/p&gt;

&lt;p&gt;&lt;a href="//rubenvoss.de"&gt;Mein Blog&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Der Settings Ordner - django in Produktion Teil 4</title>
      <dc:creator>Ruben Voß</dc:creator>
      <pubDate>Wed, 22 May 2024 21:14:49 +0000</pubDate>
      <link>https://dev.to/rubenvoss/der-settings-ordner-django-in-produktion-teil-4-40e0</link>
      <guid>https://dev.to/rubenvoss/der-settings-ordner-django-in-produktion-teil-4-40e0</guid>
      <description>&lt;h2&gt;
  
  
  Vorwort
&lt;/h2&gt;

&lt;p&gt;Im letzten Teil ging es um das Installieren von Python und der Virtuellen Umgebung auf dem Produktionsserver. Jetzt haben wir uns mehrere Umgebungen geschaffen - unsere Entwicklungsumgebung bei uns Lokal und unsere Produktionsumgebung auf dem Server. Django lädt seine Einstellungen momentan aus einer settings.py Datei. Diese Datei müssen wir nun in mehrere Dateien aufteilen, sodass wir eine Datei als Basis, eine Datei als Enwticklungsumgebung und eine Datei für die Produktionsumgebung haben. Im Nachhinein können wir dann verschiedene Dateien hinzufügen, z.B. für eine Testumgebung.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ordner erstellen
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Nachschauen ob unsere settings.py Datei vorhanden ist
cd meine_app/meine_app/
ls -l settings.py

# Erstellen des settings - Verzeichnis, neben deiner settings.py
mkdir settings

# Da in settings.py bereits alle Einstellungen Vorhanden sind, können wir das ganze einfach umbenennen in base.py. Das ist die Basis unserer Einstellungen
# settings.py in base.py umbenennen
mv settings.py settings/base.py

# Erstellen weiterer Dateien
cd settings/
touch __init__.py development.py production.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;init&lt;/strong&gt;.py
&lt;/h2&gt;

&lt;p&gt;Diese Datei füllen wir mit folgendem Inhalt, damit je nach env unseren richtigen Einstellungen geladen werden.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Wir importieren alles aus der base.py 
from .base import *
import os

# Wenn in unserem env ENV_NAME=production gesetzt ist, werden die Produktionseinstellungen aktiv, sonst die Entwicklungseinstellungen
if os.environ.get("ENV_NAME") == 'production':
    from .production import *
else:
    from .development import *
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Das ganze kannst du nun testen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Füge deinem production.py folgendes hinzu:
print("--USING PRODUCTION SETTINGS--")

# Bringe ENV_NAME=production in dein env
export ENV_NAME=production

# Beim Server start sollte nun dein print aus dem production.py angezeigt werden.
python manage.py runserver
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PS: Dein settings - Modul wird im &lt;code&gt;manage.py&lt;/code&gt; folgendermaßen aufgerufen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;os.environ.setdefault("DJANGO_SETTINGS_MODULE", "testproj.settings")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Anpassung in development.py
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Zum debuggen, lasse dir Anzeigen ob du deine development settings benutzt
print("--- Using development Settings ---")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Hole dir einige Einstellungen aus base.py
&lt;/h3&gt;

&lt;p&gt;Folgende Einstellungen musst du aus base.py entfernen und in development.py unterbringen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Bewege deinen SECRET_KEY von base.py in development.py
SECRET_KEY = "django-insecure-******************************************"

# Hole dir deine DEBUG &amp;amp; ALLOWED_HOSTS einstellungen aus base.py
DEBUG = True
ALLOWED_HOSTS = []

# Beim kopieren der Datenbank musst du BASE_DIR importieren
from .base import BASE_DIR
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.sqlite3",
        "NAME": BASE_DIR / "db.sqlite3",
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Anpassungen in production.py
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Hole dir deinen SECRET_KEY mit python
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3
&amp;gt;&amp;gt;&amp;gt; import secrets
&amp;gt;&amp;gt;&amp;gt; print(secrets.token_urlsafe())
AZ-Z_-qBzjZmJuDaX40PZVS3JmcqfdOkGU2H5ErvUPg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Baue deine production.py auf:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Zum debuggen
print("--- Using production Settings ---")

SECRET_KEY = "********************************"

# Für Produktion DEBUG Modus ausschalten
DEBUG = False

# Wenn du eine Domain über A-Record mit deinem Server verbunden hast, kannst du die Domain nutzen
ALLOWED_HOSTS = [".meineapp.de", "192.168.178.23"]

# Nutze deine Daten aus - 2. PostgreSQL für django aufsetzen.
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql",
        "OPTIONS": {
                "options": "-c search_path=meine_app_schema"
            },
        "NAME": "meine_app",
        "USER": "mein_nutzer",
        "PASSWORD": "**************",
        "HOST": "localhost",
        "PORT": "5432"
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Füge dein production.py im .gitignore hinzu
&lt;/h2&gt;

&lt;p&gt;Deine Produktionseinstellungen sollen nie in deine Codehistorie commited werden. Füge deinem &lt;code&gt;.gitignore&lt;/code&gt; folgendes hinzu:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;meine_app/meine_app/settings/production.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Jetzt kannst du dein production.py auf deinen Server syncen&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rsync -r meine_app/meine_app/settings/production.py 192.168.178.23:/srv/www/meine_repository/meine_app/meine_app/settings/production.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Anpassung in base.py
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Du musst deinem BASE_DIR ein .parent hinzufügen, da deine Einstellungen jetzt 1 Verzeichnis tiefer liegen.
BASE_DIR = Path(__file__).resolve().parent.parent.parent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deine .bashrc in Produktion
&lt;/h2&gt;

&lt;p&gt;Füge deiner .bashrc folgendes hinzu:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Setze dein env richtig
export ENV_NAME=producti on

# Du wirst den nutzer vor allem hier nutzen
cd /srv/www/meine_repository

# Aktiviere dir gleich dein Python
source /srv/www/meine_repository/venv/bin/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Datenbankmigration - python manage.py migrate
&lt;/h2&gt;

&lt;p&gt;Jetzt kannst du deine Datenbank das erste mal in Produktion migrieren:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh mein-nutzer@192.168.178.23
cd meine_app/
python manage.py migrate
# So sollte der Output ausschauen:
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying sessions.0001_initial... OK
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PS: Viel Spaß beim Coden,&lt;br&gt;
Dein Ruben&lt;/p&gt;

&lt;p&gt;&lt;a href="//rubenvoss.de"&gt;Mein Blog&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Python und venv installieren - django in Produktion Teil 3</title>
      <dc:creator>Ruben Voß</dc:creator>
      <pubDate>Wed, 15 May 2024 17:38:50 +0000</pubDate>
      <link>https://dev.to/rubenvoss/python-und-venv-installieren-django-in-produktion-teil-3-8c7</link>
      <guid>https://dev.to/rubenvoss/python-und-venv-installieren-django-in-produktion-teil-3-8c7</guid>
      <description>&lt;h2&gt;
  
  
  Vorwort
&lt;/h2&gt;

&lt;p&gt;Im letzten Teil haben wir uns um das Aufsetzen der Datenbank gekümmert. Nun werden wir unsere Repository auf den Produktionsserver bringen. Ebenso kümmern wir uns um das Aufsetzen der Python-Pakete. &lt;/p&gt;

&lt;h2&gt;
  
  
  Python Installation
&lt;/h2&gt;

&lt;p&gt;Um unseren Webserver zum laufen zu bringen brauchen wir die richtigen Python-Pakete &amp;amp; für die Datenbankverbindung libpq-dev und gcc. Diese können wir nun mit apt installieren.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt install git python3.11 python3.11-venv python3-dev libpq-dev gcc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Repository aufsetzen
&lt;/h2&gt;

&lt;p&gt;Als nächstes brauchen wir einen Ort, an dem unser Repository liegen wird. Dazu nutze Ich hier &lt;code&gt;/srv/www&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo mkdir -p /srv/www/
sudo cd /srv/www
sudo git clone git@github.com:mein_name/meine_repository.git
sudo cd meine_repository
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PS: Falls du nicht vor alle Befehle ein &lt;code&gt;sudo&lt;/code&gt; setzen willst, kannst du dich mit &lt;code&gt;sudo su -&lt;/code&gt; zum root Nutzer machen. Aber dann vorsichtig sein ;)&lt;/p&gt;

&lt;h2&gt;
  
  
  requirements.txt
&lt;/h2&gt;

&lt;p&gt;Für dein Projekt brauchst du eine requirements.txt Datei. Falls du diese noch nicht mit deinen Python Paketversionen gefüllt hast, kannst du das jetzt machen.&lt;br&gt;
In deinem Lokalen Repository ausführen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip freeze &amp;gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Zu deinem requirements.txt solltest du folgende Pakete hinzufügen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Webserver in Produktion
gunicorn

# postgresql database adapter
psycopg2
psycopg2-binary
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Diese kannst du nun bei dir Lokal installieren:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install -r requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Venv installieren
&lt;/h2&gt;

&lt;p&gt;Jetzt kannst du, wieder zurück auf deinem Produktiven Server alle Pakete im requirements.txt installieren. Dazu erstellen wir ein venv, damit du mehrere Python Umgebungen auf dem gleichen Server laufen lassen kannst.&lt;br&gt;
Vorher solltest du am besten bei dir lokal das venv - Verzeichnis in dein .gitignore hinzufügen.&lt;br&gt;
Bei dir Lokal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo "venv/" &amp;gt;&amp;gt; .gitignore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Auf dem Produktivserver:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Mache dich zum root Nutzer &amp;amp; Gehe in dein Codeverzeichnis
sudo su -
cd /srv/www/meine_repository

# hole dir die Neuesten Updates aus deiner Repository
git pull

# Installiere deine Virtuelle Python-Umgebung
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  PostgreSQL migrieren
&lt;/h2&gt;

&lt;p&gt;Nun sollte der python manage.py migrate Befehl funktionieren! Aber halt, hast du deine Datenbank schon in deiner settings.py Datei hinzugefügt? Das schauen wir uns im nächsten Post an ;)&lt;/p&gt;

&lt;p&gt;Viel Spaß beim Coden,&lt;br&gt;
Dein Ruben&lt;/p&gt;

&lt;p&gt;&lt;a href="//rubenvoss.de"&gt;Mein Blog&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>PostgreSQL für django aufsetzen - django in Produktion (Teil 2)</title>
      <dc:creator>Ruben Voß</dc:creator>
      <pubDate>Sun, 12 May 2024 20:30:56 +0000</pubDate>
      <link>https://dev.to/rubenvoss/postgresql-fur-django-aufsetzen-django-in-produktion-teil-2-4cdf</link>
      <guid>https://dev.to/rubenvoss/postgresql-fur-django-aufsetzen-django-in-produktion-teil-2-4cdf</guid>
      <description>&lt;h2&gt;
  
  
  Vorwort
&lt;/h2&gt;

&lt;p&gt;Im letzten Teil haben wir den Server bereit gemacht. In diesem Teil wird es um die Datenbank gehen. Ich habe mich für PostgreSQL entschieden, da es eine lange bewährte, viel genutzte Open - Source Datenbank ist. Ebenso ist Postgres natürlich skalierbar, d.h. wenn einmal mehr Nutzeranfragen kommen sollten kann man den Server anpassen, sodass eine große Anzahl von gleichzeitigen Anfragen verarbeitet werden kann.&lt;/p&gt;

&lt;h3&gt;
  
  
  PostgreSQL installieren
&lt;/h3&gt;

&lt;p&gt;Zuerst müssen wir das ganze via apt installieren:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt install postgresql postgresql-contrib
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Jetzt können wir auf die PostgreSQL Datenbank zugreifen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo -u postgres psql

# Nun sollte das Prompt so ausschauen:
psql (15.6 (Debian 15.6-0+deb12u1))
Type "help" for help.

postgres=#
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Datenbank &amp;amp; Nutzer erstellen
&lt;/h3&gt;

&lt;p&gt;Jetzt erstellst du deinen eigenen Datenbank Nutzer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Verbinde dich mit postgres
sudo -u postgres psql

# Erstelle deine Datenbank - benutze Natürlich deinen eigenen Namen ;)
CREATE DATABASE meine_datenbank_xyz;

# Nun kannst du dich mit deiner Datenbank Verbinden
\connect meine_datenbank_xyz

# Jetzt kannst du deinen eigenen Nutzer für die Datenbank mit Passwort erstellen.
CREATE USER mein_nutzer WITH PASSWORD 'password';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Datenbank Schema und PSQL 15
&lt;/h3&gt;

&lt;p&gt;Seit PostgreSQL 15 gibt es bei der Sicherheit von Postgres ein Update.&lt;br&gt;
&lt;code&gt;Remove PUBLIC creation permission on the public schema (Noah Misch) The new default is one of the secure schema usage patterns that Section 5.9.6 has recommended...&lt;/code&gt;&lt;br&gt;
Das hat Auswirkungen auf das Aufsetzen der Datenbank mit django. &lt;a href="https://gist.github.com/axelbdt/74898d80ceee51b69a16b575345e8457"&gt;Hier kannst du mehr darüber lesen&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wenn du also jetzt &lt;code&gt;python manage.py migrate&lt;/code&gt; ausprobieren würdest, hättest du folgende Fehlermeldung: &lt;code&gt;permission denied for schema public&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Deswegen müssen wir jetzt das Schema Autorisieren und deinen Nutzer etwas anpassen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE SCHEMA mein_schema AUTHORIZATION mein_nutzer;
ALTER ROLE mein_nutzer SET client_encoding TO 'utf8';
ALTER ROLE mein_nutzer SET default_transaction_isolation TO 'read committed';
ALTER ROLE mein_nutzer SET timezone TO 'CET';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nun sollte &lt;code&gt;python manage.py migrate&lt;/code&gt; funktionieren. Das werden wir uns im nächsten Teil anschauen!&lt;/p&gt;

</description>
      <category>django</category>
      <category>production</category>
      <category>postgres</category>
    </item>
    <item>
      <title>Wie man eine django Webapp in Produktion aufsetzt (Teil 1)</title>
      <dc:creator>Ruben Voß</dc:creator>
      <pubDate>Wed, 08 May 2024 19:36:02 +0000</pubDate>
      <link>https://dev.to/rubenvoss/wie-man-eine-django-webapp-in-produktion-aufsetzt-teil-1-1hpm</link>
      <guid>https://dev.to/rubenvoss/wie-man-eine-django-webapp-in-produktion-aufsetzt-teil-1-1hpm</guid>
      <description>&lt;h2&gt;
  
  
  Vorwort
&lt;/h2&gt;

&lt;p&gt;In dieser Post-Reihe geht es darum, eine django webapp Produktionsbereit zu machen.&lt;br&gt;
Es gibt viele verschiedene Möglichkeiten das zu tun, aber hier werden wir uns einfach einen VPS mit Debian schnappen und alle Programme darauf laufen lassen.&lt;br&gt;
Das ganze ist gut für Applikationen, die keine großen Skalierungsprobleme haben.&lt;/p&gt;

&lt;p&gt;Außerdem werden wir dem ganzen über GitHub und webhooks kontinuierliche updates zukommen lassen - Continuous Deployment.&lt;/p&gt;
&lt;h2&gt;
  
  
  Unser Stack
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Debian 12
- Django 5.0.6
- postgresql 15.6
- gunicorn 21.2.0
- nginx 1.22.1
- webhook 2.8.0
- ufw 0.36.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Wieso machen wir das so?
&lt;/h2&gt;

&lt;p&gt;Wieso sollte Ich meine App nicht einfach auf einer Cloud-Service Platform hosten?&lt;br&gt;
Du bist dann auch von dieser Platform abhängig. Sie verlangen einen Preis und den musst du dann bezahlen. Sobald deine Versionen etwas älter sind, geht deine Rechnung dann nochmal hoch. Um wirklich die Vorteile der Cloud zu nutzen, musst du sogar dann die Cloud-Services Nutzen, die es speziell nur bei einem Anbieter gibt.&lt;br&gt;
So wie wir das ganze hier aufsetzen, kann man es einfach lassen und vergessen.&lt;br&gt;
Außerdem wirst du viel darüber lernen, wie django und Webapplikationen generell sich in Produktion verhalten. In Produktion ist nämlich nochmal einiges anders als in der Entwicklung.&lt;/p&gt;

&lt;p&gt;Mit dieser Art und Weise kannst du deine App sehr günstig auf irgend einem Hoster Hosten, kannst hoster wechseln und solange deine Nutzerzahlen nicht explodieren alles einfach in Ruhe lassen. Sobald deine Nutzerzahlen dann ansteigen, lohnt es sich erste Änderungen in Skalierungsrichtung zu unternehmen. Denn Kubernetes &amp;amp; Containerisierte Infrastruktur brauchen viel Zeit um gut aufgesetzt zu werden.&lt;/p&gt;
&lt;h2&gt;
  
  
  Server Aufsetzen
&lt;/h2&gt;
&lt;h3&gt;
  
  
  VPS kaufen
&lt;/h3&gt;

&lt;p&gt;Ich habe meinen VPS auf hetzner gekauft, aber jeder andere Hosting-Anbieter geht an sich auch. &lt;br&gt;
&lt;a href="https://www.hetzner.com/de/cloud/"&gt;Hetzner Cloud Link&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Nutzer erstellen
&lt;/h3&gt;

&lt;p&gt;Direkt nach kauf kommst du normalerweise als 'root' Nutzer auf den VPS. Der root Nutzer hat alle Rechte, ist deswegen nützlich aber auch gefährlich. Es ist eine gute Idee dir einen Nutzer anzulegen und diesem Nutzer sudo-rechte zu geben. Dadurch wird dein Server sicherer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;adduser mein_nutzername
adduser mein_nutzername sudo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Sicherheit
&lt;/h3&gt;

&lt;p&gt;Weil dein Server eine Produktive app hostet, sollte es am besten nicht möglich sein sich als root Nutzer über ssh einzuloggen. Vor allem wenn du das über das Passwort tun kannst &lt;strong&gt;musst&lt;/strong&gt; du hier etwas für die Sicherheit des Servers tun. Es gibt ständig ssh log-in Versuche als root, das sind eben bots die versuchen auf deinen Server Zugriff zu bekommen. Um diesen den Eintritt zu verwehren musst du einfach das root-login ausschalten und nur das login über deinen personalisierten Nutzer erlauben.&lt;/p&gt;

&lt;p&gt;Generiere dir auf deinem eigenen Computer einen ssh-key, falls du noch keinen hast. Du kannst die Standard Einstellungen bestätigen. Nach Erstellung sollte sich der key unter ~/.ssh/ befinden. Es sollten sich dort nun eine id_rsa und eine id_rsa.pub - Datei befinden.&lt;br&gt;
Wenn du Windows nutzt, &lt;a href="https://learn.microsoft.com/en-us/windows/wsl/install"&gt;hole dir WSL&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh-keygen
ls -l ~/.ssh/id_rsa*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Jetzt kannst du deinen ssh-key bei deinem Server hinzufügen, um dich mit deinem Nutzer sicher einloggen zu können.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh-copy-id mein_nutzername@meine.server.ip
# teste das ganze
ssh mein_nutzername@meine.server.ip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nun kannst du dem root user verbieten sich via ssh key / Passwort einzuloggen. Ebenso solltest du deine eigene Möglichkeit, dich via Passwort einzuloggen entfernen. Aber vorsicht! nachdem du die sshd_config verändert hast, kannst du dich nur noch mit deinem ssh-key einloggen! Verliere ihn nicht...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo vi /etc/ssh/sshd_config

# Folgende Einstellungen setzen / ändern
PasswordAuthentication no
PubkeyAuthentication yes
PermitRootLogin no

# Jetzt probieren ob das ganze geklappt hat!!
ssh my_username@my.server.ip
ssh root@my.server.ip
# Beim root login-versuch sollte folgende Nachricht erscheinen:
root@xxx.xxx.xxx.xx: Permission denied (publickey).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vielen Dank fürs lesen!&lt;br&gt;
Im nächsten Teil wird es um die Datenbank gehen...&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
