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 em 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.3. 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.3 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.
- 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, se banco de dados é wordpress, com seu usuriocadastrado na nuvem com respectiva senha Ml0zmYeeDHzyLqAr
4. Instale o PHP8.3, NGINX e defina a permissão
No momento, o PHP 8.3 é 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.3-fpm php8.3-common php8.3-mysql php8.3-xml php8.3-xmlrpc php8.3-curl php8.3-gd php8.3-imagick php8.3-cli php8.3-dev php8.3-imap php8.3-mbstring php8.3-soap php8.3-zip php8.3-bcmath -y && sed -i 's/;cgi.fix_pathinfo=1/cgi.fix_pathinfo=0/g' /etc/php/8.3/fpm/php.ini && service php8.3-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.3/fpm/php.ini
sed -i 's/post_max_size = .*/post_max_size = 128M/g' /etc/php/8.3/fpm/php.ini
sed -i 's/max_file_uploads = .*/max_file_uploads = 30/g' /etc/php/8.3/fpm/php.ini
sed -i 's/max_execution_time = .*/max_execution_time = 900/g' /etc/php/8.3/fpm/php.ini
sed -i 's/max_input_time = .*/max_input_time = 3000/g' /etc/php/8.3/fpm/php.ini
sed -i 's/upload_max_filesize = .*/upload_max_filesize = 128M/g' /etc/php/8.3/fpm/php.ini
service php8.3-fpm restart
Faça as configurações do PHP, caso tenha alto tráfego.
nano /etc/php/8.3/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.ini
arquivo 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
- Substitua
domínio.com.br
pelo seu próprio domínio - 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.3-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.3-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.3-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+ O e Enter. 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 example.com
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.3-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.