Taula de continguts

Posada en producció d'un projecte Django + ReactJS

Hi ha diverses eines per a poder realitzar aquest desplegament. Les opcions més habituals son:

En aquest article ho farem amb Apache + mod_wsgi.


Conceptes previs

En un projecte amb Django i React, cal tenir clar que hi ha una part de processament al servidor (Django) que ha de respondre les peticions que requereixen accés i manipulació de les dades a la BD (bàsicament serà l'API i l'admin panel), i una part que s'executa al client (React) i que des del punt de vista del servidor son simples arxius estàtics.

A més d'això, per la part de servidor també caldrà servir els arxius estàtics de la part Django (al menys per l'admin panel) i les possibles càrregues (uploads) que es solen parlar com d'arxius media.

Per altra banda, cal fer servir un motor de BD adequat com Postgre, MySQL, MariaDB o Oracle. SQLite no és una opció per producció, tot i que va bé per desenvolupament i una part del testing.

En resum:


Prerequisits

Abans de començar necessitem disposar de:

Assumim que el servidor que disposem és dedicat únicament a aquesta app. És possible configurar diverses aplicacions en un server, però en ares de la simplicitat ho plategem així.


MariaDB

Configurem primer de tot la BD de producció. Farem servir MariaDB però es podrien seguir pràcticament les mateixes passes per MySQL. Per a PostgreSQL o Oracle canviara força coses de la creació de l'espai d'usuari i esquemes.

  $ sudo apt update
  $ sudo apt install mariadb-server
  $ sudo mysql
  mysql> create user biblio@localhost identified by "biblio123";
  mysql> grant all on biblio.* to biblio@localhost;
  mysql> create database biblio;

Mai poseu una password tan evident com «biblio123» en producció. Això està bé en development local, però no en cap servidor públic, per molt que els ports de la BD no siguin públics des de fora.

Amb això ja tindríem instal·lada la BD, amb un usuari biblio i amb accés a la DB biblio.


Django

Instal·lem dependències del sistema. Utilitzarem Python venv per a la gestió de les biblioteques de codi.

Haurem d'afegir el paquet mysqlclient de Python que potser no es feia servir en desenvolupament.

Assumim que el projecte Django utilitza un plugin com django-environ o django-dotenv per a la gestió de les credencials. Si no ho tens, pots fer un cop d'ull a l'article django-environ i el vcs.

També assumim que instal·larem l'aplicació Django al home directory de l'usuari principal del sistema, com super o isard. També seria adequat fer-ho en una carpeta de sistema (p.ex. /var/www/) si es tractés d'un entorn multiusuari, situació menys freqüent actualment ja que es sol tenir un contenidor LXC o VM específic per a cada aplicació.

$ sudo apt install default-libmysqlclient-dev python3-dev python3-venv git
$ git clone https://github.com/elmeuusuari/projecte-django-react
$ cd projecte-django-react
$ python3 -m venv env
$ source env/bin/activate
(env) $ pip install -r requirements.txt
(env) $ pip install mysqlclient
(env) $ cp .env.example .env

Ajusta els valors de .env, en particular activa la línia d'exemple per a MariaBD i comenta la de sqlite.

També ajusta el domini elmeudomini.com com pertoqui:

.env
SECRET_KEY=sdjfhisdfg67sdtf78ewhf8w3efheh7uf9iehfj98er
DATABASE_URL=mysql://biblio:biblio123@127.0.0.1:3306/biblio
#DATABASE_URL=sqlite:///db.sqlite3
ALLOWED_HOSTS=elmeudomini.com
CORS_ALLOWED_ORIGINS=http://localhost:5173,http://127.0.0.1:5173,https://elmeudomini.com

Fixeu-vos que ALLOWED_HOSTS hem tret el domini wildcard «*» i només deixem el domini real en producció. Son mesures de seguretat importants.

Ara ja podem acabar de fer comprovacions i crear les taules de la BD:

(env) $ ./manage.py check
(env) $ ./manage.py migrate
(env) $ ./manage.py createsuperuser

Tests

Podeu fer també un runserver i fer proves amb el servidor de desenvolupament si podeu accedir al port 8000 (sempre i quan tingueu aquest port obert externament):

(env) $ ./manage.py runserver

Amb el servidor de desenvolupament obert podeu provar d'accedir (amb una altra shell) a l'API o l'admin panel amb:

$ curl localhost:8000/api/llibres
$ curl localhost:8000/admin


ReactJS

Assumim que disposem de la part de React del projecte a la carpeta /react, tot i que podria ser perfectament un repositori a part

Instal·lem NodeJS versió LTS. Primer instal·lem la versió que hi hagi als repos del sistema operatiu que tinguem, i després fem un upgrade amb l'eina n:

sudo apt install nodejs	npm
sudo npm i -g n
sudo n lts

Tanqueu el terminal o la connexió SSH perquè els canvis de la versió de NodeJS prenguin efecte.

Aneu a la carpeta de React, configurem i compilem:

$ cd /ruta/a/la/carpeta/react
$ npm install
$ cp src/config.js.example src/config.js

