LAMP em Debian 8

3 Maio 2016 Por Adriano Afonso

A necessidade aguça o engenho, e de repente, precisei de montar um servidor LAMP, e como sempre, decidi usar Debian 8, pois já estou mais que acostumado a trabalhar com este SO. Outra das necessidades é ter sempre pronta uma snapshot (servidores virtuais é uma maravilha, já tinha dito?) deste deployment para quando for preciso um servidor de teste para a empresa (bastando repor o snapshot para o ter pronto desde a raiz).

Raspberry Pi

Para quem quer trabalhar com RPi, usem raspbian-ua-netinst que facilita bastante o trabalho de instalação. Basta descarregar e passar para o cartão SD com o Win32Disk Imager. Aconselho descarregar o ficheiro raspbian-ua-netinst-v1.x.x.img.bz2 e depois descompactar com o 7zip.

Para os mais avançados, existem duas distribuições para as duas versões (ver aqui), a armel (Rasp v1) e a armhf (Rasp v2). Fiz uso obviamente das versões mais mini, a netinstall igualmente disponível na página de descarregamentos. Escolham as que estão disponíveis debaixo de “CDs pequenos”.

Para escrever para o SD, usar o Win32Disk Imager. Não esquecer de usar uma partição/formatar o SD em FAT32.

Configuração de rede

Visto que este irá ser um servidor empresarial convém o mais possível que o IP seja fixo (até porque vão precisar dele fixo mais tarde). Usei a ajuda da Debian para o fazer, disponível aqui.

Para definir o IP fixo, editar:

nano /etc/network/interfaces

E depois definir à eth0 os seguintes valores (substituir pelos vossos):
PS: No Ubuntu14.x e Debian 8 é provável que encontrem algum texto novo, colocar a configuração estática debaixo de: “source-directory /etc/network/interfaces.d”.

allow-hotplug eth0
auto eth0
iface eth0 inet static
        address 10.0.0.35
        netmask 255.255.255.0
        gateway 10.0.0.1
        network 10.0.0.0
        broadcast 10.0.0.255

A seguir convém sempre reiniciar a placa de rede para ela poder assumir o IP atribuído:

ifdown eth0
ifup eth0

Em alguns casos será também boa ideia definir os servidores de resolução de nomes:

 nano /etc/resolv.conf

E adicionar os seguintes, OpenDNS e Google DNS, respectivamente alterando:

nameserver 208.67.222.222
nameserver 8.8.8.8
nameserver 208.67.220.220
nameserver 8.8.4.4

SSH

Se já estão a usar a versão Jenny do Debian, cuidado que o acesso SSH remoto para root está fechado por defeito. Se o quiserem abrir, o que não é recomendável senão apenas enquanto estão a fazer a instalação, deverão aceder à configuração do SSH:

nano /etc/ssh/sshd_config

e alterando a seguinte linha de:

PermitRootLogin without-password

para

PermitRootLogin yes

Por fim, reiniciar o servidor SSH

/etc/init.d/ssh restart

NOTA: Assumindo que querem sempre aceder por root, e que o vosso router não tenha a porta 22 aberta. Aconselha-se sempre a utilização de uma VPN para posterior acesso SSH, não deixem “tudo aberto”, facilitando os ataques. Mais tarde, após terminadas as configurações, fechar o acesso novamente.

Instalar o Apache

Se não instalaram o apache durante a instalação ( [X] webserver), há que o instalar agora. De notar que na versão Debian Whezzy será instalada a versão 2.2.x e no Debian Jenny será instalada a versão 2.4.x.

apt-get install apache2

PHP

Instalar o PHP é tão simples como:

apt-get install php5 php-pear php5-apcu php5-memcached memcached

Convém sempre fazer já algumas alterações que podem dar muito jeito, especialmente quando se trabalha com bases de dados de alguma dimensão, e plataformas como Zabbix, ownCloud, etc. Aceder ao ficheiro de configuração do PHP:

nano /etc/php5/apache2/php.ini

e inserir os seguintes valores:

