Moodle
  1. Moodle
  2. MDL-9276

Errors with Moodle behind a reverse proxy

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.6.4
    • Fix Version/s: 2.0
    • Component/s: Course
    • Labels:
      None
    • Environment:
      Server: Linux with Apache 2.2
    • Affected Branches:
      MOODLE_16_STABLE
    • Fixed Branches:
      MOODLE_20_STABLE
    • Rank:
      29604

      Description

      We use moodle behind an Apache web server configured with mod_proxy and we get error in some elements (links, styles, ...) in some pages.
      The internal and external name of the published application is not the same so we have the following configuration:

      in the backend web server with Moodle 1.6.4 and Apache 2.0 we have:
      in config.php
      $CFG->wwwroot = "http://external_public_name/estudios";

      in the frontend web server with Apache 2.2 we have:
      in httpd.conf
      ProxyPass /estudios http://internal_server_name/moodle
      ProxyPassReverse /estudios http://internal_server_name/moodle

      When we login into Moodle and go to a course, in the Topic outline screen, for example
      http://external_public_name/estudios/course/view.php?id=2

      the central block styles are not aplied.

      The reason is that body class is not well formed.
      If we see the source code of the generated page we see over line 65

      <body class="http:-internal_servere_namecourse course-2" id="http:-internal_server_namecourse-view">

      I supose the correct one must be <body class="course course-2" id="course-view">

      This is only one error, we have detected more of the same type in the docs link in the footer of pages and in the nav bar of archives page.

      We have already tested it in Moodle 1.7 and 1.8 and the same errors ocurred.

      Regards

      Rafael

        Issue Links

          Activity

          Hide
          Petr Škoda added a comment -

          You can not use two URLs for one Moodle instance, you can find more info here: http://docs.moodle.org/en/masquerading

          Show
          Petr Škoda added a comment - You can not use two URLs for one Moodle instance, you can find more info here: http://docs.moodle.org/en/masquerading
          Hide
          Rafael del Aguila added a comment -

          I have read http://docs.moodle.org/en/masquerading
          This article explain that "You can not use internal ip address or internal server name in config.php if you want to access the server from Internet too. If you want to use Moodle server from Internet, use real DNS hostname in $CFG->wwwroot."
          If you re-read my first post I use real DNS hostname in my config.php

          $CFG->wwwroot = "http://external_public_name/estudios ";

          The problem arise when url published in the reverse proxy [ /estudios ] is not the same that the url published in the internal server [ /moodle ]

          Beyond this error, I think this limitation has no sense.
          Why need Moodle work with absolute URLs?
          Relative URLs are much more flexible than absolute ones and allow a correct work behind reverse proxy.
          It must be an imperative improvement.

          In addition, almost all pages work fine in my configuration, only some errors are displayed in some pages where absolute urls are bad used.

          I think the errors come from the function me() and/or qualified_me() in weblib.php

          Show
          Rafael del Aguila added a comment - I have read http://docs.moodle.org/en/masquerading This article explain that "You can not use internal ip address or internal server name in config.php if you want to access the server from Internet too. If you want to use Moodle server from Internet, use real DNS hostname in $CFG->wwwroot." If you re-read my first post I use real DNS hostname in my config.php $CFG->wwwroot = "http://external_public_name/estudios "; The problem arise when url published in the reverse proxy [ /estudios ] is not the same that the url published in the internal server [ /moodle ] Beyond this error, I think this limitation has no sense. Why need Moodle work with absolute URLs? Relative URLs are much more flexible than absolute ones and allow a correct work behind reverse proxy. It must be an imperative improvement. In addition, almost all pages work fine in my configuration, only some errors are displayed in some pages where absolute urls are bad used. I think the errors come from the function me() and/or qualified_me() in weblib.php
          Hide
          Petr Škoda added a comment -

          The main reason why there are absolute urls is that people copy/pase urls from address bar. Decision to use absolute urls was done long ago and I am sure it will not be changed. If you want more info, please search the forums.

          Show
          Petr Škoda added a comment - The main reason why there are absolute urls is that people copy/pase urls from address bar. Decision to use absolute urls was done long ago and I am sure it will not be changed. If you want more info, please search the forums.
          Hide
          Joacim Breiler added a comment - - edited

          We are running moodle on a server at "http://localserver:8088/" and a reverse proxy (pound - http://www.apsis.ch/pound/).
          Pound handles all calls to "https://example.com/moodle" and directs the traffic to to the local server.

          We got the same symptoms as described above by Rafael. The module chat wouldn't even load, giving a blank page...

          We solved the issue (we havn't noticed any side effects yet) by modifing the function qualified_me() in /lib/weblib.php.

          The function parses the URL from $CFG->wwwroot and uses this information together with information from $_SERVER
          to build an absolute url.

          Replace the function qualified_me() with the one below, and set "$CFG->using_reverseproxy = true" in your config.php.

          function qualified_me() {

          global $CFG;

          $result = $CFG->wwwroot . me();

          if( !$CFG->using_reverseproxy )
          {
          if (!empty($CFG->wwwroot))

          { $url = parse_url($CFG->wwwroot); }

          if (!empty($url['host']))

          { $hostname = $url['host']; }

          else if (!empty($_SERVER['SERVER_NAME']))

          { $hostname = $_SERVER['SERVER_NAME']; }

          else if (!empty($_ENV['SERVER_NAME']))

          { $hostname = $_ENV['SERVER_NAME']; }

          else if (!empty($_SERVER['HTTP_HOST']))

          { $hostname = $_SERVER['HTTP_HOST']; }

          else if (!empty($_ENV['HTTP_HOST']))

          { $hostname = $_ENV['HTTP_HOST']; }

          else

          { notify('Warning: could not find the name of this server!'); return false; }

          if (!empty($url['port']))

          { $hostname .= ':'.$url['port']; }

          else if (!empty($_SERVER['SERVER_PORT'])) {
          if ($_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443 )

          { $hostname .= ':'.$_SERVER['SERVER_PORT']; }

          }

          if (isset($_SERVER['HTTPS']))

          { $protocol = ($_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://'; }

          else if (isset($_SERVER['SERVER_PORT']))

          { # Apache2 does not export $_SERVER['HTTPS'] $protocol = ($_SERVER['SERVER_PORT'] == '443') ? 'https://' : 'http://'; }

          else

          { $protocol = 'http://'; }

          $url_prefix = $protocol.$hostname;
          $result = $url_prefix . me();
          }

          return $result;
          }

          Show
          Joacim Breiler added a comment - - edited We are running moodle on a server at "http://localserver:8088/" and a reverse proxy (pound - http://www.apsis.ch/pound/ ). Pound handles all calls to "https://example.com/moodle" and directs the traffic to to the local server. We got the same symptoms as described above by Rafael. The module chat wouldn't even load, giving a blank page... We solved the issue (we havn't noticed any side effects yet) by modifing the function qualified_me() in /lib/weblib.php. The function parses the URL from $CFG->wwwroot and uses this information together with information from $_SERVER to build an absolute url. Replace the function qualified_me() with the one below, and set "$CFG->using_reverseproxy = true" in your config.php. function qualified_me() { global $CFG; $result = $CFG->wwwroot . me(); if( !$CFG->using_reverseproxy ) { if (!empty($CFG->wwwroot)) { $url = parse_url($CFG->wwwroot); } if (!empty($url ['host'] )) { $hostname = $url['host']; } else if (!empty($_SERVER ['SERVER_NAME'] )) { $hostname = $_SERVER['SERVER_NAME']; } else if (!empty($_ENV ['SERVER_NAME'] )) { $hostname = $_ENV['SERVER_NAME']; } else if (!empty($_SERVER ['HTTP_HOST'] )) { $hostname = $_SERVER['HTTP_HOST']; } else if (!empty($_ENV ['HTTP_HOST'] )) { $hostname = $_ENV['HTTP_HOST']; } else { notify('Warning: could not find the name of this server!'); return false; } if (!empty($url ['port'] )) { $hostname .= ':'.$url['port']; } else if (!empty($_SERVER ['SERVER_PORT'] )) { if ($_SERVER ['SERVER_PORT'] != 80 && $_SERVER ['SERVER_PORT'] != 443 ) { $hostname .= ':'.$_SERVER['SERVER_PORT']; } } if (isset($_SERVER ['HTTPS'] )) { $protocol = ($_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://'; } else if (isset($_SERVER ['SERVER_PORT'] )) { # Apache2 does not export $_SERVER['HTTPS'] $protocol = ($_SERVER['SERVER_PORT'] == '443') ? 'https://' : 'http://'; } else { $protocol = 'http://'; } $url_prefix = $protocol.$hostname; $result = $url_prefix . me(); } return $result; }
          Hide
          Carlos Alexandre S. da Fonseca added a comment - - edited

          I have the same problem, but there is when i try to modify a profile, the action url in the form point to non existem address
          because of qualified_me() end me() functions

          my solutions was put de same folder name in the moodle application

          for example:

          ProxyPass /estudios http://internal_server_name/moodle
          ProxyPassReverse /estudios http://internal_server_name/moodle

          i change to :

          ProxyPass /estudios http://internal_server_name/estudios
          ProxyPassReverse /estudios http://internal_server_name/estudios

          and works, but i think the moodle don't need to have this limitation

          the problem its the me() function takes varieable from $_SERVER,
          and takes the worng name of moodle folder , in this case, returns /moodle/any_thing.php

          so the URL http://external_public_name/moodle/any_thing.php don't exist
          ( this is retuned from qualified_my() )

          if the me() function only returns de script name (any_thing.php), the qualified_me function
          could be

          $result = $CFG->wwwroot .'/'. me();

          PS: i'm using moodle 1.8 with this new formslib

          Show
          Carlos Alexandre S. da Fonseca added a comment - - edited I have the same problem, but there is when i try to modify a profile, the action url in the form point to non existem address because of qualified_me() end me() functions my solutions was put de same folder name in the moodle application for example: ProxyPass /estudios http://internal_server_name/moodle ProxyPassReverse /estudios http://internal_server_name/moodle i change to : ProxyPass /estudios http://internal_server_name/estudios ProxyPassReverse /estudios http://internal_server_name/estudios and works, but i think the moodle don't need to have this limitation the problem its the me() function takes varieable from $_SERVER, and takes the worng name of moodle folder , in this case, returns /moodle/any_thing.php so the URL http://external_public_name/moodle/any_thing.php don't exist ( this is retuned from qualified_my() ) if the me() function only returns de script name (any_thing.php), the qualified_me function could be $result = $CFG->wwwroot .'/'. me(); PS: i'm using moodle 1.8 with this new formslib
          Hide
          Jason Dilworth added a comment -

          I've been having what I think is the same problem, but using MS ISA 2006 ;/ as the reverse proxy server.
          The solution on that system was to put in a couple of Link Translations in the 'Firewall Policy' area as follows:

          replace <form action="http://(internal-name)/user/editadvanced.php" method="post"
          with <form action="https://(external-name)/user/editadvanced.php" method="post"
          replace <form action="http://(internal-name)/blog/edit.php" method="post"
          with <form action="https://(external-name)/blog/edit.php" method="post"

          These were the only 2 pages that were causing problems in version 1.8.4 - user profile and blog editing pages.

          Show
          Jason Dilworth added a comment - I've been having what I think is the same problem, but using MS ISA 2006 ;/ as the reverse proxy server. The solution on that system was to put in a couple of Link Translations in the 'Firewall Policy' area as follows: replace <form action="http://(internal-name)/user/editadvanced.php" method="post" with <form action="https://(external-name)/user/editadvanced.php" method="post" replace <form action="http://(internal-name)/blog/edit.php" method="post" with <form action="https://(external-name)/blog/edit.php" method="post" These were the only 2 pages that were causing problems in version 1.8.4 - user profile and blog editing pages.
          Hide
          James Mitchell added a comment -

          My simplier solution

          open weblib.php find me() and replace

          function me() {

          with

          function me()

          { return str_replace('/somefolder','',notreal_me()); }

          function notreal_me() {

          This renames me() to notreal_me() and then creates a new me() which replaces /somefolder with nothing..

          e.g. if your reverse proxy is from xxx.com/ to yyy.com/~xxx then you replace /somefolder with /~xxx

          You'll need to do this after every update of moodle you do..

          Show
          James Mitchell added a comment - My simplier solution open weblib.php find me() and replace function me() { with function me() { return str_replace('/somefolder','',notreal_me()); } function notreal_me() { This renames me() to notreal_me() and then creates a new me() which replaces /somefolder with nothing.. e.g. if your reverse proxy is from xxx.com/ to yyy.com/~xxx then you replace /somefolder with /~xxx You'll need to do this after every update of moodle you do..
          Hide
          Petr Škoda added a comment -

          reopening

          Show
          Petr Škoda added a comment - reopening
          Hide
          Petr Škoda added a comment -

          Reverse proxies are now supported, but the "one address" limitation will not be removed. I can be enabled in config.php - see config-dist.php
          I think it could be used probably in some load balancing configurations.

          thanks for the report, please test and reopen if needed!

          Show
          Petr Škoda added a comment - Reverse proxies are now supported, but the "one address" limitation will not be removed. I can be enabled in config.php - see config-dist.php I think it could be used probably in some load balancing configurations. thanks for the report, please test and reopen if needed!
          Hide
          Elvira Nieto added a comment -

          Hello,

          my solution is the next:

          File: /lib/formslib.php
          Function: moodleform()

          The code must be:

          function moodleform($action=null, $customdata=null, $method='post', $target='', $attributes=null) {
          if (empty($action))

          { # @author: Elvira Nieto <aquesabenlasnubes@gmail.com> # $action = strip_querystring(qualified_me()); #Change it by: $action = basename($_SERVER['SCRIPT_NAME']); # The rest code will not change ..... }

          Not forget that $CFG->wwwroot variable must be configured in config.php

          Best Regards

          Show
          Elvira Nieto added a comment - Hello, my solution is the next: File: /lib/formslib.php Function: moodleform() The code must be: function moodleform($action=null, $customdata=null, $method='post', $target='', $attributes=null) { if (empty($action)) { # @author: Elvira Nieto <aquesabenlasnubes@gmail.com> # $action = strip_querystring(qualified_me()); #Change it by: $action = basename($_SERVER['SCRIPT_NAME']); # The rest code will not change ..... } Not forget that $CFG->wwwroot variable must be configured in config.php Best Regards
          Hide
          David Puente Bautista added a comment -

          Is there any "official answer" to this topic for 1.9.8 release? It seems to be unanswered until we have Moodle 2.0. Thanks!!!

          Show
          David Puente Bautista added a comment - Is there any "official answer" to this topic for 1.9.8 release? It seems to be unanswered until we have Moodle 2.0. Thanks!!!
          Hide
          Petr Škoda added a comment -

          no fix is planned for 1.9.x because the required changes might create serious regressions and also it would be relative difficult/time consuming, sorry

          Show
          Petr Škoda added a comment - no fix is planned for 1.9.x because the required changes might create serious regressions and also it would be relative difficult/time consuming, sorry
          Hide
          Petr Škoda added a comment -

          reclosing

          Show
          Petr Škoda added a comment - reclosing

            People

            • Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: