Ganhe eficiência com WordPress no Ubuntu 22.04, NGINX, MySQL e PHP 8.2

O ambiente de nuvem pública utilizado foi o do Luiza Labs, no datacenter de Fortaleza, Ceará. Servidor com 8 GB de RAM, 4 processadores e 50 GB de espaço em SSD. O custo mensal do servidor estava em abril de 2024 R$ 226,72. O servidor MySQL 8 estava em 720 x R$ 0,2327, totalizando R$ 167,54 – com 2 processadores e 4 GB de RAM. O processo de instalação do WordPress foi feito em um servidor Ubuntu 22.04 usando NGINX, MySQL 8 e PHP 8.2. Com isso você terá uma plataforma poderosa e eficiente para executar o seu site WordPress de um jeito prático.

Você vai precisar de uma conta na Cloudflare, que inclui certificado de segurança instalado no servdidor, para o domínio utilizado. Caso seja necessário você pode usar o Nginx para redirecionar subdomínios e domínos, ser for o caso.

Implantar WordPress na pilha LEMP

Para um melhor desempenho usamos a versão 8.2 do PHP com ajustes na configuração em dinamic, que deu a capacidade de antender um tráfego maior. Nossa aplicação recebe mais de 20 mil visitas por mês.

O Nginx traz alto desempenho para o ambiente, por sua capacidade de lidar com grande volume de tráfeco de maneira eficiente e escalável. O cache usado foi o Redis.

Para uma maior praticidade, sugiro que você execute o comando sudo -s, para evitar a repetição do comando sudo no processo de implantação e de eventais ajustes.

  1. Atualização de repositórios
sudo -s
apt update

2. Instalação do MariaDB com segurança

Você pode rodar o MariaDB no Ubuntu. Mas caso seu ambiente precise de maior desempenho, seria o caso de usar o servidor MySQL 8 da Luiza Labs.

apt install mariadb-server -y && mysql_secure_installation

Responda às perguntas abaixo

  • Enter current password for root (enter for none): Pressione Enter
  • Switch to unix_socket authentication [Y/n]: Digite n e pressione Enter.
  • Set root password? [Y/n]: Pressione Enter.
  • New password: Copie uma senha forte do Dashlane Password Generator. Para colar a senha no terminal SSH, clique com o botão direito do mouse e pressione Enter. A senha não é visível na tela.
  • Re-enter new password: Clique com o botão direito do mouse e pressione Enter novamente.

Depois disso você vai ver:

Password updated successfully!
Reloading privilege tables..
... Success!

Então, você vai responder às seguintes perguntas.

  • Remove anonymous users? [Y/n]: Pressione Enter
  • Disallow root login remotely? [Y/n]: Pressione Enter
  • Remove test database and access to it? [Y/n]: Pressione Enter
  • Reload privilege tables now? [Y/n]: Pressione Enter

3. Crie uma nova Base de dados para WordPress

Faça login no MariaDB, pressione a tecla Enter quando solicitar a senha.

mysql -u root -p

Para o caso de usar o servidor MySQL da Luiza Labs utilize usuário e senha criados na configuração do servidor:

mysql -u usuarioCadastrado -p

Crie um novo banco de dados e conceda privilégios para seu usuári com senha. É aqui que o WordPress armazena todas as informações de postagens, páginas, temas, plugins etc.

create database wordpress;
grant all on wordpress.* to usuariocadastrado@localhost identified by 'Ml0zmYeeDHzyLqAr';
flush privileges;
exit;

Aqui, sey banco de dados é wordpress, com seu usuriocadastrado na nuvem com respectiva senha Ml0zmYeeDHzyLqAr

4. Instale o PHP8.2, NGINX e defina a permissão

No momento, o PHP 8.2 é a versão mais estável e recente. Se precisar de uma versão diferente do PHP, mantenha a mesma versão em todos os comandos.

