Learn about Centmin Mod LEMP Stack today
Become a Member

Docker + Discourse

Discussion in 'Forum software usage' started by andybond, Aug 21, 2022.

  1. andybond

    andybond Member

    37
    15
    8
    Jun 1, 2017
    Ratings:
    +20
    Local Time:
    11:44 AM
    1.25.x
    10.4
    Hi,

    Has anyone a guide/tutorial to install docker and discourse on centminmod? I can get the docker part installed but fail after that!

    Thanks


    Andy
     
  2. eva2000

    eva2000 Administrator Staff Member

    53,246
    12,117
    113
    May 24, 2014
    Brisbane, Australia
    Ratings:
    +18,655
    Local Time:
    8:44 PM
    Nginx 1.27.x
    MariaDB 10.x/11.4+
    Which guides are you following for this already? Have you asked at Discourse Meta if you encounter errors?

    Docker for CentOS Install Docker Engine on CentOS

    If this sample is correct at discourse/nginx.sample.conf at main · discourse/discourse then

    the first part of
    Code (Text):
    # Additional MIME types that you'd like nginx to handle go in here
    types {
    text/csv csv;
    application/wasm wasm;
    }
    
    upstream discourse {
    server unix:/var/www/discourse/tmp/sockets/nginx.http.sock;
    server unix:/var/www/discourse/tmp/sockets/nginx.https.sock;
    }
    
    # inactive means we keep stuff around for 1440m minutes regardless of last access (1 week)
    # levels means it is a 2 deep hierarchy cause we can have lots of files
    # max_size limits the size of the cache
    proxy_cache_path /var/nginx/cache inactive=1440m levels=1:2 keys_zone=one:10m max_size=600m;
    
    # see: https://meta.discourse.org/t/x/74060
    proxy_buffer_size 8k;
    
    # If you are going to use Puma, use these:
    #
    # upstream discourse {
    # server unix:/var/www/discourse/tmp/sockets/puma.sock;
    # }
    
    # attempt to preserve the proto, must be in http context
    map $http_x_forwarded_proto $thescheme {
    default $scheme;
    https https;
    }
    
    log_format log_discourse '[$time_local] "$http_host" $remote_addr "$request" "$http_user_agent" "$sent_http_x_discourse_route" $status $bytes_sent "$http_referer" $upstream_response_time $request_time "$upstream_http_x_discourse_username" "$upstream_http_x_discourse_trackview" "$upstream_http_x_queue_time" "$upstream_http_x_redis_calls" "$upstream_http_x_redis_time" "$upstream_http_x_sql_calls" "$upstream_http_x_sql_time"';
    
    # Allow bypass cache from localhost
    geo $bypass_cache {
    default 0;
    127.0.0.1 1;
    ::1 1;
    }
    

    gets added to /usr/local/nginx/conf/nginx.conf within http{} context. You can just add a new include file /usr/local/nginx/conf/discourse.conf and add above part into that file and add that to /usr/local/nginx/conf/nginx.conf
    Code (Text):
    include /usr/local/nginx/conf/nginx.conf;

    to /usr/local/nginx/conf/nginx.conf within http{} context

    might need to adjust this part for UNIX sockets
    Code (Text):
    upstream discourse {
    server unix:/var/www/discourse/tmp/sockets/nginx.http.sock;
    server unix:/var/www/discourse/tmp/sockets/nginx.https.sock;
    }
    

    i don't see where they're created just from the sample nginx config so paths may vary when using Docker

    and this next part is your domain nginx vhost /usr/local/nginx/conf/conf.d/yourdomain.com.ssl.conf but you don't need to add everything as some existing nginx vhost settings will overlap

    Code (Text):
    server {
    
      access_log /var/log/nginx/access.log log_discourse;
    
      listen 80;
      gzip on;
      gzip_vary on;
      gzip_min_length 1000;
      gzip_comp_level 5;
      gzip_types application/json text/css text/javascript application/x-javascript application/javascript image/svg+xml application/wasm;
      gzip_proxied any;
    
      # Uncomment and configure this section for HTTPS support
      # NOTE: Put your ssl cert in your main nginx config directory (/etc/nginx)
      #
      # rewrite ^/(.*) https://enter.your.web.hostname.here/$1 permanent;
      #
      # listen 443 ssl;
      # ssl_certificate your-hostname-cert.pem;
      # ssl_certificate_key your-hostname-cert.key;
      # ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
      # ssl_ciphers HIGH:!aNULL:!MD5;
      #
    
      server_name enter.your.web.hostname.here;
      server_tokens off;
    
      sendfile on;
    
      keepalive_timeout 65;
    
      # maximum file upload size (keep up to date when changing the corresponding site setting)
      client_max_body_size 10m;
    
      # path to discourse's public directory
      set $public /var/www/discourse/public;
    
      # without weak etags we get zero benefit from etags on dynamically compressed content
      # further more etags are based on the file in nginx not sha of data
      # use dates, it solves the problem fine even cross server
      etag off;
    
      # prevent direct download of backups
      location ^~ /backups/ {
       internal;
      }
    
      # bypass rails stack with a cheap 204 for favicon.ico requests
      location /favicon.ico {
       return 204;
       access_log off;
       log_not_found off;
      }
    
      location / {
       root $public;
       add_header ETag "";
    
       # auth_basic on;
       # auth_basic_user_file /etc/nginx/htpasswd;
    
       location ~ ^/uploads/short-url/ {
         proxy_set_header Host $http_host;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header X-Request-Start "t=${msec}";
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_set_header X-Forwarded-Proto $thescheme;
         proxy_pass http://discourse;
         break;
       }
    
       location ~ ^/secure-media-uploads/ {
         proxy_set_header Host $http_host;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header X-Request-Start "t=${msec}";
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_set_header X-Forwarded-Proto $thescheme;
         proxy_pass http://discourse;
         break;
       }
    
       location ~* (fonts|assets|plugins|uploads)/.*\.(eot|ttf|woff|woff2|ico|otf)$ {
         expires 1y;
         add_header Cache-Control public,immutable;
         add_header Access-Control-Allow-Origin *;
       }
    
       location = /srv/status {
         access_log off;
         log_not_found off;
         proxy_set_header Host $http_host;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header X-Request-Start "t=${msec}";
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_set_header X-Forwarded-Proto $thescheme;
         proxy_pass http://discourse;
         break;
       }
    
       # some minimal caching here so we don't keep asking
       # longer term we should increase probably to 1y
       location ~ ^/javascripts/ {
         expires 1d;
         add_header Cache-Control public,immutable;
         add_header Access-Control-Allow-Origin *;
       }
    
       location ~ ^/assets/(?<asset_path>.+)$ {
         expires 1y;
         # asset pipeline enables this
         brotli_static on;
         gzip_static on;
         add_header Cache-Control public,immutable;
         # HOOK in asset location (used for extensibility)
         # TODO I don't think this break is needed, it just breaks out of rewrite
         break;
       }
    
       location ~ ^/plugins/ {
         expires 1y;
         add_header Cache-Control public,immutable;
         add_header Access-Control-Allow-Origin *;
       }
    
       # cache emojis
       location ~ /images/emoji/ {
         expires 1y;
         add_header Cache-Control public,immutable;
         add_header Access-Control-Allow-Origin *;
       }
    
       location ~ ^/uploads/ {
    
         # NOTE: it is really annoying that we can't just define headers
         # at the top level and inherit.
         #
         # proxy_set_header DOES NOT inherit, by design, we must repeat it,
         # otherwise headers are not set correctly
         proxy_set_header Host $http_host;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header X-Request-Start "t=${msec}";
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_set_header X-Forwarded-Proto $thescheme;
         proxy_set_header X-Sendfile-Type X-Accel-Redirect;
         proxy_set_header X-Accel-Mapping $public/=/downloads/;
         expires 1y;
         add_header Cache-Control public,immutable;
    
         ## optional upload anti-hotlinking rules
         #valid_referers none blocked mysite.com *.mysite.com;
         #if ($invalid_referer) { return 403; }
    
         # custom CSS
         location ~ /stylesheet-cache/ {
             add_header Access-Control-Allow-Origin *;
             try_files $uri =404;
         }
         # this allows us to bypass rails
         location ~* \.(gif|png|jpg|jpeg|bmp|tif|tiff|ico|webp)$ {
             add_header Access-Control-Allow-Origin *;
             try_files $uri =404;
         }
         # SVG needs an extra header attached
         location ~* \.(svg)$ {
         }
         # thumbnails & optimized images
         location ~ /_?optimized/ {
             add_header Access-Control-Allow-Origin *;
             try_files $uri =404;
         }
    
         proxy_pass http://discourse;
         break;
       }
    
       location ~ ^/admin/backups/ {
         proxy_set_header Host $http_host;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header X-Request-Start "t=${msec}";
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_set_header X-Forwarded-Proto $thescheme;
         proxy_set_header X-Sendfile-Type X-Accel-Redirect;
         proxy_set_header X-Accel-Mapping $public/=/downloads/;
         proxy_pass http://discourse;
         break;
       }
    
       # This big block is needed so we can selectively enable
       # acceleration for backups, avatars, sprites and so on.
       # see note about repetition above
       location ~ ^/(svg-sprite/|letter_avatar/|letter_avatar_proxy/|user_avatar|highlight-js|stylesheets|theme-javascripts|favicon/proxied|service-worker) {
         proxy_set_header Host $http_host;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header X-Request-Start "t=${msec}";
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_set_header X-Forwarded-Proto $thescheme;
    
         # if Set-Cookie is in the response nothing gets cached
         # this is double bad cause we are not passing last modified in
         proxy_ignore_headers "Set-Cookie";
         proxy_hide_header "Set-Cookie";
         proxy_hide_header "X-Discourse-Username";
         proxy_hide_header "X-Runtime";
    
         # note x-accel-redirect can not be used with proxy_cache
         proxy_cache one;
         proxy_cache_key "$scheme,$host,$request_uri";
         proxy_cache_valid 200 301 302 7d;
         proxy_cache_bypass $bypass_cache;
         proxy_pass http://discourse;
         break;
       }
    
       # we need buffering off for message bus
       location /message-bus/ {
         proxy_set_header X-Request-Start "t=${msec}";
         proxy_set_header Host $http_host;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_set_header X-Forwarded-Proto $thescheme;
         proxy_http_version 1.1;
         proxy_buffering off;
         proxy_pass http://discourse;
         break;
       }
    
       # this means every file in public is tried first
       try_files $uri @discourse;
      }
    
      location /downloads/ {
       internal;
       alias $public/;
      }
    
      location @discourse {
       proxy_set_header Host $http_host;
       proxy_set_header X-Request-Start "t=${msec}";
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_set_header X-Forwarded-Proto $thescheme;
       proxy_pass http://discourse;
      }
    
    }
    

    change and/or create the proxy_cache_path and give it nginx user/group permissions
    Code (Text):
    proxy_cache_path /var/nginx/cache
    

    change root path
    Code (Text):
    set $public /var/www/discourse/public;
    

    remove that access log and keep existing one from nginx vhost and remove listen 80 port as you're running SSL/HTTPS over 443 so would keep your existing HTTPS/SSL directives

    Rest is up to you to figure out :)

    I haven't used Discourse myself, so just assuming based off that nginx sample config
     
  3. andybond

    andybond Member

    37
    15
    8
    Jun 1, 2017
    Ratings:
    +20
    Local Time:
    11:44 AM
    1.25.x
    10.4

    Thank you for the pointers! I have tried to follow bits here and bits there. Nothing seemed to give me an end to end solution. I know the support in here is top notch so hence the question.

    Let me work with your suggestions and Ill go from there. Appreciate your input!
     
  4. eva2000

    eva2000 Administrator Staff Member

    53,246
    12,117
    113
    May 24, 2014
    Brisbane, Australia
    Ratings:
    +18,655
    Local Time:
    8:44 PM
    Nginx 1.27.x
    MariaDB 10.x/11.4+
    Actually i think that nginx config is if you self install Discourse in non-Docker manner. You're best bet is to ask how to use Nginx as a reverse proxy in front of a Docker installed Discourse setup at Discourse Meta and if they point to documentation/guides, share them here.
     
  5. andybond

    andybond Member

    37
    15
    8
    Jun 1, 2017
    Ratings:
    +20
    Local Time:
    11:44 AM
    1.25.x
    10.4
    This is the bit I am struggling with. I have set the docker instance to use a random port, and I can see docker is running. I am struggling to get the reverse bit working ...

    Ill try and get some input from the team
     
  6. eva2000

    eva2000 Administrator Staff Member

    53,246
    12,117
    113
    May 24, 2014
    Brisbane, Australia
    Ratings:
    +18,655
    Local Time:
    8:44 PM
    Nginx 1.27.x
    MariaDB 10.x/11.4+
    from https://www.howtoforge.com/how-to-i...bian-11/#step-8---install-and-configure-nginx it might be as simple as just setting location / {} context ?

    changing proxy_pass to docker discourse install
    Code (Text):
       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;
       }   
    

    so comment out and remove the existing one
    Code (Text):
      location / {
      include /usr/local/nginx/conf/503include-only.conf;
     
      }
    

    and also comment out
    Code (Text):
      #include /usr/local/nginx/conf/pre-staticfiles-local-yourdomain.com.conf;
      #include /usr/local/nginx/conf/pre-staticfiles-global.conf;
      #include /usr/local/nginx/conf/staticfiles.conf;
      #include /usr/local/nginx/conf/drop.conf;
      #include /usr/local/nginx/conf/errorpage.conf;
      #include /usr/local/nginx/conf/vts_server.conf;
    
     
  7. andybond

    andybond Member

    37
    15
    8
    Jun 1, 2017
    Ratings:
    +20
    Local Time:
    11:44 AM
    1.25.x
    10.4
  8. eva2000

    eva2000 Administrator Staff Member

    53,246
    12,117
    113
    May 24, 2014
    Brisbane, Australia
    Ratings:
    +18,655
    Local Time:
    8:44 PM
    Nginx 1.27.x
    MariaDB 10.x/11.4+
    ah so essentially same as above https://community.centminmod.com/threads/docker-discourse.23157/#post-94203 - just ignore all the certbot/installing nginx stuff as Centmin Mod Nginx vhost setup takes care of all that. But only change is proxy_pass set to the Unix Socket change you make for /var/discourse/containers/app.yml for adding templates/web.socketed.template.yml and commenting out:
    Code (Text):
    # - "templates/web.ssl.template.yml" # - "templates/web.letsencrypt.ssl.template.yml"

    and comment out exposed ports in same file
    Code (Text):
    # - "80:80"   # HTTP 
    # - "443:443" # https

    so you can run Discourse via Unix Socket at http://unix:/var/discourse/shared/standalone/nginx.http.sock instead of a TCP port.
     
  9. andybond

    andybond Member

    37
    15
    8
    Jun 1, 2017
    Ratings:
    +20
    Local Time:
    11:44 AM
    1.25.x
    10.4
    I have managed to get a working discourse install.


    Install docker - not covered here
    Install discourse -

    Code:
    git clone https://github.com/discourse/discourse_docker.git /var/discourse
    cd /var/discourse

    Config app.yaml in /var/discource/containers

    adjust app.yml to remove port 80+443

    Code:
    ## 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.socketed.template.yml"
      #- "templates/web.ratelimited.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:
    
      #- "25654: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: "128MB"
     
      ## 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:
      LANG: 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
      UNICORN_WORKERS: 2
    
      ## TODO: The domain name this Discourse instance will respond to
      ## Consider this as what transforms into the server_name in an Nginx configuration
      DISCOURSE_HOSTNAME: 'your.site.com'
     
      ## Uncomment if you want the container to be started with the same
      ## hostname (-h option) as specified above (default "$hostname-$config")
      #DOCKER_USE_HOSTNAME: true
    
      ## TODO: List of comma delimited emails that will be made admin and developer
      ## on initial signup example 'user1@example.com,user2@example.com'
      ## This email is what you'll use to log into Discourse instance the first time.
      DISCOURSE_DEVELOPER_EMAILS: 'email@your.com'
    
      ## TODO: The SMTP mail server used to validate new accounts and send notifications
      DISCOURSE_SMTP_ADDRESS: smtp.your.com
      DISCOURSE_SMTP_PORT: 587
      DISCOURSE_SMTP_USER_NAME: email@your.com
      DISCOURSE_SMTP_PASSWORD: addpasswordhere  # WARNING a char '#' in pw can cause problems!
      ## There wouldn't be any issue like above with password if this is a JSON object
    
      ## The CDN address for this Discourse instance (configured to pull)
      ## see https://meta.discourse.org/t/14857 for details
      #DISCOURSE_CDN_URL: //discourse-cdn.example.com
    
    ## 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
    
    ## 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='noreply@khophi.co'"
      - exec: echo "End of custom commands"


    Find /usr/local/nginx/conf/conf.d
    edit the relevant conf

    add

    Code:
    proxy_pass http://unix:/var/discourse/shared/standalone/nginx.http.sock:;
                    proxy_set_header Host $http_host;
                    proxy_http_version 1.1;
                    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;
    to location / {

    rem include /usr/local/nginx/conf/503include-only.conf; with a #

    Code:
    #include /usr/local/nginx/conf/503include-only.conf;
    also


    Code:
    #include /usr/local/nginx/conf/pre-staticfiles-local-yourdomain.com.conf;
      #include /usr/local/nginx/conf/pre-staticfiles-global.conf;
      #include /usr/local/nginx/conf/staticfiles.conf;
      #include /usr/local/nginx/conf/drop.conf;
      #include /usr/local/nginx/conf/errorpage.conf;
      #include /usr/local/nginx/conf/vts_server.conf;
     
    Last edited: Aug 26, 2022
  10. eva2000

    eva2000 Administrator Staff Member

    53,246
    12,117
    113
    May 24, 2014
    Brisbane, Australia
    Ratings:
    +18,655
    Local Time:
    8:44 PM
    Nginx 1.27.x
    MariaDB 10.x/11.4+
    Glad to see you got it working and thanks for sharing what worked for you :D
     
  11. andybond

    andybond Member

    37
    15
    8
    Jun 1, 2017
    Ratings:
    +20
    Local Time:
    11:44 AM
    1.25.x
    10.4
    Absolute least I can do considering how much time and effort you put into centminmod.