This guide installs a tagged Cluster ERP release on one Linux node, for staging or for production, and upgrades it later with the same command. It follows deploy/bootstrap-node.sh for the operating system and deploy/install.sh for the application. The reasons behind the staging and production split are in environments and promotion.
Prerequisites¶
- A fresh Ubuntu 24.04 node with root access; the bootstrap script refuses other systems (
deploy/bootstrap-node.sh:52-55). - The administrator's OpenSSH public key file (
deploy/bootstrap-node.sh:46-51). - A PostgreSQL 16 server on the node.
install.shinstalls only the PostgreSQL client (deploy/install.sh:114), andpg-tune.shstops when the PostgreSQL 16 configuration directory is missing (deploy/pg-tune.sh:23-31). - A release tag that exists on the repository remote, and read access from the node to that remote (
deploy/install.sh:47-54,deploy/install.sh:85-90). - For production: the promotion record
staging-ok/<tag>on the same commit (deploy/install.sh:101-107).
Steps¶
- Prepare the operating system once, as root. Source:
deploy/bootstrap-node.sh:8-23,deploy/bootstrap-node.sh:36-44.
bash
bash bootstrap-node.sh --admin <name> --pubkey <public-key-file> --admin-cidr <cidr>
--admin-cidr is optional; without it the SSH port stays open to every address and the script prints a note (deploy/bootstrap-node.sh:139-145). The script turns on unattended security updates, sets the clock to UTC with NTP, creates the administrator with sudo and the key, records every privileged session, switches SSH to keys only, and opens only SSH, HTTP, and HTTPS in the firewall (deploy/bootstrap-node.sh:57-149).
-
Before you close the root session, open a new session with the key. Root login and passwords are off after step 1 (
deploy/bootstrap-node.sh:151-154). -
Tune PostgreSQL for the node's memory and processor count, from a copy of the repository. The script writes one configuration file and restarts PostgreSQL. Source:
deploy/pg-tune.sh:20,deploy/pg-tune.sh:48-69.
bash
sudo deploy/pg-tune.sh
- Replace both password placeholders in
deploy/postgres-roles.sql, then create the application role and the backup role. Source:deploy/postgres-roles.sql:1-11. See PostgreSQL roles and tuning.
bash
psql -U postgres -f deploy/postgres-roles.sql
- Run the installer with the tag, the public host name, and the role. Source:
deploy/install.sh:11-13.
bash
sudo deploy/install.sh --tag <tag> --domain erp.example.com --role staging
On a node without an environment file the script copies deploy/env.example into place with mode 0640 and stops, because the file still holds <...> placeholders (deploy/install.sh:171-179).
-
Fill in every placeholder value of the environment file. The variables are listed in the configuration reference.
-
If the node has no TLS certificate yet, obtain one with the command that the script prints. Source:
deploy/install.sh:204-209.
bash
certbot certonly --webroot -w /var/www/html -d erp.example.com -m <mailbox> --agree-tos -n
-
Run the same
install.shcommand again. It now runs all eight steps: system packages, service user and directories, code at the tag, virtual environment fromrequirements.lockwith hashes, environment file check, systemd unit with nginx site and cron table, database migration with a backup first, and start or reload with a readiness check (deploy/install.sh:26-34,deploy/install.sh:110-261). -
If the node is a production node, first record the passed staging battery on the release commit, then run the installer with
--role production. Source:deploy/install.sh:20-21.
bash
git tag -a staging-ok/<tag> <tag> -m "<battery log, date>"
git push origin staging-ok/<tag>
sudo deploy/install.sh --tag <tag> --domain erp.example.com --role production
- To upgrade later, run the same command with the new tag (
deploy/install.sh:13). The script reloads a running service. It restarts the service instead when the environment file changed after the service started, when the unit file changed, or whenrequirements.lockchanged (deploy/install.sh:228-246).
Verify the result¶
- The script ends with the line
Cluster ERP <tag> is live on this <role> node (<domain>).(deploy/install.sh:261). It prints that line only after/readyanswered HTTP 200 within five minutes andresidency_checkexited with code 0 (deploy/install.sh:247-259). - The readiness answer names each backing store with
passorfail(src/cluster_erp/server/app.py:1476-1504). See security.txt and readiness. - The cron table of the service user holds the jobs of
deploy/cluster-erp.cron(deploy/install.sh:210). See scheduled jobs and retention.
Troubleshooting¶
| Symptom | Cause in code | Fix |
|---|---|---|
--tag is required: production runs a tagged release, never a branch tip |
No --tag flag (deploy/install.sh:77) |
Pass an existing release tag. |
production refuses <tag>: no staging-ok/<tag> record |
The promotion tag is missing on the remote (deploy/install.sh:104-105) |
Install the tag on staging, run the battery, push the promotion tag. |
staging-ok/<tag> points at ... the promotion record does not belong to this release |
The two tags resolve to different commits (deploy/install.sh:106) |
Set the promotion tag on the release commit. |
this node is recorded as '<role>' ... a node never changes role |
The role differs from the recorded role (deploy/install.sh:123-125) |
Reinstall the node from a clean image. |
... still contains <...> placeholders; the service is not started with a template |
A value line still holds a placeholder (deploy/install.sh:177-179) |
Fill in the value and run the script again. |
no certificate yet for <domain> |
No certificate file for the domain (deploy/install.sh:204-209) |
Run the printed certbot command, then the script again. |
/ready did not answer 200 within 5 minutes |
The service did not become ready; the script prints the last journal lines (deploy/install.sh:254-257) |
Read the journal lines; see service and process manager. |
residency_check reported findings |
A setting contradicts the declared country (deploy/install.sh:258-259) |
Fix the declaration; see data residency check. |
this script is written for Ubuntu 24.04 |
Another operating system (deploy/bootstrap-node.sh:54-55) |
Use an Ubuntu 24.04 image. |
sshd rejected the new configuration; passwords are still on |
The SSH configuration test failed (deploy/bootstrap-node.sh:132) |
Not determined from code. The script stops before the new configuration takes effect. |
Terms introduced¶
| Term | Code identifier | Definition | Turkish term | Source |
|---|---|---|---|---|
| environment file | ENV_FILE |
The node file, copied from deploy/env.example, that the service and the scripts read their settings from. |
ortam dosyası | deploy/install.sh:45 |
| service user | SERVICE_USER |
The system account that owns the checkout and runs the service and the cron jobs. | servis kullanıcısı | deploy/install.sh:46 |
| asset stamp | cluster_asset_stamp |
A short token in the web app's asset URLs that changes when the shipped files change; the server computes it as a digest of the files, and nginx receives the release tag. | varlık damgası | deploy/install.sh:197-200 |
Related pages¶
Verified against commit 92f8051 on 2026-11-13.