Etherpad is an open-source online editor providing collaborative editing in real-time in the browser. It is written in Node.js and can be self-hosted to work with various platforms like WordPress, Drupal, Odoo, Discourse, Joomla, etc.

In this tutorial, we will install Etherpad on a Rocky Linux 8 server, using the MariaDB database to store our data. We will also use Nginx as a reverse proxy for the application and install an SSL certificate using Let’s Encrypt to enable HTTPS connections to our Etherpad instance.

Prerequisites

  1. A system running Rocky Linux 8.

  2. A non-root user with sudo privileges.

  3. A domain name pointed to the server.

  4. Nodejs installed. Follow our guide on installing Nodejs on Rocky Linux 8 server. Use any of the two methods specified.

  5. Make sure everything is updated.

    $ sudo dnf update
    

Step 1 – Configure Firewall

Rocky Linux uses Firewalld Firewall. Check the firewall’s status.

$ sudo firewall-cmd --state
running

This indicates it is up and running successfully.

The firewall works with different zones and the public zone is the default one, which we will use. List all the services and ports active on the firewall.

$ sudo firewall-cmd --permanent --list-services

It should show the following output.

cockpit dhcpv6-client ssh

Allow HTTP and HTTPS ports.

$ sudo firewall-cmd --permanent --add-service=http
$ sudo firewall-cmd --permanent --add-service=https

Open the 9001 port used by the Etherpad application.

$ sudo firewall-cmd --permanent --add-port=9001/tcp

Recheck the status of the firewall.

$ sudo firewall-cmd --permanent --list-services

You should see a similar output.

cockpit dhcpv6-client http https ssh

Reload the firewall to enable the changes.

$ sudo firewall-cmd --reload

Step 2 – Install Git

Before installing Etherpad, we need to install Git. Run the following command to install Git.

$ sudo dnf install git

Verify the installation.

$ git --version
git version 2.27.0

Add initial configuration.

$ git config --global user.name "YourName"
$ git config --global user.email "[email protected]"

List the configuration you just set.

$ git config --list
user.name=YourName
[email protected]

Step 3 – Install MariaDB

Since we will use the MariaDB database to store Etherpad’s data, we need to install and configure it first.

Rocky Linux AppStream repository comes with MariaDB. To list all the available versions of MariaDB installed, run the following command.

$ sudo dnf module list mariadb
Last metadata expiration check: 1:15:26 ago on Thu 21 Oct 2021 10:20:01 AM UTC.
Rocky Linux 8 - AppStream
Name                          Stream                         Profiles                                         Summary
mariadb                       10.3 [d]                       client, galera, server [d]                       MariaDB Module
mariadb                       10.5                           client, galera, server [d]                       MariaDB Module

Hint: [d]efault, [e]nabled, [x]disabled, [i]nstalled

The default version is set to 10.3. You can however install the latest version using the following command.

$ sudo dnf module enable mariadb:10.5

Install MariaDB.

$ sudo dnf install mariadb-server

Enable and Start the MariaDB service.

$ sudo systemctl enable mariadb --now

Check the status of the service.

$ sudo systemctl status mariadb

Secure the MariaDB server.

$ sudo mysql_secure_installation

You will face various prompts. Answer them as follows.

Enter current password for root (enter for none): Press Enter
Switch to unix_socket authentication [Y/n] Type y
Change the root password? [Y/n] Type n
Remove anonymous users? [Y/n] Type y
Disallow root login remotely? [Y/n] Type y
Remove test database and access to it? [Y/n] Type y
Reload privilege tables now? [Y/n] Type y

You can now connect to the MariaDB server using the following command.

$ sudo mysql 

Step 4 – Configure MariaDB

Login to the MariaDB shell.Advertisement

$ sudo mysql

Create a new database for Etherpad.

$ create database `etherpad_lite_db`;

Create a new database user.

$ CREATE USER 'etherpaduser'@'localhost' identified by 'password';

Use a strong password.

Grant permissions on the database to the user.

$ grant CREATE,ALTER,SELECT,INSERT,UPDATE,DELETE on `etherpad_lite_db`.* to ''@'localhost';

Exit the MySQL shell.

$ exit

Step 5 – Download and Install Etherpad

To install Etherpad, we will download its source code and build it.

The first step is to create a new etherpad user using the following command.

$ sudo adduser --system --home /opt/etherpad --create-home --user-group etherpad

This command creates a --system user, which means it can’t log in and has no password. We also give it a home directory /opt/etherpad which is where we’ll download Etherpad. The --create-home flag creates the home directory with the correct permissions. The --user-group flag creates a group with the same name as the username.

Switch to the etherpad user to download and install the application.

$ sudo -u etherpad bash

Switch to the /opt/etherpad directory.

[[email protected] user] cd /opt/etherpad

Clone the Etherpad repository into the /opt/etherpad directory.

[[email protected] ~]$ git clone --branch master git://github.com/ether/etherpad-lite.git