sudo add-apt-repository ppa:ondrej/php -y && apt update && apt install php8.2-fpm php8.2-common php8.2-mysql php8.2-xml php8.2-xmlrpc php8.2-curl php8.2-gd php8.2-imagick php8.2-cli php8.2-dev php8.2-imap php8.2-mbstring php8.2-soap php8.2-zip php8.2-bcmath -y && sed -i 's/;cgi.fix_pathinfo=1/cgi.fix_pathinfo=0/g' /etc/php/8.2/fpm/php.ini && service php8.2-fpm restart && apt install nginx -y && chown -R www-data:www-data /var/www/ && chmod -R 755 /var/www

Ajuste a configuração do PHP

Os diversos temas e plugins requerem configuração de ponta para serem executados. Então faça essas alterações.

sed -i 's/memory_limit = .*/memory_limit = 512M/g' /etc/php/8.2/fpm/php.ini
sed -i 's/post_max_size = .*/post_max_size = 128M/g' /etc/php/8.2/fpm/php.ini
sed -i 's/max_file_uploads = .*/max_file_uploads = 30/g' /etc/php/8.2/fpm/php.ini
sed -i 's/max_execution_time = .*/max_execution_time = 900/g' /etc/php/8.2/fpm/php.ini
sed -i 's/max_input_time = .*/max_input_time = 3000/g' /etc/php/8.2/fpm/php.ini
sed -i 's/upload_max_filesize = .*/upload_max_filesize = 128M/g' /etc/php/8.2/fpm/php.ini
service php8.2-fpm restart

Faça as configurações do PHP, caso tenha alto tráfego.

nano /etc/php/8.2/fpm/pool.d/www.conf

Com servidor PHP operando na opção dynamic Avalie a performance do serviço web e faça ajustes em pm.start_servers, pm.min_spare_servers e pm.max_spare_servers. Segue um exemplo utilizado em meu ambiente.

; Note: This value is mandatory.
pm = dynamic
; The number of child processes to be created when pm is set to 'static' and the
; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'.
; This value sets the limit on the number of simultaneous requests that will be
; served. Equivalent to the ApacheMaxClients directive with mpm_prefork.
; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP
; CGI. The below defaults are based on a server without much resources. Don't
; forget to tweak pm.* to fit your needs.
; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand'
; Note: This value is mandatory.
pm.max_children = 60
; The number of child processes created on startup.
; Note: Used only when pm is set to 'dynamic'
; Default Value: (min_spare_servers + max_spare_servers) / 2
pm.start_servers = 16
; The desired minimum number of idle server processes.
; Note: Used only when pm is set to 'dynamic'
; Note: Mandatory when pm is set to 'dynamic'
pm.min_spare_servers = 8
; The desired maximum number of idle server processes.
; Note: Used only when pm is set to 'dynamic'
; Note: Mandatory when pm is set to 'dynamic'
pm.max_spare_servers = 20
; The number of rate to spawn child processes at once.
; Note: Used only when pm is set to 'dynamic'
; Note: Mandatory when pm is set to 'dynamic'
; Default Value: 32
pm.max_spawn_rate = 32

5. Instale o certificado Wildcard Let’s Encrypt SSL

Crie um cloudflare.iniarquivo dentro /root/.secrets/do diretório.

Crie um cloudflare.iniarquivo dentro /root/.secrets/do diretório.
mkdir -p /root/.secrets/ && cd /root/.secrets/ && nano cloudflare.ini

Adicione o código a seguir e salve com o comando CTRL + O e saia usando CTRL + X

dns_cloudflare_email = "seu-cloudflare-email@dominio.com.br"
dns_cloudflare_api_key = "XXXXXXXXXXXXXXXXX"

Encontre seu e-mail da Cloudflare e sua chave de API global em “Meu perfil” > Tokens de API > Chave de API global

chmod 0400 /root/.secrets/cloudflare.ini

Instale Certbot e DNS Authenticator de acordo com o sistema operacional e servidor web HTTP

snap install --beta --classic certbot
snap set certbot trust-plugin-with-root=ok
snap install --beta certbot-dns-cloudflare
snap connect certbot:plugin certbot-dns-cloudflare

