Install on your own server
Install Workforce Intelligence on a Linux server you manage, using install.sh and an .env file you prepare.
On a server without CloudFormation, nothing is automated for you. You copy two scripts to the
box, prepare an .env file, and run install.sh.
Read Deployment requirements first.
1. Copy the scripts to the box#
Copy install.sh and find-setup-token.sh from the deploy/ directory of the Workforce
Intelligence repository to a directory on the server, for example:
mkdir -p ~/wi && cd ~/wi
Use scp or paste them in. There is no compose file to transfer: install.sh extracts it
from the wi-server image it pulls, so the file always matches that image's version. Make the
scripts executable with chmod +x install.sh find-setup-token.sh.
2. Prepare .env#
install.sh looks for a file named .env next to itself. If it finds one, it uses it exactly
as it is and never regenerates anything in it. You can create the file yourself, or let
install.sh create it (below). The required values are the two secrets and your domain:
cd ~/wi
sudo tee .env >/dev/null <<ENVEOF
WI_MASTER_KEY=$(openssl rand -base64 32)
WI_SESSION_SECRET=$(openssl rand -base64 32)
WI_DOMAIN=wi.example.com
ENVEOF
sudo chmod 600 .env
With no domain, use WI_ALLOWED_ORIGIN=http://<your-hostname-or-ip> in place of WI_DOMAIN.
Browsers do not keep a sign-in made over plain HTTP, so use a domain with HTTPS for real use.
Each key must appear once. WI_DOMAIN is the only address setting: the web origin, the base
URLs for emailed links, webhooks and deployed Apps, and the host Builders use for git push are
all derived from it. The meaning of every value is in
Configuration reference.
Back up this file off the box straight away. WI_MASTER_KEY is generated once and the installer
never regenerates it; it changes only when you rotate it. See Master key custody.
If you run install.sh with no .env present, it creates one for you. It generates
WI_MASTER_KEY and WI_SESSION_SECRET and writes WI_DOMAIN from the environment. In that
case you must supply WI_DOMAIN on the command line (the script stops with "WI_DOMAIN must be
set" otherwise).
3. Run install.sh#
cd ~/wi
GHCR_USER=<your-github-username> \
GHCR_TOKEN=<your-token> \
./install.sh
If you let the script create .env, add WI_DOMAIN=<your-domain> to the command line as well.
GHCR_USER and GHCR_TOKEN are your GitHub username and a classic personal access token with
read:packages (see Deployment requirements). The script then:
- Makes sure
.envhasWI_DOMAIN(orWI_ALLOWED_ORIGINon a box with no domain), adding it from the environment if it is missing. It never edits a line that is already there. - Installs Docker through
get.docker.comif Docker is not already installed. - Runs
sudo docker login ghcr.io. The login is stored in/root/.docker/config.json, which the in-app updater also uses. - Pulls the
wi-serverimage (WI_IMAGE_TAG, defaultlatest) and extractsdocker-compose.prod.ymlfrom it into the script's directory. - Pulls the other images and starts the stack with the Compose project name
wi-prod: the database, the application, the web server, and Dokku.
The app container applies database migrations when it starts and never loads sample data, so
you begin with an empty database and a company waiting to be claimed.
GHCR_USER and GHCR_TOKEN are needed only while the box is not logged in to ghcr.io.
Docker remembers the login, so a re-run does not need them.
Upgrade the stack by re-running install.sh#
Run install.sh again to upgrade an installed box. It keeps your .env (the secrets are never
regenerated), adds any newly required value, replaces docker-compose.prod.yml with the one
inside the image it pulls, and recreates whatever changed, including new services and volumes.
It also moves app and web to the pulled images without the backup that Settings >
Updates takes first, so back up the database before you re-run it on a deployment that holds
data. See What an update changes for when a release
needs this.
Do not rename the wi-prod project. The scripts, the in-app updater, and the volume names all
depend on it.
4. Open the app#
Open your address in a browser and continue with First-run setup token.
If the stack does not start#
- A
docker composeerror about a missing variable means you are running Compose from a different directory than the one holding.env, or a required value is missing from it. Re-runninginstall.shadds the ones it can derive. install.shcould not read the compose file out of the image.WI_IMAGE_TAGnames an image that does not carry it. Use a newer tag.docker login ghcr.iofails with "unauthorized" almost always means the token is wrong, expired, missingread:packages, or is a fine-grained token. Create a classic token.- The
appcontainer restarts repeatedly. Runsudo docker compose -p wi-prod logs app. The application refuses to start when its production checks fail, and the log line names the problem. See Production boot checks. - The sign-in page shows instead of the setup wizard. The database is not empty. Setup appears only when no company exists yet.