Moving discourse instance to a new server

AI-generated summary

The user Headless is seeking advice on moving their Discourse instance to a new server due to persistent disk space issues on their Hetzner server, where Docker containers and images consume local storage. They aim to properly configure volumes for all data, including the database, uploads, and backups, to enable scalability and easier migration. Lee_Ars recommends storing /var/discourse on a mountable volume, allowing seamless migration between servers by simply remounting the volume and rebuilding the app. Lee_Ars shares a sanitized app.yml example, emphasizing the use of /shared for data persistence. Headless confirms that moving /var/discourse to a volume preserves existing data, but still faces issues with Docker images and containers being stored locally rather than in volumes. Lee_Ars confirms the standard setup stores data in /shared, and Headless seeks further guidance on resolving the Docker storage issue.

Before asking, did you search first? Press :magnifying_glass_tilted_left: at the upper right to search

Hello,

I first want to thank you for any support you may offer. With that being said, I would like to discuss my issue and then my goals for my self-hosted Discourse instance.

Problem

I currently use Hetzner as my server that is hosting a discourse instance. I have attached volumes for Uploads , Backups. The current Docker containers and images, as well as the app.yml and etc, are hosted on the server itself under /var/discourse.

I have had this server over the course of 3-4+ years, and throughout that time, I have always run into the issue with space on the server itself (not volumes). Anytime I wanted to rebuild the app or relaunch the app, I would run into space issues as it would install the images and Docker containers to the local server rather than a volume. I would constantly need to remove Docker and any images/containers and do a fresh reinstall so I can rebuild. I also believe the SQL data is attached to the local server instead of a volume.

Goals

I am not sure what would be best for me going forward. Is it moving specific folders or files to a new volume for the Postgres DB and Docker images, and if so, I would love support on how to do that? Or starting from scratch with a fresh server, creating a backup of the server, and restoring on a new server with all volumes in properly configured locations?


With all this being said, I would love some support on configuring the app.yml to properly have volumes for everything that takes up space, so I can individually scale when backups, uploads, db, or docker images, for example, need it.

I can provide my app.yml file later today, as I am currently at work and looking to get ahead of the game.

I do my discourse hosting on AWS, and I have had great success so far in keeping /var/discourse on its own mountable EBS volume and attaching that volume to different EC2 instances as I’ve needed to migrate. I even fully changed architecture from x64 to ARM (I switched EC2 instances from a t3a.large to an r7g.large) and after re-mounting the /var/discourse volume, I was back online after a simple launcher rebuild app even with the architecture switch.

Bottom line, if your /var/discourse is stored in a mountable volume, then you have the entire state of your forum in an essentially swing-mountable state. As long as you can set up a host and install docker on it, you can mount /var/discourse to it, run a launcher rebuild app, and be up and running. (Assuming things like hostname and other stuff specified in app.yml remain constant between hosts.)

Could you possibly provide a example app.yml for this setup? As well as is it as simple as a move from “/var/discourse” content to a different volume or do I need to clone the repo into the new volume.


What also about the database files?

Here’s a sanitized copy of my current working app.yml:

## this is the all-in-one, standalone Discourse Docker container template
##
## After making changes to this file, you MUST rebuild
## /var/discourse/launcher rebuild app
##
## BE *VERY* CAREFUL WHEN EDITING!
## YAML FILES ARE SUPER SUPER SENSITIVE TO MISTAKES IN WHITESPACE OR ALIGNMENT!
## visit http://www.yamllint.com/ to validate this file as needed

templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"
  - "templates/web.ssl.template.yml"
  - "templates/web.letsencrypt.ssl.template.yml"
  - "templates/cloudflare.template.yml"

## which TCP/IP ports should this container expose?
## If you want Discourse to share a port with another webserver like Apache or nginx,
## see https://meta.discourse.org/t/17247 for details
expose:
  - "80:80"   # http
  - "443:443" # https

params:
  db_default_text_search_config: "pg_catalog.english"

  ## Set db_shared_buffers to a max of 25% of the total memory.
  ## will be set automatically by bootstrap based on detected RAM, or you can override
  db_shared_buffers: "4096MB"

  ## can improve sorting performance, but adds memory usage per-connection
  db_work_mem: "40MB"

  ## Which Git revision should this container use? (default: tests-passed)
  #version: tests-passed

