Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to
### Added

- ✨(backend) support creating subdoc from file #1987
- ✨(buildpack) add PaaS deployment support, tested with Scalingo #2293

### Fixed

Expand Down
2 changes: 2 additions & 0 deletions Procfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
web: bin/buildpack_start.sh
postdeploy: python manage.py migrate
13 changes: 13 additions & 0 deletions bin/buildpack_postcompile.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/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"

rm -rf docker docs env.d gitlint
rm -rf src/frontend/apps
rm -rf src/frontend/packages

# Remove some of the larger packages required by the frontend only
rm -rf src/frontend/node_modules/@next src/frontend/node_modules/next src/frontend/node_modules/@gouvfr-lasuite
58 changes: 58 additions & 0 deletions bin/buildpack_postfrontend.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#!/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/impress/out build/frontend-out

# Custom logo
ASSETS_DIR=build/frontend-out/assets
if [ -n "$THEME_CUSTOMIZATION_LOGO_URL" ]; then
# Ensure https
[[ ! "$THEME_CUSTOMIZATION_LOGO_URL" =~ ^https:// ]] && echo "[custom-logo] ERROR: URL must use HTTPS" >&2 && exit 1

# Prevent SSRF
HOSTNAME=$(echo "$THEME_CUSTOMIZATION_LOGO_URL" | sed -E 's|^https://([^/:]+).*|\1|')
[[ "$HOSTNAME" =~ ^(localhost|127\.|10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.|0\.0\.0\.0|\[::1\]) ]] && echo "[custom-logo] ERROR: SSRF blocked: $HOSTNAME" >&2 && exit 1
Comment thread
zeylos marked this conversation as resolved.

LOGO_FILE="${ASSETS_DIR}/icon-docs.svg"
TMP_FILE=$(mktemp "${LOGO_FILE}.XXXXXX.tmp")

# Actual download
echo "[custom-logo] INFO: Downloading custom logo from: $THEME_CUSTOMIZATION_LOGO_URL"
curl -fsSL --tlsv1.2 -o "$TMP_FILE" "$THEME_CUSTOMIZATION_LOGO_URL"

# Validate filesize
FILESIZE=$(stat -c%s "$TMP_FILE" 2>/dev/null || stat -f%z "$TMP_FILE")
[[ "$FILESIZE" -eq 0 ]] && echo "[custom-logo] ERROR: empty file" >&2 && exit 1
[[ "$FILESIZE" -gt 5242880 ]] && echo "[custom-logo] ERROR: file too large (${FILESIZE}B > 5MB)" >&2 && exit 1

# Validate file type
IS_SVG=false

HEADER=$(head -c 100 "$TMP_FILE" | tr -d '\0' | tr '[:upper:]' '[:lower:]')
[[ "$HEADER" =~ ^.*"<svg".*$ ]] && IS_SVG=true
[[ "$HEADER" =~ ^.*"<?xml".*"<svg".*$ ]] && IS_SVG=true
Comment thread
zeylos marked this conversation as resolved.

[[ "$IS_SVG" == false ]] && echo "[custom-logo] ERROR: not a valid SVG file" >&2 && exit 1
Comment thread
zeylos marked this conversation as resolved.

mv -f "$TMP_FILE" "$LOGO_FILE"
echo "[custom-logo] INFO: Custom logo downloaded successfully"
fi

mv src/backend/* ./
mv deploy/paas/* ./

# Inject custom theme JSON
if [ -n "$THEME_CUSTOMIZATION_JSON" ]; then
echo "[custom-theme] INFO: Deploying the custom theme from THEME_CUSTOMIZATION_JSON."
mkdir -p impress/configuration/theme
echo "$THEME_CUSTOMIZATION_JSON" >impress/configuration/theme/default.json
echo "[custom-theme] INFO: Custom theme deployed successfully."
fi
Comment thread
zeylos marked this conversation as resolved.

echo "3.13" >.python-version
18 changes: 18 additions & 0 deletions bin/buildpack_start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/bash

# Start the Django backend server
uvicorn --app-dir=/app --host=0.0.0.0 --timeout-graceful-shutdown=300 --limit-max-requests=20000 --lifespan=off impress.asgi:application &
Comment thread
zeylos marked this conversation as resolved.

# Start the Y provider service
cd src/frontend/servers/y-provider && PORT=4444 ${NODE_BIN:-node} dist/start-server.js &

# Start the Nginx server
bin/run &

# if the current shell is killed, also terminate all its children
trap "pkill SIGTERM -P $$" SIGTERM
Comment thread
zeylos marked this conversation as resolved.

# wait for a single child to finish,
wait -n
# then kill all the other tasks
pkill -P $$
Comment thread
zeylos marked this conversation as resolved.
112 changes: 112 additions & 0 deletions deploy/paas/servers.conf.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# ERB templated nginx configuration
# see https://doc.scalingo.com/platform/deployment/buildpacks/nginx

upstream backend_server {
server localhost:8000 fail_timeout=0;
}

upstream collaboration_server {
server localhost:4444 fail_timeout=0;
}

server {
listen <%= ENV["PORT"] %>;
server_name _;

root /app/build/frontend-out;

error_page 404 /404.html;

location /collaboration/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://collaboration_server;
}

location /collaboration/ws/ {

proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";

# Set appropriate timeout for WebSocket
proxy_read_timeout 86400;
proxy_send_timeout 86400;

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://collaboration_server;
}

# 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_ENDPOINT_URL"] %>/<%= ENV["AWS_STORAGE_BUCKET_NAME"] %>/;
proxy_set_header Host <%= ENV["AWS_S3_ENDPOINT_URL"].split("://")[1] %>;

add_header Content-Security-Policy "default-src 'none'" always;
}

location /media-auth {
proxy_pass http://backend_server/api/v1.0/documents/media-auth/;
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;
}
Comment thread
zeylos marked this conversation as resolved.

location / {
try_files $uri index.html $uri/ =404;
}

location ~ "^/docs/[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 /docs/[id]/index.html;
}
Comment thread
zeylos marked this conversation as resolved.

location = /404.html {
internal;
}

}
12 changes: 8 additions & 4 deletions docs/installation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@ We (Docs maintainers) are only using the Kubernetes deployment method in product
Please follow the instructions laid out [here](/docs/installation/kubernetes.md).

## Docker Compose
We are aware that not everyone has Kubernetes Cluster laying around 😆.
We also provide [Docker images](https://hub.docker.com/u/lasuite?page=1&search=impress) that you can deploy using Compose.
Please follow the instructions [here](/docs/installation/compose.md).
We are aware that not everyone has Kubernetes Cluster laying around 😆.
We also provide [Docker images](https://hub.docker.com/u/lasuite?page=1&search=impress) that you can deploy using Compose.
Please follow the instructions [here](/docs/installation/compose.md).
Comment thread
zeylos marked this conversation as resolved.
⚠️ Please keep in mind that we do not use it ourselves in production. Let us know in the issues if you run into troubles, we'll try to help.

## Scalingo
Comment thread
coderabbitai[bot] marked this conversation as resolved.
You can deploy Docs on [Scalingo](https://scalingo.com/) using a custom buildpack. This method handles both frontend and backend builds, serving them through Nginx with the collaboration server (y-provider).
Comment thread
zeylos marked this conversation as resolved.
Please follow the instructions [here](/docs/installation/scalingo.md).

## Other ways to install Docs
Community members have contributed several other ways to install Docs. While we owe them a big thanks 🙏, please keep in mind we (Docs maintainers) can't provide support on these installation methods as we don't use them ourselves and there are too many options out there for us to keep track of. Of course you can contact the contributors and the broader community for assistance.

Expand All @@ -29,4 +33,4 @@ Some cloud providers are making it easy to deploy Docs on their infrastructure.
Here is the list in alphabetical order:
- Clever Cloud 🇫🇷 : [market place][https://www.clever-cloud.com/product/docs/], [technical doc](https://www.clever.cloud/developers/guides/docs/#deploy-docs)

Feel free to make a PR to add ones that are not listed above 🙏
Feel free to make a PR to add ones that are not listed above 🙏
Loading
Loading