How to operate Moodle with AWS load balancer (https from internet but http behind)

Aug 26, 2020 PHP AWS Moodle

First, make the following preparations.

Certificate (may be issued by ALB’s ACM or may be your own) efs Set session stickiness (2 hours) in ALB By the way, session stickiness for a few hours may not be so good. When the connected machine goes down, I feel like Gateway Timeout. Changed to 5 minutes.

I used this area as a reference for AWS ALB. (reference) https://recipe.kc-cloud.jp/archives/11084

httpd.conf is set to operate with http In config.php, describe as $CFG->sslproxy = true;. This makes me assume that Moodle is working on https (actually it works on http). https://moodle.org/mod/forum/discuss.php?d=351002 see remarks.

Instance where Moodle is installed (moodledata is set to efs and DB is set to RDS) As a test, I tried to migrate the installed Moodle to /mnt/nfs/html/moodle. Because when you install a new plugin, you have to install it on all instances, so one place is more efficient. In short, I put moodle and moodledata in /mnt/nfs/html, but it was very slow. So I decided to install Moodle on each of the two machines. See here for the meaning of the options https://www.skyarch.net/blog/?p=16175

By the way, in order to make ALB recognize it, I wrote the following at the top of config.php. The reason why this is necessary is that there is a redirect process next, which causes HealthChecker to fail and the Listener to get a 303 error.

$http_user_agent = $_SERVER['HTTP_USER_AGENT'];
if (strstr($http_user_agent, "ELB-HealthChecker")) {
    echo "ok";
    die;
}

The speed is a bit slow, so I installed memcached on each machine. https://blog.lawrencemcdaniel.com/install-memcached-on-amazon-linux/ Moodle includes a memcached plugin by default, so you can use it. When I check /etc/sysconfig/memcached, it seems to have 16M memory cache. I also edited [Sessions] in /etc/php.ini so that memcached has a session. ;;session.save_handler = files session.save_handler = memcached session.save_path = “127.0.0.1:11211” I rebooted the machine. I still feel late. I realized later that I didn’t start memcached. systemctl enable memcached systemctl start memcached systemctl status memcached I ran the following command, but nothing comes out. It may not be working.

memcached-tool localhost:11211 display

There was a link called Plugin -> Caching -> memcached, so I clicked it. There was an example of 127.0.0.1:11211, so I entered it there. No, I opened the settings on it and tried to add the Memcached store with the name “Moodle_cache_store” store setting “localhost”.

Then, I could confirm that memcached is working like this.

# memcached-tool localhost:11211 display
  # Item_Size Max_age Pages Count Full? Evicted Evict_Time OOM
  1 96B 17s 1 1 yes 0 0 0

# memcached-tool localhost:11211 dump
Dumping memcache contents
  Number of buckets: 1
  Number of items :1
Dumping bucket 1-1 total items

When I dumped, the display line disappeared.

I clicked on the performance test, clicked 100000, and got 504 Gateway Time-out. I tried setting count=10000 in the URI. I can’t connect, so I restarted the server. I found that there is a “known cache definition”, and when I made the item there, Moodle_cache_store, which was created earlier, it became as follows.

# memcached-tool localhost:11211 display
  # Item_Size Max_age Pages Count Full? Evicted Evict_Time OOM
  1 96B 27s 1 1 yes 0 0 0
  3 152B 31s 1 2 yes 0 0 0
  4 192B 37s 1 25 yes 0 0 0
  5 240B 30s 1 7 yes 0 0 0
  7 384B 38s 1 2 yes 0 0 0
  8 480B 38s 1 2 yes 0 0 0
  9 600B 38s 1 4 yes 0 0 0
 12 1.2K 29s 1 1 yes 0 0 0
 14 1.8K 31s 1 1 yes 0 0 0
 15 2.3K 31s 1 1 yes 0 0 0
 20 6.9K 38s 1 1 yes 0 0 0
 22 10.8K 38s 1 1 yes 0 0 0

In addition, I went to “Edit mapping” at the bottom of the setting page and changed “Application” to Moodle_cache_store.

