Skip to content

Latest commit

 

History

History
696 lines (559 loc) · 22.1 KB

File metadata and controls

696 lines (559 loc) · 22.1 KB

Comandos importantes para CentOS 7

Verificar a versão

hostnamectl

Listar programas atribuídos à portas abertas

netstat -tulnp

Listar uso de memória RAM e CPU por processo

top

Visão simplificada da memória RAM, em MB

free -m

Inicialização geral do ambiente em um CentOS 7

Instalar o wget

sudo yum install wget

Instalar o Apache

sudo yum install httpd mod_ssl

Iniciar o Apache

sudo /usr/sbin/apachectl start

Fazer o Apache iniciar automaticamente

sudo systemctl enable httpd.service

Verificar o status do serviço

sudo systemctl status httpd

Instalar o Node.js 10 + npm

https://github.com/nodesource/distributions

yum install gcc-c++ make
curl -sL https://rpm.nodesource.com/setup_10.x | bash -
sudo yum install -y nodejs

Instalar o TypeScript

sudo npm install -g typescript

Instalar o .Net Core Runtime

https://dotnet.microsoft.com/download/linux-package-manager/centos/runtime-current

sudo rpm -Uvh https://packages.microsoft.com/config/rhel/7/packages-microsoft-prod.rpm

Apesar de pedir para atualizar utilizando sudo yum update, devido ao bug que ocorreu no ambiente da última que sudo yum update foi executado no CentOS 7, resolvi não executar sudo yum update, e ainda assim o comando abaixo foi OK.

sudo yum install aspnetcore-runtime-2.2

Se algum dia precisar utilizar alguma classe do assembly System.Drawing.Common, como Bitmap ou Image, pode ocorrer a exceção "The type initializer for 'Gdip' threw an exception.". Para corrigir isso, é preciso instalar a biblioteca libgdiplus:

sudo yum install libgdiplus

Caso a biblioteca libgdiplus não seja encontrada, será necessário instalar o epel-release antes:

sudo yum install epel-release

Listar portas e serviços abertos

sudo firewall-cmd --list-all

Caso o comando firewall-cmd não seja encontrado, será preciso instalar, iniciar e habilitar o início automático do serviço:

sudo yum install firewalld
sudo systemctl start firewalld
sudo systemctl enable firewalld

Liberar a porta 80 e 443

sudo firewall-cmd --add-service=http --permanent
sudo firewall-cmd --add-service=https --permanent
sudo firewall-cmd --reload

Nesse ponto, para testar se está OK, a partir de um browser externo, basta acessar http://ip-externo (deve aparecer a página de teste do Apache).

Caminho do arquivo de configuração do Apache: /etc/httpd/conf/httpd.conf

Diretório padrão do Apache para o conteúdo dos sites: /var/www/html

Instalar o PHP 7 + Módulos PHP comuns

https://www.linuxtechi.com/install-php-7-centos-7-rhel-7-server/

sudo yum install epel-release yum-utils -y
sudo yum install http://rpms.remirepo.net/enterprise/remi-release-7.rpm
sudo yum-config-manager --enable remi-php72
sudo yum install php php-common php-opcache php-mcrypt php-cli php-gd php-curl php-mysql -y
php -v (Apenas para verificar a versão)
sudo systemctl restart httpd.service (Precisa reiniciar o Apache depois de instalar o PHP)

Para verificar se o PHP está OK, pode criar o arquivo

sudo nano /var/www/html/info.php

com o conteúdo

<?php 
phpinfo(); 
?>

e acessar http://ip-externo/info.php para confirmar se tudo está OK.


Certificado SSL do Let's Encrypt

Instalar os repositórios necessários

sudo yum install epel-release mod_ssl

Instalar o certbot do Let's Encrypt

sudo yum install python-certbot-apache

Configurar o certbot

sudo certbot --apache -d nome-do-subdominio.nome-do-dominio.com

A configuração vai pedir um e-mail de contato e vai perguntar se deseja alterar o arquivo de configuração do servidor para redirecionar o tráfico de HTTP para HTTPS por padrão (o que é comum responder sim).

Configurar o certbot renew para executar duas vezes por dia

crontab -e

O Vim será aberto para editar o crontab, então, basta acrescentar a linha

* */12 * * * /usr/bin/certbot renew >/dev/null 2>&1

Para entrar no modo de edição basta teclar Esc e depois pressionar uma letra qualquer, para então poder colar a linha acima.

Ao final, basta sair do modo de edição teclando Esc, digitando :x e teclando Enter novamente para salvar o arquivo e sair do Vim.


MySQL

