Skip to Content

Install

From a clean server to a signed-in portal.

Clone the installer

git clone https://github.com/Mangopulse/self-hosted.git
cd self-hosted

Sign in to the image registry

The images are private. Use a GitHub token that has read:packages:

docker login ghcr.io

Set the domain, the tenant and the first user

cp .env.example .env

Edit .env. The settings that matter on a first install:

SettingMeaning
DOMAINThe domain the five hosts live under.
TENANT_CODEA short lowercase code for the tenant.
TENANT_NAMEIts display name.
TENANT_LANGUAGEar or en. Arabic is right-to-left throughout the portal.
ADMIN_USERNAME, ADMIN_EMAILThe first user.
PLATFORMX_VERSION, PORTAL_VERSIONPin a version on a real server.

Leave the secrets empty. The installer generates them.

Run the installer

./install.sh

It asks for the first user’s password. With no terminal attached it reads ADMIN_PASSWORD from the environment, or generates a password and prints it once.

Start

docker compose up -d --wait

Open https://portal.<DOMAIN> and sign in.

What install.sh does

Each step is a small script in install/, run in this order:

  1. Requirements. Docker, Compose version, memory and disk.
  2. Configuration. Creates .env from .env.example, or adds settings a newer example gained. It never overwrites a value.
  3. Secrets. Generates the database password, the JWT signing key, the internal API key and the upload token, once.
  4. Images. Pulls them, or builds them from source with --build.
  5. Data services. Stops anything serving traffic, then starts PostgreSQL and blob storage.
  6. Database. Loads the schema on an empty database, applies migrations, and creates the tenant and first user if the tenant code is not there yet.

The database step comes before the services start for a reason: the APIs read tenants, configs, roles and users once, at boot. A tenant created after an API has started is invisible to it until it restarts.

Options

OptionEffect
--buildBuild the images from source. Needs platform and platform-portal cloned beside the installer.
--no-pullUse the images already on the machine.
--skip-user-creationPrepare the database and create no tenant or user.

Running on localhost

With DOMAIN=localhost the hosts are portal.localhost and so on. The proxy issues certificates from its own local authority, and the browser warns until that authority is trusted:

docker compose cp proxy:/data/caddy/pki/authorities/local/root.crt ./caddy-root.crt

TLS cannot be skipped. The sign-in cookie is Secure, and a browser drops it over plain HTTP.