max_execution_time = 300
memory_limit = 512M
post_max_size = 512M
upload_max_filesize = 512M
max_input_time = 300
date.timezone = Europe/Lisbon
database = Mysql
always_populate_raw_post_data = -1

Se quiserem que o PHP fique optimizado no que à memoria diz respeito, podem fazer as seguintes alterações no:

nano /etc/php5/cli/php.ini

e depois acrescentar as linhas (depois de ;opcache.enable_cli=0):

;opcache.enable_cli=0
apc.enabled=1
apc.enable_cli=1

 

Base de dados MySQL

apt-get install php5-mysql mysql-server mysql-client

Para limpar bases de dados de testes e coisas afins:

mysql_secure_installation

Algumas configurações podem e devem de ser alteradas no ficheiro de configuração do mySQL para que sejam o mais similares possível às anteriores configurações do PHP. Portanto, aceder ao ficheiro:

nano /etc/mysql/my.cnf

e depois alterar para (o primeiro bind-address é o localhost, e o segundo bind-address deve ser o IP de rede do servidor). Também estou a utilizar alguns tweeks de performance como vi aqui:

# Instead of skip-networking the default is now to listen only on
# localhost which is more compatible and is not less secure.
bind-address            = 127.0.0.1
bind-address            = 10.0.0.15
#
# * Fine Tuning
#
key_buffer              = 512M
max_allowed_packet      = 512M
thread_stack            = 192K
thread_cache_size       = 8
max_connections         = 500
table_cache             = 1024
# thread's pelo número de cores
thread_concurrency      = 8

#
# * Query Cache Configuration
#
query_cache_limit       = 64M


# * InnoDB
#
# InnoDB is enabled by default with a 10MB datafile in /var/lib/mysql/.
# Read the manual for more InnoDB related options. There are many!
#
innodb_thread_concurrency = 0
innodb_read_io_threads = 64
innodb_write_io_threads = 64


Um dica, para no caso de terem as vossas próprias aplicações web a correr num servidor caseiro, é definir o max_statement_time (na versão 5.7.4)/ max_execution_time (na versão 5.7.8), o qual irá definir, em milissegundos, o tempo máximo de execução de cada SELECT. É especialmente útil para casos em que são efectuadas pesquisas dentro de uma tabela grande.

#mySQL v5.7.4
SET GLOBAL MAX_STATEMENT_TIME=2000;
#mySQL v5.7.8
SET GLOBAL MAX_EXECUTION_TIME=2000;

Assim, será definido 2 segundos como o tempo máximo para cada SELECT. No entanto ainda é possível definir o tempo máximo para cada sessão especifica (no caso de vários utilizadores):

#mySQL v5.7.4
SET SESSION MAX_STATEMENT_TIME=2000;
#mySQL v5.7.8
SET SESSION MAX_EXECUTION_TIME=2000;

Ainda é possível, em último caso, se não quiserem mexer nas definições do mySQL, usar esta definição dentro da propria query, como no seguinte exemplo:

#mySQL v5.7.4
SELECT MAX_STATEMENT_TIME=1000 * FROM table;
#mySQL v5.7.8
SELECT MAX_EXECUTION_TIME=1000 * FROM table;

 

Configurar Acesso HTTPS/SSL

Seguindo este tutorial e este, consegui implementar facilmente o acesso através de HTTPS, torando o meu servidor bem mais seguro. Primeiro há que instalar o openSSL

apt-get install openssl

e de seguida activar o módulo SSL do apache.

a2enmod ssl
a2ensite default-ssl
a2enmod rewrite

Antes de criar o certificado, convém primeiro criar a pasta onde este irá ser instalado.

mkdir -p /etc/apache2/ssl

Agora podemos, sim, criar o certificado. De notar que pode ser dado outro nome à chave/certificado (apache.key e apache.crt respectivamente):

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/apache2/ssl/apache.key -out /etc/apache2/ssl/apache.crt

A pasta onde estão os certificados deverá ser sempre protegida:

