Skip to content

New customer

This page creates one facility on a host and leaves it serving: its own settings, its database and the account that owns it, its tables, its owner account, its server and its web address. One command does all of it, and refuses a facility that already exists rather than writing over it.

Use it for a facility with no records yet — one whose people will type their stocks in. A facility moving records off another system is a different job, and its dump is loaded before the schema is built: see Migrate customer.

Prerequisites

  • The host is running ZFM, from Install it on a host, and has its own settings file, from First time setup for ZFM. Every facility on the host reads that file for the mail account, the database server and who owns the platform, and nothing here changes it however many facilities the host ends up with.
  • This host has mysql, from Prepare the hosts. The facility's database is created from here.
  • The admin db user name and the admin db password — the account on the database server that may create databases and the accounts that use them. You are asked for both when you run the command, they are used for two statements, and they are kept nowhere.

What to decide first

Two names identify a facility, and they are not the same string:

<facility> the short name — zri — naming its settings file, its service and its subdomain
<db-name> its database, and the account that connects to it; zf_uva by the convention these facilities follow, and what you get if you say nothing

Choose the short name with care. ZFM uses it as the name of the facility's settings file and of its service on the host, and it is the word that names the facility in every command you run for it. Changing it afterwards means a new settings file and a new service, so it is chosen once and lived with. A facility's subdomain is normally the same word, which keeps a host readable, but the web address is a setting of its own and nothing requires the two to match.

Write the client URL with the scheme you mean, https:// or http://. It decides whether this facility is served with a certificate. https:// gets one, fetched and renewed for the facility without anybody asking, which needs a name the public internet already resolves to this host — so the DNS record comes first. The command resolves the name before it creates anything and refuses the facility if it does not reach this host, naming the address it found instead. http:// gets no certificate, which is the form for a facility reachable only on a private network, or for a name no certificate authority will ever vouch for; nothing requires such a name to resolve here.

The URL is also the base for the links ZFM emails, the invitation and the password reset, so it has to be the address somebody at the facility really types.

Pick a port no other facility on this host uses. The command refuses a port already in use, and says which facility holds it, before it creates anything.

Create it

sudo /srv/zfm/releases/<version>/deploy/new-facility.sh \
  --facility <facility> --url https://<facility>.<domain> --port <port>

Four more options, for the cases that want them:

--db-name <name> its database, where the convention is not wanted
--release <dir> the release it runs. It runs the release the command itself came out of unless you say otherwise
--mail-reply-to <address> where replies to this facility's mail go. Left out, the host's value applies, including a later change to it, which a value written here would shadow
--mail-cc <address> copied on this facility's mail, on the same terms

It prints what it is about to create, then names each thing as it does it:

  1. Its settings, generated and installed where the server reads them. The database password and the token signing secret are generated rather than invented by anybody, and the result is checked with the same check the server runs at startup — so a file it writes is one the server accepts. This comes before the database, because it is where the facility's db account and password are decided, and the account is then created with the password the file already states.
  2. Its database and the account that owns it, as the admin db user. This is the only step that credential is used for, and the command drops it immediately afterwards.
  3. Its schema, by running the migration chain against the new database as the facility's own db account — so a failure here is a fault in the facility's own credential rather than something an administrator papered over.
  4. The platform owner's account, which exists in every facility and can invite that facility's own administrators. A random must-change password is printed; it is the one thing in the output you need to keep.
  5. The release it runs, named by a pointer that its server and the web client at its address both follow.
  6. Its web address, served, so that the name its people type reaches this facility.
  7. Its server, enabled so it survives a reboot, started, and checked — at its own web address as well as on its port, because a healthy server behind an address nobody can reach serves nobody.

A failure at any point says what to do about it, and names the command that removes what was created: Uninstall a facility.

What the facility's own db account can do

The account holds every privilege over the facility's own database and over the _bak database beside it, and nothing at all over any other database on the same server. So the facility reads and writes its records, runs its own migrations and keeps its own copy, while every other facility's records are beyond its reach — and no administrator credential has to live on the host for any of it.

The grant on _bak names a database that does not exist yet, and that is deliberate: the facility creates and removes that copy itself during an upgrade. A grant has to name a database exactly, so a copy named for each release would need a fresh grant, and an administrator, at every upgrade.

Each grant covers a whole database rather than a list of tables, so tables that later migrations add are already included and this account never has to be re-granted as the schema grows.

Am I ready to move on?

sudo /srv/zfm/releases/<version>/deploy/check-facilities.sh \
  --release /srv/zfm/releases/<version>

The new facility should be up, yes, read, ok and reached — its server answering, set to start at boot, its own database reachable, its schema holding exactly the migrations that release carries, and its own web address answering for it. Every facility already on the host should read the same, because creating one touches nothing that belongs to another.

To see every setting the facility will run on, and which file each value came from:

sudo env FACILITY=<facility> node \
  /srv/zfm/releases/<version>/zf-server/dist/scripts/config-sources.js

That is how you answer "which database server is this facility on?" without merging two files in your head. Passwords and signing secrets are listed but not shown.

Where the settings live

A facility's settings live in /etc/zfm/<facility>.env, beside /etc/zfm/zfm.conf. Both sit outside every release directory, so installing a new version never touches a facility's credentials. The service is told the facility's name and the server reads both files itself. They hold secrets, so they belong to the account the server runs as, mode 600.

On a development machine set ZFM_CONFIG_DIR to a directory holding zfm.conf and <facility>.env and the server reads them from there instead, which is how a checkout runs facilities against settings of its own. Nothing in production sets it.

Hand the facility over

The facility is serving. Log in as the platform owner with the password the command printed, change it, and create the facility's admin user or users — those are logins for people; the facility's db account is the server's own and nobody signs in with it. Then set the facility up with its administrator: the facility's GUI-side settings.