Obtenha certificado SSL curinga

certbot certonly --dns-cloudflare --dns-cloudflare-credentials /root/.secrets/cloudflare.ini -d example.com,*.example.com --preferred-challenges dns-01 --dns-cloudflare-propagation-seconds 30

Definir renovação automática usando Cron Job

  • Digite crontab -e
  • Escolha a opção 1 para o editor nano
  • Digite o comando abaixo e salve
0 0 * * *  /etc/init.d/nginx reload >/dev/null 2>&1

Renovação de teste

certbot renew --dry-run

6. Configurar bloco de servidor Nginx

Isso é importante quando você for configurar o seu domínio, como o NGINX deve lidar com suas solicitações HTTP. É onde você também pode incluir redirecionamentos, uso de CACHE etc.

Exclua blocos de servidor padrão.

rm /etc/nginx/sites-available/default && rm /etc/nginx/sites-enabled/default

Crie um novo bloco de servidor

cd /etc/nginx/sites-available/
nano dominio.com.br
  1. Substitua domínio.com.br pelo seu próprio domínio
  2. Digite o código abaixo e pressione ctrl + o para salvar e ctrl + x para sair.

server {
listen         80;
server_name .example.com;
return 301 https://$host$request_uri;
}
server {
# Document Root
root /var/www/html;
index index.php index.html index.htm;
server_name .example.com;
client_max_body_size 0;
set_real_ip_from 0.0.0.0/0;
set_real_ip_from ::/0;
real_ip_header X-Forwarded-For;
listen [::]:443 ssl http2 ipv6only=on;
listen 443 ssl http2;
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_prefer_server_ciphers on;
ssl_session_cache   shared:SSL:20m;
ssl_session_timeout 20m;
ssl_ciphers 'TLS13+AESGCM+AES128:EECDH+AES128';
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
# Block XMLRPC
location = /xmlrpc.php {
deny all;
}
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~* \.php$ {
if ($uri !~ "^/uploads/") {
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
}
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
}
location = /favicon.ico {
log_not_found off;
access_log off;
}
location = /robots.txt {
log_not_found off;
access_log off;
allow all;
}
location ~* \.(css|js|gif|svg|ico|jpe?g|png|webp|woff2|eot)$ {
add_header  Cache-Control "public, max-age=31536000, immutable";
log_not_found off;
access_log off;
}
# Enable Gzip compression.
gzip on;
# Disable Gzip on IE6.
gzip_disable "msie6";
# Allow proxies to cache both compressed and regular version of file.
# Avoids clients that don't support Gzip outputting gibberish.
gzip_vary on;
# Compress data, even when the client connects through a proxy.
gzip_proxied any;
# The level of compression to apply to files. A higher compression level increases
# CPU usage. Level 5 is a happy medium resulting in roughly 75% compression.
gzip_comp_level 5;
# Compress the following MIME types.
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;
}

Você precisa instalar o plugins Nginx Helper e Redis Object Cache para aproveitar os benefícios do cache.

