Document 7 of 13
Installation
Delivery options, step-by-step installation, external database, configuration.
For whom: IT
This document explains how Orafila is put into service: the delivery options, installation on a server with the Docker package, the optional external database, a trial run on a computer and the configuration reference.
The step-by-step guides with screenshots of the cloud providers, written also for people who are not system administrators, are in the package:
- Deployment on Oracle Cloud (in Italian): a free Always Free VM, suitable for demos and pilots;
- Deployment on DigitalOcean (in Italian): a paid Droplet, also suitable for customers in production;
- External database (in Italian).
1. Delivery options
| Managed service | Dedicated installation | |
|---|---|---|
| Who manages the server | The Orafila provider | The provider or the company's IT, on the server the company chooses |
| What the company receives | The application's address, the company code and an invitation link for the first administrator | A complete installation, possibly with several companies (for example the companies of a group) |
| Installation | None for the company | An Ubuntu server with Docker, about 2-3 hours the first time (almost all of it waiting) |
| Updates and backups | Taken care of by the provider | One command to update; automatic nightly backups once configured |
| AI keys | The provider's or the company's, depending on the contract | The company's, with its own direct contract with the AI provider |
In both cases the application is the same and each company's data is kept separate by the database. With the managed service the company starts from step 8 of this document and then from Getting started with a company.
2. Before you start
- An Ubuntu 24.04 server (or 22.04) that meets the requirements in Requirements and architecture, reachable via SSH with a key.
- A domain name whose DNS you can change (for example
psa.yourcompany.com) and an e-mail address for registering the HTTPS certificates. - The release address of Orafila and, if the Orafila provider uses them, the server's access credentials (Client ID and Client Secret): the provider sends them (step 4).
- A password manager in which to save the keys generated by the installation. It is essential.
- Optional: an Anthropic, OpenAI or Google API key for AI; an S3-compatible bucket for the copy of the backups; an account with an external monitoring service (for example Healthchecks.io and an uptime service).
From here on, commands that start with deploy/ are typed on the server, from the orafila folder.
3. Creating the server and the DNS
- Create the server with the provider you have chosen, preferably in a European Union region. The Oracle and DigitalOcean guides describe every screen.
- In the provider's firewall open inbound TCP 80, TCP 443 and UDP 443 from everywhere, and TCP 22 (SSH) preferably only from your IP address.
- In the domain's DNS create an A record with the chosen name (for example
psa) pointing to the server's public IP. Before going on, the name must answer with the right IP (nslookup psa.yourcompany.com).
4. Downloading the package
Orafila is downloaded with the installer: it takes the latest version from the release server, checks its digital signature (the proof that the package comes from the Orafila provider and that nobody has altered it) and creates the orafila folder. Instead of https://rilasci.orafila.com, use the release address the provider gave you:
cd ~
curl -fsSLO https://rilasci.orafila.com/install.sh
bash install.sh
cd orafila
If the provider sent you the installer's fingerprint, before bash install.sh check that sha256sum install.sh prints the same one. If the release server is protected, the installer asks for the Client ID and Client Secret and saves them in deploy/.env: updates need them too. No sudo is needed and nothing changes outside the orafila folder. If the installer reports that the signature does not match, do not go on and tell the Orafila provider.
5. Preparing the server
sudo deploy/setup-host.sh
The script (5 to 15 minutes; it can be run again without harm):
- recognises the provider (Oracle Cloud, DigitalOcean or another Ubuntu);
- creates 2 GB of swap on servers with less than 3.5 GB of RAM;
- updates Ubuntu and turns on automatic security updates;
- installs Docker (from Docker's official repository), git, age and rclone;
- opens ports 80 and 443 in the server's internal firewall, if it blocks them;
- checks whether the outbound SMTP ports are blocked (465, 587) and suggests port 2525.
As a user other than root (for example ubuntu on Oracle), log out and back in with SSH so that the docker group applies to you too; docker ps must answer without errors.
6. Configuring and saving the keys
deploy/nova.sh init --domain psa.yourcompany.com --email it@yourcompany.com
The script creates deploy/.env (readable only by your user), generates all the passwords and secrets and creates the key for encrypting the backups in deploy/secrets/backup.agekey. If run again, it never changes the values already there.
Straight away, save in the password manager:
cat deploy/secrets/backup.agekey # all of the content, lines with # included
grep '^APP_ENCRYPTION_KEY=' deploy/.env
cat deploy/.env # recommended: the whole configuration
- Without the backups' private key the backups cannot be opened.
- Without
APP_ENCRYPTION_KEY, after a restore the two-step verification and the mailbox passwords can no longer be read. - Update the copy every time you change
deploy/.env. Never send these keys by e-mail or in a chat.
AI (optional): to turn it on, write the key of at least one provider in deploy/.env (ANTHROPIC_API_KEY=, OPENAI_API_KEY= or GEMINI_API_KEY=, with no spaces after =). It is a good idea to also set a spending limit in the provider's console. You can also do this later: every change to deploy/.env is applied with deploy/nova.sh up.
7. Starting
deploy/nova.sh up
The script checks the memory, builds the image (10-15 minutes the first time), starts the database, applies the schema migrations, then starts the app, the mail worker and Caddy, and waits for the app to answer.
Checks:
deploy/nova.sh status:app,workeranddbhealthy,caddyrunning,migrateexited (normal: it has finished).https://psa.yourcompany.comshows the padlock and the sign-in page (Company code, E-mail, Password).https://psa.yourcompany.com/api/healthanswers{"status":"ok"}.
If the HTTPS certificate does not arrive: wait 2-3 minutes; check the DNS and ports 80/443 (also with sudo deploy/setup-host.sh --firewall-only); read deploy/nova.sh logs caddy (certificate obtained successfully means it is fine). After the fix, deploy/nova.sh up restarts the request straight away. Too many failed attempts in a row make Let's Encrypt block you for about an hour.
8. Activating the first company
Each company has a company code of 3 to 40 characters made of lower-case letters, digits and hyphens:
deploy/nova.sh tenant-create --name "Rossi Software Srl" --slug rossi \
--admin-email anna.rossi@rossisoftware.it --admin-name "Anna Rossi"
The command creates the company, the seven default roles, the Assistenza queue (ticket prefix TCK) and the invitation for the first administrator, and prints the invitation link (https://psa.yourcompany.com/invite/...), valid for 7 days and only once. Send it to the administrator over a secure channel: Orafila does not send it by e-mail.
Useful options:
| Option | Effect |
|---|---|
--lingua en |
Company in English: roles and queue with English names, documents and e-mails to customers in English, interface in English for the administrator |
--queue-address assistenza@rossisoftware.it |
Address of the queue for the e-mail forwarding gateway (see Integrations) |
--reinvite --slug rossi |
A new link for the first administrator, if the previous one has expired or been lost (the old one stops working); with --admin-email it also corrects the address |
The administrator opens the link, chooses a password (at least 12 characters), signs in with company code, e-mail and password and turns on two-step verification. From there they carry on with Getting started with a company.
Sample data (optional, for a demo or for training): deploy/nova.sh sample-data --slug rossi fills every screen with made-up, recognisable data (ESEMPIO-... codes, @esempio.example addresses, two years of history); deploy/nova.sh sample-data --slug rossi --remove removes it without touching the real data. Remove it before working with real customers.
9. Configuring the backups
- Create an S3-compatible private bucket (Oracle Object Storage, DigitalOcean Spaces or another) and an access key limited to that bucket. On Oracle, add a retention rule that prevents files from being deleted for 29 days.
- In
deploy/.env, fill inBACKUP_RCLONE_REMOTEand theRCLONE_CONFIG_...lines for your storage (the templatedeploy/env.examplehas ready-made blocks for Oracle and DigitalOcean). - First test backup:
deploy/nova.sh backup(it creates the backup, verifies it by decrypting it and copies it to the bucket).deploy/nova.sh backupslists the local and remote backups. - Automatic backup every night at 02:30:
deploy/nova.sh install-timer(check withsystemctl list-timers nova-backup.timer). - Recommended: a check on Healthchecks.io (period 1 day, grace 2 hours) with its address in
BACKUP_PING_URL: if a night's backup does not arrive or fails, you receive an e-mail.
| Variable | Default | Meaning |
|---|---|---|
BACKUP_KEEP_LOCAL |
7 | Backups kept on the server |
BACKUP_KEEP_REMOTE_DAYS |
30 | Days in the bucket (longer than the retention rule) |
BACKUP_PING_URL |
empty | Monitoring address called after every backup |
10. External monitoring and restore test
- Create an HTTPS availability (uptime) check on
https://psa.yourcompany.com/api/healthevery 5 minutes, with an e-mail alert: the server cannot warn you if it is off. - Test the restore straight away, not on the day you need it:
deploy/nova.sh restore nova-YYYYMMDDTHHMMSSZ.dump.age --yes(it takes a safety backup first). The complete rebuild on a new server (package,deploy/.envand keys from the password manager, restore from the bucket) is described in the providers' guides. See also Operations and maintenance.
11. External database (optional)
PostgreSQL usually runs in a container on the same server. For a managed database (high availability, backups and point-in-time recovery from the provider) or a company PostgreSQL server:
- After
deploy/nova.sh init, copy the provider's CA certificate todeploy/db-ca.crt. - In
deploy/.env, fill in:NOVA_DB_HOST=database-server-name NOVA_DB_PORT=5432 # 25060 on DigitalOcean NOVA_DB_NAME=nova NOVA_DB_SSLMODE=verify-full # or verify-ca; other values are refused NOVA_DB_CA_FILE=./db-ca.crt # empty = public authorities, only with verify-full deploy/nova.sh db-setup: asks for the credentials of a database administrator (it does not save them) and creates the rolesnova_owner,nova_app,nova_app_user, the database and, if the provider allows it,nova_backupfor backups. The passwords reach the database as SCRAM verifiers, never in clear text.deploy/nova.sh up: checks the connection, stops the internal database (its volume is kept) and applies the migrations to the external database.
From then on, backup, restore, updates and tools work on the external database. To move the data of an installation that is already running, take a backup before filling in NOVA_DB_HOST, then run db-setup, restore and up. All the details, the common problems and the security checklist are in the guide External database (in Italian).
12. Trial run on a computer (without Docker)
For a technical evaluation or for development, on Linux or macOS with Node.js 22.18 or later and PostgreSQL 15 or later:
cd orafila
npm install
cp .env.example .env.local # then fill in the variables (see below)
sudo -u postgres scripts/setup-dev-db.sh # roles nova_owner, nova_app, nova_app_user and database nova_dev
npm run db:migrate
npm run db:seed # demo data: companies "demo" and "altra"
npm run build && npm start # in another terminal: npm run mail:worker
Demo sign-in at http://localhost:3000: company demo, e-mail responsabile@demo.example (administrator), password Demo-Orafila-2026!; other roles with commerciale@, amministrazione@, magazzino@, marco.galli@ (technician), all @demo.example. These credentials are public and are valid only for the local trial: never use db:seed on a real installation.
13. Reference: server configuration (deploy/.env)
| Variable | Required | Meaning |
|---|---|---|
NOVA_DOMAIN |
yes | Domain name, without https:// |
ACME_EMAIL |
yes | E-mail address for the Let's Encrypt certificates |
POSTGRES_PASSWORD, NOVA_OWNER_PASSWORD, NOVA_APP_PASSWORD |
yes (generated) | Passwords of the database roles; up applies them to the database |
APP_ENCRYPTION_KEY |
yes (generated) | 32 bytes in base64 that encrypt the secrets; on a server that is already running it must never be regenerated |
INBOUND_EMAIL_SECRET |
yes (generated) | Secret of the e-mail forwarding gateway |
ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY |
no | Keys of the AI providers; one is enough |
NOVA_AI_MODEL |
no | Default agent for the companies that do not choose one (for example claude-sonnet-5-5; empty = Claude Opus 5.5) |
MAIL_POLL_SECONDS |
no (60) | How often, in seconds, the mailboxes are read (10 or more) |
BACKUP_AGE_RECIPIENT |
yes (generated) | Public key for encrypting the backups |
BACKUP_KEEP_LOCAL, BACKUP_KEEP_REMOTE_DAYS, BACKUP_RCLONE_REMOTE, BACKUP_PING_URL, RCLONE_CONFIG_* |
no | Retention and copying of the backups |
NOVA_DB_HOST, NOVA_DB_PORT, NOVA_DB_NAME, NOVA_DB_SSLMODE, NOVA_DB_CA_FILE, NOVA_BACKUP_PASSWORD, NOVA_DB_CLIENT_IMAGE |
no | External database |
Format: one KEY=value line, with no spaces around =, comments on their own lines; a value containing $ goes in single quotes.
For an installation without the package (a local run or another platform) the app reads: DATABASE_URL (application role, subject to the isolation), ADMIN_DATABASE_URL (owner, only for migrations and tools), APP_ENCRYPTION_KEY, INBOUND_EMAIL_SECRET, APP_BASE_URL (public address for the invitation links), TRUST_PROXY=1 only behind a proxy that sets X-Forwarded-For, the AI keys and, with a database using TLS, ?sslmode=verify-full&sslrootcert=/path/to/ca.crt in the address plus NOVA_DB_REQUIRE_VERIFIED_TLS=1.
14. Reference: deploy/nova.sh commands
| Command | What it does |
|---|---|
init [--domain D] [--email E] |
Creates .env with new secrets and the backup key (does not change the values already there) |
db-setup |
Only with an external database: creates roles and database with the credentials of an administrator, which are not saved |
up |
Builds the image and starts or restarts everything |
install-timer |
Turns on the automatic backup every night at 02:30 |
status |
Services, external database, disk, memory, last backup, outgoing e-mails |
logs [-f] [service...] |
Logs of app, worker, db, caddy, migrate |
version |
Installed version and latest available version |
update [--no-backup] [--version V] |
Downloads the new version from the release server and checks its signature, takes a backup and restarts (--version for a specific version) |
tenant-create ... |
Activates a company and prints the invitation link |
queue-address ... |
Assigns or removes the address of a queue for the forwarding gateway |
sample-data --slug CODE [--remove] |
Adds or removes a company's sample data |
backup |
An encrypted backup now, plus the remote copy if configured |
backups |
Lists the local and remote backups |
restore FILE --yes [--key K] [--no-safety-backup] |
Restores a backup, after a safety backup (--no-safety-backup only with an external database that nova.sh cannot back up, after a copy from the provider) |
help |
List of commands |
Never use
docker compose down -v,docker volume rmordocker system prune --volumes: they delete the database.