Editeu src/config.js, bàsicament canviar les URLs d'accés amb l'esquema complert de https://elmeudomini.com .

Un cop configurat amb els dominis adequats, podem compilar l'app React.

$ npm run build

El npm run build crearà una carpeta dist/ on hi haurà els arxius estàtics per al desplegament, en particular el punt d'entrada únic index.html.


Configurar Apache2


Permisos de carpetes

Probablement haureu clonat el repositori del projecte al home directory de l'usuari que tingueu, per exemeple super o isard. Aquesta carpeta del home directory com /home/super/ sol tenir permisos restringits per protegir les dades en sistemes multiusuari, però com que no és el nostre cas (assumim un entorn monousuari), podem obrir els permisos per facilitar que Apache pugui arribar i llegir les carpetes del projecte:

$ chmod 755 ~


Arxius estàtics Django

Necessitem recollir tots els arxius estàtics del projecte Django per servir-los a la URL /static. La instrucció collectstatic ens ho facilitarà, però abans caldrà modificar settings.py per indicar el nom de la carpeta d'arxius estàtics. Localitzeu la línia amb:

STATIC_URL = 'static/'

I afegiu a darrera el nom de la carpeta o vulgueu els arxius estàtics (podeu triar el nom):

STATIC_ROOT = 'static/'

Ara ja podeu recollir tots els arxius estàtics de l'app Django i del seu admin panel:

(env) $ ./manage.py collectstatic


Instal·lem Apache

Ara sí! Instal·lem Apache i el mòdul mod_wsgi que ens permetrà connectar Apache a l'app Python. WSGI és un estàndard de comunicació entre servidors i aplicacions web (Web Server Gateway Interface), tot que es fa servir bàsicament en aquestes apps Python com Django, Flask o FastAPI.

$ sudo apt install apache2 libapache2-mod-wsgi-py3
$ sudo a2enmod rewrite


Configuració Apache

La configuració, com hem vist al principi, no és senzilla. Recopilem el què anem a fer:

Assumim que tenim una configuració monousuari i monoaplicació (una VM o CT dedicat per a aquesta app). En aquest cas podeu implementar directament a la site per defecte d'Apache /etc/apache2/sites-available/000-default.conf:

/etc/apache2/sites-available/000-default.conf
<VirtualHost *:80>
	# Si només tenim 1 domini, no cal anomenar-lo
	#ServerName www.example.com
 
	WSGIDaemonProcess myapp python-home=/home/super/django-react/env python-path=/home/super/django-react
	WSGIProcessGroup myapp
	WSGIScriptAlias / /home/super/django-react/djangoreact/wsgi.py
 
	<Directory /home/super/django-react/djangoreact>
		<Files wsgi.py>
		Require all granted
		</Files>
	</Directory>
 
	Alias /static/ /home/super/django-react/static/
	<Directory /home/super/django-react/static>
		Require all granted
	</Directory>
	Alias /media/ /home/super/django-react/media/
	<Directory /home/super/django-react/media>
		Require all granted
	</Directory>
 
	# REACT FRONTEND
	Alias /assets /home/super/django-react/react/dist/assets/
	Alias /index.html /home/super/django-react/react/dist/index.html
	AliasMatch ^/$ /home/super/django-react/react/dist/index.html
	<Directory /home/super/django-react/react/dist>
		Require all granted
	</Directory>
 
	# Regla de reescriptura per a React Router
	# Les rutes conegudes no entren: /admin /api /static /media i /assets
	# La resta de rutes van a dist/index.html (React Router)
	RewriteEngine On
	RewriteCond %{REQUEST_URI} !^/admin
	RewriteCond %{REQUEST_URI} !^/api
	RewriteCond %{REQUEST_URI} !^/static
	RewriteCond %{REQUEST_URI} !^/media
	RewriteCond %{REQUEST_URI} !^/assets
	RewriteCond %{REQUEST_FILENAME} !-f
	RewriteRule ^ /home/super/django-react/react/dist/index.html [L]
 
	ServerAdmin webmaster@localhost
	DocumentRoot /var/www/html
 
	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

Reinicia Apache amb:

$ sudo systemctl restart apache2.service


Comprovacions

Si no et dona errors al reiniciar Apache, prova les següents comprovacions.

Django funciona a /api i /admin:

$ curl https://elmeudomini.com/api/llibres
$ curl https://elmeudomini.com/admin

Si no es veu des de fora amb el domini, intenta comprovar que sí que funciona des de dins:

$ curl http://localhost/api/llibres
$ curl http://localhost/admin

En particular, comprova que els arxius estàtics es veuen quan anem a /admin.

Funciona el frontend de React a https://elmeudomini.com (amb el navegador).

Si no es veu des de fora, intenta la comprovació interna:

$ curl http://localhost

Si apareix la pàgina de React però no carrega les dades de l'API, obre la consola de Javascript del navegador i investiga el problema que estigui succeint (CORS, etc.)


Media Uploads

Comproveu que es pot accedir a /admin i que podeu afegir llibres amb imatges.

Si us dona problemes, segurament és que necessitareu donar permisos a /media perquè Apache hi pugui escriure:

$ sudo chown -R www-data /home/super/django-react/media