Na przykładzie Fedora Linux 38
Plik settings.py:
DEBUG = False ALLOWED_HOSTS = ['localhost', '127.0.0.1'] STATIC_URL = '/static/' STATIC_ROOT = BASE_DIR / 'static'
Dla wersji starszej niż 3.6 powinniśmy użyć:
import os STATIC_ROOT = os.path.join(BASE_DIR, 'static')
W niektórych wypadkach może zajść konieczność dodania parametru:
CSRF_TRUSTED_ORIGINS = ['http://127.0.0.1',]
user nginx;
http {
include /etc/nginx/conf.d/*.conf;
server {
listen 81;
listen [::]:81;
}
server {
listen 80;
listen [::]:80;
server_name localhost;
charset utf-8;
# max upload size
client_max_body_size 75M;
# Django media
location /media {
alias /path/to/your/mysite/media;
}
location /static {
alias /home/user_app/PycharmProjects/venvFolder/FolderProjektDjango/FolerApp/static;
}
location / {
proxy_pass http://localhost:8080;
}
}
systemctl restart nginx
[Unit] Description=Gunicorn instance to serve application After=network.target [Service] User=user_app Group=user_app StandardOutput=journal StandardError=journal WorkingDirectory=/home/user_app/PycharmProjects/venvFolder/FolderProjektDjango ExecStart=/home/user_app/PycharmProjects/venvFolder/venv/bin/gunicorn --workers 3 --bind 127.0.0.1:8080 ProjektDjango.wsgi ExecReload=/bin/kill -s HUP $MAINPID KillMode=mixed TimeoutStopSec=5 PrivateTmp=true [Install] WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable gunicorn.service
systemctl start gunicorn.service
systemctl status gunicorn.service
journalctl -xe
Katalog /home powinien mieć uprawnienia 755. Katalog static i nadrzędne powinny mieć uprawnienia 750 a użytkownik nginx, który uruchamia usługę nginx powinien być dodany do grupy użytkownika Gunicorn:
usermod -aG user_app nginx
Wydajemy polecenie getfacl dla katalogu użytkownika aplikacji:
getfacl /home/user_app getfacl: Usunięcie wiodącego '/' ze ścieżek bezwzględnych # file: home/user_app # owner: user_app # group: user_app user::rwx user:qemu:--x group::--- mask::r-x other::---
Jak widać katalog nie należy do żadnej grupy. Dodajemy katalog do grupy użytkownika (taka sama nazwa jak nazwa użytkownika.
setfacl -m g:user_app:r-x /home/user_app
Możemy sprawdzić zmiany:
getfacl /home/user_app getfacl: Usunięcie wiodącego '/' ze ścieżek bezwzględnych # file: home/user_app # owner: user_app # group: user_app user::rwx user:qemu:--x group::--- group:user_app:r-x mask::r-x other::---
Jeżeli nadal nie mamy dostępu musimy sprawdzić poszczególne katalogi:
ls -all -d /home/user_app/ drwxr-x---+ 1 user_app user_app 1380 01-03 11:01 /home/user_app/
Różnica między drwxr-x—+ a drwxr-x—. polega na obecności atrybutu + w pierwszym przypadku. Ten atrybut oznacza, że istnieje dodatkowa kontrola dostępu, tak zwane Access Control List (ACL).
1. drwxr-x—+
d: Katalog.rwx: Prawa dostępu właściciela (czytanie, zapisywanie, wykonywanie).r-x: Prawa dostępu grupy (czytanie, brak zapisywania, wykonywanie).—: Brak praw dostępu dla innych.+: Wskaźnik na fakt, że istnieje ACL, który może zawierać dodatkowe reguły dostępu dla konkretnych użytkowników i grup.2. drwxr-x—.:
d: Katalog.rwx: Prawa dostępu właściciela (czytanie, zapisywanie, wykonywanie).r-x: Prawa dostępu grupy (czytanie, brak zapisywania, wykonywanie).—: Brak praw dostępu dla innych..: Wskazuje na to, że nie ma dodatkowych reguł ACL. To zazwyczaj oznacza, że kontrola dostępu opiera się wyłącznie na standardowych prawach dostępu (owner, group, others).Atrybut ACL pozwala na bardziej elastyczną kontrolę dostępu niż standardowe prawa dostępu. Dzięki ACL można, na przykład, precyzyjnie kontrolować dostęp dla konkretnych użytkowników i grup, a także określać dodatkowe uprawnienia.
Na koniec przykład zmian uprawnień dla użytkownika:
setfacl -m u:nginx:r-x /home/user_app
setsebool -P httpd_read_user_content 1 setenforce 1 getenforce ausearch -c '(gunicorn)' --raw | audit2allow -M my-gunicorn semodule -X 300 -i my-gunicorn.pp && rm -f my-gunicorn.*
Jeżeli Gunicon i NGINX jest na jednym serwerze komunikację między nimi najlepiej użyć za pomocą pliku socket.
Decyzja, czy plik socket Gunicorn powinien być tworzony w katalogu /tmp czy /run, zazwyczaj zależy od preferencji i praktyk administratora systemu oraz zaleceń dystrybucji.
1. /tmp
2. /run
/tmp.Najważniejsze jest, aby pamiętać o tym, żeby nadać odpowiednie uprawnienia do katalogu, w którym utworzysz plik socket, aby Gunicorn i Nginx mogły współpracować. Upewnij się również, że obie usługi (Gunicorn i Nginx) mają dostęp do tego samego katalogu i pliku socket. Ostateczna decyzja zależy od wymagań twojej konkretnego środowiska i preferencji.
Plik uruchamiający usługę Gunicorn:
[Unit] Description=Gunicorn instance to serve application After=network.target [Service] User=user_app Group=user_app StandardOutput=journal StandardError=journal WorkingDirectory=/home/user_app/PycharmProjects/venvFolder/FolderProjektDjango ExecStart=/home/user_app/PycharmProjects/venvFolder/venv/bin/gunicorn --workers 3 --bind unix:/tmp/gunicorn.sock ProjektDjango.wsgi ExecReload=/bin/kill -s HUP $MAINPID KillMode=mixed TimeoutStopSec=5 PrivateTmp=false [Install] WantedBy=multi-user.target
Należy zwrócić uwagę na opcję PrivateTmp=false. Bez niej usługa może utworzyć plik w losowym podkatalogu. Przykładowo /tmp/systemd-private-1ab04e6700c74be2a90e7f49edc79e19-gunicorn.service-94a5le/tmp/gunicorn.sock.
Plik konfiguracji NGiNX do Gunicorn:
server { listen 80; server_name localhost; charset utf-8; client_max_body_size 75M; location /media { alias /path/to/your/mysite/media; } location /static { alias /home/user_app/PycharmProjects/venvFolder/FolderProjektDjango/static; } location / { proxy_pass http://unix:/tmp/gunicorn.sock; } }
Podobnie jak z usługą gunicorn.service w pliku /etc/systemd/system/multi-user.target.wants/nginx.service musimy dokonać zmiany i opcję PrivateTmp=true zmienić na PrivateTmp=false.
Możliwe, że SELinux będzie blokował dostęp NGiNX do pliku /tmp/gunicorn.sock. Na to może pomóc:
ausearch -c 'nginx' --raw | audit2allow -M my-nginx semodule -X 300 -i my-nginx.pp && rm -f my-nginx.*
Zachowanie określonej kolejności przy uruchamianiu i wyłączaniu usług Nginx i Gunicorn może być kluczowe w niektórych przypadkach. Oto kilka uwag na ten temat:
1. Uruchamianie:
2. Wyłączanie:
Przykładowy scenariusz wyłączania:
sudo systemctl stop nginxsudo systemctl stop gunicornPamiętaj, że konkretna kolejność może się różnić w zależności od konfiguracji systemu operacyjnego. Ważne jest, aby dostosować się do specyfiki środowiska i stosować praktyki zgodne z dokumentacją usług oraz zaleceniami dostawcy systemu operacyjnego.
Korzystnie jest zmodyfikować skrypt uruchamiania serwisu nginx i dodać opcje ustalającą uruchomienie nginx po usłudze gunicorn:
After=network-online.target remote-fs.target nss-lookup.target gunicorn.service
Pobieramy najnowszą wersję nginx. Rozpakowujemy przykładowo w lokalizacji C:\nginx.
W pliku C:\nginx\nginx.conf w sekcji http dodajemy opcję:
http{
...
include waitress.onf;
...
}
W tym samym katalogu tworzymy plik waitress.conf z zawartością:
server{
listen localhost:81;
location /static {
alias "C:/Python/PycharmProjects/DjangoProjects/project/static";
}
location / {
proxy_pass http://localhost:8080;
}
}
Należy zwrócić uwagę, że mimo konfiguracji nginx w systemie windows to w ścieżkach używamy ukośnika jak w systemie UNIX.
Pobieramy najnowszą wersję php. Rozpakowujemy w katalogu C:\nginx\php.
Oczywiście Django nie wymaga PHP ale tak przy okazji instalacji DokuWiki podaje jak to zrobić. Wracamy ponownie do pliku nginx.conf. Domyślnie w pliku powinna znajdować się sekcja jak poniżej. Należy ją odkomentować i jedynie domyślny wpis /scripts$fastcgi_script_name zmienić na $document_root$fastcgi_script_name. Efekt jak poniżej:
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
location ~ \.php$ {
root html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
W środowisku naszej aplikacji Django instalujemy pakiet waitress:
pip install waitress
W katalogu naszego projekty Django tworzymy plik runserver.py z zawartością:
from waitress import serve from project.wsgi import application if __name__ == '__main__': serve(application, host = 'localhost', port='8080')
Przy czym project w from project.wsgi import application to nazwa naszego projektu Django. Projektu, a nie aplikacji Django.
Pobieramy najnowszą wersję nssm. Rozpakowujemy w katalogu C:\nginx\nssm. Jeżeli używamy wersji 64bit to wykonujemy następujące polecenia.
C:\nginx\nssm\win64\nssm.exe install WaitressService "C:\Python\PycharmProjects\DjangoProjects\.venv\Scripts\python.exe" "C:\Python\PycharmProjects\DjangoProjects\project\runserver.py"
Możemy sprawdzić status usługi:
C:\nginx\nssm\win64\nssm.exe status WaitressService
lub uruchomić:
C:\nginx\nssm\win64\nssm.exe start WaitressService
C:\nginx\nssm\win64\nssm.exe install PHPService "C:\nginx\php\php-cgi.exe" -b 127.0.0.1:9000
Możemy sprawdzić status usługi:
C:\nginx\nssm\win64\nssm.exe status PHPService
lub uruchomić:
C:\nginx\nssm\win64\nssm.exe start PHPService
C:\nginx\nssm\win64\nssm.exe install NGINXService "C:\nginx\nginx.exe"
Możemy sprawdzić status usługi:
C:\nginx\nssm\win64\nssm.exe status NGINXService
lub uruchomić:
C:\nginx\nssm\win64\nssm.exe start NGINXService
Jeżeli zajdzie taka konieczność to usługę możemy zatrzymać:
C:\nginx\nssm\win64\nssm.exe stop NGINXService
lub usunąć:
C:\nginx\nssm\win64\nssm.exe remove NGINXService confirm
runserver.py i waitress.confnginx.conf i poleceniu startu usługi PHPService
Możemy katalog C:\nginx\html zmienić na C:\nginx\html_old. Utworzyć nowy katalog C:\nginx\html. W nowym katalogu html pobrać i rozpakować pliki dokuwiki. Na potrzeby bezpieczeństwa aplikacji wprowadzić zmiany w pliku C:\nginx\nginx.conf i usunąć komentarze:
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
location ~ /\.ht {
deny all;
}
a pod nimi dodać:
location ~ /(data|conf|bin|inc|vendor)/ {
deny all;
}
Po zmianach restart usługi:
C:\nginx\nssm\win64\nssm.exe restart NGINXService
Tym sposobem zanim powstanie nasza aplikacja Django możemy na bieżąco w DokuWiki tworzyć do niej dokumentację.
Aby przesyłać pliki multimedialne przykładowo .jpg to w w pliku C:\nginx\nginx.conf dodajemy opcję:
http {
...
client_max_body_size 40M;
...
}
Następnie w pliku konfiguracyjnym C:\nginx\php\php.ini:
[PHP] post_max_size = 40M upload_max_filesize = 40M display_errors = Off
Restartujemy usługi PHP i NGINX.