env:
  LC_ALL: en_US.UTF-8
  LANG: en_US.UTF-8
  LANGUAGE: en_US.UTF-8
  # DISCOURSE_DEFAULT_LOCALE: en

  ## How many concurrent web requests are supported? Depends on memory and CPU cores.
  ## will be set automatically by bootstrap based on detected CPUs, or you can override

  ## Changed by Lee on 2025/8/2
  # UNICORN_WORKERS: 8
  UNICORN_WORKERS: 10

  ## TODO: The domain name this Discourse instance will respond to
  ## Required. Discourse will not work with a bare IP number.
  DISCOURSE_HOSTNAME: discourse.spacecityweather.com

  ## TODO: List of comma delimited emails that will be made admin and developer
  ## on initial signup example 'user1@example.com,user2@example.com'
  DISCOURSE_DEVELOPER_EMAILS: [redacted]

  ## TODO: The SMTP mail server used to validate new accounts and send notifications
  # SMTP ADDRESS is required
  # WARNING: SMTP password should be wrapped in quotes to avoid problems
  DISCOURSE_SMTP_ADDRESS: [redacted]
  DISCOURSE_SMTP_PORT: [redacted]
  DISCOURSE_SMTP_USER_NAME: [redacted]
  DISCOURSE_SMTP_PASSWORD: [redacted]
  DISCOURSE_SMTP_DOMAIN: [redacted]
  DISCOURSE_NOTIFICATION_EMAIL: [redacted]

  ## If you added the Lets Encrypt template, uncomment below to get a free SSL certificate
  LETSENCRYPT_ACCOUNT_EMAIL: [redacted]

  ## The maxmind geolocation IP account ID and license key for IP address lookups
  ## see https://meta.discourse.org/t/-/173941 for details
  DISCOURSE_MAXMIND_ACCOUNT_ID: [redacted]
  DISCOURSE_MAXMIND_LICENSE_KEY: [redacted]

  ## S3 backup crap
  ## Added by Lee on 2025/7/20
  DISCOURSE_USE_S3: true
  DISCOURSE_S3_REGION: [redacted]
  DISCOURSE_S3_USE_IAM_PROFILE: true
  DISCOURSE_S3_BACKUP_BUCKET: [redacted]
  DISCOURSE_BACKUP_LOCATION: s3

  ## Maybe fix sidekiq using too much memory errors?
  UNICORN_SIDEKIQ_MAX_RSS: 1024

  ## Added by Lee on 2025/8/2
  SIDEKIQ_CONCURRENCY: 6
  RUBY_GC_HEAP_GROWTH_MAX_SLOTS: 40000
  RUBY_GC_HEAP_GROWTH_FACTOR: 1.1
  RUBY_GLOBAL_METHOD_CACHE_SIZE: 131072
  MALLOC_ARENA_MAX: 2

## The Docker container is stateless; all data is stored in /shared
volumes:
  - volume:
      host: /var/discourse/shared/standalone
      guest: /shared
  - volume:
      host: /var/discourse/shared/standalone/log/var-log
      guest: /var/log

## Docker args?
docker_args: "--add-host spacecityweather.com:[redacted] --add-host theeyewall.com:[redacted]"

## Plugins go here
## see https://meta.discourse.org/t/19157 for details
hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git

## Any custom commands to run after building
run:
  - exec: echo "Beginning of custom commands"
  ## If you want to set the 'From' email address for your first registration, uncomment and change:
  ## After getting the first signup email, re-comment the line. It only needs to run once.
  #- exec: rails r "SiteSetting.notification_email='info@unconfigured.discourse.org'"
  - exec: echo "End of custom commands"

And all the contents of the DB are stored in /var/discourse? So if I move all the contents of /var/discourse to a mountable volume, it should continue to use all the existing data?

I’m using the standard single-container self hosted install, so it’s all set up however the defaults are set!

Question, even though I moved the /discourse folder over to a mountable volume, I still am struggling with docker. As containers and images are still being ran on the local drive instead of a volume. Any idea on how to fix this?