EMS HA installation with native Postgres HA without Docker
This guide gives instructions on how to set up a PostgreSQL (Postgres) high availability (HA) cluster when Postgres is natively installed (not Postgres containers) and install EMS HA.
Postgres HA requires at least three servers or virtual machines (VM):
Node |
Purpose |
---|---|
Postgres node 1 |
Starts as the primary node |
Postgres node 2 |
Starts as the standby node |
Postgres witness 1 |
Serves as a witness to prevent split-brain scenarios where both nodes may self-promote to become the primary and clash |
The configuration also requires two servers or VMs for EMS nodes.
To configure Postgres node 1:
- Install Postgres 15:
sudo apt install -y --no-install-recommends curl ca-certificates sudo install -d /usr/share/postgresql-common/pgdg sudo curl -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc --fail https://www.postgresql.org/media/keys/ACCC4CF8.asc sudo sh -c 'echo "deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list' sudo apt update sudo apt install -y postgresql-15
- Install Replication Manager. Postgres recommends this replication tool:
sudo apt-get install apt-transport-https sudo sh -c 'echo "deb https://apt.2ndquadrant.com/ $(lsb_release -cs)-2ndquadrant main" > /etc/apt/sources.list.d/2ndquadrant.list' sudo apt-get install curl ca-certificates curl https://apt.2ndquadrant.com/site/keys/9904CD4BD6BAF0C3.asc| sudo apt-key add sudo apt-get update sudo apt-get install -y postgresql-15-repmgr
- Install EMS custom extensions (ems_pg_extensions.tar.gz) for Postgres. You can download the extensions from the Fortinet Support site. Use the ems_pg_extensions.tar.gz file under the EMS 7.4.0 page to install extensions for EMS 7.4.1:
sudo tar zxvf ems_pg_extensions.tar.gz -C /
- Create the symmetric key required that the custom extension requires. Copy the value in symmetric_key.txt as you must share it with the other nodes:
sh -c 'head -c 20 /dev/urandom | md5sum | head -c 20;' |sudo tee /var/lib/postgresql/15/symmetric_key.txt > /dev/null cat /var/lib/postgresql/15/symmetric_key.txt
- Set the password for the Postgres Linux user:
sudo passwd postgres
- Modify postgresql.conf to add replication parameters. Change the following settings on
/etc/postgresql/15/main/postgresql.conf
with the indicated values:listen_addresses = ‘localhost, <ip of the PostgreSQL node1 server>’ max_wal_senders = 10 max_replication_slots = 10 wal_level = replica hot_standby = on archive_mode = on archive_command = '/bin/true' shared_preload_libraries = 'repmgr'
- Set up Postgres access to the replication user. Add the following to
/etc/postgresql/15/main/pg_hba.conf
:host all all 0.0.0.0/0 trust local replication repmgr trust host replication repmgr 127.0.0.1/32 trust host replication repmgr <node1 ip>/32 trust host replication repmgr <node2 ip>/32 trust host replication repmgr <witnesse ip>/32 trust local repmgr repmgr trust host repmgr repmgr 127.0.0.1/32 trust host repmgr repmgr <node1 ip>/32 trust host repmgr repmgr <node2 ip>/32 trust host repmgr repmgr <witness ip>/32 trust
Replace
<node1 ip>
,<node2 ip>
, and<witness ip>
accordingly. - Create the repmgr user and database. Run the following to create the repmgr user and database on Postgres:
sudo -u postgres createuser -s repmgr
sudo -u postgres createdb repmgr -O repmgr
- Restart the postgresql service:
sudo systemctl restart postgresql@15-main.service
To configure Postgres node 2:
- Install Postgres 15:
sudo apt install -y --no-install-recommends curl ca-certificates sudo install -d /usr/share/postgresql-common/pgdg sudo curl -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc --fail https://www.postgresql.org/media/keys/ACCC4CF8.asc sudo sh -c 'echo "deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list' sudo apt update sudo apt install -y postgresql-15
- Install Replication Manager. Postgres recommends this replication tool:
sudo apt-get install apt-transport-https sudo sh -c 'echo "deb https://apt.2ndquadrant.com/ $(lsb_release -cs)-2ndquadrant main" > /etc/apt/sources.list.d/2ndquadrant.list' sudo apt-get install curl ca-certificates curl https://apt.2ndquadrant.com/site/keys/9904CD4BD6BAF0C3.asc| sudo apt-key add sudo apt-get update sudo apt-get install -y postgresql-15-repmgr
- Install EMS custom extensions (ems_pg_extensions.tar.gz) for Postgres. You can download the extensions from the Fortinet Support site:
sudo tar zxvf ems_pg_extensions.tar.gz -C /
- Create the symmetric key required that the custom extension requires. The value must be the one copied from the symmetric key from the PostgreSQL node 1:
sh -c 'echo "<value copied from PostgreSQL node 1>"|head -c 20 | head -c 20;'|sudo tee /var/lib/postgresql/15/symmetric_key.txt > /dev/null
- Set the password for the Postgres Linux user:
sudo passwd postgres
- Modify postgresql.conf to add replication parameters. Change the following settings on
/etc/postgresql/15/main/postgresql.conf
with the indicated values:listen_addresses = ‘localhost, <ip of the PostgreSQL node2 server>
max_wal_senders =
max_replication_slots = 10
wal_level = replica
hot_standby = on
archive_mode = on
archive_command = '/bin/true'
shared_preload_libraries = 'repmgr'
- Set up Postgres access to the replication user. Add the following to
/etc/postgresql/15/main/pg_hba.conf
:host all all 0.0.0.0/0 trust local replication repmgr trust host replication repmgr 127.0.0.1/32 trust host replication repmgr <node1 ip>/32 trust host replication repmgr <node2 ip>/32 trust host replication repmgr <witnesse ip>/32 trust local repmgr repmgr trust host repmgr repmgr 127.0.0.1/32 trust host repmgr repmgr <node1 ip>/32 trust host repmgr repmgr <node2 ip>/32 trust host repmgr repmgr <witness ip>/32 trust
Replace
<node1 ip>
,<node2 ip>
, and<witness ip>
accordingly. - Restart the postgresql service:
sudo systemctl restart postgresql@15-main.service
To set up SSH access between Postgres nodes 1 and 2:
- On Postgres node 1, run the following:
sudo -H -u postgres bash -c “ssh-keygen -t rsa -f ~/.ssh/id_rsa -N ‘’” sudo -H -u postgres bash -c “ssh-copy-id -i ~/.ssh/id_rsa.pub -o StrictHostKeyChecking=no 'postgres@<node2 ip>’”
- On Postgres node 2, run the following:
sudo -H -u postgres bash -c “ssh-keygen -t rsa -f ~/.ssh/id_rsa -N ‘’” sudo -H -u postgres bash -c “ssh-copy-id -i ~/.ssh/id_rsa.pub -o StrictHostKeyChecking=no 'postgres@<node2 ip>’”
To register Postgres node1 to the cluster:
- Create the /etc/repmgr.conf file on Postgres node1:
cluster='emscluster' node_id=1 node_name=postgresqlnode1 conninfo='host=<PostgresSQL node1 ip> user=repmgr dbname=repmgr connect_timeout=2' data_directory='/var/lib/postgresql/15/main/' pg_bindir='/usr/bin/' log_file='/var/log/repmgr/repmgr.log' log_level=DEBUG failover=automatic promote_command='/usr/bin/repmgr standby promote -f /etc/repmgr.conf' follow_command='/usr/bin/repmgr standby follow -f /etc/repmgr.conf --upstream-node-id=%n'
Replace
<node1 ip>
accordingly. - Create the log directory for repmgr:
sudo mkdir /var/log/repmgr sudo chown -R postgres /var/log/repmgr
- Register the node as the primary:
sudo -u postgres /usr/bin/repmgr -f /etc/repmgr.conf primary register
- Confirm registration:
sudo -u postgres /usr/bin/repmgr -f /etc/repmgr.conf cluster show
- Create a systemd service config for repmgr by creating the file:
[Unit] Description=PostgreSQL Replication Manager Daemon After=network.target postgresql.service [Service] Type=forking User=postgres ExecStart=/usr/bin/repmgrd -f /etc/repmgr.conf --daemonize PIDFile=/tmp/repmgrd.pid ExecStop=/bin/kill -s TERM $(cat /tmp/repmgrd.pid) ExecReload=/bin/kill -s HUP $(cat /tmp/repmgrd.pid) Restart=on-failure LimitNOFILE=16384 [Install] WantedBy=multi-user.target
- Edit /etc/default/repmgrd to change default settings. The following provides an example:
# default settings for repmgrd. This file is source by /bin/sh from # /etc/init.d/repmgrd # disable repmgrd by default so it won't get started upon installation # valid values: yes/no
REPMGRD_ENABLED=yes
# configuration file (required) REPMGRD_CONF="/etc/repmgr.conf" # additional options #REPMGRD_OPTS="" # user to run repmgrd as #REPMGRD_USER=postgres # repmgrd binary #REPMGRD_BIN=/usr/bin/repmgrd # pid file REPMGRD_PIDFILE=/tmp/repmgrd.pid
REPMGR_ENABLED
changed toyes
,REPMGRD_CONF
was uncommented and value changed to"/tmp/repmgrd.conf"
andREPMGRD_PIDFILE
was uncommented and value changed to/tmp/repmgrd.pid
. - Kill any previous instance of repmgrd that may be running:
ps -ef|grep "bin/repmgrd"|grep -v grep|xargs -t -i sudo kill {}
- Enable and start the repmgrd service:
sudo systemctl enable repmgrd.service && sudo systemctl start repmgrd
- Create a monitor and reconciliation service to support automatic failover. Create the script /var/lib/postgresql/node_monitor.sh with ownership to the Postgres user:
#!/bin/bash # Script to detect a new primary and rejoin the cluster as standby if necessary # Configuration variables REPMGR_CONF="/etc/repmgr.conf" PG_SERVICE="postgresql@15-main" CHECK_INTERVAL=10 # Check every 10 seconds REPMGR_CMD="/usr/bin/repmgr" PG_CTL="/usr/bin/pg_ctl" NODE_NAME="node1" # Function to log messages log_message() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" } # Main loop while true; do # Ensure PostgreSQL is running before checking the cluster status systemctl is-active --quiet $PG_SERVICE PG_STATUS=$? if [ $PG_STATUS -eq 0 ]; then # Check if there is another primary in the cluster OTHER_PRIMARY=$(sudo -u postgres $REPMGR_CMD -f $REPMGR_CONF cluster show 2>/dev/null | grep -v "$NODE_NAME" | grep "primary"|grep "running as primary"|sed -n 's/.*host=\([^ ]*\).*/\1/p') # Get current node's role CURRENT_ROLE=$(sudo -u postgres $REPMGR_CMD -f $REPMGR_CONF node check --role 2>/dev/null | grep -oP '(?<=\().*(?=\))'|awk '{print $NF}') if [[ ! -z "$OTHER_PRIMARY" && "$CURRENT_ROLE" == "primary" ]]; then log_message "Another primary detected in the cluster. Attempting to rejoin as standby." # Ensure PostgreSQL is stopped before rejoining systemctl stop $PG_SERVICE sleep 5 # Ensure PostgreSQL is fully stopped systemctl is-active --quiet $PG_SERVICE if [ $? -eq 0 ]; then log_message "Failed to stop PostgreSQL service. Skipping rejoin." else # Clone the data from the current primary and rejoin as standby sudo -u postgres $REPMGR_CMD -h $OTHER_PRIMARY -U repmgr -d repmgr -f $REPMGR_CONF standby clone --force 2>/dev/null && \ sudo systemctl start $PG_SERVICE && \ sudo -u postgres $REPMGR_CMD -f $REPMGR_CONF standby register --force 2>/dev/null if [ $? -eq 0 ]; then log_message "Node rejoined as standby successfully." else log_message "Failed to rejoin node as standby." fi fi elif [[ -z "$CLUSTER_STATUS" ]]; then log_message "No other primary detected, or the current node is already a standby. Nothing to do." fi else log_message "PostgreSQL service is not running. Skipping checks." fi # Wait for the next check sleep $CHECK_INTERVAL done
- Create a monitor service by creating the file /etc/systemd/system/pg_node_monitor.service:
[Unit] Description=Automatic Rejoin Standby Service After=network.target postgresql.service [Service] Type=simple User=root ExecStart=/var/lib/postgresql/node_monitor.sh Restart=on-failure RestartSec=5s [Install] WantedBy=multi-user.target
- Enable and start the monitor service:
sudo systemctl enable pg_node_monitor && sudo systemctl start pg_node_monitor
To register Postgres node2 to the cluster:
- Create the /etc/repmgr.conf file on Postgres node2:
cluster='emscluster' node_id=2 node_name=postgresqlnode2 conninfo='host=<PostgresSQL node2 ip> user=repmgr dbname=repmgr connect_timeout=2' data_directory='/var/lib/postgresql/15/main/' pg_bindir='/usr/bin/' log_file='/var/log/repmgr/repmgr.log' log_level=DEBUG failover=automatic promote_command='/usr/bin/repmgr standby promote -f /etc/repmgr.conf' follow_command='/usr/bin/repmgr standby follow -f /etc/repmgr.conf --upstream-node-id=%n'
Replace
<node2 ip>
accordingly. - Create the log directory for repmgr:
sudo mkdir /var/log/repmgr sudo chown -R postgres /var/log/repmgr
- Stop the Postgres service:
sudo systemctl stop postgresql
- Create a clone from Postgres node1:
sudo -u postgres repmgr -h <node1 ip> -U repmgr -d repmgr -f /etc/repmgr.conf standby clone --force
Replace
<node1 ip>
accordingly. - Restart the Postgres service:
sudo systemctl start postgresql
- Register the node as the standby:
sudo -u postgres /usr/bin/repmgr -f /etc/repmgr.conf standby register
- Confirm registration:
sudo -u postgres /usr/bin/repmgr -f /etc/repmgr.conf cluster show
- Create a systemd service config for repmgr by creating file /etc/systemd/system/repmgrd.service:
[Unit] Description=PostgreSQL Replication Manager Daemon After=network.target postgresql.service [Service] Type=forking User=postgres ExecStart=/usr/bin/repmgrd -f /etc/repmgr.conf --daemonize PIDFile=/tmp/repmgrd.pid ExecStop=/bin/kill -s TERM $(cat /tmp/repmgrd.pid) ExecReload=/bin/kill -s HUP $(cat /tmp/repmgrd.pid) Restart=on-failure LimitNOFILE=16384 [Install] WantedBy=multi-user.target
- Edit /etc/default/repmgrd to change default settings. The following provides an example:
# default settings for repmgrd. This file is source by /bin/sh from # /etc/init.d/repmgrd # disable repmgrd by default so it won't get started upon installation # valid values: yes/no
REPMGRD_ENABLED=yes
# configuration file (required) REPMGRD_CONF="/etc/repmgr.conf" # additional options #REPMGRD_OPTS="" # user to run repmgrd as #REPMGRD_USER=postgres # repmgrd binary #REPMGRD_BIN=/usr/bin/repmgrd # pid file REPMGRD_PIDFILE=/tmp/repmgrd.pid
REPMGR_ENABLED
changed toyes
,REPMGRD_CONF
was uncommented and value changed to"/tmp/repmgrd.conf"
andREPMGRD_PIDFILE
was uncommented and value changed to/tmp/repmgrd.pid
. - Kill any previous instance of repmgrd that may be running:
ps -ef|grep "bin/repmgrd"|grep -v grep|xargs -t -i sudo kill {}
- Enable and start the repmgrd service:
sudo systemctl enable repmgrd.service && sudo systemctl start repmgrd
- Create a monitor and reconciliation service to support automatic failover. Create the script /var/lib/postgresql/node_monitor.sh with ownership to the Postgres user:
#!/bin/bash # Script to detect a new primary and rejoin the cluster as standby if necessary # Configuration variables REPMGR_CONF="/etc/repmgr.conf" PG_SERVICE="postgresql@15-main" CHECK_INTERVAL=10 # Check every 10 seconds REPMGR_CMD="/usr/bin/repmgr" PG_CTL="/usr/bin/pg_ctl" NODE_NAME="node2" # Function to log messages log_message() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" } # Main loop while true; do # Ensure PostgreSQL is running before checking the cluster status systemctl is-active --quiet $PG_SERVICE PG_STATUS=$? if [ $PG_STATUS -eq 0 ]; then # Check if there is another primary in the cluster OTHER_PRIMARY=$(sudo -u postgres $REPMGR_CMD -f $REPMGR_CONF cluster show 2>/dev/null | grep -v "$NODE_NAME" | grep "primary"|grep "running as primary"|sed -n 's/.*host=\([^ ]*\).*/\1/p') # Get current node's role CURRENT_ROLE=$(sudo -u postgres $REPMGR_CMD -f $REPMGR_CONF node check --role 2>/dev/null | grep -oP '(?<=\().*(?=\))'|awk '{print $NF}') if [[ ! -z "$OTHER_PRIMARY" && "$CURRENT_ROLE" == "primary" ]]; then log_message "Another primary detected in the cluster. Attempting to rejoin as standby." # Ensure PostgreSQL is stopped before rejoining systemctl stop $PG_SERVICE sleep 5 # Ensure PostgreSQL is fully stopped systemctl is-active --quiet $PG_SERVICE if [ $? -eq 0 ]; then log_message "Failed to stop PostgreSQL service. Skipping rejoin." else # Clone the data from the current primary and rejoin as standby sudo -u postgres $REPMGR_CMD -h $OTHER_PRIMARY -U repmgr -d repmgr -f $REPMGR_CONF standby clone --force 2>/dev/null && \ sudo systemctl start $PG_SERVICE && \ sudo -u postgres $REPMGR_CMD -f $REPMGR_CONF standby register --force 2>/dev/null if [ $? -eq 0 ]; then log_message "Node rejoined as standby successfully." else log_message "Failed to rejoin node as standby." fi fi elif [[ -z "$CLUSTER_STATUS" ]]; then log_message "No other primary detected, or the current node is already a standby. Nothing to do." fi else log_message "PostgreSQL service is not running. Skipping checks." fi # Wait for the next check sleep $CHECK_INTERVAL done
- Create a monitor service by creating the file /etc/systemd/system/pg_node_monitor.service:
[Unit] Description=Automatic Rejoin Standby Service After=network.target postgresql.service [Service] Type=simple User=root ExecStart=/var/lib/postgresql/node_monitor.sh Restart=on-failure RestartSec=5s [Install] WantedBy=multi-user.target
- Enable and start the monitor service:
sudo systemctl enable pg_node_monitor && sudo systemctl start pg_node_monitor
To register Postgres witness server:
- Install Postgres 15:
sudo apt install -y --no-install-recommends curl ca-certificates sudo install -d /usr/share/postgresql-common/pgdg sudo curl -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc --fail https://www.postgresql.org/media/keys/ACCC4CF8.asc sudo sh -c 'echo "deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list' sudo apt update sudo apt install -y postgresql-15
- Install Replication Manager. Postgres recommends this replication tool:
sudo apt-get install apt-transport-https sudo sh -c 'echo "deb https://apt.2ndquadrant.com/ $(lsb_release -cs)-2ndquadrant main" > /etc/apt/sources.list.d/2ndquadrant.list' sudo apt-get install curl ca-certificates curl https://apt.2ndquadrant.com/site/keys/9904CD4BD6BAF0C3.asc| sudo apt-key add sudo apt-get update sudo apt-get install -y postgresql-15-repmgr
- Modify postgresql.conf to add replication parameters. Change the following settings on
/etc/postgresql/15/main/postgresql.conf
with the indicated values:listen_addresses = ‘localhost, <ip of witness server>’ shared_preload_libraries = 'repmgr'
- Set up Postgres access to the replication user. Add the following to
/etc/postgresql/15/main/pg_hba.conf
:host all all 0.0.0.0/0 trust local replication repmgr trust host replication repmgr 127.0.0.1/32 trust host replication repmgr <node1 ip>/32 trust host replication repmgr <node2 ip>/32 trust host replication repmgr <witnesse ip>/32 trust local repmgr repmgr trust host repmgr repmgr 127.0.0.1/32 trust host repmgr repmgr <node1 ip>/32 trust host repmgr repmgr <node2 ip>/32 trust host repmgr repmgr <witness ip>/32 trust
Replace
<node1 ip>
,<node2 ip>
, and<witness ip>
accordingly. - Restart the postgresql service:
sudo sytemctl restart postgresql
- Create the repmgr user and database. Run the following to create the repmgr user and database on Postgres:
sudo -u postgres createuser -s repmgr sudo -u postgres createdb repmgr -O repmgr
- Create the log directory for repmgr:
sudo mkdir /var/log/repmgr sudo chown -R postgres /var/log/repmgr
- Create the /etc/repmgr.conf file:
cluster='emscluster' node_id=3 node_name='witness1' conninfo='host=<witness node ip> user=repmgr dbname=repmgr connect_timeout=2' data_directory='/var/lib/postgresql/15/main' # Not used but required by repmgr pg_bindir='/usr/bin/' log_file='/var/log/repmgr/repmgr.log'
- Register as witness informing the host of the primary node:
sudo -u postgres /usr/bin/repmgr -f /etc/repmgr.conf witness register -h <node1 ip>
- Create a systemd service config for repmgr by creating file /etc/systemd/system/repmgrd.service:
[Unit] Description=PostgreSQL Replication Manager Daemon After=network.target postgresql.service [Service] Type=forking User=postgres ExecStart=/usr/bin/repmgrd -f /etc/repmgr.conf --daemonize PIDFile=/tmp/repmgrd.pid ExecStop=/bin/kill -s TERM $(cat /tmp/repmgrd.pid) ExecReload=/bin/kill -s HUP $(cat /tmp/repmgrd.pid) Restart=on-failure LimitNOFILE=16384 [Install] WantedBy=multi-user.target
- Edit /etc/default/repmgrd to change default settings. It should look like this:
# default settings for repmgrd. This file is source by /bin/sh from # /etc/init.d/repmgrd # disable repmgrd by default so it won't get started upon installation # valid values: yes/no REPMGRD_ENABLED=yes # configuration file (required) REPMGRD_CONF="/etc/repmgr.conf" # additional options #REPMGRD_OPTS="" # user to run repmgrd as #REPMGRD_USER=postgres # repmgrd binary #REPMGRD_BIN=/usr/bin/repmgrd # pid file REPMGRD_PIDFILE=/tmp/repmgrd.pid
REPMGR_ENABLED
changed toyes
,REPMGRD_CONF
was uncommented and value changed to"/tmp/repmgrd.conf"
andREPMGRD_PIDFILE
was uncommented and value changed to/tmp/repmgrd.pid
. - Kill any previous instance of the repmgrd that might be running:
ps -ef|grep "bin/repmgrd"|grep -v grep|xargs -t -i sudo kill {}
- Enable and start the repmgrd service:
sudo systemctl enable repmgrd.service && sudo systemctl start repmgrd
To test failover:
Stop the Postgres service on the primary node or shut down the primary node. By default, the health check happens every 10 seconds. Before promoting itself to the primary node, the secondary node checks if the primary is down at least six times. Therefore, failover takes 60 seconds to happen. This is configurable but an acceptable timeout or downtime.
To configure EMS HA:
-
After the database cluster is up and running, configure EMS HA:
- On both nodes, do the following:
- Download the forticlientems_7.4.1.XXXX.bin file from https://support.fortinet.com.
- Change permissions and add execute permissions to the installation file:
chmod +x forticlientems_7.4.0.XXXX.bin
- On the primary node, install EMS:
- Set
umask
to 022 on file/etc/login.defs
if the existingumask
setting is more restrictive. - Install EMS:
./forticlientems_7.4.0.1745.bin -- --db_host "172.16.1.12,172.16.1.15" --db_user postgres --db_pass postgres --skip_db_install --allowed_hosts '*' --enable_remote_https
Run the installer to/from any directory other than
/tmp
. Running the installer to/from/tmp
causes issues.In the example,
db_host
contains IP addresses for both database nodes. Replace the IP addresses with your database server IP addresses or FQDNs. After installation completes, check that all EMS services are running by entering the following command:
systemctl --all --type=service | grep -E 'fcems|apache|redis|postgres'
The output shows that postgresql.service status displays as
exited
. This is the expected status. EMS does not create this service, which only exists to pass commands to version-specific Postgres services. It displays as part of the output as the command filters for all services that contain "postgres" in the name.
- Set
- On the secondary node, install EMS:
- Set
umask
to 022 if the existingumask
setting is more restrictive. - Install EMS:
./forticlientems_7.4.1.XXXX.bin -- --db_host "172.16.1.12,172.16.1.15" --db_user postgres --db_pass postgres --skip_db_install --skip_db_deploy --allowed_hosts '*' --enable_remote_https
Run the installer to/from any directory other than
/tmp
. Running the installer to/from/tmp
causes issues. - After installation completes, check that EMS services are running by entering the following command. On the secondary EMS, only fcems_monitor, fcems_pgbouncer, fcems_wspgbouncer, and redis-server services should be running:
systemctl --all --type=service | grep -E 'fcems|apache|redis|postgres'
- Set
-
After installation on both nodes is complete, access the EMS GUI from the primary node using a browser by going to https://localhost. Complete initial configuration for EMS by doing the following:
-
Set the password for the default administrator. See Starting FortiClient EMS and logging in.
-
Configure the EMS FQDN and remote access. See Configuring EMS after installation.
-
License EMS. See Licensing FortiClient EMS.
-
Confirm that Listen on IP is set to All. See Configuring EMS settings.
-
-
Go to System Settings > EMS Settings.
-
In the Custom hostname field, enter a virtual IP address (VIP) that is configured in the FortiGate load balancer (LB) as the VIP for EMS. In this example, the VIP is 172.16.1.50.
- On both nodes, do the following:
-
Configure a FortiGate as an LB for EMS HA:
- Create a health check:
- Go to Policy & Objects > Health Check. Click Create New.
For Type, select TCP.
- In the Interval field, enter 10.
- In the Timeout field, enter 2.
- In the Retry field, enter 3.
In the Port field, enter 8013. Click OK.
- Create a virtual server:
- Go to Policy & Objects and create a virtual server.
- Configure the fields as follows:
Field
Value
Virtual server IP
VIP that you configured in step 4.f. In this example, the VIP is 172.16.1.50.
Virtual server port
10443
Load Balancing method
First Alive
Health check
Monitor that you configured.
Network Type
TCP
- Under Real Servers, select Create New.
- In the IPv4 address field, enter the primary EMS node IP address. In this example, it is 192.168.1.10.
- In the Port field, enter 10443.
- In the Max connections field, enter 0.
- For Mode, select Active.
- Create a real server for the secondary EMS node. Click Save.
- Repeat steps i-ix to create five additional virtual servers. The additional servers use ports 443, 8013, 8015, 8443, and 8871, but otherwise have identical settings to the first virtual server created. If you have enabled Chromebook management, create a virtual server for port 8443. Similarly, if you require importing an ACME certificate, create a virtual server for port 80.
- Create a security policy that includes the LB virtual server as a destination address:
- Go to Policy & Objects > Firewall Policy.
- Click Create New.
- Configure the Incoming Interface and Outgoing Interface fields. The outgoing interface connects to the primary EMS node.
- For Source, select all.
- In the Destination field, select ports 10443, 443, 8013, 8015, 8443, and 8871.
- For Service, select ALL.
- For Inspection Mode, select Proxy-based.
- Save the policy.
- If the EMS nodes are in different subnets, repeat these steps to configure a policy for the secondary EMS node. In this example, the nodes are in the same subnet, so you do not need to add a separate policy for the secondary EMS.
- Create a health check:
-
After the FortiGate LB configuration is complete, you can access EMS using the VIP configured in the FortiGate LB. If after initially installing EMS 7.4.1 you need to upgrade to a newer build, repeat steps 4.a.-c. with the new installation file.