# Ubuntu Server

# Overview

This chapter introduces how to install GROWI on Ubuntu Server 22.04 (Jammy). Other versions are currently untested.

The software required for setup is as follows:

  • Node.js 24.x
  • npm 11.x (bundled with Node.js 24.x)
  • pnpm
  • MongoDB 6.0 or higher (a replica set configuration is required)
  • (Option) Elasticsearch 8.x or 9.x
  • (Option) systemd
  • (Option) Apache or nginx

Optional items are not mandatory. However, this section explains how to build an environment that uses all of these to create a GROWI with full-text search capabilities, reverse-proxied with Apache or nginx, and automatically started with systemd along with the host.

# Installing Tools

Install git and curl which are required during the installation process.

$ sudo apt update && sudo apt -y install git curl

# Installing Node.js 24.x & npm

# Using NodeSource repository

Get the Node.js installation script from https://deb.nodesource.com/ (opens new window). Work in the home directory.

$ cd ~
$ curl -sL https://deb.nodesource.com/setup_24.x -o nodesource_setup.sh

Execute the downloaded script.

$ sudo bash nodesource_setup.sh

This enables node.js to be obtained via apt, so install it using the apt command.

$ sudo apt -y install nodejs

Since GROWI uses pnpm for package installation, install the pnpm command here.

For the <version> part, use the value that the GROWI you are installing declares in packageManager in its package.json (v8.0.0 declares pnpm@11.1.1).

$ curl -fsSL https://get.pnpm.io/install.sh | env PNPM_VERSION=<version> sudo sh -
$ sudo pnpm setup

GROWI uses Turborepo for building, but turbo is in devDependencies, so pnpm install below installs it. You do not need to install it globally.

After installing Node.js, npm, and pnpm, check the installed versions.

$ nodejs -v
v24.14.0
$ npm -v
11.9.0
$ pnpm -v
11.1.1

# Elasticsearch

# Installation

Follow the official page (opens new window) to proceed with installation. Here we install Elasticsearch 8.x.

GROWI v8.0 supports Elasticsearch 8.x and 9.x. GROWI defaults to 9.x, so when you use 8.x, set the environment variable ELASTICSEARCH_VERSION to 8 (see "Startup verification" below).

First, install JDK17 to run Elasticsearch.

$ sudo apt -y install openjdk-17-jdk

Add the Elasticsearch repository GPG key to install packages.

$ wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo gpg --dearmor -o /usr/share/keyrings/elasticsearch-keyring.gpg

Add the Elasticsearch repository.

$ sudo echo "deb [signed-by=/usr/share/keyrings/elasticsearch-keyring.gpg] https://artifacts.elastic.co/packages/8.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-8.x.list

Now Elasticsearch can be installed via apt, so proceed with installation.

$ sudo apt update && sudo apt -y install elasticsearch

After installation is complete, the default password for the elastic user will be displayed, so make sure to note it down somewhere.

--------------------------- Security autoconfiguration information ------------------------------ 
Authentication and authorization are enabled. 
TLS for the transport and HTTP layers is enabled and configured. 
The generated password for the elastic built-in superuser is : ~~~~~~~

Here, adjust the memory allocated to Elasticsearch. For personal use, 256MB is sufficient. Change according to team size and the number of pages.

$ sudo vim /etc/elasticsearch/jvm.options
# Add after the IMPORTANT: JVM heap size comment block
-Xms256m
-Xmx256m

After installation is complete, check the package version.

$ dpkg -l elasticsearch
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name           Version      Architecture Description
+++-==============-============-============-=====================================================
ii  elasticsearch  8.13.2       amd64        Distributed RESTful search engine built for the cloud

# Disabling TLS

Elasticsearch 8.x only accepts TLS communication by default. Since GROWI communicates via HTTP, configuration changes are necessary.

Edit /etc/elasticsearch/elasticsearch.yml and change the three settings from true to false, referring to the following diff.

diff -uNr old/elasticsearch.yml new/elasticsearch.yml
--- old/elasticsearch.yml       2024-04-30 13:36:37.106652641 +0000
+++ new/elasticsearch.yml       2024-04-30 13:38:07.739773922 +0000
@@ -89,18 +89,18 @@
 # --------------------------------------------------------------------------------

 # Enable security features
-xpack.security.enabled: true
+xpack.security.enabled: false

 xpack.security.enrollment.enabled: true

 # Enable encryption for HTTP API client connections, such as Kibana, Logstash, and Agents
 xpack.security.http.ssl:
-  enabled: true
+  enabled: false
   keystore.path: certs/http.p12

 # Enable encryption and mutual authentication between cluster nodes
 xpack.security.transport.ssl:
-  enabled: true
+  enabled: false
   verification_mode: certificate
   keystore.path: certs/transport.p12
   truststore.path: certs/transport.p12

# Installing Elasticsearch plugins required for GROWI

Install the following Elasticsearch plugins:

First, search for the command used to install Elasticsearch plugins.

$ dpkg -L elasticsearch | grep bin | grep plugin
/usr/share/elasticsearch/bin/elasticsearch-plugin

Use the command output above to install the analysis-kuromoji plugin and analysis-icu plugin.

# Install analysis-kuromoji
$ sudo /usr/share/elasticsearch/bin/elasticsearch-plugin install analysis-kuromoji
# Install analysis-icu plugin
$ sudo /usr/share/elasticsearch/bin/elasticsearch-plugin install analysis-icu

# Starting Elasticsearch and enabling auto-start

Use the systemctl command to enable auto-start for Elasticsearch and start it.

$ sudo systemctl enable --now elasticsearch

Check if it's running normally.

$ systemctl status elasticsearch
● elasticsearch.service - Elasticsearch
     Loaded: loaded (/lib/systemd/system/elasticsearch.service; enabled; vendor preset: enabled)
     Active: active (running) since Fri 2024-05-03 08:46:23 JST; 11min ago
...

Also, verify that http communication is possible.

$ curl http://localhost:9200/
{
  "name" : "localhost.localdomain",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "_na_",
  "version" : {
    "number" : "8.13.3",
    "build_flavor" : "default",
    "build_type" : "rpm",
    "build_hash" : "617f7b76c4ebcb5a7f1e70d409a99c437c896aea",
    "build_date" : "2024-04-29T22:05:16.051731935Z",
    "build_snapshot" : false,
    "lucene_version" : "9.10.0",
    "minimum_wire_compatibility_version" : "7.17.0",
    "minimum_index_compatibility_version" : "7.0.0"
  },
  "tagline" : "You Know, for Search"
}

# MongoDB

# Installation

Follow the official page (opens new window) to proceed with installation. The version is MongoDB 6.0.

First, import the public key for apt.

curl -fsSL https://www.mongodb.org/static/pgp/server-6.0.asc | \
   sudo gpg -o /usr/share/keyrings/mongodb-server-6.0.gpg \
   --dearmor

Add the repository. Here are examples for Ubuntu 20.04 and Ubuntu 22.04.

Ubuntu 20.04

echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-6.0.gpg ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/6.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list

Ubuntu 22.04

echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-6.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/6.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list

After adding the repository, install MongoDB.

$ sudo apt update && sudo apt -y install mongodb-org

After installation is complete, check the package version.

$ dpkg-query -l "mongodb-org*:amd64"
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name                             Version      Architecture Description
+++-================================-============-============-===================================================================
ii  mongodb-org                      6.0.15       amd64        MongoDB open source document-oriented database system (metapackage)
ii  mongodb-org-database             6.0.15       amd64        MongoDB open source document-oriented database system (metapackage)
ii  mongodb-org-database-tools-extra 6.0.15       amd64        Extra MongoDB database tools
ii  mongodb-org-mongos               6.0.15       amd64        MongoDB sharded cluster query router
ii  mongodb-org-server               6.0.15       amd64        MongoDB database server
ii  mongodb-org-shell                6.0.15       amd64        MongoDB shell client
ii  mongodb-org-tools                6.0.15       amd64        MongoDB tools

Use the systemctl command to enable auto-start for MongoDB and start it.

$ sudo systemctl enable --now mongod

Check if it's running normally.

$ systemctl status mongod
● mongod.service - MongoDB Database Server
     Loaded: loaded (/lib/systemd/system/mongod.service; enabled; vendor preset: enabled)
     Active: active (running) since Fri 2024-05-03 08:45:35 JST; 14min ago
...

# Enabling a replica set configuration

From GROWI v8.0, GROWI uses MongoDB change streams, so MongoDB has to run as a replica set. A single-node replica set is acceptable.

Add the replica set name to /etc/mongod.conf. This example uses rs0.

replication:
  replSetName: rs0

Restart MongoDB to apply the setting.

$ sudo systemctl restart mongod

Initiate the replica set. This is only needed the first time.

$ mongosh --eval 'rs.initiate({ _id: "rs0", members: [{ _id: 0, host: "localhost:27017" }] })'