# memcached-tool localhost:11211 display
  # Item_Size Max_age Pages Count Full? Evicted Evict_Time OOM
  1 96B 2s 1 1 yes 0 0 0
  2 120B 25s 1 12 yes 0 0 0
  3 152B 25s 1 14 yes 0 0 0
  4 192B 126s 1 44 yes 0 0 0
  5 240B 299s 1 15 yes 0 0 0
  6 304B 25s 1 18 yes 0 0 0
  7 384B 126s 1 33 yes 0 0 0
  8 480B 123s 1 33 yes 0 0 0
  9 600B 25s 1 22 yes 0 0 0
 10 752B 25s 1 23 yes 0 0 0
 11 944B 25s 1 20 yes 0 0 0
 12 1.2K 126s 1 24 yes 0 0 0
 13 1.4K 25s 1 40 yes 0 0 0
 14 1.8K 126s 1 51 yes 0 0 0
 15 2.3K 25s 1 31 yes 0 0 0
 16 2.8K 25s 1 16 yes 0 0 0
 17 3.5K 25s 1 12 yes 0 0 0
 18 4.4K 25s 1 11 yes 0 0 0
 19 5.5K 25s 1 14 yes 0 0 020 6.9K 25s 1 8 yes 0 0 0
 21 8.7K 25s 1 12 yes 0 0 0
 22 10.8K 25s 1 10 yes 0 0 0
 23 13.6K 25s 1 3 yes 0 0 0
 24 16.9K 25s 1 5 yes 0 0 0
 25 21.2K 25s 1 6 yes 0 0 0
 26 26.5K 25s 1 2 yes 0 0 0
 27 33.1K 25s 1 2 yes 0 0 0
 28 41.4K 25s 1 2 yes 0 0 0
 31 80.9K 25s 1 1 yes 0 0 0
 32 101.1K 25s 1 1 yes 0 0 0

Much faster! (reference) http://taka512.hatenablog.com/entry/20110830/1314698515

I tried to make each machine have $CFG->localcachedir by referring to the following. $CFG->localcachedir = “/var/www/html/moodledata/localcachdir”; https://moodle.org/mod/forum/discuss.php?d=351002 For instance, t3.small is enough. RDS should also be t3.small. Both EC2 and RDS are still acceptable with t3.medium. By the way, if you try to use EC2 instance and RDS as t3.medium, it feels pretty good. It’s a little expensive.

After all, the config.php looks like this: As you can see in the settings, moodledata basically uses the efs space and only localcachedir Use the resources of each EC2.

unset($CFG);
global $CFG;
$CFG = new stdClass();

$CFG->dbtype ='mariadb';
$CFG->dblibrary ='native';
$CFG->dbhost ='database-1.xxxxxxxx.ap-northeast-1.rds.amazonaws.com';
$CFG->dbname ='moodle';
$CFG->dbuser ='admin';
$CFG->dbpass ='xxxxxxxx';
$CFG->prefix ='mdl_';
$CFG->dboptions = array (
  'dbpersist' => 0,
  'dbport' => ``,
  'dbsocket' => ``,
  'dbcollation' =>'utf8mb4_unicode_ci',
);

// This is needed to make believe SSL is used by Moodle.
$CFG->sslproxy = true;
$CFG->wwwroot ='https://xxxx.xxx';
$CFG->dataroot ='/mnt/efs/html/moodledata';
$CFG->localcachedir ='/var/www/html/moodledata/localcachedir';
$CFG->admin ='admin';

$CFG->directorypermissions = 02777;

require_once(__DIR__ .'/lib/setup.php');

I also tried enabling SELinux. Moodledata is nfs_t, so I executed the following command.

setsebool -P httpd_use_nfs on

(reference) https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/selinux_users_and_administrators_guide/sect-managing_confined_services-the_apache_http_server-configuration_examples

When I restarted, I got an error that the database could not be accessed. The following command was executed.

setsebool -P httpd_can_network_connect_db 1

(reference) https://serverfault.com/questions/240015/how-do-i-allow-mysql-connections-through-selinux

I still can’t get the error. After checking, it was as follows.

# less /var/log/audit/audit.log | grep denied

type=AVC msg=audit(1590352121.329:94): avc: denied {name_connect} for pid=2318 comm="php-fpm" dest=3306 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:mysqld_port_t:s0 tclass=tcp_socket permissive=0

I also ran the following command:

setsebool -P httpd_can_network_connect 1

(reference) https://dev.classmethod.jp/articles/redhat-selinx-might-block-network-connection-to-servers-from-apache-php/

After restarting and accessing the web, the following display was displayed.

Invalid permissions detected when trying to create a directory. Turn debugging on for further details.

When I checked it, I got the following error.

type=AVC msg=audit(1590352587.167:90): avc: denied {write} for pid=2347 comm="php-fpm” name="localcachedir” dev="nvme0n1p1” ino=239410 scontext=system_u:system_r:httpd_t: s0 tcontext=system_u:object_r:httpd_sys_content_t:s0 tclass=dir permissive=0

# vim /etc/selinux/targeted/contexts/files/file_contexts.local

