Deployment¶
FirebirdREST is one static binary with no dependencies. Run it close to the database: every request makes a few round trips, so latency between the two adds up.
Docker¶
docker run -d --name firebirdrest -p 3000:3000 -p 3001:3001 \
-e FBREST_DB_URI='authenticator:secret@db.internal:3050/data/app.fdb' \
-e FBREST_DB_ANON_ROLE=web_anon \
-e FBREST_JWT_SECRET="$(cat /run/secrets/jwt_secret)" \
-e FBREST_ADMIN_SERVER_PORT=3001 \
ghcr.io/mariuz/firebirdrest:latest
Images are published for linux/amd64 and linux/arm64 with tags latest, X.Y and X.Y.Z.
They are based on distroless and run as a non-root user.
docker-compose.yml in the
repository runs Firebird, FirebirdREST and Swagger UI together.
Debian, Ubuntu, RHEL, Fedora: packages¶
Every release has .deb and .rpm packages for amd64 and arm64. They install the binary, a
hardened systemd service that runs as a firebirdrest system user, and a configuration in
/etc/firebirdrest/ that upgrades leave alone:
# Debian, Ubuntu
curl -LO https://github.com/mariuz/firebirdrest/releases/download/v0.6.0/firebirdrest_0.6.0_amd64.deb
sudo apt install ./firebirdrest_0.6.0_amd64.deb
# RHEL, Rocky, Alma, Fedora, openSUSE
sudo dnf install https://github.com/mariuz/firebirdrest/releases/download/v0.6.0/firebirdrest-0.6.0.x86_64.rpm
sudoedit /etc/firebirdrest/firebirdrest.conf # db-uri, jwt-secret, ...
sudo systemctl enable --now firebirdrest
| Path | |
|---|---|
/usr/bin/firebirdrest |
the binary |
/etc/firebirdrest/firebirdrest.conf |
the configuration, root:firebirdrest, mode 0640 (it holds the database password); kept on upgrade and on removal |
/usr/lib/systemd/system/firebirdrest.service |
the service; override settings with systemctl edit firebirdrest |
/usr/share/doc/firebirdrest/ |
README, changelog, license and the example database scripts |
The service checks the configuration (firebirdrest -check) before starting, so a typo shows up
in systemctl status firebirdrest instead of a crash loop. systemctl reload firebirdrest
reloads the TLS certificate and the schema cache. The first install doesn't start the service;
an upgrade restarts it if it was running. Logs go to the journal:
journalctl -u firebirdrest -f.
systemd¶
Without the packages, the same unit works for a binary in /usr/local/bin:
# /etc/systemd/system/firebirdrest.service
[Unit]
Description=FirebirdREST
After=network-online.target firebird.service
Wants=network-online.target
[Service]
ExecStartPre=/usr/local/bin/firebirdrest -check /etc/firebirdrest/firebirdrest.conf
ExecStart=/usr/local/bin/firebirdrest /etc/firebirdrest/firebirdrest.conf
# SIGHUP reloads the TLS certificate and the schema cache; SIGUSR1 only the schema cache
ExecReload=/bin/sh -c 'kill -HUP $MAINPID'
Restart=on-failure
DynamicUser=yes
NoNewPrivileges=yes
ProtectSystem=strict
[Install]
WantedBy=multi-user.target
The packaged unit adds further hardening; see
packaging/firebirdrest.service.
TLS¶
FirebirdREST can serve HTTPS itself, without a reverse proxy:
server-tls-cert = "/etc/firebirdrest/tls/fullchain.pem" # certificate and chain, PEM
server-tls-key = "/etc/firebirdrest/tls/privkey.pem"
It speaks TLS 1.2 and 1.3, and HTTP/2 when the client offers it (event streams included). The
certificate is read at startup, checked by firebirdrest -check (which prints its expiry), and
read again on SIGHUP (systemctl reload firebirdrest): new connections get the renewed
certificate, open ones keep theirs, and a renewal that fails to load keeps the current
certificate and logs an error. A certificate that expires within 14 days is logged as a warning
at startup and on reload. With Let's Encrypt and certbot, a deploy hook copies the files where the
service user can read them and reloads:
# /etc/letsencrypt/renewal-hooks/deploy/firebirdrest
#!/bin/sh
install -m 0640 -g firebirdrest "$RENEWED_LINEAGE/fullchain.pem" "$RENEWED_LINEAGE/privkey.pem" /etc/firebirdrest/tls/
systemctl reload firebirdrest
The admin server (admin-server-port: health checks, metrics) stays plain HTTP; keep it on a
local or private address. On Windows a renewed certificate needs a restart.
Behind a reverse proxy¶
A reverse proxy is the place for rate limiting, and for TLS when it terminates several services; for example with nginx:
location /api/ {
proxy_pass http://127.0.0.1:3000/;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
Set openapi-server-proxy-uri = "https://example.com/api" so the OpenAPI document shows the public
URL. X-Forwarded-For is available to PSQL as request.header.x-forwarded-for.
Health checks¶
With admin-server-port set:
| Endpoint | |
|---|---|
GET /live |
200 while the process runs |
GET /ready |
200 when the database answers, 503 otherwise |
POST /reload |
reload the schema cache (204) |
GET /metrics |
metrics in the Prometheus format (list) |
# Kubernetes
livenessProbe: { httpGet: { path: /live, port: 3001 } }
readinessProbe: { httpGet: { path: /ready, port: 3001 } }
Sizing¶
db-poolis per role. With several roles in use, the database sees up to roles ×db-poolconnections from each FirebirdREST instance.- FirebirdREST keeps no state besides its caches, so you can run several instances behind a load
balancer. Reload each one after DDL; the
POST_EVENTroute reaches all of them at once. - See Benchmarks for throughput figures and the load tool.
Upgrading¶
Download the new binary or pull the new image and restart. Settings and behaviour changes are listed in the changelog.
Firebird 6¶
Firebird 6 is not released yet. CI runs the full integration suite against the nightly
firebirdsql/firebird:6-snapshot image on every push and once a week, so problems show up
before the release. Firebird 6 adds SQL schemas, which FirebirdREST can expose with db-schemas
(see Schemas); by default it serves PUBLIC.
Known issue with the current snapshot: text columns declared CHARACTER SET NONE (the default
in a database created without DEFAULT CHARACTER SET) fail with string right truncation
once a value is longer than a quarter of the column's size, when the client connects as UTF8
(FirebirdREST's default). Firebird 6 reads the row buffer the driver asks for as UTF8 characters
(4 bytes each) instead of bytes, as Firebird 5 does. A fix in the Go driver FirebirdREST uses,
which sizes that buffer for the connection character set, is proposed in
nakagami/firebirdsql#317. The Python driver
firebirdsql has the same problem and the same fix, proposed in
nakagami/pyfirebirdsql#142. Until a
driver release includes it, either create the database with a character set:
or connect with the database's own character set, for example
db-uri = "user:pass@host/app.fdb?charset=NONE".
A second issue of the same kind affects binary data: with the current driver, Firebird 6 refuses
to read CHARACTER SET OCTETS columns and to write binary values under 32 KB (into BLOB
SUB_TYPE BINARY or OCTETS columns) with Malformed string, because it validates them as
UTF8 text. BLOB SUB_TYPE BINARY reads, and writes of 32 KB and more, work. The driver fix is
on the branch fix-fb6-octets, being sent upstream.