diff --git a/db/install.php b/db/install.php
index 4ca1457ba592203f8004f5cbad4c34735bdea607..27e8fa20b7889a17ff1a665228b16e8f9f516aa5 100644
--- a/db/install.php
+++ b/db/install.php
@@ -77,7 +77,8 @@ function xmldb_qtype_stack_install() {
         set_config('casdebugging', 1, 'qtype_stack');
         set_config('mathsdisplay', 'mathjax', 'qtype_stack');
 
-        if (!defined('QTYPE_STACK_TEST_CONFIG_PLATFORM') || !in_array(QTYPE_STACK_TEST_CONFIG_PLATFORM, ['server', 'none'])) {
+        if (!defined('QTYPE_STACK_TEST_CONFIG_PLATFORM')
+                    || !in_array(QTYPE_STACK_TEST_CONFIG_PLATFORM, ['server', 'server-proxy', 'none'])) {
             list($ok, $message) = stack_cas_configuration::create_auto_maxima_image();
             if (!$ok) {
                 throw new coding_exception('maxima_opt_auto creation failed.', $message);
diff --git a/db/upgrade.php b/db/upgrade.php
index e2a6062f1d3faba835cb9be5e8412c90d5fad2c4..9afe4f3393e01a1b4ffd8c98d10215ffd1190c1f 100644
--- a/db/upgrade.php
+++ b/db/upgrade.php
@@ -968,7 +968,7 @@ function xmldb_qtype_stack_upgrade($oldversion) {
     // If appropriate, clear the CAS cache and re-generate the image.
     if ($latestversion != $currentlyusedversion) {
         stack_cas_connection_db_cache::clear_cache($DB);
-        if (get_config('qtype_stack', 'platform') !== 'server') {
+        if (!in_array(get_config('qtype_stack', 'platform'), ['server', 'server-proxy'])) {
             $pbar = new progress_bar('healthautomaxopt', 500, true);
             list($ok, $message) = stack_cas_configuration::create_auto_maxima_image();
             $pbar->update(500, 500, get_string('healthautomaxopt', 'qtype_stack', array()));
diff --git a/lang/en/qtype_stack.php b/lang/en/qtype_stack.php
index 0e35e7e281acec9e30a645655e09cd9b073fe01f..db97d6429ed219f758c216beee81da30bc8eae1e 100644
--- a/lang/en/qtype_stack.php
+++ b/lang/en/qtype_stack.php
@@ -457,6 +457,7 @@ $string['settingplatformtypelinux'] = 'Linux';
 $string['settingplatformtypelinuxoptimised'] = 'Linux (optimised)';
 $string['settingplatformtypewin']  = 'Windows';
 $string['settingplatformtypeserver'] = 'Server';
+$string['settingplatformtypeserverproxy'] = 'Server (via proxy)';
 $string['settingplatformmaximacommand'] = 'Maxima command';
 $string['settingplatformmaximacommand_desc'] = 'If this is blank, STACK will make an educated guess as to where to find Maxima. If that fails, this should be set to the full path of the maxima or maxima-optimised executable.  Use for development and debugging only. Do not use on a production system: use optimised, or better, the Maxima Pool option.';
 $string['settingplatformmaximacommandopt'] = 'Optimised Maxima command';
@@ -629,6 +630,7 @@ $string['healthchecklatexmathjax'] = 'STACK relies on the Moodle MathJax filter.
 $string['healthcheckmathsdisplaymethod'] = 'Maths display method being used: {$a}.';
 $string['healthcheckmaximabat'] = 'The maxima.bat file is missing';
 $string['healthcheckmaximabatinfo'] = 'This script tried to automatically copy the maxima.bat script from inside "C:\Program files\Maxima-1.xx.y\bin" into "{$a}\stack". However, this seems not to have worked. Please copy this file manually.';
+$string['healthcheckproxysettings'] = '<strong>Warning:</strong> Moodle is set to use a proxy server but calls to maxima are bypassing this. Switch platform from "server" to "server (via proxy)" to route calls via the proxy server or add the maxima server to $CFG->proxybypass to make the bypass explicit. STACK should still function for now even if you do not make a change but Moodle proxy settings will be enforced in a later version.';
 $string['healthchecksamplecas'] = 'The derivative of {@ x^4/(1+x^4) @} is \[ \frac{d}{dx} \frac{x^4}{1+x^4} = {@ diff(x^4/(1+x^4),x) @}. \]';
 $string['healthcheckconnectunicode'] = 'Trying to send unicode to the CAS';
 $string['healthchecksamplecasunicode'] = 'Confirm if unicode is supported: \(\forall\) should be displayed {@unicode(8704)@}.';
diff --git a/settings.php b/settings.php
index 50a9c4402316516f0629771fc51fce675e16d533..449dc6684cf9d881289205c06e014f2f7d7e267b 100644
--- a/settings.php
+++ b/settings.php
@@ -61,11 +61,13 @@ $settings->add(new admin_setting_heading('maixmasettingsheading',
 $settings->add(new admin_setting_configselect('qtype_stack/platform',
         get_string('settingplatformtype', 'qtype_stack'),
         // Note, install.php tries to auto-detect Windows installs, and set the default appropriately.
-        get_string('settingplatformtype_desc', 'qtype_stack'), null, array(
+        get_string('settingplatformtype_desc', 'qtype_stack'), null, [
                 'linux'            => get_string('settingplatformtypelinux',                'qtype_stack'),
                 'linux-optimised'  => get_string('settingplatformtypelinuxoptimised',       'qtype_stack'),
                 'win'              => get_string('settingplatformtypewin',                 'qtype_stack'),
-                'server'           => get_string('settingplatformtypeserver',              'qtype_stack'))));
+                'server'           => get_string('settingplatformtypeserver',              'qtype_stack'),
+                'server-proxy'     => get_string('settingplatformtypeserverproxy',         'qtype_stack'),
+        ]));
 
 $settings->add(new admin_setting_configselect('qtype_stack/maximaversion',
         get_string('settingcasmaximaversion', 'qtype_stack'),
diff --git a/stack/cas/connector.class.php b/stack/cas/connector.class.php
index 8f9be8fb8b81546dfe46791662f38f27488cac7f..617dd132883822679ec18363c3288ce9489918cf 100644
--- a/stack/cas/connector.class.php
+++ b/stack/cas/connector.class.php
@@ -177,7 +177,7 @@ abstract class stack_cas_connection_base implements stack_cas_connection {
         $cmd = $settings->maximacommand;
         if ($settings->platform == 'linux-optimised') {
             $cmd = $settings->maximacommandopt;
-        } else if ($settings->platform == 'server') {
+        } else if (in_array($settings->platform, ['server', 'server-proxy'])) {
             $cmd = $settings->maximacommandserver;
         }
         if ('' === trim($cmd)) {
diff --git a/stack/cas/connector.healthcheck.class.php b/stack/cas/connector.healthcheck.class.php
index 3b6b28445e20e5c4c3b08bee0cce4a93ea3f6b3f..8b1ea03617e8e0b58a1d39ba3748fb4d798844ff 100644
--- a/stack/cas/connector.healthcheck.class.php
+++ b/stack/cas/connector.healthcheck.class.php
@@ -117,8 +117,17 @@ class stack_cas_healthcheck {
                 $test['details'] = html_writer::tag('pre', $connection->get_maxima_available());
                 $this->tests[] = $test;
                 break;
+            case 'server':
+                if (!empty($CFG->proxyhost) && !is_proxybypass(get_config('qtype_stack', 'maximacommandserver'))) {
+                    $test = [];
+                    $test['tag'] = 'healthcheckproxysettings';
+                    $test['result'] = null;
+                    $test['summary'] = stack_string('healthcheckproxysettings');
+                    $this->tests[] = $test;
+                    break;
+                }
             default:
-                // Server/optimised.
+                // Server-proxy/optimised.
                 // TODO: add in any specific tests for these setups?
                 break;
         }
diff --git a/stack/cas/connector.server_proxy.class.php b/stack/cas/connector.server_proxy.class.php
new file mode 100644
index 0000000000000000000000000000000000000000..e83de1d1e411c4fcb1cc313720b31869e7ea78b6
--- /dev/null
+++ b/stack/cas/connector.server_proxy.class.php
@@ -0,0 +1,134 @@
+<?php
+// This file is part of Stack - http://stack.maths.ed.ac.uk/
+//
+// Stack is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Stack is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Stack.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Connection via proxy to Maxima running in a tomcat-server using the MaximaPool-servlet.
+ * This version handles transfer of the plots generated on possibly remote servlet.
+ * For details of this see https://github.com/maths/stack_util_maximapool/
+ *
+ * @copyright  2012 The University of Birmingham
+ * @copyright  2012 Aalto University - Matti Harjula
+ * @copyright  2014 Loughborough University
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class stack_cas_connection_server_proxy extends stack_cas_connection_base {
+
+    protected function guess_maxima_command($path) {
+        return 'http://localhost:8080/MaximaPool/MaximaPool';
+    }
+
+    protected function call_maxima($command) {
+        global $CFG;
+        $err = '';
+
+        $starttime = microtime(true);
+
+        $request = curl_init($this->command);
+
+        $postdata = 'input=' . urlencode($command) .
+                '&timeout=' . ($this->timeout * 1000) .
+                '&ploturlbase=!ploturl!' .
+                '&version=' . stack_connection_helper::get_required_stackmaxima_version();
+
+        curl_setopt($request, CURLOPT_POST, true);
+        curl_setopt($request, CURLOPT_POSTFIELDS, $postdata);
+        curl_setopt($request, CURLOPT_RETURNTRANSFER, true);
+        curl_setopt($request, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
+        if (!empty($this->serveruserpass)) {
+            curl_setopt($request, CURLOPT_USERPWD, $this->serveruserpass);
+        }
+
+        // Set extra curl options to deal with using proxy server.
+        // If Moodle proxy settings are not set or maxima is in the
+        // proxy bypass then, this will just
+        // carry on as if we're using the server platform.
+        // Based on auth/cas/auth.php/auth_plugin_cas->connectCAS() checks.
+        if (!empty($CFG->proxyhost) && !is_proxybypass($this->command)) {
+            curl_setopt($request, CURLOPT_PROXY, $CFG->proxyhost);
+            if (!empty($CFG->proxyport)) {
+                curl_setopt($request, CURLOPT_PROXYPORT, $CFG->proxyport);
+            }
+            if (!empty($CFG->proxytype)) {
+                // Only set CURLOPT_PROXYTYPE if it's something other than the curl-default http.
+                if ($CFG->proxytype == 'SOCKS5') {
+                    curl_setopt($request, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
+                }
+            }
+            if (!empty($CFG->proxyuser) && !empty($CFG->proxypassword)) {
+                curl_setopt($request, CURLOPT_PROXYUSERPWD, $CFG->proxyuser.':'.$CFG->proxypassword);
+                if (defined('CURLOPT_PROXYAUTH')) {
+                    // Use any proxy authentication if required - PHP 5.1+.
+                    curl_setopt($request, CURLOPT_PROXYAUTH, CURLAUTH_BASIC | CURLAUTH_NTLM);
+                }
+            }
+        }
+
+        $ret = curl_exec($request);
+
+        $timedout = false;
+
+        // The servlet will return 416 if the evaluation hits the timelimit.
+        if (curl_getinfo($request, CURLINFO_HTTP_CODE) != '200') {
+            if (curl_getinfo($request, CURLINFO_HTTP_CODE) != '416') {
+                throw new Exception('stack_cas_connection: MaximaPool error: '.curl_getinfo($request, CURLINFO_HTTP_CODE));
+            } else {
+                $timedout = true;
+            }
+        }
+
+        // Did we get files?
+        if (strpos(curl_getinfo($request, CURLINFO_CONTENT_TYPE), "text/plain") === false) {
+            // We have to save the zip file on local disk before opening.
+            $ziptemp = tempnam($CFG->dataroot . '/stack/tmp/', 'zip');
+            file_put_contents($ziptemp, $ret);
+
+            // Loop over the contents of the zip.
+            $zip = new ZipArchive();
+            $zip->open($ziptemp);
+            for ($i = 0; $i < $zip->numFiles; $i++) {
+                $filenameinzip = $zip->getNameIndex($i);
+
+                if ($filenameinzip === 'OUTPUT') {
+                    // This one contains the output from maxima.
+                    $ret = $zip->getFromIndex($i);
+
+                } else {
+                    // Otherwise this is a plot.
+                    $filename = $CFG->dataroot . "/stack/plots/" . $filenameinzip;
+                    file_put_contents($filename, $zip->getFromIndex($i));
+                }
+            }
+
+            // Clean up.
+            $zip->close();
+            unlink($ziptemp);
+        }
+
+        curl_close($request);
+
+        $now = microtime(true);
+
+        $this->debug->log('Timings', "Start: {$starttime}, End: {$now}, Taken = ".($now - $starttime));
+
+        // Add sufficient closing ]'s to allow something to be un-parsed from the CAS.
+        // WARNING: the string 'The CAS timed out' is used by the cache to serach for a timout occurance.
+        if ($timedout) {
+            $ret .= ' The CAS timed out. ] ] ] ]';
+        }
+
+        return $ret;
+    }
+}
diff --git a/stack/cas/connectorhelper.class.php b/stack/cas/connectorhelper.class.php
index e5ccffcdfe4bd36eb0569a8ddb9b372497b8b93e..3b90b5a2e0c8b74d971672c558228035352bd6a3 100644
--- a/stack/cas/connectorhelper.class.php
+++ b/stack/cas/connectorhelper.class.php
@@ -67,6 +67,10 @@ abstract class stack_connection_helper {
                 require_once(__DIR__ . '/connector.server.class.php');
                 $connection = new stack_cas_connection_server(self::$config, $debuglog);
                 break;
+            case 'server-proxy':
+                require_once(__DIR__ . '/connector.server_proxy.class.php');
+                $connection = new stack_cas_connection_server_proxy(self::$config, $debuglog);
+                break;
             case 'tomcat':
             case 'tomcat-optimised':
                 throw new stack_exception('stack_connection_helper: ' .
@@ -261,6 +265,7 @@ abstract class stack_connection_helper {
                 break;
 
             case 'server':
+            case 'server-proxy':
                 $fix = stack_string('healthchecksstackmaximaversionfixserver');
                 break;