sudo chmod 600 /etc/apache2/ssl/*

Para que o servidor passe a usar SSL na pasta default, há que configurar o default-ssl.conf:

nano /etc/apache2/sites-enabled/default-ssl.conf

E alterar os seguintes parâmetros (substituir pela vossa “pasta”):

<VirtualHost _default_:443>
ServerAdmin webmaster@localhost
ServerName example.com:443

DocumentRoot /var/www/html/<pasta>

....

SSLEngine on
SSLCertificateFile /etc/apache2/ssl/apache.crt
SSLCertificateKeyFile /etc/apache2/ssl/apache.key

<Directory /var/www/html/"pasta">
# AllowOverride All
AllowOverride AuthConfig
DirectoryIndex index.php
# Order allow,deny
# Require all granted
# Require all denied
Options All -Indexes
</Directory>

NOTA: em DocumentRoot podemos redireccionar logo para a pasta/sitio pretendido. De seguida bastará reiniciar o apache:

service apache2 restart

phpMyAdmin

Aproveitar para instalar também o phpMyAdmin, que para o qual usei este tutorial:

apt-get install mcrypt phpmyadmin

Uma das grandes preocupações que deve existir, é, configurar não só o acesso SSL:

nano  /etc/phpmyadmin/config.inc.php

E adicionar a seguinte linha em “Server(s) configuration”

/**
 * Server(s) configuration
 */
$cfg['ForceSSL'] = 'true';
$i = 0;

mas também, sempre que possível, bloquear o acesso externo ao phpMyAdmin , desta forma aceder ao:

nano /etc/apache2/conf-available/phpmyadmin.conf

e adicionar as seguintes linhas:

<Directory /usr/share/phpmyadmin>
Options FollowSymLinks
DirectoryIndex index.php
Deny from all
Allow from 10.0.0.0/24

Permitindo assim apenas o acesso a partir da rede interna.

Assim que phpMyAdmin for instalado,e devidamente configurado, acho que é a altura certa para criar o snapshot, para mais tarde, se for necessário, repor a máquina virtual.

 

Redireccionamentos

Na pasta de raiz (/var/www/html) criar o ficheiro .htaccess:

touch .htaccess

Introduzir:

<IfModule mod_rewrite.c>
RewriteEngine On
        RewriteCond %{HTTP_HOST} !^http://domain.tld$ [NC]
        RewriteRule ^(.*)$ https://futurcabo.no-ip.info:440/€ 0,91 (€0.87) [L,R=301]

E não esquecer de alterar as permissões do ficheiro:

chown -R www-data:www-data .htaccess

Copias de Segurança das BD’s

Recorri a vários tutoriais e a várias ideias para construir um sistema de copias de segurança simples. Um dos conselhos que posso dar é: nunca guardar as cópias apenas num sítio, e muito menos na própria máquina.

Para inicio do processo, quero aproveitar uma partilha de rede já existente onde já são efectuadas copias de segurança, no entanto essa partilha é em Windows Server, e requer algumas opções. O objectivo é fazer um mount point com essa partilha. Para isso vamos já criar uma pasta dentro de /mnt:

cd /mnt
mkdir windowsserver

Agora podemos proceder ao mount da partilha, o qual aconselho que tenha obviamente <username>:<password> e respectivas permissões de leitura e escrita:

UPDATED [nova versão do cifs 2.0x / 3.16.0-4-amd64]

mount -vt cifs -o domain=meudominio.local,username=<username>,password='password',rw,nounix,iocharset=utf8,file_mode=0777,dir_mode=0777,sec=ntlm //10.0.0.50/BackupBD /mnt/windowsserver

onde “//10.0.0.50/Data/BackupBD” é o caminho de rede para a partilha no Windows Server.

O passo seguinte é criar um script bash que efectue alguns procedimentos:

cd /usr/local/sbin/
nano backupprocedure.sh

