setting up the server
These are the requirements for running InterpretersOffice. My intention is make installation easier than what is described below, with less manual setup involved, but for now illud est quod est. And of course, if you already have your web and database servers installed, there is less to do. These instructions assume a server with a Linux OS and little else.
web server: Apache or Nginx
Since I’m personally more familiar with Apache, we’ll assume the use of Apache.
- Install the web server.
- Set up the virtual host.
- Decide whether you want to allow per-directory overrides (with a
.htaccess
file) and put the url-rewriting recipe there, or else put it in the vhost configuration and (optionally) disable overrides. The latter strategy gives you marginally better performance, at the cost of having to reload the server should you need to change this configuration. - Set as web document root the full path to
public
subdirectory under the application root. - Set an environment variable called environment to: production.
- Decide whether you want to allow per-directory overrides (with a
- Enable
mod_rewrite
(or equivalent)
This is necessary because InterpretersOffice uses an MVC framework that depends on URL rewriting to route requests to the proper controller/action.
- sufficient permissions to stop, start, reload the web server
- sufficient permissions to edit the web server configuration files
- ownership of the entire application directory tree, or at least read/write access to it
php support
- Install
php7.4-fpm
. (The minimum supported version is 7.3) - Install php extensions:
php7.4‑mysql
,php7.4‑curl
,php7.4‑mbstring
,php7.4‑json
,php7.4‑dom
,php7.4‑intl
- Install php composer
database server: mariadb or mysql
- Install the database server.
You can use either mysql or mariadb, but if you opt to set up master-server replication, it is recommended that you choose one or the other exclusively. I have been happy with both but currently my preference is mariadb. - Create the database.
You can call it what you like, but the name I have been using is office. - Create the database user and grant privileges:
CREATE USER 'interpreters'@'localhost' IDENTIFIED BY 'their_password';
GRANT ALL PRIVILEGES ON `office`.* TO 'interpreters'@'localhost';
- a mysql user account with permissions to create the database
- permissions to edit the database server configuration files
- permissions to stop, start, reload the database server
installing the application
get the code and its dependencies
Install git
if you haven’t already. This step also requires the
the php dependency manager composer.
cd /path/to/application/
git clone https://github.com/davidmintz/court-interpreters-office
cd court-interpreters-office
composer install
You can safely ignore any warning about package container-interop/container-interop having been abandoned. Moving on:
set up the data directory
mkdir -p data/log
mkdir data/session
mkdir data/cache
Make these writeable by the web server, e.g.,
setfacl -Rm u:www-data:rwx data
set up the database
Create and edit the database configuration file:
cd config/autoload
cp doctrine.local.php.dist doctrine.local.php
Open doctrine.local.php
in a text editor, set the values for user, password, and host appropriately, and save.
You should now be able to load the index page in a browser without incident, but there is still more to do, starting with database initialization.
If you are migrating from an existing installation, simply mysqldump
the old database into the new one, and your database is good to go. (After first
shutting off access the old installation, to avoid losing data in the transition.)
If you are starting from scratch with an empty database, you need to seed the database by running SQL scripts found in bin/sql
. From
your application root,
cat bin/sql/mysql-schema.sql bin/sql/initial-data.sql | mysql -p -h your_host office
Next, you need to set up an initial administrative user, using the provided interactive CLI script. From the application root,
bin/admin-cli setup:create-admin-user
Supply the answers as prompted, and you’ll have an admin user who can log in and carry on using the web interface. (Please note: at this point it is technically possible to move forward with the database as is, but there are several data tables that would have to be populated by the admin users, row by row, and it would be tedious. It’s worth considering writing some one-off scripts to import data from existing sources. Feel free to contact davidmintz@interpretersoffice.org to discuss.)
InterpretersOffice relies heavily on outbound email. Copy the file
config/autoload/local.production.php.dist
to config/autoload/local.production.php
, and then edit the mail
section:
<?php
use Laminas\Mail\Transport\Smtp;
use Laminas\Mail\Transport\SmtpOptions;
return [
// stuff omitted...
'mail' => [
'transport' => Smtp::class,
'transport_options' => [
'class' => SmtpOptions::class,
'options' => [
'name' => 'your.stmp.server',
'host' => 'host_ip_address',
'port' => 465,
'connection_class' => 'login',
'connection_config' => [
'username' => 'your_username',
'password' => 'your_password',
'ssl' => 'ssl',
],
],
],
'from_address' => 'default_from_address@example.org',
'from_entity' => 'Interpreters Office',
],
];
replacing all the values appropriately. This array has to contain configuration that a Laminas\Mail transport class
constructor can consume. It does not necessarily have to be the SMTP transport per se. If, for example, your system has postfix configured to relay to an
SMTP server, you can use Laminas\Mail\Transport\Sendmail
instead:
'mail' => [
'transport' => 'Laminas\Mail\Transport\Sendmail',
'transport_options' => [
// optional
],
]
Set the values of from_address
and from_entity
appropriately; these are the defaults used to populate the From:
header of outgoing messages.
If you want to use Mailgun, put in the config/autoload
directory a configuration file called
mailgun.local.php
with contents like
return [
'mailgun' => [
'smtp' => [
'user' => 'you@your_email_domain.org',
'password' => 'your_password',
'host' => 'smtp.mailgun.org',
],
'api' => [
'key' => 'your_api_key',
'base_url' => 'https://api.mailgun.net/v3',
'domain'=> 'your_email_domain.org',
],
],
];
and then Mailgun’s SMTP services will be used for sending most emails, but the Mailgun API will be used for the batch email feature (which allows administrative users to send email en masse to particular groups, such as all active contract interpreters).
other configuration
There is some more configuration data to be set manually because InterpretersOffice does not yet provide a GUI for all the application configuration.
In config/autoload/local.production.php
there a couple more sections to be edited.
/** contact information variables for your layout */
'site' => [
'contact' => [
'organization_name' => 'Your Office',
'organization_locality' => 'Your City',
'telephone' => 'Your phone number',
'email' => 'contact@example.org',
'website' => 'https://interpreters.example.org',
],
],
/**
* optional list of IP addresses from which users can read the interpreters schedule
* without logging in, and/or strings one of which the hosting domain must match
*/
'permissions' => [
'schedule' => [
'anonymous_ips_allowed' => [],
'host_domains_allowed' => [],
],
],
'security' => [
'max_login_failures' => 6,
],
The contact
array is injected into the main layout and into some email templates.
The permissions
settings are used to determine under what conditions, if any, read-access to the
Interpreters schedule is allowed to anonymous users. The value of this is for contract interpreters who
legitimately need to see the schedule, but since they do not have user accounts they can never log in.
If the host domain is one you know to be running on a private network, anyone
using the application is presumptively authorized to be inside that network, so you may wish to enable
anonymous schedule access by adding that host name to the host_domains_allowed
array. The anonymous_ips_allowed
applies similar logic in reverse. If, for example, you know a particular IP address to be that of the gateway in front
of a private network, you may wish to add it to the anonymous_ips_allowed
array.
If you simply leave this permissions
array untouched, all users will be required to be authenticated
in order to view the Interpreters schedule.
The max_login_failures
variable refers to how many consecutive failed logins are permitted
before a user account is disabled. You can set this value pretty high if you like, but currently you cannot set it to
zero to mean unlimited. The default (six) seems sensible.
There are a couple more configuration files that have to be present and writeable by the server: module/Admin/config/forms.json
and module/Rotation/config/config.json
. In the Interpreters Office for the Southern District of New York,
the former configuration looks like
{
"interpreters": {
"optional_elements": {
"banned_by_persons": "1",
"BOP_form_submission_date": "1",
"fingerprint_date": "1",
"contract_expiration_date": "1",
"oath_date": "1",
"security_clearance_date": "1"
}
},
"events": {
"optional_elements": {
"end_time": "1"
}
},
"users" : {
"allow_email_domains" : [
"nysd.uscourts.gov",
"nysp.uscourts.gov",
"nyspt.uscourts.gov",
"ca2.uscourts.gov"
]
}
}
The first two sections are for enabling/disabling optional fields for interpreter entities and event entities.
The users
section is a whitelist of email domains users of the system are permitted to have, preventing users from
registering accounts from arbitrary email addresses. It also imposes validation rules for the user profile and
administrative user editing forms. If you want to disable this, leave the allow_email_domains
section as an empty array.
Additionally, the subdirectory module/Requests/config
has to be server-writeable.
Hashicorp Vault for sensitive data
InterpretersOffice includes an optional module called Vault. If you intend to handle sensitive contract interpreter data (dates of birth and social security numbers), the Vault module must be configured and enabled. A prerequisite is an installation Hashicorp Vault itself. Initial setup of the InterpretersOffice Vault module is a chore, though the increased security is more than worth the effort. We have some notes here but they need updating, as Vault development keeps moving forward.
There is a blog post about our Vault integration with InterpretersOffice that explains how it works. Briefly, the interpreters’ sensitive data at rest is symmetrically encryted, and the cipher for encryption/decryption is secured in Vault rather than lying around in plain text. In other words the encryption/decryption key is never stored anywhere on the server in plain text.
- full permissions to manage the Hashicorp Vault service, including its
init
,seal
andunseal
commands