Instalación de Moodle con NGINX + PHP-FPM + POSTGRESQL + MEMCACHED en CentOS 7

Actualizamos el Sistema Operativo

$ yum update -y
$ yum install epel-release -y

Instalar utilitarios para moodle

$ yum install aspell rsync unzip ghostscript graphviz -y
$ #HABILITAR FIREWALL
$ firewall-cmd --add-port 80/tcp --permanent
$ firewall-cmd --add-port 443/tcp --permanent

Instalar MEMCACHED

$ yum install memcached -y
$ systemctl enable memcached
$ systemctl start memcached
$ vim /etc/memcached.conf

Instalar PHP-FPM

$ yum install php-fpm php-curl php-pgsql php-zip php-xml php-mbstring \
$ php-gd php-intl php-xmlrpc php-soap php-pecl-apcu php-pecl-memcached php-json php-opcache pecl install igbinary
$ systemctl enable php-fpm
$ systemctl start php-fpm
$ vim /etc/php.ini
$ vim /etc/php-fpm/www.conf

Instalar NGINX

$ yum install nginx -y
$ systemctl enable nginx
$ systemctl start nginx
$ chown nginx:root /var/cache/nginx/ -R
$ vim /etc/nginx/nginx.conf

Instalar PostgreSQL 9.5

$ sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt-get $(lsb_release -cs)-pgdg main" \
$ > /etc/apt/sources.list.d/pgdg.list'
$ cat /etc/apt/sources.list.d/pgdg.list
$ wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -
$ apt-get update -y
$ apt-get install postgresql-client-9.5 postgresql-9.5 postgresql-common-9.5 postgresql-contrib-9.5 -y
$ systemctl enable postgresql-9.5
$ systemctl start postgresql-9.5
$ vim /etc/postgresql/9.5/main/pg_hba.conf
$ vim /etc/postgresql/9.5/main/postgresql.conf

Crear base de datos y usuario para MOODLE

$ su - postgres
$ psql -c "CREATE DATABASE moodle;CREATE USER usuario WITH ENCRYPTED PASSWORD 'UNA CONTRASEÑA';GRANT ALL PRIVILEGES ON DATABASE moodle TO usuario;"
$ exit

Descarga y despliegue de MOODLE

$ mkdir -p /var/www/plataforma/moodledata
$ chown nginx: /var/www/plataforma
$ cd /var/www/plataforma
$ wget https://download.moodle.org/download.php/direct/stable39/moodle-latest-39.zip
$ unzip moodle-latest-39.zip
$ rm moodle-latest-39.zip -f
$ vim /etc/nginx/conf.d/moodle.conf
$ vim /var/www/plataforma/moodle/config.php

Certificado gratuito de LET’S ENCRYPT

$ add-apt-repository ppa:certbot/certbot
$ yum update -y
$ yum install certbot python-certbot-nginx -y
$ add-apt-repository ppa:certbot/certbot
$ add-apt-repository universe
$ certbot certonly --webroot -d UNDOMINIO.com \
$ -d www.UNDOMINIO.com \
$ --rsa-key-size 4096 \
$ --webroot-path /var/www/plataforma/moodle

Configuración de Nginx