# NGINX Cache path
fastcgi_cache_path /var/run/nginx-cache levels=1:2 keys_zone=WORDPRESS:100m inactive=6h;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_use_stale error timeout invalid_header http_500;
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
server {
listen         80;
server_name .example.com;
return 301 https://$host$request_uri;
}
server {
root /var/www/html;
index index.php index.html index.htm;
server_name .example.com;
client_max_body_size 0;
set_real_ip_from 0.0.0.0/0;
set_real_ip_from ::/0;
real_ip_header X-Forwarded-For;
listen [::]:443 ssl http2 ipv6only=on;
listen 443 ssl http2;
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_prefer_server_ciphers on;
ssl_session_cache   shared:SSL:20m;
ssl_session_timeout 20m;
ssl_ciphers 'TLS13+AESGCM+AES128:EECDH+AES128';
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
set $skip_cache 0;
if ($request_method = POST) {set $skip_cache 1;}
if ($request_uri ~* "/wp-admin/|/xmlrpc.php|/wp-.*.php|index.php|sitemap") {set $skip_cache 1;}
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {set $skip_cache 1;}
if ($query_string = "unapproved*") {set $skip_cache 1;}
if ($cookie_woocommerce_items_in_cart = "1" ){ set $skip_cache 1;}
if ($request_uri ~* "/(cart|checkout|my-account)/*$") {set $skip_cache 1;}
# Block XMLRPC
location = /xmlrpc.php {
deny all;
}
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~* \.php$ {
if ($uri !~ "^/uploads/") {
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
}
try_files                       $uri =404;
include                         /etc/nginx/fastcgi_params;
fastcgi_param                   SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass                    unix:/run/php/php8.2-fpm.sock;
fastcgi_index                   index.php;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
fastcgi_cache WORDPRESS;
fastcgi_cache_valid 200 30d;
fastcgi_cache_valid 301 302 303 307 308 404 410 451 1m;
add_header X-Cache $upstream_cache_status;
}
location = /favicon.ico {
log_not_found off;
access_log off;
}
location = /robots.txt {
log_not_found off;
access_log off;
allow all;
}
location ~* \.(css|js|gif|svg|ico|jpe?g|png|webp|woff2|eot)$ {
add_header  Cache-Control "public, max-age=31536000, immutable";
log_not_found off;
access_log off;
}
# Enable Gzip compression.
gzip on;
# Disable Gzip on IE6.
gzip_disable "msie6";
# Allow proxies to cache both compressed and regular version of file.
# Avoids clients that don't support Gzip outputting gibberish.
gzip_vary on;
# Compress data, even when the client connects through a proxy.
gzip_proxied any;
# The level of compression to apply to files. A higher compression level increases
# CPU usage. Level 5 is a happy medium resulting in roughly 75% compression.
gzip_comp_level 5;
# Compress the following MIME types.
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;
}

Para salvar, pressione a tecla CTRL+ OEnter. Em seguida, saia do editor nano usando o comando CTRL + X. Evite o uso do AMP.

Outra alternativa é usar o plugin WP Rocket.

7. Crie links simbólicos entre dois diretórios

Se você deixar de fazer esta etapa, poderá obter ERR_CONNECTION_REFUSED

Exclua blocos de servidor padrão.

rm /etc/nginx/sites-available/default && rm /etc/nginx/sites-enabled/default

Para ativar o bloco do servidor, crie um link simbólico do arquivo do bloco do servidor NGINX do diretório /etc/nginx/sites-available/para /etc/nginx/sites-enabled

Antes de executar o comando abaixo, substitua dominio.com.br pelo próprio domínio.

ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/

Configuração de teste

nginx -t

Reinicie e atualize

service nginx restart && service php8.2-fpm restart && service mysql restart && apt-get update && apt upgrade -y

8. Instale o WordPress

Baixe os arquivos do WordPress no diretório /var/www/html e defina a permissão.

cd /var/www/html && wget https://wordpress.org/latest.tar.gz && tar -xvzf latest.tar.gz && mv -v wordpress/* /var/www/html && rm -rf index.nginx-debian.html latest.tar.gz wordpress && chown -R www-data:www-data /var/www/ && sudo chmod -R 755 /var/www

Para atualizar a permissão no futuro, use os comandos a seguir. Entre no diretório /var/www para executar os seguintes comandos.

sudo find html -type d -exec chmod 775 {} \;
sudo find html -type f -exec chmod 664 {} \;
sudo chmod 640 html/wp-config.php

9. Atualizando DNS

Se você estiver hospedando o WordPress localmente, quiser ignorar o proxy ou realizar uma migração com tempo de inatividade zero, esta etapa será útil.

Para Windows

Abra o prompt do MS DOS e digite o comando ipconfig /flushdns

Agora, faça todos os ajustes dos plugins de sua preferência para envio de e-mail, Cache, loja de comércio eletrônico, venda de conteúdo por assinatura etc.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *