How to Install Discourse Forum with Nginx on Rocky Linux 9
Discourse is an open-source community discussion platform built using the Ruby language. It is designed to work as a forum, chat software, or mailing list. It integrates easily with other platforms and can be extended via plugins.
In this tutorial, you will learn how to install Discourse Forum with the Nginx server on a server running Rocky Linux 9.
Prerequisites
-
A server running Rocky Linux 9 with a minimum of 1GB RAM and 1 Core CPU. Discourse setup will automatically create a swap partition on systems with 1GB or less RAM. Therefore, it is recommended to install it on a system with at least 2GB RAM.
-
A non-root user with
sudoprivileges. -
A Domain name (
discourse.example.com) pointing to the server. -
Everything is updated.
$ sudo dnf update
-
Few packages that your system needs.
$ sudo dnf install wget curl nano unzip yum-utils -y
Some of these packages may already be installed on your system.
Step 1 - Configure Firewall
The first step is to configure the firewall. Rocky Linux uses Firewalld Firewall. Check the firewall's status.
$ sudo firewall-cmd --state running
The firewall works with different zones, and the public zone is the default one that 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
Discourse needs HTTP and HTTPS ports to function. Open them.
$ sudo firewall-cmd --permanent --add-service=http $ sudo firewall-cmd --permanent --add-service=https
Add masquerade, as the application will contact other instances.
$ sudo firewall-cmd --permanent --add-masquerade
Reload the firewall to apply the changes.
$ sudo firewall-cmd --reload
List all the services again.
$ sudo firewall-cmd --permanent --list-services
You should get the following output.
cockpit dhcpv6-client http https ssh
Configure SELinux
Discourse won't be accessible even if you open the ports due to SELinux's access policy. Configure SELinux to allow network connections.
$ sudo setsebool -P httpd_can_network_connect 1
Step 2 - Install Git
Install Git.
$ sudo dnf install git
Confirm the installation.
$ git --version git version 2.31.1
Run the following commands to configure the Git installation.
$ git config --global user.name "Your Name" $ git config --global user.email "[email protected]"
Step 3 - Install Docker
Rocky Linux ships with an older version of Docker. To install the latest version, first, install the official Docker repository.
$ sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
Install the latest version of Docker.
$ sudo dnf install docker-ce docker-ce-cli containerd.io
You may get the following error while trying to install Docker.
ror: Problem: problem with installed package buildah-1:1.26.2-1.el9_0.x86_64 - package buildah-1:1.26.2-1.el9_0.x86_64 requires runc >= 1.0.0-26, but none of the providers can be installed - package containerd.io-1.6.9-3.1.el9.x86_64 conflicts with runc provided by runc-4:1.1.3-2.el9_0.x86_64 - package containerd.io-1.6.9-3.1.el9.x86_64 obsoletes runc provided by runc-4:1.1.3-2.el9_0.x86_64 - cannot install the best candidate for the job
Use the following command if you get the error above.
$ sudo dnf install docker-ce docker-ce-cli containerd.io --allowerasing
Enable and run the Docker daemon.
$ sudo systemctl enable docker --now
Verify that it is running.
? docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)
Active: active (running) since Sat 2023-01-20 06:49:44 UTC; 6s ago
TriggeredBy: ? docker.socket
Docs: https://docs.docker.com
Main PID: 99263 (dockerd)
Tasks: 8
Memory: 28.1M
CPU: 210ms
CGroup: /system.slice/docker.service
??99263 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
By default, Docker requires root privileges. If you want to avoid using sudo every time you run the docker command, add your username to the docker group.
$ sudo usermod -aG docker $(whoami)
You will need to log out of the server and back in as the same user to enable this change or use the following command.
$ su - ${USER}
Confirm that your user is added to the Docker group.
$ groups navjot wheel docker
Step 4 - Download Discourse
Clone the official Discourse Docker GitHub repository to the /var/discourse directory.
$ sudo git clone https://github.com/discourse/discourse_docker.git /var/discourse
Switch to the Discourse directory.
$ cd /var/discourse
Remove writing and executable permissions from the containers directory.
$ sudo chmod 700 containers
Step 5 - Configure Discourse
Create the configuration file app.yml by copying the sample standalone.yml file.
$ sudo cp samples/standalone.yml containers/app.yml
Open the app.yml for editing.
$ sudo nano containers/app.yml
Set Domain
Set the variable DISCOURSE_HOSTNAME to the domain name, you chose for your forum. If you don't have a domain name, you can use an IP address here.
DISCOURSE_HOSTNAME: 'discourse.example.com'
Configure Exposed ports
Change the line "80:80 to "8080:80". This will change the external HTTP port for Discourse to 8080 since we will use Nginx at port 80. Comment out the "443:443" line since we will install SSL externally.
expose: - "8080:80" # http #- "443:443" # https
Configure Email IDs for the Administrator
Set the email for your administrator account and the developer using the variable DISCOURSE_DEVELOPER_EMAILS. This step is compulsory otherwise, your forum won't be bootstrapped.
DISCOURSE_DEVELOPER_EMAILS: '[email protected],[email protected]'
Configure SMTP Settings
Fill out the following variables depending on the transactional email service you are using.
DISCOURSE_SMTP_ADDRESS: smtp.example.com DISCOURSE_SMTP_PORT: 587 DISCOURSE_SMTP_USER_NAME: [email protected] DISCOURSE_SMTP_PASSWORD: your_smtp_password #DISCOURSE_SMTP_ENABLE_START_TLS: true # (optional, default true) DISCOURSE_SMTP_DOMAIN: discourse.example.com # (required by some providers) DISCOURSE_NOTIFICATION_EMAIL: [email protected] # (address to send notifications from)
Memory Settings (Optional)
If your server has low RAM, you can configure the following variables accordingly to reduce Discourse's memory footprint.
db_shared_buffers: '128MB' UNICORN_WORKERS: 2
The variable db_shared_buffers is usually set to 25% of the available memory.
GeoLite2 Settings (Optional)
If you want the IP lookup feature on Discourse, signup for the free Maxmind Geolite2 account and get a license key. Paste that license key as the value for the following variable.
DISCOURSE_MAXMIND_LICENSE_KEY: your_maxmind_license_key
Save the file by pressing Ctrl + X and entering Y when prompted.
Step 6 - Install Discourse
Run the following command to bootstrap your Discourse container.
$ sudo ./launcher bootstrap app
Start Discourse application.
$ sudo ./launcher start app
Open port to test Discourse application.
$ sudo firewall-cmd --permanent --add-port=8080/tcp
You can now access the forum by visiting the URLs http://yourserver_IP:8080 or http://discourse.example.com:8080 in your browser. You will get the following screen.

Step 7 - Install Nginx
Rocky Linux 9 ships with an older version of Nginx. You need to download the official Nginx repository to install the latest version.
Create and open the /etc/yum.repos.d/nginx.repo file for creating the official Nginx repository.
$ 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.
Install the Nginx server.
$ sudo dnf install nginx
Verify the installation.
$ nginx -v nginx version: nginx/1.22.1
Enable and start the Nginx server.
$ sudo systemctl enable nginx --now
Check the status of the server.
$ sudo systemctl status nginx
? nginx.service - nginx - high performance web server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled)
Active: active (running) since Sun 2023-01-20 07:49:55 UTC; 1s ago
Docs: http://nginx.org/en/docs/
Process: 230797 ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf (code=exited, status=0/SUCCESS)
Main PID: 230798 (nginx)
Tasks: 3 (limit: 12355)
Memory: 2.8M
CPU: 13ms
CGroup: /system.slice/nginx.service
??230798 "nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf"
??230799 "nginx: worker process"
??230800 "nginx: worker process"
Step 8 - Install SSL
To install an SSL certificate using Let's Encrypt, we need to install the Certbot tool.
We will use the Snapd package installer for that. Since Rocky Linux doesn't ship with it, install the Snapd installer. It requires the EPEL repository to work.
$ sudo dnf install epel-release
Install Snapd.
$ sudo dnf install snapd
Enable and Start the Snap service.
$ sudo systemctl enable snapd --now
Install the Snap core package, and ensure that your version of Snapd is up to date.
$ sudo snap install core && sudo snap refresh core
Create necessary links for Snapd to work.
$ sudo ln -s /var/lib/snapd/snap /snap $ echo 'export PATH=$PATH:/var/lib/snapd/snap/bin' | sudo tee -a /etc/profile.d/snapd.sh
Issue the following command to install Certbot.
$ sudo snap install --classic certbot
Use the following command to ensure that the Certbot command can be run by creating a symbolic link to the /usr/bin directory.
$ sudo ln -s /snap/bin/certbot /usr/bin/certbot
Verify the installation.
$ certbot --version certbot 1.32.2
Generate the SSL certificate.
$ sudo certbot certonly --nginx --agree-tos --no-eff-email --staple-ocsp --preferred-challenges http -m [email protected] -d discourse.example.com
The above command will download a certificate to the /etc/letsencrypt/live/discourse.example.com directory on your server.
Generate a Diffie-Hellman group certificate.
$ sudo openssl dhparam -dsaparam -out /etc/ssl/certs/dhparam.pem 4096
To check whether the SSL renewal is working fine, do a dry run of the process.
$ sudo certbot renew --dry-run
If you see no errors, you are all set. Your certificate will renew automatically.
Step 9 - Configure Nginx
Create and open the file /etc/nginx/conf.d/discourse.conf for editing.
$ sudo nano /etc/nginx/conf.d/discourse.conf
Paste the following code in it.
# enforce HTTPS
server {
listen 80;
listen [::]:80;
server_name discourse.example.com;
location / { return 301 https://$host$request_uri; }
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name discourse.example.com;
access_log /var/log/nginx/discourse.access.log;
error_log /var/log/nginx/discourse.error.log;
# SSL
ssl_certificate /etc/letsencrypt/live/discourse.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/discourse.example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/discourse.example.com/chain.pem;
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:10m;
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;
resolver 8.8.8.8;
http2_push_preload on; # Enable HTTP/2 Server Push
# Enable TLSv1.3's 0-RTT. Use $ssl_early_data when reverse proxying to
# prevent replay attacks.
#
# @see: https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_early_data
ssl_early_data on;
# Security / XSS Mitigation Headers
# NOTE: X-Frame-Options may cause issues with the webOS app
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
add_header X-Early-Data $tls1_3_early_data;
client_max_body_size 100m;
location / {
proxy_pass http://discourse.example.com:8080/;
proxy_set_header Host $http_host;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
}
}
# This block is useful for debugging TLS v1.3. Please feel free to remove this
# and use the `$ssl_early_data` variable exposed by NGINX directly should you
# wish to do so.
map $ssl_early_data $tls1_3_early_data {
"~." $ssl_early_data;
default "";
}
Save the file by pressing Ctrl + X and entering Y when prompted once finished.
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.
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
Restart the Nginx service to enable the new configuration.
$ sudo systemctl restart nginx
Step 10 - Access and Finish Discourse Install
You can access the forum by visiting the URL https://discourse.example.com in your browser. You will get the following screen.

Click the Register button to proceed. The email id set in the app.yml file will be pre-filled for you.

Click the Register button to register the administrator account. You will proceed to the email confirmation screen.

If your SMTP settings are correct, you will receive a mail to activate the account. Click the link from your email to finish setting up the account.

Click the Activate button to finish the instal