Switch to the newly downloaded directory.

[[email protected] ~]$ cd etherpad-lite

Run the Etherpad’s run.sh script to set up and install dependencies.

[[email protected] etherpad-lite]$ src/bin/run.sh

You can launch the URL http://YOURSERVERIP:9001 in the browser to launch Etherpad. You will get the following screen.

<img alt="Etherpad Home" data-ezsrc="https://kirelos.com/wp-content/uploads/2021/11/echo/etherpad-home.png61892b8b25496.jpg" ezimgfmt="rs rscb5 src ng ngcb5" height="663" loading="lazy" src="data:image/svg xml,” width=”750″>

There is an issue with the above installation. It requires you to keep the current shell open with Node running in the foreground. To make it a persistent installation, we need to run Etherpad as a service. Press Ctrl C on your terminal to stop Etherpad from running.

Step 6 – Configure Etherpad

Before proceeding ahead, we need to set some settings and configure our installation according to our needs. Etherpad stores its settings in the settings.json file in the installation directory.

Open the file for editing.

[[email protected] etherpad-lite]$ nano settings.json

The settings file is formatted as JSON. The first thing you need to configure is the database settings.

Find the following code and comment it out by putting // in front of it.

//  "dbType": "dirty",
//  "dbSettings": {
//    "filename": "var/dirty.db"
//  },

Then, find the following code and change its values as follows. Make sure to remove /* and */ at the beginning and the end.

  "dbType" : "mysql",
  "dbSettings" : {
    "user":     "etherpaduser",
    "host":     "localhost",
    "port":     3306,
    "password": "password",
    "database": "etherpad_lite_db",
    "charset":  "utf8mb4"
  },

Finally, scroll down a little to find the trustProxy setting and change its value from false to true.

  "trustProxy": true,

This setting is needed to make Etherpad work along with Nginx.

Save the file by pressing Ctrl X and entering Y when prompted once finished.

Exit the Etherpad user shell.

[[email protected] etherpad-lite]$ exit

Step 7 – Create Etherpad Service

To start Etherpad on boot and to manage the process using systemctl, we need to create a service file.

Create and open the service file.

$ sudo nano /etc/systemd/system/etherpad.service

Paste the following code in it.

[Unit]
Description=Etherpad, a collaborative web editor.
After=syslog.target network.target

[Service]
Type=simple
User=etherpad
Group=etherpad
WorkingDirectory=/opt/etherpad
Environment=NODE_ENV=production
ExecStart=/usr/bin/node --experimental-worker /opt/etherpad/etherpad-lite/node_modules/ep_etherpad-lite/node/server.js
Restart=always

[Install]
WantedBy=multi-user.target

Save the file by pressing Ctrl X and entering Y when prompted once finished.

Reload the service daemon to pull in the new configuration.

$ sudo systemctl daemon-reload

Enable Start the Etherpad service.

$ sudo systemctl enable etherpad --now

Check the status of the service.

$ sudo systemctl status etherpad
? etherpad.service - Etherpad, a collaborative web editor.
   Loaded: loaded (/etc/systemd/system/etherpad.service; disabled; vendor preset: disabled)
   Active: active (running) since Thu 2021-10-21 15:06:53 UTC; 6s ago
 Main PID: 47228 (node)
    Tasks: 13 (limit: 11411)
   Memory: 102.8M
   CGroup: /system.slice/etherpad.service
           ??47228 /usr/bin/node --experimental-worker /opt/etherpad/etherpad-lite/node_modules/ep_etherpad-lite/node/server.js
.......

Step 8 – Install SSL using Let’s Encrypt

To install an SSL certificate using Let’s Encrypt, we need to install the Certbot tool.

Firstly, you need to download and install the EPEL repository.

$ sudo dnf install epel-release

Run the following commands to install Certbot.

$ sudo dnf install certbot

Generate the SSL certificate.

$ sudo certbot certonly --standalone --agree-tos --preferred-challenges http -m [email protected] -d example.com

The above command will download a certificate to the /etc/letsencrypt/live/etherpad.example.com directory on your server.

Generate a Diffie-Hellman group certificate.

$ sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

Create a challenge webroot directory for Let’s Encrypt auto-renewal.

$ sudo mkdir -p /var/lib/letsencrypt

Create a Cron Job to renew the SSL. It will run every day to check the certificate and renew if needed. For that, first, create the file /etc/cron.daily/certbot-renew and open it for editing.

$ sudo nano /etc/cron.daily/certbot-renew

Paste the following code.

#!/bin/sh
certbot renew --cert-name etherpad.example.com --webroot -w /var/lib/letsencrypt/ --post-hook "systemctl reload nginx"

Save the file by pressing Ctrl X and entering Y when prompted.

Change the permissions on the task file to make it executable.

$ sudo chmod  x /etc/cron.daily/certbot-renew

Step 9 – Install and Configure Nginx

Rocky Linux ships with an older version of Nginx. To install the latest version, you need to add the Nginx repository.