/var/www/html/moodledata(/.*)? system_u:object_r:httpd_sys_rw_content_t:s0

# restorecon -R -v /var/www/html/moodledata

Rebooted and confirmed.

# ls -laZ /var/www/html/moodledata

The following label is attached and the error seems to have disappeared.

httpd_sys_rw_content_t

httpd.conf. As you can see, http communication is performed.

ServerRoot "/etc/httpd"
Listen 80
Include conf.d/modules.conf
Include conf.d/php.conf
User apache
Group apache
ServerName xxxx.xxx:80
ServerAdmin [email protected]
<Directory />
    AllowOverride none
    Require all denied
</Directory>
<Directory "/var/www">
    AllowOverride None
# Allow open access:
    Require all granted
</Directory>
<Directory "/var/www/html">
    Options FollowSymLinks
    AllowOverride None
    Require all granted
</Directory>
<IfModule dir_module>
    DirectoryIndex index.php
</IfModule>
<Files ".ht*">
    Require all denied
</Files>
ErrorLog "logs/error_log"
LogLevel warn
<IfModule log_config_module>
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
    LogFormat "%h %l %u %t \"%r\" %>s %b" common
    <IfModule logio_module>
      LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
    </IfModule>
    CustomLog "logs/access_log" combined
</IfModule>
<IfModule mime_module>
    TypesConfig /etc/mime.types
    AddType application/x-compress .Z
    AddType application/x-gzip .gz .tgz
    AddType text/html .shtml
    AddOutputFilter INCLUDES .shtml
</IfModule>
AddDefaultCharset UTF-8<IfModule mime_magic_module>
    MIMEMagicFile conf/magic
</IfModule>
EnableSendfile on
<IfModule mod_http2.c>
    Protocols h2 h2c http/1.1
</IfModule>
IncludeOptional conf.d/*.conf
TraceEnable off
Header append X-FRAME-OPTIONS "SAMEORIGIN"
ServerTokens ProductOnly
ServerSignature off
<VirtualHost *:80>
    ServerName xxxx.xxx:80
    DocumentRoot /var/www/html/moodle
</VirtualHost>

modules.conf です。

#00-base.conf
LoadModule alias_module modules/mod_alias.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule dir_module modules/mod_dir.so
LoadModule headers_module modules/mod_headers.so
LoadModule http2_module modules/mod_http2.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule logio_module modules/mod_logio.so
LoadModule mime_module modules/mod_mime.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
LoadModule unixd_module modules/mod_unixd.so
#00-mpm.conf
LoadModule mpm_event_module modules/mod_mpm_event.so
#00-proxy.conf
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
#00-ssl.conf
LoadModule ssl_module modules/mod_ssl.so
#00-systemd.conf
LoadModule systemd_module modules/mod_systemd.so

AWS の Memcached を使うには、セキュリティグループを作成して、web サーバのセキュリティグループをソースとする。 そして、マシンには、ライブラリモジュールをインストールする必要がある。 まずは、ライブラリをダウンロードする。

# cd
# wget https://elasticache-downloads.s3.amazonaws.com/ClusterClient/PHP-7.3/latest-64bit

解凍する

#tar -zxvf latest-64bit

ライブラリディレクトリにコピーする。

#cp amazon-elasticache-cluster-client.so /usr/lib64/php/modules

確認する。

# ls /usr/lib64/php/modules
amazon-elasticache-cluster-client.so  exif.so      igbinary.so   msgpack.so    pdo_sqlite.so  sockets.so    wddx.so       zip.so
bz2.so                                fileinfo.so  intl.so       mysqli.so     phar.so        sqlite3.so    xmlreader.so
calendar.so                           ftp.so       json.so       mysqlnd.so    posix.so       sysvmsg.so    xmlrpc.so
ctype.so                              gd.so        ldap.so       opcache.so    shmop.so       sysvsem.so    xml.so
curl.so                               gettext.so   mbstring.so   pdo_mysql.so  simplexml.so   sysvshm.so    xmlwriter.so
dom.so                                iconv.so     memcached.so  pdo.so        soap.so        tokenizer.so  xsl.so

php.ini に追記する。

# vim /etc/php.ini
extension=amazon-elasticache-cluster-client.so

再起動する。

# shutdown -r now

(参考) https://aws.amazon.com/jp/elasticache/memcached/wordpress-with-memcached/

(備考) Moodle vim +811 /var/www/html/moodle/lib/setuplib.php

initialize_fullme() を見ると、config.php に以下の設定をすれば良い事が分かった。

$CFG->sslproxy = true;