Linux Server setup

Django

Das open-source Webframework Django ist in Python geschrieben und wird von der Django Software Foundation betreut. Es folgt dem Model View Presenter (MVP) Paradigma.

Wie schon erwähnt werden wir mit dem python3-venv Modul eine virtuelle Umgebung anlegen, um die Applikation darin zu kapseln. So können mehrere Django Installationen unabhängig voneinander laufen, ohne dass sie oder deren Abhängigkeiten sich gegenseitig beeinflussen.

Als Datenbank verwenden wir PostgreSQL.

Das Projektverzeichnis ist in meinem Beispiel /var/www/com.linuxserversetup.dev.

Nächsten Schritte:


Virtuelle Umgebung erstellen

Eine virtuelle Umgebung erstellen wir mit dem Befehl python3 gefolgt von dem Parameter -m (Modul Name), also venv und einem Ordnernamen oder einem Pfad:


__$ python3 -m venv /var/www/com.linuxserversetup.dev/vm1
 

Der Ordner vm1 wird automatisch angelegt und darin auch weitere Ordner und Dateien.

Schauen wir kurz nach:


__$ ls -la /var/www/com.linuxserversetup.dev/vm1
 

Ausgabe:


drwxrwxr-x 6 tom tom 4096 Jan  4 13:08 .
drwxr-xr-x 7 tom tom 4096 Jan  3 20:52 ..
drwxrwxr-x 2 tom tom 4096 Jan  4 13:08 bin
drwxrwxr-x 2 tom tom 4096 Jan  4 13:08 include
-rw-rw-r-- 1 tom tom  143 Jan  3 20:05 index.htm
drwxrwxr-x 3 tom tom 4096 Jan  4 13:08 lib
lrwxrwxrwx 1 tom tom    3 Jan  4 13:08 lib64 -> lib
-rw-rw-r-- 1 tom tom   70 Jan  4 13:08 pyvenv.cfg
drwxrwxr-x 3 tom tom 4096 Jan  4 13:08 share


Virtuelle Umgebung starten und deaktivieren

Aktivieren

Der Befehl activate wurde in dem Unterverzeichnis bin als ausführbare Datei angelegt. Um in der virtuellen Umgebung arbeiten zu können, muss sie erst gestartet werden:


__$ source /var/www/com.linuxserversetup.dev/vm1/bin/activate
 

Nach der Aktivierung erscheint der Name der virtuellen Umgebung in Klammern vor dem Benutzernamen:


(vm1) tom@srv1:~$

Deaktivieren

Im aktivierten Zustand kann die virtuelle Umgebung mit dem Befehl deactivate beendet bzw. verlassen werden:


(vm1) tom@srv1:~$ deactivate

Die Symbolik für den aktivierten Zustand (vm1) tom@srv1:~$ lasse ich von nun an weg, damit die Befehle ohne Aufwand kopiert werden können!


Django installieren

Für die Installation von Django müssen wir uns in einer aktivierten virtuellen Umgebung befinden:


__$ source /var/www/com.linuxserversetup.dev/vm1/bin/activate
	

Für die Installation benötigen wir die Paketverwaltung pip, was wir schon auf dieser Python, pip, PostgreSQL installiert hatten.

Im aktivierten Zustand installieren wir die neueste Version von Django:


__$ python3 -m pip install django

Wir können eine Modulliste mit freeze erstellen lassen. Ohne Angabe eines Dateinamens wird die Datei requirements.txt erzeugt. Um eine optische Zuordnung zur virtuellen Umgebung erkennbar zu machen, gebe ich den Dateinamen vm1.pip vor:


__$ python3 -m pip freeze > /var/www/com.linuxserversetup.dev/vm1.pip

Diese Datei liegt nun neben dem Ordner mit der virtuellen Umgebung:


__$ ls -la /var/www/com.linuxserversetup.dev

Ausgabe:


drwxrwxr-x 3 tom tom 4096 Jan  4 14:59 .
drwxr-xr-x 7 tom tom 4096 Jan  3 20:52 ..
drwxrwxr-x 7 tom tom 4096 Jan  4 15:00 vm1
-rw-rw-r-- 1 tom tom   69 Jan  4 14:59 vm1.pip

Lassen wir uns noch kurz den Inhalt von vm1.pip ausgeben:


__$ less /var/www/com.linuxserversetup.dev/vm1.pip

Installierte Module und Abhängigkeiten der Django Applikation (erstellt mit freeze):

/var/www/com.linuxserversetup.dev/vm1.pip


asgiref==3.4.1
backports.zoneinfo==0.2.1
Django==4.0
sqlparse==0.4.2

Django wäre damit in der virtuellen Umgebung installiert, aber noch nicht lauffähig. Dazu müssen wir erst ein Django Projekt erstellen.


Django Projekt erzeugen

Django stellt ein paar Python Skripte zur Verfügung, die uns helfen eine Django Instanz zu erzeugen. Wir bekommen dadurch eine Verzeichnisstruktur und Konfigurationsdateien, die wir Schritt für Schritt editieren werden.

Wechseln wir der Einfachheit halber mit cd in das entsprechende Verzeichnis:


__$ cd /var/www/com.linuxserversetup.dev/vm1

Die Shell nach dem Verzeichniswechsel:


tom@srv1:/var/www/com.linuxserversetup.dev/vm1$

Auch diese Vorzeichen tom@srv1:/var/www/com.linuxserversetup.dev/vm1$ aus der Shell lasse ich fortan weg!

Ein Projekt erstellen wir mit startproject gefolgt von einem frei zu wählenden Instanznamen. In meinem Fall app1:


__$ django-admin startproject app1

Das hat uns den Ordner app1 erzeugt. Schauen wir kurz hinein:


__$ ls -la app1

Inhalt von /var/www/com.linuxserversetup.dev/vm1/app1:


drwxrwxr-x 2 tom tom 4096 Jan  4 15:00 app1
-rwxrwxr-x 1 tom tom  660 Jan  4 15:00 manage.py

Werfen wir auch einen Blick in den Ordner app1/app1:


__$ ls -la app1/app1

Inhalt von /var/www/com.linuxserversetup.dev/vm1/app1/app1:


-rw-rw-r-- 1 tom tom  385 Jan  4 15:00 asgi.py
-rw-rw-r-- 1 tom tom    0 Jan  4 15:00 __init__.py
-rw-rw-r-- 1 tom tom 3213 Jan  4 15:00 settings.py
-rw-rw-r-- 1 tom tom  746 Jan  4 15:00 urls.py
-rw-rw-r-- 1 tom tom  385 Jan  4 15:00 wsgi.py


ALLOWED_HOSTS konfigurieren

In der settings.py im Abschnitt ALLOWED_HOSTS müssen wir den Domainnamen und die interne Adresse hinterlegen:


__$ nano /var/www/com.linuxserversetup.dev/vm1/app1/app1/settings.py

Dieser Abschnitt sieht bei mir dann so aus:

Auszug von /var/www/com.linuxserversetup.dev/vm1/app1/app1/settings.py


. . .
ALLOWED_HOSTS = ['127.0.0.1', 'dev.linuxserversetup.com']
. . .

Speichern und schließen (STRG+s, STRG+x).


Datenbank konfigurieren

Für die Unterstützung von PostgreSQL benötigt Django das Modul Psycopg. Wir installieren den Adapter mit pip:


__$ pip install psycopg2-binary
 

Anschließend editieren wir die settings.py im Abschnitt DATABASES:


__$ nano /var/www/com.linuxserversetup.dev/vm1/app1/app1/settings.py

Und geben die Verbindungsdaten zu unserer PostgreSQL Datenbank ein. Dieser Abschnitt sollte dann so aussehen:

Auszug von /var/www/com.linuxserversetup.dev/vm1/app1/app1/settings.py


. . .
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'django_db',
        'USER': 'tom',
        'Password': 'tom123',
        'HOST': 'localhost',
        'PORT': '5432',
    }
}
. . .

Speichern und schließen (STRG+s, STRG+x).


Django Instanz testen

Mit dem Skript manage.py können wir die Django App starten und die bisherige Konfiguration überprüfen. Falls die virtuelle Umgebung zwischenzeitlich deaktivert wurde, kannst Du sie mit (source bin/activate) wieder aktivieren.


__$ python app1/manage.py runserver
 

Ausgabe:


Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).

You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
January 20, 2022 - 20:50:57
Django version 4.0, using settings 'app1.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Du solltest die Meldung System check identified no issues (0 silenced) sehen, denn die besagt, dass es zu keinem unerwarteten Systemfehler gekommen ist. Es sind allerdings Bestandteile des Webframeworks noch nicht in die Datenbank migriert worden (unapplied migration(s)). Das erledigen wir im nächsten Abschnitt. Vorher beenden wir den Dienst mit STRG+c.


Daten migrieren

Wir führen erneut manage.py mit dem Parameter migrate aus:


__$ python app1/manage.py migrate
 

Ausgabe:


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

Jetzt sollte der Django Dienst korrekt laufen. Wir starten den Dienst erneut:


__$ python app1/manage.py runserver
 

Die Ausgabe sollte dann so aussehen:


Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).
January 20, 2022 - 21:20:24
Django version 4.0, using settings 'app1.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Django läuft jetzt als interner Dienst auf 127.0.0.1:8000. Als nächstes müssen wir unseren Nginx Server (Reverse Proxy) dahin kommunizieren lassen.


Nginx für Django konfigurieren

Den Nginx Serverblock für die Subdomain dev.linuxserversetup.com hatten wir bereits in dem Kapitel Subdomain Server Block (dev) angelegt.

Nginx ist an dieser Stelle dafür verantwortlich HTTPS zu erzwingen und die Verbindung für die Subdomain zu verschlüsseln. Nun müssen wir den Server Block so abändern, dass die Kommunikation über die Domain zum Django Dienst hin- und auch zurückgeleitet wird.


__$ sudo nano /etc/nginx/sites-available/com.linuxserversetup.dev.conf
 

Die Nginx Konfiguration soll schließlich so aussehen:

/etc/nginx/sites-available/com.linuxserversetup.dev.conf


# force https
server {
  listen      80;
  server_name dev.linuxserversetup.com;
  return      301 https://$server_name$request_uri;
}

# main block
server {
  listen      443 ssl http2;
  listen      [::]:443 ssl http2;
  server_name dev.linuxserversetup.com;

  root        /var/www/com.linuxserversetup.dev/;
  index       index.htm;

  location / {
    proxy_pass http://127.0.0.1:8000;
    proxy_http_version 1.1;
    proxy_cache_bypass $http_upgrade;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_set_header x-real-ip $remote_addr;
    proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Host  $host;
    proxy_set_header X-Forwarded-Port  $server_port;
    proxy_set_header Referer           $http_referer;
    proxy_pass_header content-security-policy;
  }

  ssl_certificate /etc/letsencrypt/live/dev.linuxserversetup.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/dev.linuxserversetup.com/privkey.pem;
  ssl_trusted_certificate /etc/letsencrypt/live/dev.linuxserversetup.com/chain.pem;

  # dhparam
  ssl_dhparam /etc/ssl/certs/dhparam.pem;

  # HSTS
  add_header Strict-Transport-Security "max-age=31536000";
}

Es wurde hauptsächlich der location Block geändert. Einige Proxy Direktiven sind dort hinzugekommen. Ganz entscheidend ist hier proxy_pass http://127.0.0.1:8000.

Damit die Konfiguration von Nginx übernommen wird, überprüfen wir die neuen Einstellungen und starten den Dienst neu:


__$ sudo nginx -t
__$ sudo systemctl restart nginx
 

Wenn die Nginx Konfiguration in Ordnung ist, sollte diese Rückmeldung kommen:


nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
 

Django App starten und testen

Wir starten die Django App erneut:


__$ python app1/manage.py runserver
 

Jetzt können wir die Domain dev.linuxserversetup.com über einen Browser aufrufen und es sollte die Django Debug Seite erscheinen.


Virtuelle Umgebung löschen

Wie eine venv Umgebung gelöscht wird, soll hier nur der Vollständigkeit halber erwähnt werden.

Falls noch aktiviert, verlassen wir die virtuelle Umgebung deactivate:


__$ deactivate

Anschließend genügt es den Ordner mit rm zu löschen:


__$ rm -rf /var/www/com.linuxserversetup.dev/vm1