Check that this member has become PRIMARY.

$ mongosh --eval 'rs.status().members[0].stateStr'
PRIMARY

GROWI connects to it with ?replicaSet=rs0 in MONGO_URI (see "Startup verification" below).

# GROWI

# Installation

Get the source code from https://github.com/growilabs/growi (opens new window) and check the latest stable version at https://github.com/growilabs/growi/releases (opens new window).

Here we describe the procedure for installing under /opt/growi. To change the owner user and group to the GROWI execution user, please modify <username> and <usergroup> as appropriate.

$ sudo mkdir -p /opt/
$ sudo chown <username>:<usergroup> /opt/
$ cd /opt/
$ git clone https://github.com/growilabs/growi growi
$ cd growi
# Check tags
$ git tag --sort=-version:refname | head -10
...
v7.2.0
v7.2.1
v7.2.3
v7.2.4
...
# Use the latest version without RC
$ git checkout -b v7.2.4 refs/tags/v7.2.4

After cloning the source code, use the pnpm command to install packages required for GROWI.

$ cd /opt/growi
$ pnpm install

# Build

After package installation is complete, perform the build.

$ pnpm run app:build

This will take some time.

# Startup verification

After the build is complete, perform startup verification.

This assumes that MongoDB and Elasticsearch are running on the same host.

Please modify MONGO_URI and ELASTICSEARCH_URI according to your environment. ELASTICSEARCH_VERSION takes the major version of the Elasticsearch you connect to. The steps on this page install 8.x, so set it to 8 (GROWI defaults to 9).

$ sudo \
MONGO_URI=mongodb://localhost:27017/growi?replicaSet=rs0 \
ELASTICSEARCH_URI=http://localhost:9200/growi \
ELASTICSEARCH_VERSION=8 \
npm run app:server
...
# Wait until the following message is displayed
{"name":"growi:crowi","hostname":"growi-server","pid":29259,"level":30,"msg":"[production] Express server is listening on port 3000","time":"2024-04-30T21:50:05.549Z","v":0}

Access http://<hostname or ip address>:3000/ and verify that the initial setup screen is displayed.

# Auto-start configuration with systemd

Refer to "Auto-start with systemd".

# Reverse Proxy Configuration

Here we describe configuration examples for setting up a reverse proxy for the started GROWI.

# Apache

# Installation

$ sudo apt update && sudo apt -y install apache2

# Enabling required modules

Install proxy, proxy_http, proxy_wstunnel modules.

$ sudo a2enmod proxy proxy_http proxy_wstunnel

# Reverse proxy configuration example

Here we extract and describe the parts related to reverse proxy.

<IfModule mod_ssl.c>
  <VirtualHost _default_:443>
    ...
    ###
    # reverse proxy to crowi
    # To add Host: example.com to Header
    ProxyPreserveHost On
    # When using HTTPS: To add x-forwarded-proto: https to Header
    RequestHeader set x-forwarded-proto 'https'
    # Disable ETag because Apache may not return 304 for static assets
    <ifModule mod_headers.c>
            Header unset ETag
    </ifModule>
    FileETag None
    # Rewrite socket.io path
    RewriteEngine On
    RewriteCond %{REQUEST_URI}  ^/socket.io            [NC]
    RewriteCond %{QUERY_STRING} transport=websocket    [NC]
    RewriteRule /(.*) ws://localhost:3000/$1 [P,L]
    ProxyPass / http://localhost:3000/
    ProxyPassReverse / http://localhost:3000/
    ...
  </VirtualHost>
</IfModule>

# Auto-start configuration

$ sudo systemctl enable --now apache2

# Nginx Installation and Configuration

# Installation

$ sudo apt update && sudo apt -y install nginx

# Reverse proxy configuration example

Here we describe a configuration example using HTTPS. Please configure the parts enclosed in <> such as <server> according to your environment.

upstream growi {
    server localhost:3000;
}
map $http_upgrade $connection_upgrade {
    default Upgrade;
    ''      close;
}
server {
    listen 443 ssl http;
    server_name <server>;
    ssl_certificate <cert_file>;
    ssl_certificate_key <key_file>;
    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Port $server_port;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://growi;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_read_timeout 900s;
    }
}
server {
    listen 80;
    server_name <server>;
    return 301 https://$server_name$request_uri;
}

Verify that there are no issues with the configuration file.

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

# Auto-start configuration

$ sudo systemctl enable --now nginx