Install on a Linux server with Node
This page takes you from a bare Linux server to a site that starts and answers. It is for whoever manages the server. The commands assume Debian or Ubuntu and a user who can use sudo; adapt them to your system. The next two pages make it run permanently and put HTTPS in front of it.
You need the download and a licence key and Node.js 22.13 or newer on the server:
node --version
1. Make a user and unpack the software
Run the site as its own user with no login, so it can write only to its own data folder.
sudo useradd --system --no-create-home --shell /usr/sbin/nologin choirmaster
sudo mkdir -p /opt/choirmaster
sudo tar -xzf choirmaster-cms-1.6.12.tar.gz -C /opt/choirmaster
The archive has no top-level folder, so -C into a folder that already exists is what keeps your files tidy. See What is in the download.
2. Make the data folder
Everything the site keeps (the database, uploaded files, downloaded updates and copies made before an update) goes in a data folder. Make it, and give it to the site's user:
sudo mkdir -p /opt/choirmaster/data
sudo chown -R choirmaster:choirmaster /opt/choirmaster/data
sudo chmod 750 /opt/choirmaster/data
The code in /opt/choirmaster can stay owned by root. The site writes only inside data. A one-click update unpacks the new version into data/releases, not over the code.
Where the data folder is depends on the folder the server is started from. SQLITE_PATH, STORAGE_LOCAL_DIR, DATA_DIR and the built website are all found relative to the working directory unless you give a full path. Either always start from /opt/choirmaster (the systemd unit on the next page does) or use full paths, as the file below does.
3. Write the settings file
Keep the settings in a file only the site's user and root can read, because it holds passwords.
sudo mkdir -p /etc/choirmaster
sudo install -m 640 -o root -g choirmaster /dev/null /etc/choirmaster/env
sudo nano /etc/choirmaster/env
A starting point:
SITE_URL=https://choir.example.org
ADMIN_USERNAME=admin
ADMIN_PASSWORD=change-me-to-something-long-and-random
LICENSE_KEY=cmk_your_key_here
# Where things live: full paths, so the working directory does not matter
DATA_DIR=/opt/choirmaster/data
SQLITE_PATH=/opt/choirmaster/data/choir.sqlite
STORAGE_LOCAL_DIR=/opt/choirmaster/data/storage
# Email: choose a real service before you go live
EMAIL_PROVIDER=log
EMAIL_FROM="Harmony Community Choir <noreply@example.org>"
SITE_URLis the address people will use, withhttps://.EMAIL_PROVIDER=logonly writes emails to the log. Replace it with a real service before the choir uses the site: see Email: what the site sends and how to choose a provider.- The defaults are SQLite and local files, which is right for most choirs. For other choices see Choose a database and How files are stored.
- Every setting is listed in The settings every site needs and Environment variables.
PORT (default 3001) and DATA_DIR must be real environment variables, as they are here. The launcher reads them before the server starts, so it does not see values that arrive only through a secrets manager or a NAME_FILE variable.
4. Check the settings
cd /opt/choirmaster
sudo -u choirmaster node --env-file=/etc/choirmaster/env scripts/check-config.js
It prints what the server will use, with secrets hidden, then lists problems. Until you have a real email service you will see the log warning; that is expected. Anything else needs fixing. The command ends with a failure exit code whenever it lists any problem, even a warning. See Check your configuration.
5. Start it once by hand
cd /opt/choirmaster
sudo -u choirmaster node --env-file=/etc/choirmaster/env server/launcher.js
You should see these lines, with some [config] warnings between the first two until the settings are complete:
[launcher] starting 1.6.12
[db] schema is up to date (sqlite)
[server] version 1.6.12 listening on http://localhost:3001 (production)
In a second terminal on the server:
curl http://localhost:3001/api/health
{"status":"ok","platform":"node","version":"1.6.12"}
Stop it with Ctrl+C. The server finishes what it is doing and exits. Now make it run for good: Run it as a systemd service.
npm start or start:direct
| Command | What it runs | One-click updates |
|---|---|---|
npm start | The launcher, server/launcher.js, which starts the server. | Yes. |
npm run start:direct | The server itself, server/entry/node.js. | No: the site can only tell you about a new version and show the steps. |
Use the launcher (the commands on this page do) unless you have a reason not to. npm does not read your settings file, so with either command you must provide the settings another way; that is why the examples use node --env-file=... directly.
Things to know
- The server listens on all network interfaces, and there is no setting to limit it to the local machine. Firewall port 3001 from the outside and let only your proxy reach it. Open ports 80 and 443 for the proxy.
- Logs go to the terminal's standard output and standard error. There is no log file. systemd keeps them for you: see Logs and health checks.
- Stopping with SIGTERM or SIGINT makes the server stop taking requests, close the database and exit, in at most five seconds.
- A second copy on the same port fails with
EADDRINUSE.
If something goes wrong
| What you see | What to do |
|---|---|
Permission denied or unable to open database file | The site's user cannot write to the data folder. Check step 2. |
| It starts, but the data is in the wrong place | You started from a different folder and used relative paths. Use full paths as above. |
[config] lines when it starts | Each one names a setting to fix. See The site will not start, or ignores my settings. |