Baixar o rpm correto na pasta ~ (Para confirmar o link abaixo, basta entrar em https://dev.mysql.com/downloads/repo/yum/, fazer o download manual e conferir o link do arquivo RPM)

sudo wget https://repo.mysql.com/mysql80-community-release-el7-3.noarch.rpm

Se quiser conferir o download, basta executar o comando abaixo e comparar o hash com o hash mostrado no site https://dev.mysql.com/downloads/repo/yum/

sudo md5sum mysql80-community-release-el7-3.noarch.rpm

Atualizar o repositório

sudo rpm -ivh mysql80-community-release-el7-3.noarch.rpm

Para o CentOS 8, utilizar mysql80-community-release-el8-1.noarch.rpm.

Instalar o MySQL

sudo yum install mysql-server

Iniciar o MySQL

sudo systemctl start mysqld

Fazer o MySQL iniciar automaticamente

sudo systemctl enable mysqld

Mostrar na tela a senha padrão gerada para o usuário root

sudo grep 'temporary password' /var/log/mysqld.log

Se der errado, ou aparecer vazio, basta alterar a senha do usuário root manualmente

/usr/bin/mysqladmin -u root password 'nova-senha-do-root'

Executar o script para terminar a instalação com segurança (quando pedir a senha atual do root, coloca a senha listada acima, depois escolhe uma senha nova para o root)

sudo mysql_secure_installation

Efetuar login on MySQL com o usuário root

mysql -u root -p

Criar um banco novo

CREATE DATABASE nome-do-banco;

Criar um usuário novo

CREATE USER 'nome-do-usuario'@'localhost' IDENTIFIED BY 'senha-do-usuario';

Conceder permissões ao usuário novo somente a esse banco de dados

GRANT ALL PRIVILEGES ON nome-do-banco.* TO 'nome-do-usuario'@'localhost';

Se quiser limitar apenas para as permissões comuns

GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES ON nome-do-banco.* TO 'nome-do-usuario'@'localhost';

Toda vez que uma tabela/view/etc for criada pelo root, ou por outro usuário que não o usuário nome-do-usuario, será preciso executar o comando GRANT acima, ou ocorrerão erros na hora do usuário tentar logar/acessar!

Caso ocorra algum problema de conexão remota utilizando Node.js, .Net ou outra linguagem/framework

ALTER USER 'nome-do-usuario'@'localhost' IDENTIFIED WITH mysql_native_password BY 'senha-do-usuario';

Para criar um arquivo de dump no formato .sql, basta executar o comando abaixo

mysqldump -u nome-do-usuario -p nome-do-banco > dump.sql

Para restaurar um arquivo de dump no formato .sql, basta criar o banco e o usuário utilizando os comandos acima, copiar o arquivo de dump, por exemplo dump.sql, para um diretório do servidor, ir até o diretório e executar o comando abaixo

mysql -u nome-do-usuario -p nome-do-banco < dump.sql

Dependendo dos comandos utilizados dentro do arquivo de dump, antes de executar o dump será necessário executar GRANT ALL PRIVILEGES em vez da versão apenas com permissões comuns.


Configurando o Apache para servir diversos hosts/hosts virtuais

Criar as pastas sites-available e sites-enabled

sudo mkdir /etc/httpd/sites-available /etc/httpd/sites-enabled

Alterar o arquivo de configuração do Apache para procurar por hosts virtuais

sudo nano /etc/httpd/conf/httpd.conf

Depois, acrescentar essa linha ao final

IncludeOptional sites-enabled/*.conf

Com isso feito, basta criar o arquivo de configuração (poderia ser /etc/httpd/sites-available/site-teste.conf caso fosse uma "subpasta virtual" do domínio raiz)

sudo nano /etc/httpd/sites-available/teste.com.br.conf
<VirtualHost ...>
...
</VirtualHost>

O conteúdo do arquivo varia conforme o objetivo desejado/linguagem utilizada.

Por fim, basta criar um link simbólico de sites-enabled/xxx.conf apontando para o arquivo real sites-available/xxx.conf (faz isso para poder excluir o arquivo/link da pasta sites-enabled, que é onde o Apache vai procurar de verdade, mas não perder o arquivo de configuração real, que pode ser reutilizado depois)

sudo ln -s /etc/httpd/sites-available/teste.com.br.conf /etc/httpd/sites-enabled/teste.com.br.conf

Depois disso, deve-se reiniciar o Apache

sudo systemctl restart httpd.service

Normalmente o SELinux vai bloquear o Apache de realizar conexões remotas, o que faz com que o Apache nunca funcione como proxy reverso no CentOS, nem que ele consiga realizar requisições para outros servidores!!! Para corrigir isso:

sudo /usr/sbin/setsebool -P httpd_can_network_connect 1

Se o Apache for acessar os arquivos por si próprio, deve-se criar as pastas do Apache para o subdomínio teste.com.br (poderia ser /var/www/site-teste/xxx caso fosse uma "subpasta virtual" do domínio raiz). As pastas convencionais são:

sudo mkdir -p /var/www/teste.com.br/html
sudo mkdir -p /var/www/teste.com.br/log
sudo mkdir -p /var/www/teste.com.br/code

Executar as linhas abaixo apenas nos diretórios onde o usuário apache terá permissão de escrita:

sudo chown -R apache /var/www/teste.com.br/log

Para garantir que as permissões estejam corretas

sudo chmod -R 755 /var/www

Permissões

Read (r)    4
Write (w)   2 
Execute (x) 1

755 = owner (primeiro dígito: 7) group (segundo dígito: 5) others (terceiro dígito: 5)

Isso fará com que o usuário apache (que é o usuário padrão do Apache) consiga apenas ler e executar os arquivos das pastas. Para conferir as permissões de um arquivo, basta executar ls -l para ver todos os arquivos/diretórios do diretório atual, ou ls -l nome-do-arquivo, como ls -l app.js, para ver apenas as permissões daquele arquivo.

A saída vai ser algo como

-rw-r--r--. 1 root root 1479 Ago 12 21:48 app.js

-rw-r--r-- é dividido em 4 partes:

O primeiro caractere é o tipo (- arquivo comum, d diretório ou l link simbólico). Depois são três grupos com três caracteres com as permissões do owner, grupo e others.

  1. -: arquivo comum
  2. rw-: owner rw
  3. r--: group r
  4. r--: others r

O primeiro root é o owner e o segundo root é o grupo ao qual aquele arquivo pertence


Deploy de aplicações Node

Antes de fazer deploy de qualquer aplicação, é preciso instalar o PM2, que é um gerenciador de processos de aplicações Node.js. Ele reinicia a aplicação Node caso ela pare de funcionar.

sudo npm install -g pm2@latest

Para evitar que o PM2 seja executado com qualquer usuário, é interessante criar um usuário específico, sob o qual as aplicações serão executadas (aqui o usuário é pm2, com a home do usuário definida para /home/pm2, diretório que será criado durante o processo)

sudo useradd -d /home/pm2 -m -s /bin/bash pm2
sudo passwd pm2

Fazer com que o PM2 inicie automaticamente (deve configurar corretamente o usuário e o diretório inicial, que aqui serão os mostrados acima, lembrando que o segundo pm2 no nome do serviço pm2-pm2 é na verdade o nome do usuário criado, que no caso também é pm2)

http://pm2.keymetrics.io/docs/usage/startup/

sudo pm2 startup systemd --user pm2 --hp /home/pm2
sudo systemctl enable pm2-pm2
sudo systemctl start pm2-pm2

Para cada aplicação a ser adicionada, assim como ocorre com o Apache, deve-se configurar as permissões dos diretórios/arquivos que serão utilizados pelas aplicações Node gerenciadas pelo PM2

sudo chown -R pm2 /var/www/nome-do-app
sudo chmod -R 755 /var/www/nome-do-app

Para iniciar uma aplicação e já adicioná-la à lista de aplicações gerenciadas (deve executar esse comando dentro do diretório onde está o arquivo app.js, e ajustar o usuário corretamente)

cd /var/www/nome-do-app
pm2 start app.js --name nome-do-app
pm2 save

Caso fosse necessário realizar um balanceamento de carga, subindo mais de uma instância da mesma aplicação, poderia ser utilizada a opção -i x com x valendo

  • 0 ou max: para criar uma instância para cada CPU do sistema
  • -1: para criar uma instância para cada CPU do sistema, exceto uma CPU
  • número: para criar uma quantidade específica de instâncias
cd /var/www/nome-do-app
pm2 start app.js --name nome-do-app -i x
pm2 save

Para reiniciar uma aplicação

pm2 restart nome-do-app --update-env

Para listar aplicações Node registradas/executando

pm2 list

ATENÇÃO!

Os comandos pm2 start, pm2 restart devem ser executados pelo usuário desejado, que no caso desse exemplo é o usuário pm2, pois as opções -u, --user e afins foram descontinuadas!

O comando pm2 save também deve ser executado pelo usuário desejado, caso contrário o arquivo de dump gerado será salvo no diretório errado, e não será lido corretamente durante a inicialização! O caminho do arquivo de dump é salvo é ~/.pm2/dump.pm2, que no caso do exemplo é /home/pm2/.pm2/dump.pm2.

Executar comandos como pm2 start, ou até mesmo pm2 list, utilizando outro usuário que não o usuário desejado, no caso do exemplo, pm2, fará com que uma nova instância do daemon do PM2 seja executada, não mostrando a situação real.

Assim, para facilitar o processo todo e vitar confusão, convém efetuar o login via SSH como o usuário desejado (pm2) e executar as tarefas relacionadas ao PM2 apenas através desse usuário!

Mais documentação sobre o PM2

http://pm2.keymetrics.io/docs/usage/quick-start/

http://pm2.keymetrics.io/docs/usage/memory-limit/

http://pm2.keymetrics.io/docs/usage/pm2-doc-single-page/


Deploy de aplicações .Net Core

https://github.com/aspnet/AspNetCore.Docs/blob/master/aspnetcore/host-and-deploy/linux-apache.md

https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-apache?view=aspnetcore-2.1

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel?view=aspnetcore-2.1

https://github.com/aspnet/MetaPackages/blob/master/src/Microsoft.AspNetCore/WebHost.cs#L161

Antes de fazer deploy de qualquer aplicação, é preciso ter instalado o runtime do .Net Core, como descrito anteriormente.

Dentro de Program.cs, configurar o Kestrel (mesmo não utilizando .UseKestrel(), ele é utilizado por padrão, a não ser que outro servidor seja especificado)

return WebHost.CreateDefaultBuilder(args)
    .ConfigureAppConfiguration((hostingContext, config) => {
        var env = hostingContext.HostingEnvironment;

        config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
              .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
    })
    .UseKestrel((builderContext, options) => {
        options.Configure(builderContext.Configuration.GetSection("Kestrel"));
    })
    .UseStartup<Startup>();

Configurar as opções do Kestrel, inclusive a porta, dentro de appsettings.json:

{
    "Logging": {
        "LogLevel": {
            "Default": "Warning"
        }
    },
    "AllowedHosts": "*",
    ...
    "Kestrel": {
        "EndPoints": {
            "Http": {
                ...
                "Url": "http://localhost:5003"
            }
        }
    }
}

Essa porta não afeta o comportamento durante o debug pelo IIS Express.

Em seguida, alterar o arquivo Startup.cs:

Caso a aplicação não esteja sendo executada a partir da raiz, deve-se especificar qual é a raiz, para fazer funcionar os links, controllers e o mapeamento de "~/..." do Razor:

app.UsePathBase("/teste");

Com isso, convém deixar o arquivo de configuração do Apache assim:

ProxyPass /teste http://127.0.0.1:5005/teste retry=0
ProxyPassReverse /teste http://127.0.0.1:5003/teste

Configurar o app para usar encaminhamento de cabeçalhos (que será necessário quando utilizar o app .Net Core via proxy do Apache no Linux)

app.UseForwardedHeaders(new ForwardedHeadersOptions {
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});

Fazer o deploy via Publish, utilizando

Deployment Mode: Framework Dependent
Target Runtime: linux-x64

Copiar os arquivos publicados para uma pasta dentro do local padrão do Apache: /var/www/nome-do-app

Configurar um serviço no Linux para iniciar/reiniciar o app automaticamente

sudo nano /etc/systemd/system/kestrel-nome-do-app.service

Conteúdo:

[Unit]
Description=nome-do-app app

[Service]
WorkingDirectory=/var/www/nome-do-app
ExecStart=/usr/bin/dotnet /var/www/nome-do-app/nome-do-app.dll
Restart=always
# Reiniciar depois de 10 segundos em caso de problemas
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=dotnet-nome-do-app
# Configurar o user correto
User=apache
Environment=ASPNETCORE_ENVIRONMENT=Production 

[Install]
WantedBy=multi-user.target

Configurar o serviço para iniciar automaticamente

sudo systemctl enable kestrel-nome-do-app.service

Iniciar o serviço

sudo systemctl start kestrel-nome-do-app.service

Verificar o status do serviço/app funcionando (utilizar a porta correta)

sudo systemctl status kestrel-nome-do-app.service
curl localhost:5003

Por fim, configurar um proxy no Apache, apontando para localhost:5003

sudo nano /etc/httpd/sites-available/nome-do-app.conf
<VirtualHost ...>
...
</VirtualHost>
sudo ln -s /etc/httpd/sites-available/nome-do-app.conf /etc/httpd/sites-enabled/nome-do-app.conf

Depois disso, deve-se reiniciar o Apache

sudo systemctl restart httpd.service

Exemplos de arquivos de configuração

Pasta virtual redirecionando para o Node

<VirtualHost *:80>
    ProxyPreserveHost On

    # Cuidado para não colocar o destino como http://127.0.0.1:3000/
    # porque o Apache vai concatenar tudo depois da origem ao final
    # do destino. Por exemplo, se vier /teste/ o Apache vai chamar
    # http://127.0.0.1:3000/. Se o destino já fosse http://127.0.0.1:3000/
    # então o Apache chamaria http://127.0.0.1:3000// o que pode dar
    # problemas com Node e com .Net Core!!!
    # Mais um exemplo: se a URL pedida for /teste/a/b/c/, como a origem
    # está configurada como /teste, /a/b/c/ será concatenado ao final do
    # destino, que se for http://127.0.0.1:3000, fará com que o Apache
    # chame http://127.0.0.1:3000/a/b/c/
    ProxyPass /teste http://127.0.0.1:3000
    ProxyPassReverse /teste http://127.0.0.1:3000
</VirtualHost>

Sub-domínio redirecionando para o Node

<VirtualHost teste.com.br:80>
    ProxyPreserveHost On

    # Se fosse o caso da raiz, aí deve-se colocar a barra ao final!
    # A regra é: se a string à esquerda termina com uma barra, a da
    # direita deve terminar com uma barra, também; e se a da esquerda
    # não termina com uma barra, a da direita também não deve terminar
    # com uma barra!
    ProxyPass / http://127.0.0.1:3000/ retry=0
    ProxyPassReverse / http://127.0.0.1:3000/

    ServerName teste.com.br
</VirtualHost>

Pasta virtual redirecionando para o Node, mas servindo arquivos estáticos direto pelo Apache, sem o Node

<VirtualHost *:80>
    ProxyPreserveHost On

    # Habilitando compressão conforme o tipo da resposta (vai valer
    # tanto para os arquivos estáticos, como para as respostas geradas
    # dinamicamente pelo Node.js)
    AddOutputFilterByType DEFLATE application/json
    AddOutputFilterByType DEFLATE application/javascript
    AddOutputFilterByType DEFLATE application/rss+xml
    AddOutputFilterByType DEFLATE application/xhtml+xml
    AddOutputFilterByType DEFLATE application/xml
    AddOutputFilterByType DEFLATE font/opentype
    AddOutputFilterByType DEFLATE font/otf
    AddOutputFilterByType DEFLATE font/ttf
    AddOutputFilterByType DEFLATE image/svg+xml
    AddOutputFilterByType DEFLATE image/x-icon
    AddOutputFilterByType DEFLATE text/css
    AddOutputFilterByType DEFLATE text/html
    AddOutputFilterByType DEFLATE text/javascript
    AddOutputFilterByType DEFLATE text/plain
    AddOutputFilterByType DEFLATE text/xml

    # Definindo cabeçalhos específicos para um diretório
    <Directory /var/www/teste.com.br/html>
        Header Set Cache-Control "public,max-age=31536000"
        Header Unset ETag
        FileETag None
    </Directory>

    Alias "/teste/public" "/var/www/teste.com.br/html"
    # A ordem dos ProxyPass é importante!!!
    # ProxyPass /teste/public ! fará com que tudo que começar por
    # /teste/public não seja encaminhado para o proxy
    # https://stackoverflow.com/a/35928307/3569421
    ProxyPass /teste/public !
    ProxyPass /teste http://127.0.0.1:3000 retry=0
    ProxyPassReverse /teste http://127.0.0.1:3000
</VirtualHost>

Domínio principal (único domínio)

<VirtualHost *:80>
    ServerName teste.com.br
    ServerAlias www.teste.com.br
    DocumentRoot /var/www/teste.com.br/public_html
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

Caso tenha instalado o SSL

<VirtualHost *:80>
    ... Conteúdo original do arquivo ...
RewriteEngine on
RewriteCond %{SERVER_NAME} =nome-do-subdominio.nome-do-dominio.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
<IfModule mod_ssl.c>
<VirtualHost *:443>
    ... Conteúdo original do arquivo, igual ao mostrado acima ...
ServerName nome-do-subdominio.nome-do-dominio.com
SSLCertificateFile /etc/letsencrypt/live/nome-do-subdominio.nome-do-dominio.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/nome-do-subdominio.nome-do-dominio.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateChainFile /etc/letsencrypt/live/nome-do-subdominio.nome-do-dominio.com/chain.pem
</VirtualHost>
</IfModule>