From 06a6bddcffb43e974e38bdf226479c4054b99987 Mon Sep 17 00:00:00 2001 From: NothRen Date: Tue, 23 Dec 2025 12:57:27 +0100 Subject: [PATCH] Add a docker compose prod file that runs postgresql as database + edit settings.py and readme.md --- .gitignore | 3 ++ README.md | 23 ++++++++++++-- docker-compose-prod.yml | 66 +++++++++++++++++++++++++++++++++++++++++ env_exemple | 6 ++++ fossbadge/settings.py | 26 +++++++++++----- pyproject.toml | 1 + start.sh | 13 ++++---- start_dev.sh | 2 ++ uv.lock | 37 +++++++++++++++++++++++ 9 files changed, 160 insertions(+), 17 deletions(-) create mode 100644 docker-compose-prod.yml create mode 100644 env_exemple diff --git a/.gitignore b/.gitignore index 26ae07d..f491b79 100644 --- a/.gitignore +++ b/.gitignore @@ -71,3 +71,6 @@ venv.bak/ # Poetry poetry.lock + +# Logs +logs/ \ No newline at end of file diff --git a/README.md b/README.md index c514d67..54b6444 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [English](#english) | [Français](#français) - + ## 🏆 FossBadge - Open Badge Platform FossBadge is a free and open source platform for creating, managing, and sharing digital badges. It allows organizations to recognize skills and achievements through a simple, accessible interface. @@ -66,6 +66,15 @@ Run the tests : uv run python manage.py test ``` +### Launch in production +1. Set `Debug` to `False` in `fossbadge/settings.py`. +2. Install [docker](https://docs.docker.com/engine/install/) +3. Create à `.env` file : `$ cp env_exemple .env` and edit its values +4. Create a network in docker : `$ docker network create frontend` +5. Run the docker compose : `$ docker compose -f docker-compose-prod.yml up` + +After that, nginx will run on port 80. + ### 📁 Project Structure - `core/`: Main application with views, models, and templates @@ -84,7 +93,7 @@ This project is licensed under the AGPLv3 License - see the LICENSE file for det --- - + ## 🏆 FossBadge - Plateforme de Badges Ouverts FossBadge est une plateforme libre et open source pour créer, gérer et partager des badges numériques. Elle permet aux organisations de reconnaître les compétences et les réalisations à travers une interface simple et accessible. @@ -148,6 +157,16 @@ Lancer les tests : uv run python manage.py test ``` + +### Lancer en production +1. Mettre `Debug` à `False` dans `fossbadge/settings.py`. +2. Installer [docker](https://docs.docker.com/engine/install/) +3. Créer un fichier `.env` : `$ cp env_exemple .env` et éditer ses valeurs +4. Créer un réseau dans docker : `$ docker network create frontend` +5. Lancer le docker compose : `$ docker compose -f docker-compose-prod.yml up` + +Après ça, nginx tournera sur le port 80. + ### 📁 Structure du Projet - `core/` : Application principale avec les vues, modèles et templates diff --git a/docker-compose-prod.yml b/docker-compose-prod.yml new file mode 100644 index 0000000..66b6c4f --- /dev/null +++ b/docker-compose-prod.yml @@ -0,0 +1,66 @@ +services: + fossbadge_django: + build: . + container_name: fossbadge_django + hostname: fossbadge_django + restart: always + env_file: .env + user: fossbadge + volumes: + - ./ssh:/home/fossbadge/.ssh + - ./:/home/fossbadge/FossBadge + - static_volume:/home/fossbadge/FossBadge/staticfiles + depends_on: + - postgres + command: "bash start.sh" + networks: + - fossbadge_backend + + postgres: + image: postgres + restart: always + container_name: postgres + hostname: postgres + ports: + - "5432:5432" + env_file: + - .env + environment: + - "POSTGRES_HOST_AUTH_METHOD=trust" + networks: + - fossbadge_backend + + fossbadge_nginx: + image: nginx + restart: always + ports: + - 80:80 + container_name: fossbadge_nginx + hostname: fossbadge_nginx + volumes: + - ./media:/www/media + - static_volume:/www/static + - ./logs:/logs + - ./nginx:/etc/nginx/conf.d + depends_on: + - fossbadge_django + links: + - fossbadge_django:fossbadge_django + labels: + - traefik.enable=true + - traefik.docker.network=frontend + - traefik.http.routers.fossbadge_nginx.tls.certresolver=myresolver + - traefik.http.routers.fossbadge_nginx.rule=Host(`$DOMAIN`) + - traefik.http.services.fossbadge_nginx.loadbalancer.server.port=80 + - traefik.http.routers.fossbadge_nginx.middlewares=crowdsec@file + networks: + - frontend + - fossbadge_backend + +volumes: + static_volume: + +networks: + frontend: + external: true + fossbadge_backend: \ No newline at end of file diff --git a/env_exemple b/env_exemple new file mode 100644 index 0000000..0b11d2f --- /dev/null +++ b/env_exemple @@ -0,0 +1,6 @@ +DOMAIN="" # your domain + +# POSTGRES settings +POSTGRES_USER= +POSTGRES_DBNAME= +POSTGRES_PASSWORD= \ No newline at end of file diff --git a/fossbadge/settings.py b/fossbadge/settings.py index aa8dabc..e5ee257 100644 --- a/fossbadge/settings.py +++ b/fossbadge/settings.py @@ -11,7 +11,7 @@ """ from pathlib import Path - +import os # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent @@ -104,13 +104,25 @@ # Database # https://docs.djangoproject.com/en/5.2/ref/settings/#databases -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': BASE_DIR / 'db.sqlite3', - } -} +if DEBUG: + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + }, + } +else: + DATABASES = { + 'default': { + "ENGINE": "django.db.backends.postgresql", + "NAME": os.getenv("POSTGRES_DBNAME"), + "USER": os.getenv("POSTGRES_USER"), + "PASSWORD": os.getenv("POSTGRES_PASSWORD"), + "HOST": "postgres", + "PORT": 5432 + } + } # Password validation # https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators diff --git a/pyproject.toml b/pyproject.toml index bdf6040..efb962b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,6 +15,7 @@ dependencies = [ "django-cleanup (>=9.0.0,<10.0.0)", "gunicorn (>=23.0.0,<24.0.0)", "beautifulsoup4>=4.14.3", + "psycopg[binary]>=3.3.2", ] [dependency-groups] diff --git a/start.sh b/start.sh index cd01d00..1ecdcf6 100644 --- a/start.sh +++ b/start.sh @@ -6,17 +6,14 @@ export PATH="/home/fossbadge/.local/bin:$PATH" uv sync echo "UV install ok" +# Migrate uv run python3 manage.py migrate -# Install if no asset created : -uv run python3 manage.py install -# New static for nginx ? +# Add static to nginx uv run python3 manage.py collectstatic --noinput echo "Run GUNICORN" -echo "You should be able to see the Fedow dashbord at :" -echo "https://$DOMAIN/dashboard/" -sqlite3 ./database/db.sqlite3 'PRAGMA journal_mode=WAL;' -sqlite3 ./database/db.sqlite3 'PRAGMA synchronous=normal;' -uv run gunicorn fossbadge.wsgi --log-level=info --log-file /home/fossbadge/FossBadge/logs/gunicorn.logs -w 3 -b 0.0.0.0:8000 +echo "You should be able to see the fossbadge home at :" +echo "https://$DOMAIN/" +uv run gunicorn fossbadge.wsgi --log-level=info --log-file /home/fossbadge/FossBadge/logs/gunicorn.logs -w 3 -b 0.0.0.0:8000 \ No newline at end of file diff --git a/start_dev.sh b/start_dev.sh index 8be481a..60aee66 100644 --- a/start_dev.sh +++ b/start_dev.sh @@ -15,6 +15,8 @@ echo "UV install ok" sqlite3 ./db.sqlite3 'PRAGMA journal_mode=WAL;' sqlite3 ./db.sqlite3 'PRAGMA synchronous=normal;' +uv run python manage.py migrate + if [[ "$GUNICORN" == "1" ]]; then echo "→ Gunicorn activé, démarrage…" uv run python3 manage.py collectstatic --noinput diff --git a/uv.lock b/uv.lock index e6ac953..e10f096 100644 --- a/uv.lock +++ b/uv.lock @@ -146,6 +146,7 @@ dependencies = [ { name = "djangorestframework" }, { name = "gunicorn" }, { name = "pillow" }, + { name = "psycopg", extra = ["binary"] }, ] [package.dev-dependencies] @@ -165,6 +166,7 @@ requires-dist = [ { name = "djangorestframework", specifier = ">=3.16,<4.0.0" }, { name = "gunicorn", specifier = ">=23.0.0,<24.0.0" }, { name = "pillow", specifier = ">=10" }, + { name = "psycopg", extras = ["binary"], specifier = ">=3.3.2" }, ] [package.metadata.requires-dev] @@ -361,6 +363,41 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" }, ] +[[package]] +name = "psycopg" +version = "3.3.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "tzdata", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e0/1a/7d9ef4fdc13ef7f15b934c393edc97a35c281bb7d3c3329fbfcbe915a7c2/psycopg-3.3.2.tar.gz", hash = "sha256:707a67975ee214d200511177a6a80e56e654754c9afca06a7194ea6bbfde9ca7", size = 165630, upload-time = "2025-12-06T17:34:53.899Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8c/51/2779ccdf9305981a06b21a6b27e8547c948d85c41c76ff434192784a4c93/psycopg-3.3.2-py3-none-any.whl", hash = "sha256:3e94bc5f4690247d734599af56e51bae8e0db8e4311ea413f801fef82b14a99b", size = 212774, upload-time = "2025-12-06T17:31:41.414Z" }, +] + +[package.optional-dependencies] +binary = [ + { name = "psycopg-binary", marker = "implementation_name != 'pypy'" }, +] + +[[package]] +name = "psycopg-binary" +version = "3.3.2" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/75/ad18c0b97b852aba286d06befb398cc6d383e9dfd0a518369af275a5a526/psycopg_binary-3.3.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:9ca24062cd9b2270e4d77576042e9cc2b1d543f09da5aba1f1a3d016cea28390", size = 4596371, upload-time = "2025-12-06T17:34:18.007Z" }, + { url = "https://files.pythonhosted.org/packages/5a/79/91649d94c8d89f84af5da7c9d474bfba35b08eb8f492ca3422b08f0a6427/psycopg_binary-3.3.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c749770da0947bc972e512f35366dd4950c0e34afad89e60b9787a37e97cb443", size = 4675139, upload-time = "2025-12-06T17:34:21.374Z" }, + { url = "https://files.pythonhosted.org/packages/56/ac/b26e004880f054549ec9396594e1ffe435810b0673e428e619ed722e4244/psycopg_binary-3.3.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:03b7cd73fb8c45d272a34ae7249713e32492891492681e3cf11dff9531cf37e9", size = 5456120, upload-time = "2025-12-06T17:34:25.102Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8d/410681dccd6f2999fb115cc248521ec50dd2b0aba66ae8de7e81efdebbee/psycopg_binary-3.3.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:43b130e3b6edcb5ee856c7167ccb8561b473308c870ed83978ae478613764f1c", size = 5133484, upload-time = "2025-12-06T17:34:28.933Z" }, + { url = "https://files.pythonhosted.org/packages/66/30/ebbab99ea2cfa099d7b11b742ce13415d44f800555bfa4ad2911dc645b71/psycopg_binary-3.3.2-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7c1feba5a8c617922321aef945865334e468337b8fc5c73074f5e63143013b5a", size = 6731818, upload-time = "2025-12-06T17:34:33.094Z" }, + { url = "https://files.pythonhosted.org/packages/70/02/d260646253b7ad805d60e0de47f9b811d6544078452579466a098598b6f4/psycopg_binary-3.3.2-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cabb2a554d9a0a6bf84037d86ca91782f087dfff2a61298d0b00c19c0bc43f6d", size = 4983859, upload-time = "2025-12-06T17:34:36.457Z" }, + { url = "https://files.pythonhosted.org/packages/72/8d/e778d7bad1a7910aa36281f092bd85c5702f508fd9bb0ea2020ffbb6585c/psycopg_binary-3.3.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:74bc306c4b4df35b09bc8cecf806b271e1c5d708f7900145e4e54a2e5dedfed0", size = 4516388, upload-time = "2025-12-06T17:34:40.129Z" }, + { url = "https://files.pythonhosted.org/packages/bd/f1/64e82098722e2ab3521797584caf515284be09c1e08a872551b6edbb0074/psycopg_binary-3.3.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:d79b0093f0fbf7a962d6a46ae292dc056c65d16a8ee9361f3cfbafd4c197ab14", size = 4192382, upload-time = "2025-12-06T17:34:43.279Z" }, + { url = "https://files.pythonhosted.org/packages/fa/d0/c20f4e668e89494972e551c31be2a0016e3f50d552d7ae9ac07086407599/psycopg_binary-3.3.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:1586e220be05547c77afc326741dd41cc7fba38a81f9931f616ae98865439678", size = 3928660, upload-time = "2025-12-06T17:34:46.757Z" }, + { url = "https://files.pythonhosted.org/packages/0f/e1/99746c171de22539fd5eb1c9ca21dc805b54cfae502d7451d237d1dbc349/psycopg_binary-3.3.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:458696a5fa5dad5b6fb5d5862c22454434ce4fe1cf66ca6c0de5f904cbc1ae3e", size = 4239169, upload-time = "2025-12-06T17:34:49.751Z" }, + { url = "https://files.pythonhosted.org/packages/72/f7/212343c1c9cfac35fd943c527af85e9091d633176e2a407a0797856ff7b9/psycopg_binary-3.3.2-cp314-cp314-win_amd64.whl", hash = "sha256:04bb2de4ba69d6f8395b446ede795e8884c040ec71d01dd07ac2b2d18d4153d1", size = 3642122, upload-time = "2025-12-06T17:34:52.506Z" }, +] + [[package]] name = "ptyprocess" version = "0.7.0"