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

      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

        Gliffy Diagrams

          Issue Links

            Activity

            Hide
            Petr Skoda 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 Skoda 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 Skoda 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 Skoda 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 Skoda added a comment -

            reopening

            Show
            Petr Skoda added a comment - reopening
            Hide
            Petr Skoda 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 Skoda 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 Skoda 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 Skoda 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 Skoda added a comment -

            reclosing

            Show
            Petr Skoda added a comment - reclosing

              People

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

                Dates

                • Created:
                  Updated:
                  Resolved: