Skip to content

Bare-Metal Installation Guide

This guide explains how to install Endurain bare-metal on Debian without Docker.

1. Install Required Dependencies

apt install -y \
  build-essential \
  git \
  curl \
  python3-dev

2. Install Required Runtime Tools

Install the required tools from their official sources:

  • uv (Python) → https://docs.astral.sh/uv/
  • Node.js 22 → https://nodejs.org/en/download
  • PostgreSQL 17 → https://www.postgresql.org/download/

3. Download Endurain Release

Run the following command to download and unpack the latest release.

mkdir -p /path/to/endurain
cd /path/to/endurain

TAG=$(curl -s https://codeberg.org/api/v1/repos/endurain-project/endurain/releases | grep -oP '"tag_name": "\K([^"]+)' | head -n 1)
curl -L "https://codeberg.org/endurain-project/endurain/archive/$TAG.tar.gz" \
  | tar xz
EXTRACTED=$(ls -d endurain-*)
shopt -s dotglob
mv "$EXTRACTED"/* .
shopt -u dotglob
rm -rf "$EXTRACTED"

4. Create Environment Configuration

Prepare data storage.

mkdir -p /path/to/endurain_data/{data,logs}

Copy the provided example.

cp /path/to/endurain/.env.example /path/to/endurain/.env

Generate your SECRET_KEY and FERNET_KEY. These keys are required for Endurain to work, so be sure to paste them into your .env file. You can run the commands below or use the Secret Generators tool.

openssl rand -hex 32 # SECRET_KEY
openssl rand -base64 32 # FERNET_KEY

Edit .env file.

nano /path/to/endurain/.env

Adjust the environment variables and set keys. You definitely have to adjust FRONTEND_DIR, BACKEND_DIR and DB_HOST.
Environment variables are explained in the Environment Variables Guide.

DB_HOST=localhost
BACKEND_DIR="/path/to/endurain/backend/app"
FRONTEND_DIR="/path/to/endurain/frontend/app/dist"
DATA_DIR="/path/to/endurain_data/data"
LOGS_DIR="/path/to/endurain_data/logs"

5. Build the Frontend

cd /path/to/endurain/frontend/app
npm ci
npm run build

Create env.js. Edit the URL if you use a reverse proxy.

cat << 'EOF' > /path/to/endurain/frontend/app/dist/env.js
window.env = {
  ENDURAIN_HOST: "http://YOUR_SERVER_IP:8080",
};
EOF

6. Set Up the Backend

cd /path/to/endurain/backend

uv sync --no-dev

7. Setup Postgres Database

Run the following commands to create a PostgreSQL user and database for Endurain:

sudo -u postgres createuser -P endurain
sudo -u postgres createdb -O endurain endurain

Check that the PostgreSQL client and server encodings are set to UTF-8.

sudo -u postgres psql -c "SHOW client_encoding;"
sudo -u postgres psql -c "SHOW server_encoding;"

If either value is SQL_ASCII, set UTF-8 explicitly for the user and the database.

sudo -u postgres psql -c "ALTER ROLE endurain SET client_encoding = 'UTF8';"
sudo -u postgres psql -c "ALTER DATABASE endurain SET client_encoding = 'UTF8';"

This ensures that all connections to the endurain database default to proper UTF-8 encoding.

8. Systemd Service

This is an example how you could set up your systemd service.

cat << 'EOF' > /etc/systemd/system/endurain.service
[Unit]
Description=Endurain FastAPI Backend
After=network.target postgresql.service

[Service]
WorkingDirectory=/path/to/endurain/backend/app
EnvironmentFile=/path/to/endurain/.env
ExecStart=/path/to/endurain/backend/.venv/bin/uvicorn main:app --host 0.0.0.0 --port 8080
Restart=always
RestartSec=5
User=root
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
EOF

Enable and start the service.

systemctl daemon-reload
systemctl enable endurain
systemctl start endurain

9. (Optional) Reverse Proxy with Nginx

If you want to serve Endurain over HTTPS on a standard domain, you can put Nginx in front of the service. Endurain serves both the frontend and the API from the same origin (the uvicorn process on port 8080), so a single location / is enough — you do not need a separate location block for the backend or for static assets.

# Redirect plain HTTP to HTTPS
server {
    listen 80;
    listen [::]:80;
    server_name endurain.yourdomain.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;

    server_name endurain.yourdomain.com;

    # Adjust to your certificate paths
    ssl_certificate     /etc/letsencrypt/live/endurain.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/endurain.yourdomain.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;

    # Endurain accepts large uploads (activity files, bulk imports, media).
    # Nginx defaults to 1m, which causes 413 errors — raise it generously.
    client_max_body_size 2000m;

    location / {
        include            proxy_params;
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection "upgrade";
        proxy_pass         http://127.0.0.1:8080;
    }
}

When running behind a reverse proxy, make sure ENDURAIN_HOST in env.js (step 5) and in your .env match the public URL (e.g. https://endurain.yourdomain.com). So that uvicorn trusts the forwarded protocol headers, add --proxy-headers to the ExecStart command in the systemd unit (step 8):

ExecStart=/path/to/endurain/backend/.venv/bin/uvicorn main:app --host 0.0.0.0 --port 8080 --proxy-headers

10. Update to a new version of Endurain.

Remove old version and get the latest.

systemctl stop endurain
rm -rf /path/to/endurain/*
cd /path/to/endurain

TAG=$(curl -s https://codeberg.org/api/v1/repos/endurain-project/endurain/releases | grep -oP '"tag_name": "\K([^"]+)' | head -n 1)
curl -L "https://codeberg.org/endurain-project/endurain/archive/$TAG.tar.gz" \
  | tar xz
EXTRACTED=$(ls -d endurain-*)
shopt -s dotglob
mv "$EXTRACTED"/* .
shopt -u dotglob
rm -rf "$EXTRACTED"

Build the Frontend.

cd /path/to/endurain/frontend/app
npm ci
npm run build

Set Up the Backend.

cd /path/to/endurain/backend
uv sync --no-dev

start the service.

systemctl start endurain