4 min read

Setting Up Discourse and Ghost blog (in Subdirectory) with Docker and NGINX Proxy Manager

Important Disclaimer

WARNING: This guide includes setting up Ghost as a subdirectory under your Discourse installation, which is explicitly discouraged by the Discourse team. While using a reverse proxy with Discourse is perfectly fine, running other applications (like Ghost) in subdirectories under Discourse can lead to various issues.

Issues include:

  • Unexpected behavior with routes
  • Complications with Discourse's URL handling
  • Potential conflicts with Discourse's internal routing
  • Maintenance challenges

The recommended approach by Discourse is to:

  • Have Discourse occupy the main domain or subdomain (e.g., forum.com)
  • Put other applications like Ghost on subdomains (e.g., blog.forum.com)
  • Avoid putting applications in subdirectories under Discourse (e.g., forum.com/blog)

Personal Context

I want to be transparent about my experience putting this guide together:

  • I'm not a Linux expert or professional developer
  • This setup was achieved through lots of trial and error
  • Some solutions might not be the most elegant
  • You might need to adapt these steps for your specific situation
  • It works for my needs, but might not be suitable for everyone

If you want to follow Discourse's best practices, you should:

  1. Keep Discourse on your main domain or its own subdomain
  2. Put Ghost on a subdomain instead of a subdirectory

Now that we have gotten the disclaimers out of our way, let's get into our setup.


Overview

This comprehensive guide walks you through setting up Discourse (forum software) and Ghost (blogging platform) behind NGINX Proxy Manager.

Prerequisites

This was my configuration when I tried this setup:

  • Ubuntu (22.04 LTS)
  • A registered domain name with DNS configured
  • Root or sudo access to your server
  • Basic command line knowledge
  • 4GB recommended
  • At least 30GB free disk space

Installing Docker on Ubuntu Server {#installing-docker}

First, we'll install Docker to manage our containerized applications.

  1. Update your system packages:
sudo apt update && sudo apt upgrade -y
  1. Install required dependencies:
sudo apt install apt-transport-https ca-certificates curl software-properties-common
  1. Add Docker's official GPG key and repository:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
  1. Install Docker:
sudo apt update
sudo apt-get install docker-ce docker-ce-cli containerd.io

Setting Up NGINX Proxy Manager {#setting-up-nginx}

NGINX Proxy Manager provides a user-friendly interface for managing reverse proxy configurations.

  1. Create the application directory:
mkdir -p /opt/nginx-proxy-manager
cd /opt/nginx-proxy-manager
  1. Create your docker-compose.yml file:
nano docker-compose.yml
  1. Add the following configuration:
version: '3'
services:
  app:
    image: 'jc21/nginx-proxy-manager:latest'
    restart: always
    ports:
      - '80:80'    # HTTP port
      - '81:81'    # Web-admin interface
      - '443:443'  # HTTPS port
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
  1. Start NGINX Proxy Manager:
docker-compose up -d

Installing and Configuring Discourse Forum {#setting-up-discourse}

Discourse provides a robust platform for community discussions and forums.

  1. Clone the Discourse repository:
git clone https://github.com/discourse/discourse_docker.git /var/discourse
  1. Set up the configuration:
cp /var/discourse/samples/standalone.yml /var/discourse/containers/app.yml
nano /var/discourse/containers/app.yml
  1. Configure the ports in app.yml:
expose:
  - "8083:80"   # HTTP port
  - "2443:443"  # HTTPS port
  1. Build the Discourse container:
./launcher rebuild app

Installing and Configuring Ghost Blog {#setting-up-ghost}

Ghost provides a modern publishing platform for professional bloggers.

  1. Create and navigate to Ghost directory:
mkdir -p /opt/ghost
cd /opt/ghost
  1. Create the docker-compose.yml file:
nano docker-compose.yml
  1. Add the following configuration:
version: '3'
services:
  ghost:
    image: ghost:latest
    restart: always
    ports:
      - 8081:2368
    environment:
      database__client: sqlite3
      database__connection__filename: /var/lib/ghost/content/data/ghost.db
      url: https://yourdomain.com/blog
      NODE_ENV: production
    volumes:
      - ./content:/var/lib/ghost/content
volumes:
  ghost_data:
  1. Start the Ghost container:
docker-compose up -d

Configuring Reverse Proxy with NGINX Proxy Manager {#configuring-proxy}

Set up reverse proxy rules to route traffic to your applications.

  1. Access NGINX Proxy Manager at http://<your-server-ip>:81
  2. Create a new Proxy Host for Discourse:
    • Domain Names: yourdomain.com
    • Scheme: https
    • Forward Hostname/IP: your-server-ip
    • Forward Port: 8083
  3. Create a new Proxy Host for Ghost:
    • Domain Names: yourdomain.com/blog
    • Scheme: https
    • Forward Hostname/IP: your-server-ip
    • Forward Port: 8081
  4. Advanced Configuration:
location / {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header Host $http_host;
    proxy_pass http://your_server_ip:8083;
}

location /blog {
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
    proxy_pass http://your_server_ip:2368/blog;
}

Troubleshooting and Verification {#troubleshooting}

After setup, verify your installation:

  1. Check container status:
docker ps
  1. View container logs:
docker logs nginx-proxy-manager
docker logs discourse_app
docker logs ghost_ghost_1
  1. Test your URLs:

Why I Chose This Setup (Despite the Warnings)

Despite Discourse's recommendations against subdirectory installations of other apps, I chose this setup primarily for SEO reasons:

SEO Considerations

  • Subdirectories vs Subdomains: Search engines generally treat subdomains (blog.example.com) as separate websites from the main domain (example.com)
  • SEO Authority: When using subdirectories (example.com/blog), the SEO authority and ranking power is shared across your entire domain
  • Link Equity: Internal linking between your forum and blog has more SEO value when they're under the same domain (Still dealing with issues here, especially with discourse linking to the blog.)
  • Domain Authority: All backlinks contribute to the same domain's authority rather than being split across subdomains

This SEO advantage was important enough for me to accept the technical challenges of setting up Ghost in a subdirectory under Discourse. While this might not be the recommended approach from Discourse's perspective, it can make sense if:

  1. SEO is a critical factor for your website
  2. You want to maximize the ranking potential of both your forum and blog
  3. You're willing to handle the technical complexities involved
  4. You understand and accept the maintenance challenges

Trade-offs to Consider

Remember that this decision involves balancing:

  • ✅ Better SEO performance
  • ✅ Unified domain authority
  • ✅ Stronger internal linking value
  • ❌ More complex setup
  • ❌ Potential routing issues
  • ❌ Harder maintenance
  • ❌ Against Discourse's recommendations

FAQs {#faqs}

Q: Why use NGINX Proxy Manager?
A: NGINX Proxy Manager simplifies SSL certificate management and reverse proxy configuration through a user-friendly interface.

Q: Can I run multiple instances of Ghost or Discourse?
A: Yes, by modifying the port mappings and creating additional proxy hosts in NGINX Proxy Manager.

Q: What are the system requirements for this setup?
A: Minimum 3GB RAM, 20GB storage, and Ubuntu 22.04 or newer. For production environments, 4GB RAM is recommended.