Install
From a clean server to a signed-in portal.
Clone the installer
git clone https://github.com/Mangopulse/self-hosted.gitcd self-hostedSign in to the image registry
The images are private. Use a GitHub token that has read:packages:
docker login ghcr.ioSet the domain, the tenant and the first user
cp .env.example .envEdit .env. The settings that matter on a first install:
| Setting | Meaning |
|---|---|
DOMAIN | The domain the five hosts live under. |
TENANT_CODE | A short lowercase code for the tenant. |
TENANT_NAME | Its display name. |
TENANT_LANGUAGE | ar or en. Arabic is right-to-left throughout the portal. |
ADMIN_USERNAME, ADMIN_EMAIL | The first user. |
PLATFORMX_VERSION, PORTAL_VERSION | Pin a version on a real server. |
Leave the secrets empty. The installer generates them.
Run the installer
./install.shIt 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 --waitOpen https://portal.<DOMAIN> and sign in.
What install.sh does
Each step is a small script in install/, run in this order:
- Requirements. Docker, Compose version, memory and disk.
- Configuration. Creates
.envfrom.env.example, or adds settings a newer example gained. It never overwrites a value. - Secrets. Generates the database password, the JWT signing key, the internal API key and the upload token, once.
- Images. Pulls them, or builds them from source with
--build. - Data services. Stops anything serving traffic, then starts PostgreSQL and blob storage.
- 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
| Option | Effect |
|---|---|
--build | Build the images from source. Needs platform and platform-portal cloned beside the installer. |
--no-pull | Use the images already on the machine. |
--skip-user-creation | Prepare 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.crtTLS cannot be skipped. The sign-in cookie is Secure, and a browser drops it over plain HTTP.