E introduzir o seguinte código que faz o seguinte:

  • procura na pasta /var/tmp todos os ficheiros mais velhos que 7 dias e apaga-os
  • faz o dump da base de dados, comprime em bzip2 com a data de hoje no nome e guarda em /var/tmp
  • pega em todos os ficheiros .sql.bz2 com data de ontem para a frente e move para o mount da partilha
#!/bin/sh
find /var/tmp/ -type f -mtime +7 -exec rm {} +
mysqldump -u<user> -p<password> nome_da_bd | bzip2 > /var/tmp/nome_da_bd$(date +%F).sql.bz2
find /var/tmp/ -name "*.sql.bz2" -mtime -1 -print -exec mv {} /mnt/windowsserver\;

UPDATE: Entretanto tive a necessidade de aumentar o script e prever uma futura redundância na falha do servidor que actualmente disponibiliza o sistema. O objectivo é ter uma cópia com pelo menos 8h (ver hora do CronJob mais à frente) num servidor remoto, e numa emergência, poder redireccionar o trafego para este.

#!/bin/sh

mysqldump -h$RDS_HOSTNAME -u$RDS_USERNAME -p$RDS_PASSWORD --add-drop-table --no-data $RDS_DB_NAME | grep -e '^DROP  \| FOREIGN_KEY_CHECKS' | mysql -h$RDS_HOSTNAME -u$RDS_USERNAME -p$RDS_PASSWORD $RDS_DB_NAME 

mysqldump -u$localuser -p$localserverpassword $localdatabase | mysql -hremoteserver -uremoteuser -premoteserverpassword

Não esquecer de alterar as permissões ao ficheiro:

chmod +x /usr/local/sbin/backupprocedure.sh

Não esquecer de testar sempre o script, para ver se ele está realmente a fazer aquilo que é suposto:

cd /usr/local/sbin/
./backupprocedure.sh

Agora só falta criar um cronjob que corra este scrip, todos os dias por volta das 23h (meia hora antes da copia de segurança do Windows Server, que neste caso o intervalo de tempo chega):

crontab -e

e inserir a linha:

00 23 * * * bash /usr/local/sbin/backupprocedure.sh > /dev/null 2>&1

 

Mail / PHP Mail / SSMTP

Muitos de vós devem ter servidores LAMP como eu, caseiros, ou internos na empresa, mas que normalmente são secundários. O correio electrónico está sempre à responsabilidade de um servidor externo (alugado). O problema é quando é necessário enviar e-mails das aplicações/servidor internas para fora. Encontrei a solução aqui, visto que apenas preciso de um forward, e não propriamente um servidor SMTP interno.

ssmtp is a send-only sendmail emulator for machines which normally pick their mail up from a centralized mailhub (via pop, imap, nfs mounts or other means). It provides the functionality required for humans and programs to send mail via the standard or /usr/bin/mail user agents.

Ora, então, há que instalar primeiro o SSMTP.

apt-get install ssmtp

E começar a devida configuração:

nano /etc/ssmtp/ssmtp.conf

E alterar as seguintes linhas:

root=webmaster@domain
...
mailhub=mail.domain.pt
...
#este deve de ser o nome da máquina, que em principio está preenchido por defeito
hostname=lamp.domain
FromLineOverride=YES

Descomentar a última opção é importante, caso queiram/usem formulários em que o e-mail do remetente é automáticamente preenchido (cuidado com user error). Se o servidor requerer autenticação (inluindo Gmail), então as seguintes configurações deverão ser também introduzidas:

AuthUser=youremail@mail.tld
AuthPass=yourpassword
UseSTARTTLS=yes
UseTLS=yes
##Metodo de autenticação para Gmail
#AuthMethod=LOGIN

Caso definam a opção “FromLineOverride=NO”, terão que configurar o seguinte ficheiro:

nano /etc/ssmtp/revaliases

e alterar a seguinte linha para o e-mail a ser utilizado:

www-data:webmaster@example.com

Em principio, agora basta utilizar um qualquer formulário de contacto e o e-mail deverá ser enviado. Testem e vejam se não dá erro e se recebem (ver por vezes a caixa de spam).

 

Recursos