server {
  listen UNAIP:80;
  return 301 https://$host$request_uri;
}
server {
    listen      UNAIP:443 ssl http2;
    server_name UNDOMINIO.com;
    ssl_certificate      /etc/letsencrypt/live/UNDOMINIO.com/fullchain.pem;
    ssl_certificate_key  /etc/letsencrypt/live/UNDOMINIO.com/privkey.pem;
    add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
    return 301 https://www.UNDOMINIO.com$request_uri;
}
server {
    listen      UNAIP:443 ssl http2;
    server_name www.UNDOMINIO.com;
    root        /var/www/plataforma/moodle;
    index       index.php index.html index.htm;
    access_log  /var/log/nginx/domains/UNDOMINIO.com.log combined;
    access_log  /var/log/nginx/domains/UNDOMINIO.com.bytes bytes;
    error_log   /var/log/nginx/domains/UNDOMINIO.com.error.log error;

    ssl_certificate      /etc/letsencrypt/live/UNDOMINIO.com/fullchain.pem;
    ssl_certificate_key  /etc/letsencrypt/live/UNDOMINIO.com/privkey.pem;

    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }

    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }

    location ~* \.(txt|log)$ {
        allow 192.168.0.0/16;
        deny all;
    }

    location ~ \..*/.*\.php$ {
        return 403;
    }

    # No no for private
    location ~ ^/sites/.*/private/ {
        return 403;
    }

    location ~* "/\.(htaccess|htpasswd)$" {
        deny    all;
        return  404;
    }

    rewrite ^/(.*.php)(/)(.*)$ /$1?file=/$3 last;

    location / {

        location ~* ^.+\.(jpeg|jpg|png|gif|bmp|ico|svg|css|js|woff|woff2)$ {
            etag on;
            if_modified_since exact;
            expires        365d;
            access_log     off;
            add_header Pragma "public";
            add_header Cache-Control "max-age=31536000, public";
            fastcgi_hide_header "Cache-Control";
        }

       location ~ [^/]\.php(/|$) {
           root                                 /var/www/plataforma/moodle;
           fastcgi_split_path_info              ^(.+\.php)(/.*)$;
           fastcgi_index                        index.php;
           fastcgi_pass                         unix:/var/run/php72-fpm.sock;
           include                              /etc/nginx/mime.types;
           include                              /etc/nginx/fastcgi_params;
           fastcgi_param   PATH_INFO            $fastcgi_path_info;
           fastcgi_param   SCRIPT_FILENAME      $document_root$fastcgi_script_name;
		   fastcgi_connect_timeout 300s;
           fastcgi_read_timeout 300s;
           fastcgi_send_timeout 300s;
       }
    }

    location /dataroot/ {
        internal;
        alias  /var/www/plataforma/moodledata/;
    }

    location ~* "/\.(htaccess|htpasswd)$" {
        deny    all;
        return  404;
    }

    error_page  404 /error/index.php;

    #Soporte TLS 
    ssl_protocols TLSv1.2 TLSv1.3;

    #Cabeceras
    add_header X-Frame-Options SAMEORIGIN;
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";

	#Politicas de Seguridad de Contenido
    add_header Content-Security-Policy "form-action 'self'; manifest-src https:;base-uri 'self';connect-src 'self' https:;frame-src https:;style-src 'self' 'unsafe-inline' *.googleapis.com;media-src 'self';script-src 'self' 'unsafe-eval' 'unsafe-inline' cdn.jsdelivr.net *.youtube.com *.googleapis.com *.google-analytics.com;worker-src https: blob:;font-src 'self' data: *.googleapis.com fonts.gstatic.com;frame-ancestors 'self' *.youtube.com;default-src 'none';object-src 'none';img-src 'self' data: blob:";

    #bloquear sparmmer
    if ( $http_referer ~* (babes|forsale|girl|jewelry|love|nudit|organic|poker|porn|sex|teen) ){
        return 403;
    }
    #Bloquear Agentes y robots
     if ($http_user_agent ~* (acunetix|sqlmap|nikto|metasploit|hping3|maltego|nessus|webscarab|sqlsus|sqlninja|aranchni|netsparker|nmap|dirbuster|zenmap|hydra|owasp-zap|w3af|vega|burpsuite|aircrack-ng|whatweb|medusa) ) {
        return 403;
    }
    ## Block some nasty robots
    if ($http_user_agent ~ (msnbot|Purebot|Baiduspider|Lipperhey|Mail.Ru|scrapbot) ) {
        return 403;
    }
    ## Block download agent
    if ($http_user_agent ~* LWP::Simple|wget|libwww-perl) {
        return 403;
    }
}

Configuración de PHP-FPM

[www]
listen = /var/run/php72-fpm.socket
listen.owner = nginx
listen.group = nginx

user=nginx
group=nginx

pm = ondemand
pm.max_children = 2
pm.max_requests = 4000
pm.process_idle_timeout = 10s

php_value[upload_max_filesize] = 20M
php_value[post_max_size] = 28M
php_value[max_execution_time] = 180
php_value[memory_limit] = 512M
php_value[date.timezone] = America/Guayaquil
php_value[session.cookie_httponly] = 1

env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin

Configuración de Moodle

<?php  // Moodle configuration file

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

$CFG->dbtype    = 'pgsql';
$CFG->dblibrary = 'native';
$CFG->dbhost    = 'localhost';
$CFG->dbname    = 'moodle';
$CFG->dbuser    = 'usuario';
$CFG->dbpass    = 'UNA CONTRASEÑA';
$CFG->prefix    = 'prefix_';
$CFG->dboptions = array (
  'dbpersist' => 0,
  'dbport' => 5432,
  'dbsocket' => '',
);

