🚀(scalingo) add Scalingo deployment scripts and fix frontend build

This commit, with contributions from Sylvain Grizard, adds support
for PaaS deployment platforms such as Scalingo, which build the
project on commit. It uses the La Suite Buildpack, which compiles
the frontend first as static files, and serves them along with
the backend with nginx.
This commit is contained in:
Sylvain Zimmer
2025-04-25 10:12:29 +02:00
parent f77d2875e1
commit dd6f0be90a
11 changed files with 146 additions and 8 deletions

2
Procfile Normal file
View File

@@ -0,0 +1,2 @@
web: bin/scalingo_run_web
postdeploy: python manage.py migrate

11
bin/scalingo_postcompile Normal file
View File

@@ -0,0 +1,11 @@
#!/bin/bash
set -o errexit # always exit on error
set -o pipefail # don't ignore exit codes when piping output
echo "-----> Running post-compile script"
# Remove all the files we don't need
rm -rf src docker env.d .cursor .github compose.yaml README.md .cache
chmod +x bin/scalingo_run_web

15
bin/scalingo_postfrontend Normal file
View File

@@ -0,0 +1,15 @@
#!/bin/bash
set -o errexit # always exit on error
set -o pipefail # don't ignore exit codes when piping output
echo "-----> Running post-frontend script"
# Move the frontend build to the nginx root and clean up
mkdir -p build/
mv src/frontend/apps/drive/out build/frontend-out
mv src/backend/* ./
mv src/nginx/* ./
echo "3.13" > .python-version

15
bin/scalingo_run_web Normal file
View File

@@ -0,0 +1,15 @@
#!/bin/bash
# Start the Django backend
gunicorn -b :8000 drive.wsgi:application --log-file - &
# Start the Nginx server
bin/run &
# if the current shell is killed, also terminate all its children
trap "pkill SIGTERM -P $$" SIGTERM
# wait for a single child to finish,
wait -n
# then kill all the other tasks
pkill -P $$

View File

@@ -65,7 +65,7 @@ server {
}
location /media-auth {
proxy_pass http://docs_backend/api/v1.0/documents/media-auth/;
proxy_pass http://docs_backend/api/v1.0/items/media-auth/;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;

View File

@@ -16,6 +16,7 @@ from socket import gethostbyname, gethostname
from django.utils.translation import gettext_lazy as _
import dj_database_url
import posthog
import sentry_sdk
from configurations import Configuration, values
@@ -23,7 +24,7 @@ from sentry_sdk.integrations.django import DjangoIntegration
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
DATA_DIR = os.path.join("/", "data")
DATA_DIR = os.environ.get("DATA_DIR", os.path.join("/", "data"))
def get_release():
@@ -74,7 +75,9 @@ class Base(Configuration):
# Database
DATABASES = {
"default": {
"default": dj_database_url.config()
if os.environ.get("DATABASE_URL")
else {
"ENGINE": values.Value(
"django.db.backends.postgresql_psycopg2",
environ_name="DB_ENGINE",

View File

@@ -27,6 +27,7 @@ requires-python = ">=3.12"
dependencies = [
"boto3==1.36.7",
"Brotli==1.1.0",
"dj-database-url==2.3.0",
"celery[redis]==5.5.0",
"django==5.1.9",
"django-configurations==2.5.1",

View File

@@ -4,11 +4,14 @@
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"build": "next build --no-lint",
"start": "next start",
"lint": "next lint",
"build-theme": "cunningham -g css,scss -o src/styles && mv src/styles/cunningham-tokens.scss src/styles/cunningham-tokens-sass.scss"
},
"engines": {
"node": ">=22.0.0 <23.0.0"
},
"dependencies": {
"@gouvfr-lasuite/ui-kit": "0.5.0",
"@openfun/cunningham-react": "3.0.0",

View File

@@ -10,8 +10,8 @@ export interface ExplorerProps {
childrenItems?: Item[];
gridActionsCell?: (params: ExplorerGridActionsCellProps) => React.ReactNode;
disableItemDragAndDrop?: boolean;
gridHeader?: JSX.Element;
selectionBarActions?: JSX.Element;
gridHeader?: React.ReactNode;
selectionBarActions?: React.ReactNode;
filters?: ItemFilters;
onFiltersChange?: (filters: ItemFilters) => void;
// Override the default onNavigate from ExplorerContext

View File

@@ -7,11 +7,12 @@
"packages/*"
],
"scripts": {
"lint": "yarn workspaces run lint"
"dev": "turbo run dev",
"build": "cd apps/drive && yarn build"
},
"resolutions": {},
"devDependencies": {
"turbo": "2.0.10"
},
"packageManager": "yarn@1.22.22"
}
}

View File

@@ -0,0 +1,87 @@
# ERB templated nginx configuration
# see https://doc.scalingo.com/platform/deployment/buildpacks/nginx
upstream backend_server {
server localhost:8000 fail_timeout=0;
}
server {
listen <%= ENV["PORT"] %>;
server_name _;
root /app/build/frontend-out;
error_page 404 /404.html;
# Django rest framework
location ^~ /api/ {
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_redirect off;
proxy_pass http://backend_server;
}
# Django admin
location ^~ /admin/ {
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_redirect off;
proxy_pass http://backend_server;
}
# Proxy auth for media
location /media/ {
# Auth request configuration
auth_request /media-auth;
auth_request_set $authHeader $upstream_http_authorization;
auth_request_set $authDate $upstream_http_x_amz_date;
auth_request_set $authContentSha256 $upstream_http_x_amz_content_sha256;
# Pass specific headers from the auth response
proxy_set_header Authorization $authHeader;
proxy_set_header X-Amz-Date $authDate;
proxy_set_header X-Amz-Content-SHA256 $authContentSha256;
# Get resource from Object Storage
proxy_pass <%= ENV["AWS_S3_BUCKET_INTERNAL_URL"] %>;
proxy_set_header Host <%= ENV["AWS_S3_BUCKET_INTERNAL_HOST"] %>;
add_header Content-Security-Policy "default-src 'none'" always;
}
location /media-auth {
proxy_pass http://backend_server/api/v1.0/items/media-auth/;
proxy_set_header X-Forwarded-Proto https;
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-Original-URL $request_uri;
# Prevent the body from being passed
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-Method $request_method;
}
location ~ "^/explorer/items/[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/?$" {
try_files $uri /explorer/items/[id].html;
}
location ~ "^/sdk/explorer/items/[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/?$" {
try_files $uri /sdk/explorer/items/[id].html;
}
location = /404.html {
internal;
}
# Frontend export
location / {
try_files $uri index.html $uri/ =404;
}
}