Discourse
Overview
Discourse is the leading open-source platform for community discussion, forums and mailing lists. It is a modern Ruby on Rails application backed by PostgreSQL and Redis and served by a bundled nginx. It is distributed as a single official Docker container built with the discourse_docker launcher.
This SecureAnyCloud image installs Discourse 3.4 the only officially supported way. It pre-builds and bootstraps the container at image-bake time, so your VM starts serving in under a minute instead of running a lengthy build on first boot. The database and uploads live on a dedicated Azure data disk, and each VM generates a unique administrator account and admin API key on first boot.
What you get:
- Discourse 3.4 (stable) running as the official single standalone Docker container (Rails, PostgreSQL, Redis and nginx bundled)
- Docker Engine (Docker CE) with the container published on port
80 discourse.service(manages the container lifecycle) anddiscourse-firstboot.service(per-VM admin) as enabled, active systemd units- A per-VM administrator account and admin API key generated on first boot and recorded in a root-only credentials file
- A dedicated 40 GiB Azure data disk at
/var/lib/discourseholding the PostgreSQL cluster, uploads and Redis data, captured into the image and re-provisioned with every VM - 24/7 SecureAnyCloud support
Prerequisites
You need an active Azure subscription, an SSH key pair, and a VNet with a subnet in the target region.
Standard_B4ms (4 vCPU / 16 GiB RAM) is a good starting size. Discourse rebuilds and Rails are memory-hungry, so do not go below 8 GiB of RAM for production.
Configure the network security group (NSG) to allow inbound 22/tcp from your management network and 80/tcp for the web interface. Discourse serves plain HTTP on port 80, so for production, put it behind TLS with your own domain (see the final section).
Step 1 - Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Discourse by SecureAnyCloud, and select Create.
On the Basics tab, pick your subscription, resource group, region and size. Under Administrator account, choose SSH public key and paste your key. Under Inbound port rules, allow SSH (22) and HTTP (80).
Review the dedicated data disk on the Disks tab, then select Review + create and Create.
Step 2 - Deploy from the Azure CLI
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:discourse-ubuntu-24-04:default:latest
az vm create \
--resource-group <your-rg> \
--name discourse \
--image sac1647283583153:discourse-ubuntu-24-04:default:latest \
--size Standard_B4ms \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_ed25519.pub \
--vnet-name <your-vnet> --subnet <your-subnet> \
--public-ip-sku Standard
az vm open-port --resource-group <your-rg> --name discourse --port 80 --priority 1010Step 3 - Connect to your VM
Connect to the VM over SSH with the admin user you created:
ssh azureuser@<vm-public-ip>Step 4 - Confirm the services are running
On first boot, the image starts the pre-built Discourse container and creates a per-VM administrator. Confirm that Docker and the Discourse service are active:
systemctl is-active docker.service discourse.serviceBoth report active. Then inspect the running container and the port 80 listener:
sudo docker ps --format 'table {{.Names}}\t{{.Status}}'
sudo ss -tln | grep ':80 'Step 5 - Check the health endpoint
Discourse exposes an unauthenticated status endpoint that returns ok when the application is healthy. Request it and print the HTTP status:
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/srv/statusThe command prints 200. To see the raw status text, run:
curl -s http://127.0.0.1/srv/status; echoStep 6 - Retrieve the per-VM admin credentials
Each VM generates a unique administrator password and admin API key on first boot and writes them to a root-only file:
sudo cat /root/discourse-credentials.txtThe file contains DISCOURSE_ADMIN_EMAIL (admin@sac.local), DISCOURSE_ADMIN_USERNAME (admin), a unique DISCOURSE_ADMIN_PASSWORD and a unique DISCOURSE_ADMIN_API_KEY. Store these somewhere safe.
Step 7 - Sign in to the web interface
Open http://<vm-public-ip>/ in your browser and choose Log In. Sign in as admin@sac.local with the password from Step 6.
The full administrator dashboard is at http://<vm-public-ip>/admin. There you can manage users, categories, site settings, plugins, backups and more.
Browse a category to see its discussions. The seeded General category already contains a welcome topic.
Manage community members from the users administration screen.
Step 8 - Verify the admin API key
Discourse exposes a full REST API, and the per-VM admin key authenticates as the admin user. Run these commands to confirm that a wrong key is rejected and the valid key returns the active users list:
KEY=$(sudo grep '^DISCOURSE_ADMIN_API_KEY=' /root/discourse-credentials.txt | cut -d= -f2-)
echo -n 'wrong key: '; curl -s -o /dev/null -w '%{http_code}\n' -H 'Api-Key: wrong-key-xyz' -H 'Api-Username: admin' http://127.0.0.1/admin/users/list/active.json
echo -n 'valid key: '; curl -s -o /dev/null -w '%{http_code}\n' -H "Api-Key: $KEY" -H 'Api-Username: admin' http://127.0.0.1/admin/users/list/active.jsonThe wrong key returns a non-200 status, and the valid key returns 200.
Step 9 - Confirm data lives on the dedicated data disk
The PostgreSQL cluster, uploads and Redis data are stored on the dedicated Azure data disk mounted at /var/lib/discourse, so they persist independently of the OS disk. Confirm the mount:
findmnt -no SOURCE,TARGET,FSTYPE /var/lib/discourseSet your real hostname and SMTP for production
This appliance boots with the default hostname discourse.sac.local and a loopback SMTP setting, so it can bootstrap without a real domain or mail server. Before you invite real users, set your own DNS hostname and a working SMTP provider. Discourse relies on email for signups, password resets and notifications.
Point a DNS A record at the VM's public IP. Then edit /var/discourse/containers/app.yml and update these keys under env:
DISCOURSE_HOSTNAME: 'forum.example.com' DISCOURSE_DEVELOPER_EMAILS: 'you@example.com' DISCOURSE_SMTP_ADDRESS: smtp.example.com DISCOURSE_SMTP_PORT: 587 DISCOURSE_SMTP_USER_NAME: 'your-smtp-user' DISCOURSE_SMTP_PASSWORD: 'your-smtp-password' DISCOURSE_SMTP_ENABLE_START_TLS: trueThen rebuild the container so the new configuration takes effect. The rebuild repackages the container and takes several minutes:
cd /var/discourse
sudo ./launcher rebuild appFor HTTPS, either add the templates/web.ssl.template.yml and templates/web.letsencrypt.ssl.template.yml templates plus a 443 entry to app.yml and rebuild, or terminate TLS at an Azure load balancer or reverse proxy in front of the VM.
Maintenance
- Restart Discourse:
sudo systemctl restart discourse.service - View container logs:
sudo docker logs app - Back up: use the admin dashboard (Admin > Backups) or
cd /var/discourse && sudo ./launcher run app 'discourse backup'. Backups are written under/var/lib/discourse/standalone/backups. - Upgrade Discourse: upgrade minor versions from Admin > Upgrade, or rebuild the container with
cd /var/discourse && sudo ./launcher rebuild appto pull the latest stable build. - OS updates: the image ships with unattended security upgrades enabled.
Support
SecureAnyCloud provides 24/7 support for this image. Discourse is licensed under the GPL-2.0 and is free. The SecureAnyCloud charge covers packaging, security patching, image maintenance and support.
Deploy on Azure
Launch Discourse on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com
Overview
Discourse is the leading open-source platform for community discussion, support forums and mailing lists. It is a modern Ruby on Rails and Ember application backed by PostgreSQL and Redis and served by a bundled nginx. It is distributed as a single official Docker container built with the discourse_docker launcher.
This SecureAnyCloud AMI installs Discourse the only officially supported way. It pre-builds and bootstraps the container at image-bake time, so your instance starts serving in under a minute instead of running a lengthy build on first boot. The database and uploads live on a dedicated EBS data volume. Each instance generates a unique administrator account and admin API key on first boot, and mints a per-instance self-signed TLS certificate served on port 443.
What you get:
- Discourse (stable) running as the official single standalone Docker container, with Rails, PostgreSQL and nginx bundled, and a BSD-3-Clause Redis
- Docker Engine (Docker CE) with the container published on port
80 - A host nginx that terminates TLS on port
443with a per-instance self-signed certificate and proxies to the container discourse.service,discourse-firstboot.serviceandnginx.serviceas enabled, active systemd units- A per-instance administrator account and admin API key generated on first boot and recorded in a root-only credentials file
- A dedicated 40 GiB EBS data volume at
/var/lib/discourseholding the PostgreSQL cluster, uploads and Redis data, captured into the image and re-provisioned with every instance - 24/7 SecureAnyCloud support
Connecting to your instance
Connect over SSH as the default login user for your AMI variant. For Ubuntu 24.04, the login user is ubuntu:
ssh ubuntu@<public-ip>Prerequisites
You need an AWS account, an EC2 key pair, and a VPC with a public subnet.
The recommended instance type is m5.large (2 vCPU / 8 GiB RAM). Discourse rebuilds and Rails are memory-hungry, so do not go below 8 GiB of RAM for production.
Configure the security group to allow inbound 22/tcp from your management network, and 80/tcp and 443/tcp for the web interface. Discourse serves plain HTTP on port 80 and HTTPS (self-signed) on port 443. For production, replace the certificate with your own, or front the instance with an Application Load Balancer and an ACM certificate (see the final section).
Step 1 - Launch from the AWS Marketplace
Open the product in the AWS Marketplace and choose Continue to Subscribe, then Continue to Configuration and Continue to Launch.
Pick the m5.large instance type, your VPC and subnet, and a security group that allows ports 22, 80 and 443. Select your EC2 key pair and launch. The dedicated data volume is attached automatically.
Step 2 - Launch from the AWS CLI
Run the following command, replacing the values in angle brackets:
aws ec2 run-instances \
--image-id <ami-id> \
--instance-type m5.large \
--key-name <your-key-pair> \
--security-group-ids <sg-with-22-80-443> \
--subnet-id <your-public-subnet> \
--metadata-options "HttpTokens=required" \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=discourse}]'Step 3 - Confirm the services are running
On first boot, the image starts the pre-built Discourse container, mints the per-instance TLS certificate and creates a per-instance administrator. Confirm that Docker, Discourse and nginx are active:
systemctl is-active docker.service discourse.service nginx.serviceAll three report active. Then inspect the running container and the port listeners:
sudo docker ps --format 'table {{.Names}}\t{{.Status}}'
sudo ss -tln | grep -E ':(80|443) 'Step 4 - Check the health endpoint
Discourse exposes an unauthenticated status endpoint that returns ok when the application is healthy. Request it on both the HTTP listener and the self-signed HTTPS listener:
curl -s -o /dev/null -w 'http %{http_code}\n' http://127.0.0.1/srv/status
curl -sk -o /dev/null -w 'https %{http_code}\n' https://127.0.0.1/srv/statusBoth commands print 200.
Step 5 - Retrieve the per-instance admin credentials
Each instance generates a unique administrator password and admin API key on first boot and writes them to a root-only file. Read it with:
sudo cat /root/discourse-credentials.txtThe file contains DISCOURSE_URL, DISCOURSE_ADMIN_EMAIL (admin@sac.local), DISCOURSE_ADMIN_USERNAME (admin), a unique DISCOURSE_ADMIN_PASSWORD and a unique DISCOURSE_ADMIN_API_KEY. Confirm that the file is present and root-only. These commands print the non-secret lines only:
sudo stat -c '%a %U' /root/discourse-credentials.txt
sudo grep -E '^DISCOURSE_(URL|ADMIN_EMAIL|ADMIN_USERNAME)=' /root/discourse-credentials.txtStep 6 - Sign in to the web interface
Open https://<public-ip>/ in your browser, or http://<public-ip>/, and choose Log In. The HTTPS certificate is self-signed, so accept the browser warning. Sign in as admin@sac.local with the password from Step 5.
The full administrator dashboard is at /admin. There you manage users, categories, site settings, plugins, backups and more.
Browse a category to see its discussions and start new topics.
Step 7 - Verify the admin API and create a topic
Discourse exposes a full REST API, and the per-instance admin key authenticates as the admin user. A wrong key is rejected, while the valid key can read the site and create content. These commands create a topic in the first public category and read it back:
KEY=$(sudo grep '^DISCOURSE_ADMIN_API_KEY=' /root/discourse-credentials.txt | cut -d= -f2-)
echo -n 'wrong key: '; curl -s -o /dev/null -w '%{http_code}\n' -H 'Api-Key: wrong-key-xyz' -H 'Api-Username: admin' http://127.0.0.1/admin/users/list/active.json
CAT=$(curl -s -H "Api-Key: $KEY" -H 'Api-Username: admin' http://127.0.0.1/categories.json | jq -r '[.category_list.categories[]|select(.read_restricted==false)][0].id')
TID=$(curl -s -H "Api-Key: $KEY" -H 'Api-Username: admin' -H 'Content-Type: application/json' -X POST -d "{\"title\":\"Getting started with our new forum\",\"raw\":\"Welcome. This first topic was created through the Discourse REST API to confirm the forum is working.\",\"category\":$CAT}" http://127.0.0.1/posts.json | jq -r '.topic_id')
echo "created topic $TID"; curl -s -H "Api-Key: $KEY" -H 'Api-Username: admin' http://127.0.0.1/t/$TID.json | jq -r '.title'The wrong key returns a non-200 status. The valid key creates the topic and reads back its title.
Step 8 - Confirm data lives on the dedicated data volume
The PostgreSQL cluster, uploads and Redis data are stored on the dedicated EBS data volume mounted at /var/lib/discourse. They persist independently of the OS disk, and you can resize the volume independently. Confirm the mount:
findmnt -no SOURCE,TARGET,FSTYPE /var/lib/discourse test -d /var/lib/discourse/standalone/postgres_data && echo 'PostgreSQL cluster is on the data volume'Set your real hostname, TLS and SMTP for production
This appliance boots with the default hostname discourse.sac.local, a per-instance self-signed TLS certificate and a loopback SMTP setting, so it can bootstrap without a real domain or mail server. Before you invite real users, work through these steps:
- Point a DNS
Arecord at the instance's public IP, or front the instance with a load balancer. - Edit
/var/discourse/containers/app.ymland set your real values underenv:
DISCOURSE_HOSTNAME: 'forum.example.com' DISCOURSE_DEVELOPER_EMAILS: 'you@example.com' DISCOURSE_SMTP_ADDRESS: smtp.example.com DISCOURSE_SMTP_PORT: 587 DISCOURSE_SMTP_USER_NAME: 'your-smtp-user' DISCOURSE_SMTP_PASSWORD: 'your-smtp-password' DISCOURSE_SMTP_ENABLE_START_TLS: true- Rebuild the container so the new configuration takes effect. The rebuild repackages the container and takes several minutes, and the bundled template preserves the BSD-licensed Redis automatically:
cd /var/discourse
sudo ./launcher rebuild app/etc/sac/discourse/tls.crt and /etc/sac/discourse/tls.key with your own and reload nginx (sudo systemctl reload nginx). Alternatively, terminate TLS at an Application Load Balancer with an ACM certificate in front of the instance.Maintenance
- Restart Discourse:
sudo systemctl restart discourse.service - View container logs:
sudo docker logs app - Back up: use the admin dashboard (Admin > Backups) or
cd /var/discourse && sudo ./launcher run app 'discourse backup'. Backups are written under/var/lib/discourse/standalone/backups. You can also snapshot the EBS data volume with EBS snapshots or AWS Backup. - Upgrade Discourse: upgrade minor versions from Admin > Upgrade, or rebuild the container with
cd /var/discourse && sudo ./launcher rebuild app. - OS updates: the image ships with unattended security upgrades enabled.
Support
SecureAnyCloud provides 24/7 support for this image. Discourse is licensed under the GPL-2.0 and is free. The SecureAnyCloud charge covers packaging, security hardening, image maintenance and support.
Deploy on AWS
Launch Discourse Community Forum on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com