Create and open the file /etc/yum.repos.d/nginx.repo for editing.

$ sudo nano /etc/yum.repos.d/nginx.repo

Paste the following code in it.

[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true

[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true

Save the file by pressing Ctrl X and entering Y when prompted once finished.

Install Nginx.

$ sudo dnf install nginx

Enable the Nginx service.

$ sudo systemctl enable nginx

Next, create and open the /etc/nginx/conf.d/etherpad.conf for editing.

$ sudo nano /etc/nginx/conf.d/etherpad.conf

Paste the following code in it.

server {
    listen       443 ssl http2;
    listen       [::]:443 ssl http2;
    server_name  etherpad.example.com;

    access_log  /var/log/nginx/etherpad.access.log;
    error_log   /var/log/nginx/etherpad.error.log;
    
    ssl_certificate      /etc/letsencrypt/live/etherpad.example.com/fullchain.pem;
    ssl_certificate_key  /etc/letsencrypt/live/etherpad.example.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/etherpad.example.com/chain.pem;

    ssl_session_timeout  5m;
    ssl_session_cache shared:MozSSL:10m;  # about 40000 sessions
    ssl_session_tickets off;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_ecdh_curve X25519:prime256v1:secp384r1:secp521r1;
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;

    location / {
        rewrite  ^/$ / break;
        rewrite  ^/locales/(.*) /locales/$1 break;
        rewrite  ^/locales.json /locales.json break;
        rewrite  ^/admin(.*) /admin/$1 break;
        rewrite  ^/p/(.*) /p/$1 break;
        rewrite  ^/static/(.*) /static/$1 break;
        rewrite  ^/pluginfw/(.*) /pluginfw/$1 break;
        rewrite  ^/javascripts/(.*) /javascripts/$1 break;
        rewrite  ^/socket.io/(.*) /socket.io/$1 break;
        rewrite  ^/ep/(.*) /ep/$1 break;
        rewrite  ^/minified/(.*) /minified/$1 break;
        rewrite  ^/api/(.*) /api/$1 break;
        rewrite  ^/ro/(.*) /ro/$1 break;
        rewrite  ^/error/(.*) /error/$1 break;
        rewrite  ^/jserror(.*) /jserror$1 break;
        rewrite  ^/redirect(.*) /redirect$1 break;
        rewrite  /favicon.ico /favicon.ico break;
        rewrite  /robots.txt /robots.txt break;
        rewrite  /(.*) /p/$1;
        
        proxy_pass         http://127.0.0.1:9001;
        proxy_buffering    off;
        proxy_set_header   Host $host;
        proxy_pass_header  Server;

        # proxy headers
        proxy_set_header    X-Real-IP $remote_addr;
        proxy_set_header    X-Forwarded-For $remote_addr;
        proxy_set_header    X-Forwarded-Proto $scheme;
        proxy_http_version  1.1;

        # websocket proxying
        proxy_set_header  Upgrade $http_upgrade;
        proxy_set_header  Connection $connection_upgrade;
    }
}

# we're in the http context here
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

# enforce HTTPS
server {
    listen       80;
    listen       [::]:80;
    server_name  etherpad.example.com;
    return 301   https://$host$request_uri;
}

Save the file by pressing Ctrl X and entering Y when prompted once finished.

Verify the Nginx configuration file syntax.

$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

If you get the following error, you will need to edit the file /etc/nginx/nginx.conf to add/adjust the size of the variable server_names_hash_bucket_size.

nginx: [emerg] could not build the server_names_hash, you should increase server_names_hash_bucket_size

Open the file /etc/nginx/nginx.conf for editing.

$ sudo nano /etc/nginx/nginx.conf

Add the following line before the line include /etc/nginx/conf.d/*.conf;.

server_names_hash_bucket_size  64;

Save the file by pressing Ctrl X and entering Y when prompted. Validate Nginx again.

Finally, start the Nginx service to enable the new configuration.

$ sudo systemctl start nginx

Launch the URL https://etherpad.example.com in your browser and Etherpad home will open. You can now use it to edit documents and invite collaborators.

Updating Etherpad

Updating Etherpad is easy. The first step is to switch to the Etherpad user shell.

$ sudo -u etherpad bash

Switch to the /opt/etherpad/etherpad-lite directory.

[[email protected] user] cd /opt/etherpad/etherpad-lite

Pull the latest Etherpad repository into the /opt/etherpad/etherpad-lite directory.

[[email protected] ~]$ git pull origin

Run the Etherpad’s run.sh script to set up the latest version of Etherpad.

[[email protected] etherpad-lite]$ src/bin/run.sh

Conclusion

In this tutorial, we set up Etherpad Collaborative Editor with Nginx server and secured using Let’s Encrypt SSL certificates. Your Etherpad installation is ready to use which you can extend with more features including authenticated users, plugins and user interface customizations.

If you have any questions, post them in the comments below.