$CFG->wwwroot   = 'https://UNDOMINIO.com';
$CFG->dataroot  = '/var/www/plataforma/moodledata/';
$CFG->admin     = 'admin';

$CFG->xsendfile = 'X-Accel-Redirect';
$CFG->xsendfilealiases = array(
            '/dataroot/' => $CFG->dataroot
    );

$CFG->directorypermissions = 0777;
#$CFG->preventexecpath = true;

/********************************************/
/************ MEMCACHED SETUP ***************/
$CFG->session_handler_class = '\core\session\memcached';
$CFG->session_memcached_save_path = '127.0.0.1:11211';
$CFG->session_memcached_prefix = 'memc.sess.key.';
$CFG->session_memcached_acquire_lock_timeout = 120;
$CFG->session_memcached_lock_expire = 7200;       // Ignored if memcached extension <= 2.1.0 $CFG->session_memcached_lock_retry_sleep = 150;   // Spin-lock retry sleeptime (msec). Only effective
/********************************************/


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

// There is no php closing tag in this file,
// it is intentional because it prevents trailing whitespace problems!

Optimizar tus imágenes con jpegoptim y optiPNG

En las tareas de SEO, una de las principales tareas es optimizar las imágenes. Sí quieres ver el puntaje de SEO de tu sitio visita la herramienta PageSpeed

Para optimizar las imágenes vamos a utilizar los programas CLI jpegoptim y optiPNG

Requisitos previos:
Manejo de una terminal Linux, en este caso lo realizaremos con la distribución CentOS 7,
Tener instalado el Repositorio de Epel si no lo tienes puedes instalarlo

[byron@grupotbs ~]# yum install epel-release -y

Instalar los paquetes de jpegoptim y optiPNG

[byron@grupotbs ~]# yum install jpegoptim optipng -y

Optimizar imágenes PNG

Ingresamos a la carpeta donde están las imágenes que vamos a optimizar, cabe señalar que las imágenes son sobreescritas.

[byron@grupotbs ~]# cd imagenes
[byron@grupotbs imagenes]$ optipng imagen.png

Si quieres optimizar de forma masiva usamos el comando find

[byron@grupotbs imagenes]#  find . -name '*.png' -exec optipng {} \;

para más detalle de como utilizar el comando

[byron@grupotbs jpegoptim ]# man optipng

Optimizar imágenes JPG y JPEG

Ingresamos a la carpeta donde están las imágenes que vamos a optimizar, cabe señalar que las imágenes son sobreescritas.

[byron@grupotbs ~]# cd imagenes
[byron@grupotbs imagenes]$ jpegoptim imagen.jpg
[byron@grupotbs imagenes]$ jpegoptim imagen.jpeg

Si quieres optimizar de forma masiva usamos caracteres comodín

[byron@grupotbs imagenes]# find . -name '*.jpg' -exec jpegoptim {} \;
[byron@grupotbs imagenes]# find . -name '*.jpeg' -exec jpegoptim {} \;

para más detalle de como utilizar el comando

[byron@grupotbs jpegoptim ]# man jpegoptim 

Si necesitas ayuda para instalar esto en tu sitio no dudes en preguntarnos  Aquí

Personalizar tu página web con nieve por las fiestas de Navidad

Por temporada de fiestas y principio de año resulta interesante adecuar el sitio web con arreglos propios de estas fechas como modificando el logotipo, cambiando imágenes y lo que proponemos en este post animar con el efecto de caída de nieve.

Lo primero es revisar la librería loktar00/JQuery-Snowfall

Cargamos la librería JS antes de que se cierre la etiqueta </body> cabe señalar que el sitio debe soportar jQuery para que se ejecute la librería,

<script src="https://cdnjs.cloudflare.com/ajax/libs/JQuery-Snowfall/1.7.4/snowfall.jquery.min.js"
integrity="sha256-vAReE/QJn5mPeP9+QvOI8X6AEAAFrSBO1F9gLNb44cg=" crossorigin="anonymous"></script>
<script>
jQuery(document).snowfall({
image: "https://www.grupotbs.com/img/copo16.png",
flakeCount: 50, maxSpeed: 3, maxSize: 30, round: true, shadow: false
});
</script>

Las opciones de la nieve se configura con los parámetros de la librería. La imagen es un  copo de nieve descargado de IconFinder

Si necesitas ayuda para instalar esto en tu sitio no dudes en preguntarnos  Aquí