Nextcloud con PHP 7 Nginx y SSL/TLS
2017-09-28
Índice
- Nginx
- Instalación de Nextcloud
- Instalación modulos PHP
- Instalando y configurando PHP-FPM
- Dominios verificados
- Instalación y configuración MariaDB
- Nombre de dominio y virtualhost
- SSL/TLS con Let’s Encrypt
- Mejorar el rendimiento de Nextcloud
- Referencias:
Despuós de un tiempo utilizando como servidor HTTP Lighttpd, y aprovechado una nueva instalación del sistema en la raspberry, he decidido probar la instalación de Nextcloud 12 sobre un servidor HTTP Nginx, primero por aprender a hacerlo y ya de paso comprobar su rendimiento. Junto a Nextcloud y Nginx, instalare MariaDB como gestor de base de datos y mi certificado Letsencryt, que ya expliquó en este articulo como obtenerlo.
Para la nueva instalación voy a utilizar raspbian scretch como sistema operativo que ya viene con PHP 7 en sus repositorios.
Antes de empezar, si utilizas algun tipo de firewall en tu red, deberás dar permisos para el trafico HTTPS hacia tu servidor, yo utilizo UFW, como explique en este articulo
sudo ufw allow 'WWW Secure'
Nginx
Instalación de Nginx
sudo apt-get -y install nginx
Configuración de Nginx
Modificamos las directivas del fichero de configuración de Nginx /etc/nginx/nginx.conf
:
worker_processes 4;
server_tokens off;
workerprocesses 4; : numero de procesadores disponibles, para un mayor rendimiento le asigno los 4. Para conocer el numero de procesadores disponibles :
grep processor /proc/cpuinfo | wc -l
servertokens off; : se desactiva por razones de seguridad, evitamos que se envíe el numero de versión del servidor Nginx en el bloque HTTP.
Instalación de Nextcloud
Descargamos la ultima versión de Nextcloud :
cd /var/www
sudo wget https://download.nextcloud.com/server/releases/latest.tar.bz2
Descargamos su fichero SHA256 y verificamos la integridad del fichero descargado :
sudo wget https://download.nextcloud.com/server/releases/latest.tar.bz2.sha256
sha256sum -c latest.tar.bz2.sha256 < latest.tar.bz2
La salida del ultimo comando debería ser
latest.tar.bz2: La suma coincide
Verificamos la firma PGP y la fuente del archivo que acabamos de descargar :
sudo wget https://download.nextcloud.com/server/releases/latest.tar.bz2.asc
sudo wget https://nextcloud.com/nextcloud.asc
gpg --import nextcloud.asc
gpg --verify latest.tar.bz2.asc latest.tar.bz2
Esto nos devolverá una salida como esta:
gpg: Firmado el lun 22 may 2017 10:33:42 CEST usando clave RSA ID A724937A
gpg: Firma correcta de "Nextcloud Security <[email protected]>"
gpg: ATENCIÓN: ¡Esta clave no está certificada por una firma de confianza!
gpg: No hay indicios de que la firma pertenezca al propietario.
Huellas digitales de la clave primaria: 2880 6A87 8AE4 23A2 8372 792E D758 99B9 A724 937A
Descomprimidos el archivo Nextcloud :
sudo tar -xvf latest.tar.bz2
Borramos los ficheros y firmas descargados :
sudo rm latest.tar.bz2* nextcloud.asc
Permisos Unix
Por temas de seguridad vamos a crear un usuario llamado nextcloud para gestionar Nextcloud.
Por defecto cuando implementamos un servidor HTTP, el usuario que lo administra suele ser www-data, nobody, apache, etc. Si vamos a tener varios sitios corriendo en el servidor, todos van a utilizar el mismo usuario para ser administrados.
Si uno de los sitios cae por un usuario malicioso, el atacante tendrá acceso a todos nuestros sitios.
Es por ello que se recomienda crear usuarios separados para cada sitio.
Vamos a cambiar el propietario al directorio /var/www/nextcloud
y asignárselo al usuario nextcloud.
Nginx se puso en marcha con el usuario www-data, por lo que debe tener acceso de lectura al directorio /var/www/nextcloud
para leer los recursos estáticos (HTML, CSS, JS, etc.), vamos a asignar el usuario nextcloud al grupo www-data y por último vamos a eliminar el acceso a la carpeta /var/www/nextcloud a otros usuarios.
Creamos el usuario nextcloud :
sudo adduser nextcloud
Añadiendo el usuario `nextcloud' ...
Añadiendo el nuevo grupo `nextcloud' (1003) ...
Añadiendo el nuevo usuario `nextcloud' (1003) con grupo `next' ...
Creando el directorio personal `/home/nextcloud' ...
Copiando los ficheros desde `/etc/skel' ...
Introduzca la nueva contraseña de UNIX:
Cambiamos el propietario y el grupo del directorio /var/www/nextcloud
:
sudo chown -R nextcloud:www-data /var/www/nextcloud
Eliminamos todos los permisos para otros usuarios:
sudo chmod -R o-rwx /var/www/nextcloud
Instalación modulos PHP
sudo apt install php7.0-mysql php7.0-common php7.0-gd php7.0-json php7.0-cli
sudo apt install php7.0-curl php7.0-mbstring php7.0-xml php7.0-zip
sudo apt install php-apcu
Instalando y configurando PHP-FPM
El módulo de PHP-FPM permite la comunicación entre el servidor Nginx y el protocolo FastCGI basado en PHP. Este módulo ejecuta los scripts PHP en un proceso independiente a Nginx con UID y GID diferentes, incluso diferentes php.ini, reduciendo el tiempo de respuesta.
Instalación PHP-FPM
sudo apt-get install php7.0-fpm
Configuración
Creamos el fichero
sudo nano /etc/php/7.0/fpm/pool.d/nextcloud.conf
Y ponemos el siguiente código :
[nextcloud]
listen = /var/run/nextcloud.sock
listen.owner = nextcloud
listen.group = www-data
user = nextcloud
group = www-data
pm = ondemand
pm.max_children = 3
pm.process_idle_timeout = 60s
;pm.max_requests = 500
env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin
env[TMP] = /tmp
env[TMPDIR] = /tmp
env[TEMP] = /tmp
Permisos php-fpm
Debemos indicar a PHP-FPM con que permisos se crearan los archivo o carpetas dentro de Nextcloud, deben de coincidir con los mismos permisos que indicamos durante la instalación de Nextcloud:
sudo systemctl edit php7.0-fpm.service
Añadimos el siguiente código:
[Service]
UMask=0027
Reiniciamos el servicio para que actualice los nuevos valores :
sudo systemctl restart php7.0-fpm.service
Dominios verificados
Debemos añadir nuestro dominio al fichero de configuración de nextcloud
Cambiamos de usuario
su nextcloud
Editamos el fichero de configuración
nano /var/www/nextcloud/config/config.php
Y añadimos
'trusted_domains' =>
array (
0 => 'tu.dominio.es',
),
Instalación y configuración MariaDB
Instalación de MariaDB
sudo apt-get install -y mariadb-server mariadb-client
Terminada la instalación ejecutamos el siguiente script para proteger la base e datos:
sudo mysql_secure_installation
NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB
SERVERS IN PRODUCTION USE! PLEASE READ EACH STEP CAREFULLY!
In order to log into MariaDB to secure it, we'll need the current
password for the root user. If you've just installed MariaDB, and
you haven't set the root password yet, the password will be blank,
so you should just press enter here.
Enter current password for root (enter for none):
Como acabamos de realizar la instalación de MariaDB la contraseña del usuario root estará en blanco por lo que simplemente pulsaremos la tecla intro Cambiamos la contraseña para el usuario root
Set root password? [Y/n] y
New password:
Re-enter new password:
Password updated successfully!
Reloading privilege tables..
... Success!
Para el resto de preguntas seleccionamos Y
By default, a MariaDB installation has an anonymous user, allowing anyone
to log into MariaDB without having to have a user account created for
them. This is intended only for testing, and to make the installation
go a bit smoother. You should remove them before moving into a
production environment.
Remove anonymous users? [Y/n] y
... Success!
Normally, root should only be allowed to connect from 'localhost'. This
ensures that someone cannot guess at the root password from the network.
Disallow root login remotely? [Y/n] y
... Success!
By default, MariaDB comes with a database named 'test' that anyone can
access. This is also intended only for testing, and should be removed
before moving into a production environment.
Remove test database and access to it? [Y/n] y
- Dropping test database...
... Success!
- Removing privileges on test database...
... Success!
Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.
Reload privilege tables now? [Y/n] y
... Success!
Cleaning up...
All done! If you've completed all of the above steps, your MariaDB
installation should now be secure.
Accedemos con el usuario root a la consola de MariaDB, nos pedirá la contraseña que pusimos durante la instalación de MariaDB :
mysql -u root -p
Creamos un usuario nuevo en MariaDB, cambiando “miusuario” y “micontraseña” por los que correspondan en cada caso
CREATE USER 'miusuario'@'localhost' IDENTIFIED BY 'micontraseña';
Creamos una base de datos nueva llamada nextcloud
CREATE DATABASE IF NOT EXISTS nextcloud;
Damos todos los privilegios de la base de datos nextcloud al nuevo usuario que hemos creado anteriormente.
GRANT ALL PRIVILEGES ON nextcloud.* TO 'miusuario'@'localhost' IDENTIFIED BY 'micontraseña';
Recargamos la tabla de privilegios
flush privileges;
Salimos de la consola de MariaDB
quit
Error de autenticación
Si al ejecutar el comando mysql -u root -p
aparece el siguiente error:
mysql -u root -p
Enter password:
ERROR 1698 (28000): Access denied for user 'root'@'localhost'
La solución es :
sudo mysql -u root
use mysql;
update user set plugin='' where User='root';
flush privileges;
exit;
Nombre de dominio y virtualhost
Si vamos a acceder a Nectcloud desde fuera de nuestra red local necesitamos enlazar nuestro nombre de dominio a la dirección IP de nuestro servidor.
Creeamos el archivo /etc/nginx/sites-available/nextcloud
sudo nano /etc/nginx/sites-available/nextcloud
Y pegamos el siguiente texto, cambiamos las líneas servername tu.dominio.com y root var/www/nextcloud según nuestra configuración:
upstream php-handler {
server unix:/var/run/nextcloud.sock;
}
server {
listen 80;
listen [::]:80;
server_name www.tu.dominio.com tu.dominio.com;
# Path to the root of your installation
root /var/www/nextcloud/;
# Add headers to serve security related headers
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains;';
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
location = /.well-known/carddav {
return 301 $scheme://$host/remote.php/dav;
}
location = /.well-known/caldav {
return 301 $scheme://$host/remote.php/dav;
}
# set max upload size
client_max_body_size 512M;
fastcgi_buffers 64 4K;
# Enable gzip but do not remove ETag headers
gzip on;
gzip_vary on;
gzip_comp_level 4;
gzip_min_length 256;
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
location / {
rewrite ^ /index.php$uri;
}
location ~ ^/.well-known/acme-challenge/* {
allow all;
}
location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ {
deny all;
}
location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
deny all;
}
location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+)\.php(?:$|/) {
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param modHeadersAvailable true;
fastcgi_param front_controller_active true;
fastcgi_pass php-handler;
fastcgi_intercept_errors on;
#fastcgi_request_buffering off;
}
location ~ ^/(?:updater|ocs-provider)(?:$|/) {
try_files $uri/ =404;
index index.php;
}
# Adding the cache control header for js and css files
# Make sure it is BELOW the PHP block
location ~* \.(?:css|js|woff|svg|gif)$ {
try_files $uri /index.php$uri$is_args$args;
add_header Cache-Control "public, max-age=7200";
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
# Optional: Don't log access to assets
access_log off;
}
location ~* \.(?:png|html|ttf|ico|jpg|jpeg)$ {
try_files $uri /index.php$uri$is_args$args;
# Optional: Don't log access to other assets
access_log off;
}
}
Activamos el virtual host :
sudo ln -s /etc/nginx/sites-available/nextcloud /etc/nginx/sites-enabled/nextcloud
sudo systemctl restart nginx.service
sudo systemctl restart php7.0-fpm.service
SSL/TLS con Let’s Encrypt
Instalando Certbot
Para la obtención de nuestro certificado SSH proporcionado por Letsencryt, vamos a utilizar la herramienta Certbot, que nos facilitara la obtención del mismo.
Certbot ya viene habilitado en los repositorios de raspian scretch, además, instalamos el modulo para que configure automáticamente SSL en nginx
sudo apt-get install certbot python-certbot-nginx
Obtención del certificado
sudo certbot --nginx
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Which names would you like to activate HTTPS for?
-------------------------------------------------------------------------------
1: tu.dominio.es
2: www.tu.dominio.es
-------------------------------------------------------------------------------
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel):
Pulsamos intro para seleccionar todos los dominios
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Enter email address (used for urgent renewal and security notices) (Enter 'c' to
cancel):hefistion.arroba.mail.com
-------------------------------------------------------------------------------
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf. You must agree
in order to register with the ACME server at
https://acme-v01.api.letsencrypt.org/directory
-------------------------------------------------------------------------------
(A)gree/(C)ancel: a
Obtaining a new certificate
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Obtaining a new certificate
Performing the following challenges:
tls-sni-01 challenge for tu.dominio.es
tls-sni-01 challenge for www.tu.dominio.es
Generating key (1024 bits): /var/lib/letsencrypt/snakeoil/0006_key.pem
Waiting for verification...
Cleaning up challenges
Generating key (2048 bits): /etc/letsencrypt/keys/0000_key-certbot.pem
Creating CSR: /etc/letsencrypt/csr/0000_csr-certbot.pem
Generating key (1024 bits): /var/lib/letsencrypt/snakeoil/0007_key.pem
Deployed Certificate to VirtualHost /etc/nginx/sites-enabled/nextcloud for set(['www.tu.dominio.es', 'tu.dominio.es'])
Deployed Certificate to VirtualHost /etc/nginx/sites-enabled/nextcloud for set(['www.tu.dominio.es', 'tu.dominio.es'])
Podemos elegir que todo el trafico HTTP hacia el servidor sea redirigido al puerto HHTPS, opción 2.
Please choose whether HTTPS access is required or optional.
-------------------------------------------------------------------------------
1: Easy - Allow both HTTP and HTTPS access to these sites
2: Secure - Make all requests redirect to secure HTTPS access
-------------------------------------------------------------------------------
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Redirecting all traffic on port 80 to ssl in /etc/nginx/sites-enabled/default
The appropriate server block is already redirecting traffic. To enable redirect anyway, uncomment the redirect lines in /etc/nginx/sites-enabled/default.
-------------------------------------------------------------------------------
Congratulations! You have successfully enabled https://tu.dominio.es and
https://www.tu.dominio.es
You should test your configuration at:
https://www.ssllabs.com/ssltest/analyze.html?d=tu.dominio.es
https://www.ssllabs.com/ssltest/analyze.html?d=www.tu.dominio.es
-------------------------------------------------------------------------------
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/tu.dominio.es/fullchain.pem. Your
cert will expire on 2017-12-07. To obtain a new or tweaked version
of this certificate in the future, simply run certbot again with
the "certonly" option. To non-interactively renew *all* of your
certificates, run "certbot renew"
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
Con esto ya tendremos nuestro certificado descargado e instalado y nginx configurado.
Diffie-Hellman
Creamos los parámetros Diffie-Hellman utilizados para establecer la conexión SSL/TLS.
sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
Generating DH parameters, 2048 bit long safe prime, generator 2
This is going to take a long time
..................................................................................
.+...............................+....+.....................................................................................
.......................................................................................+..........................................................................................
.......................................................................................
.............................................................+........................
.............+................+............................+...................
.+..................................................+.....................+
Modificamos el fichero de configuración
sudo nano /etc/nginx/sites-available/nextcloud
Y al final antes del ultimo =}=añadimos el siguiente código:
ssl_dhparam /etc/ssl/certs/dhparam.pem;
Comprobamos la configuración:
sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Si no da error, reiniciamos el servidor
sudo systemctl reload nginx
Renovar el certificados
El certificado ofrecido por letsencrypt solo es válido para tres meses, para renovarlo, simplemente ejecutamos:
sudo certbot renew
Podemos simular la renovación con:
sudo certbot renew --dry-run
Saving debug log to /var/log/letsencrypt/letsencrypt.log
-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/tu.dominio.es.conf
-------------------------------------------------------------------------------
Cert not due for renewal, but simulating renewal for dry run
Renewing an existing certificate
Performing the following challenges:
tls-sni-01 challenge for tu.dominio.es
tls-sni-01 challenge for www.tu.dominio.es
Waiting for verification...
Cleaning up challenges
Generating key (2048 bits): /etc/letsencrypt/keys/0002_key-certbot.pem
Creating CSR: /etc/letsencrypt/csr/0002_csr-certbot.pem
** DRY RUN: simulating 'certbot renew' close to cert expiry
** (The test certificates below have not been saved.)
Congratulations, all renewals succeeded. The following certs have been renewed:
/etc/letsencrypt/live/tu.dominio.es/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
** (The test certificates above have not been saved.)
Si todo ha funcionado bien, podemos programar su renovación de forma automática
Si es la primera vez que vamos a programar una tarea en cron debemos elegir el editor de texto con el que trabajar
crontab -e
Select an editor. To change later, run 'select-editor'.
1. /bin/ed
2. /bin/nano <---- easiest
3. /usr/bin/vim.tiny
Choose 1-3 [2]: 2
Añadimos
0 2 * * * /usr/bin/sudo 15 3 * * * /usr/bin/certbot renew --quiet
Con esto hacemos que cron se ejecute todos los días a las 2 de la mañana
Mejorar el rendimiento de Nextcloud
Cache de PHP: OPcache
Usaremos OPcache para optimizar el codigo PHP
Editamos el fichero /etc/php/7.0/fpm/php.ini
y descomentamos o modificamos los siguientes valores
[opcache]
opcache.enable=1
opcache.enable_cli=1
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.memory_consumption=128
opcache.save_comments=1
opcache.revalidate_freq=1
Cache de datos con Apcu
Apcu cachea en memoria las versiones compiladas de las páginas PHP
sudo apt install php-apcu -y
Iniciamos sesión con el usuario nextcloud
su nextcloud
y añadimos la siguiente línea en el archivo /var/www/nextcloud/config/config.php
:
'memcache.local' => '\OC\Memcache\APCu',
Salimos del usuario nextcloud :
exit
Para finalizar, reiniciamos PHP-FPM para que los nuevos camilos tengan efectos:
sudo systemctl restart php7.0-fpm.service
Referencias:
- https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-16-04
- http://howto.wared.fr/ubuntu-installation-nextcloud-nginx/
- http://enmilocalfunciona.io/aceleracion-ssl-tls-con-nginx/
Espero que te haya gustado, pasa un buen día. 🐧