Executando verificação de segurança...
1

Sem FTP: Subindo sites WordPress com GitHub Actions

Você ainda abre o FileZilla para enviar arquivo por arquivo para o servidor? Chegou a hora de mudar! Depois deste post bastará subir os arquivos para um repositório no GitHub e eles serão enviados para o servidor automaticamente.

Se você está com pressa... tudo bem!

Não tem problema se você está com pressa. De forma bem resumida isso é o que vamos fazer:

  1. Criar um par de chaves SSH que se conectem ao seu servidor;
  2. Criar os segredos DEPLOY_SSH_HOST, DEPLOY_SSH_USER e DEPLOY_SSH_KEY no GitHub;
  3. Criar o arquivo bin/rsync-excludes.txt no seu repositório;
  4. Criar o arquivo .github/workflows/deploy.yml no seu repositório;
  5. Fazer qualquer modificação na branch trunk.

O que você precisa

A lista do que vamos precisar para esse post é bem simples:

  • Acesso SSH ao seu servidor: Disponível em quase todas as hospedagens atualmente;
  • Um repositório no GitHub: Grátis e ilimitados, inclusive os privados.

Não se esqueça de fazer um backup do conteúdo do seu servidor antes de continuar. Assim, se algo der errado, será mais fácil reverter.

O que a GitHub Action vai fazer

Basicamente, o que vai acontecer é que ao atualizar os arquivos em uma determinada branch do repositório, uma GitHub Action se conectará via SSH com o servidor e enviará os arquivos usando o comando rsync.

O ✓ verde significa que uma Action foi disparada e executada com sucesso.

Acesso SSH

A sua GitHub Action precisará se conectar através do SSH (Secure SHell) com o seu servidor para enviar os arquivos. Para que isso seja possível, vamos criar um par de chaves SSH e configurar o servidor para aceitá-lo.

1. Criar um par de chaves SSH

A criptografia usada pelo protocolo SSH usa duas chaves: uma pública e uma privada. Para que a sua GitHub Action consiga enviar os arquivos para o seu servidor, você precisará de um novo par de chaves. Embora possível, não recomendo usar a mesma chave que você usa normalmente.

O comando para criar uma nova chave é o seguinte:

ssh-keygen -t ed25519 -C "usuario@dominio"
  • ssh-keygen: O comando que gera uma nova chave;
  • -t ed25519: O algoritmo usado na criação da chave;
  • -C "usuario@dominio": Não precisa ser um e-mail de verdade. Só é usado para diferenciar as chaves, como um comentário. Algo como [email protected] já é o suficiente.

O comando pedirá:

  • Uma senha: deixe em branco para facilitar o processo;
  • Um nome de arquivo: não use o padrão, coloque um novo como deploy ou o nome do projeto. Não use nenhuma extensão.
Chamada do comando ssh-keygen e seu retorno

2. Autorizar a chave a conectar com o seu servidor

Cada serviço de hospedagem cuida disso de uma forma diferente. Em hospedagens com algum tipo de painel de controle isso pode estar em Minha conta > SSH ou similar.

Na Cloudways, por exemplo, as chaves SSH são gerenciadas por aplicação. Na seção Access Details, é possível gerenciar as chaves SSH em Application Credentials.

Painel de controle de uma aplicação na Cloudways

Na imagem vemos setas para três elementos:

  • Public IP: Será usado como Host na nossa configuração. Em muitos casos é a URL do próprio site.
  • Username: A Cloudways tem um username diferente por aplicação. Algumas hospedagens usam o mesmo usuário para acessar tanto o painel quanto o servidor via SSH.
  • SSH Keys: Este é o lugar onde é possível configurar novas chaves para essa aplicação. Lá você deve fornecer a chave pública (arquivo.pub) do par gerado.

3. Testar a chave SSH (Opcional)

Do seu computador é possível testar o acesso com a nova chave. Para isso basta executar o seguinte comando:

ssh -i <caminho-chave-privada> <usuario>@<servidor>
  • <caminho-chave-privada>: O caminho do arquivo da chave privada (sem .pub) no seu computador
  • <usuario>@<servidor>: Varia de serviço para serviço. No caso da Cloudways teríamos [email protected].

Se usássemos a chave gerada no exemplo, a chamada ficaria assim:

ssh -i /home/elia/.ssh/exemplopost [email protected]

Se tudo deu certo você vai conseguir acessar o terminal do seu servidor.

GitHub Actions

GitHub Actions é a ferramenta de automação do GitHub. Basicamente, o GitHub vai analisar qualquer arquivo .yml na pasta .github/workflows do seu repositório e tentar executá-lo cada vez que alguma coisa acontecer no seu repositório.

No nosso caso vamos criar um arquivo chamado .github/workflows/deploy.yml. Você pode dar o nome que quiser, desde que mantenha a extensão .yml e a localização do arquivo.

ATENÇÃO: Arquivos .yml não permitem tabs, só espaços (2 ou 4).

O conteúdo do nosso arquivo .github/workflows/deploy.yml será o seguinte:

name: Deploy

env:
  SSH_USER: ${{ secrets.DEPLOY_SSH_USER }}
  SSH_HOST: ${{ secrets.DEPLOY_SSH_HOST }}

on:
  push:
    branches:
      - trunk

jobs:
  deploy_cloudways:
    name: Deploy to Cloudways
    runs-on: ubuntu-latest

    steps:
    - name: Checkout
      uses: actions/checkout@v2

    - name: Configure SSH
      run: |
        mkdir -p ~/.ssh/
        echo "$SSH_KEY" > ~/.ssh/deploy.key
        chmod 600 ~/.ssh/deploy.key
        cat >>~/.ssh/config <<END
        Host cloudways
          HostName $SSH_HOST
          User $SSH_USER
          IdentityFile ~/.ssh/deploy.key
          StrictHostKeyChecking no
        END
      env:
        SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}

    - name: Send files
      run: "rsync --delete -avO ${{ env.RSYNC_FLAGS }} --exclude-from=${{ env.EXCLUDES }} ./ ${{ env.SSH_USER }}@${{ env.SSH_HOST }}:${{ env.DESTINATION }}"
      env:
        RSYNC_FLAGS: '' #--dry-run
        EXCLUDES: bin/rsync-excludes.txt
        SSH_HOST: cloudways
        DESTINATION: "~/public_html/wp-content/"

Nome do fluxo de trabalho

A primeira linha do nosso arquivo simplesmente dá nome ao nosso workflow. O nome é usado simplesmente para visualizações e não interfere no funcionamento da automação.

name: Deploy

Segredos no GitHub Action

A segunda seção do nosso arquivo configura algumas variáveis de ambiente compartilhadas por alguns "passos" mais adiante.

env:
  SSH_USER: ${{ secrets.DEPLOY_SSH_USER }}
  SSH_HOST: ${{ secrets.DEPLOY_SSH_HOST }}

Como a descrição do fluxo de trabalho é feita em um arquivo visível para qualquer um que tenha acesso ao repositório, o GitHub fornece um jeito de criar segredos, editáveis apenas por administradores do repositório ou organização.

Como criar um segredo no GitHub Actions

Vamos relembrar o comando de acesso SSH que usamos para testar anteriormente:

ssh -i <caminho-chave-privada> <usuario>@<servidor>

Com esse comando em mente, acesse o repositório e vá até Settings > Secrets and Variables > Actions. Vamos criar três segredos:

  • DEPLOY_SSH_KEY: O conteúdo da chave privada que você criou.
  • DEPLOY_SSH_USER: O que você usou como <usuario>;
  • DEPLOY_SSH_HOST: O que você usou como <servidor>;

Repare que DEPLOY_SSH_KEY é diferente das outras: passamos o caminho do arquivo no comando, mas o segredo tem o conteúdo do arquivo. Isso acontece porque criaremos o arquivo durante a execução da action.

Formulário para a criação de um segredo no GitHub

O segredo DEPLOY_SSH_KEY não está nessa seção env de propósito. Ele será usado mais adiante.

Gatilhos e eventos

on:
  push:
    branches:
      - trunk

O conteúdo dessa seção é bem auto-explicativo: os passos neste arquivo só devem ser executados quando o conteúdo da branch trunk for modificado.

Ao invés de push, poderia ser pull_request ou schedule, por exemplo.

Jobs

Um conjunto de passos que serão executados. Nosso arquivo de workflow só tem um job, mas é possível ter mais de um. Diferentes jobs são executados em paralelo.

jobs:
  deploy_cloudways:
    name: Deploy to Cloudways
    runs-on: ubuntu-latest

No nosso caso deploy_cloudways poderia ser qualquer slug, assim como Deploy to Cloudways. Esses são só nomes.

A string ubuntu-latest especifica em que sistema operacional o job deve ser executado. É possível especificar versões de Linux, Windows e MacOS. Veja a lista completa.

Etapas ou steps

Steps são subdivisões do nosso job, executadas em ordem.

    steps:
    - name: Checkout
      uses: actions/checkout@v2

O nosso primeiro passo é o checkout do repositório. Essa é, normalmente, a primeira etapa de todos os workflows que você verá por aí. Simplesmente traz o conteúdo do repositório para dentro do ambiente da action.

Configuração do SSH

Esta seção configura o SSH da máquina executando a nossa ação no GitHub.

    - name: Configure SSH
      run: |
        mkdir -p ~/.ssh/
        echo "$SSH_KEY" > ~/.ssh/deploy.key
        chmod 600 ~/.ssh/deploy.key
        cat >>~/.ssh/config <<END
        Host cloudways
          HostName $SSH_HOST
          User $SSH_USER
          IdentityFile ~/.ssh/deploy.key
          StrictHostKeyChecking no
        END
      env:
        SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
  • mkdir -p ~/.ssh/: Cria o diretório .ssh dentro da pasta $HOME do servidor.
  • echo "$SSH_KEY" > ~/.ssh/deploy.key: Coloca o conteúdo da variável SSH_KEY dentro do arquivo deploy.key.
  • chmod 600 ~/.ssh/deploy.key: Configura as permissões do arquivo deploy.key. Nessa caso, 600 significa que o dono do arquivo tem permissão de leitura e escrita. Nenhum outro usuário pode acessá-lo.
  • cat >>~/.ssh/config <<END: O que estiver entre <<END e END será inserido no arquivo config da pasta .ssh.
    • Host cloudways: Cria um nome para a configuração a seguir. Ao chamar o SSH passando cloudways, os dados seguintes serão usados;
    • HostName $SSH_HOST: O endereço do servidor. Se você lembrar do que falamos na seção env, essa variável receberá o valor do segredo DEPLOY_SSH_HOST;
    • User $SSH_USER: Similar ao HostName, mas aplicado ao usuário;
    • IdentityFile ~/.ssh/deploy.key: Especifica o caminho da chave a ser usada para se conectar com o Host;
    • StrictHostKeyChecking no: Pula a verificação da identificação do servidor com o conteúdo do arquivo known_hosts.

Logo abaixo vemos uma seção env, similar àquela global, declarada no começo do nosso arquivo. Repare que nesse caso a variável é criada apenas para esse passo. No caso, estamos passando o conteúdo do segredo DEPLOY_SSH_KEY para uma variável de ambiente chamada SSH_KEY. O conteúdo dessa variável será adicionado ao arquivo deploy.key como vimos acima.

Enviar os arquivos com rsync

No último passo vamos finalmente alterar o conteúdo do servidor. Para isso vamos usar o comando rsync, que sincroniza os arquivos de um lugar com outro. Nesse caso, os arquivos da máquina do GitHub (origem) com os arquivos no seu servidor (destino).

    - name: Send files
      run: "rsync --delete -avO ${{ env.RSYNC_FLAGS }} --exclude-from=${{ env.EXCLUDES }} ./ ${{ env.SSH_USER }}@${{ env.SSH_HOST }}:${{ env.DESTINATION }}"
      env:
        RSYNC_FLAGS: '' #--dry-run
        EXCLUDES: bin/rsync-excludes.txt
        SSH_HOST: cloudways
        DESTINATION: "~/public_html/wp-content/"

Se o comando rsync é novidade para você, vamos ver cada um dos parâmetros passados:

  • --delete: Se um arquivo não está na origem, ele deve ser excluído do destino.
  • -avO: -a significa sincronizar todos os arquivos, pastas e links simbólicos preservando suas permissões. O v é para verbose, ou seja, imprime no terminal a lista de modificações sendo feitas. O (um "o" maiúsculo) configura rsync para não se preocupar com datas de modificações de pastas.
  • ${{ env.RSYNC_FLAGS }}: Como você já deve imaginar, será substituído pelo conteúdo da variável RSYNC_FLAGS configurada mais abaixo. Normalmente, não recebe nada, mas você pode, por exemplo, passar --dry-run que só simula o chamado ao comando, sem fazer nenhuma mudança.
  • --exclude-from=${{ env.EXCLUDES }}: Você pode passar o endereço de um arquivo com a lista de tudo o que deve ser ignorado por rsync. Veja a próxima seção para saber mais sobre isso.
  • ./: o endereço da pasta local que deve ser sincronizada.
  • ${{ env.SSH_USER }}@${{ env.SSH_HOST }}:${{ env.DESTINATION }}: O endereço de destino. A última parte será substituída pela pasta no endereço de destino. No caso aqui o repositório contém os arquivos da pasta wp-content e o site está localizado na pasta $HOME/public_html do servidor. No seu caso a pasta pode estar em outro lugar, como /var/www/html. Acesse seu servidor ou procure nas configurações da sua hospedagem para saber a pasta em que seu site está localizado.

Sobre exclusões no rsync

No exemplo acima estamos usando um arquivo chamado rsync-excludes.txt localizado na pasta bin do repositório. Esse arquivo tem uma lista de arquivos e pastas que devem ser ignorados pelo comando rsync. Por exemplo:

*.gitignore
*.gitmodules
*.git
*.gitkeep
*.github

/bin
*rsync-excludes.txt

/uploads
/upgrade
/themes/index.php
/plugins/index.php

Ao invés de usar --exclude-from=<arquivo> você também pode alterar a chamada a rsync e usar --exclude .git --exclude README.md, por exemplo.

Fazendo mais com GitHub Actions

Se você quiser, também é possível chamar comandos como composer install ou npm install durante o processo, evitando que você tenha que versionar arquivos de terceiros no seu repositório. Além disso, o processo também pode ser iniciado pela criação de um Pull Request ou por períodos (uma vez a cada dia, semana, etc.).

Para exemplos reais, veja o repositório do ElasticPress. Lá tem ações executadas uma vez por dia, testes automatizados, deploy para o repositório do WordPress.org e mais.

Por que abandonar o SFTP

Para começar, você deve usar um controle de versão como o git, mesmo que trabalhe sozinho. Ter seus projetos em um repositório git serve tanto para o controle das mudanças quanto como backup, além de ser requisito mínimo para a maioria das vagas atualmente.

O processo descrito aqui tem várias vantagens sobre o método antigo de subir arquivo por arquivo em um programa de SFTP como FileZilla, por exemplo. O meu favorito é que com esse método somente os arquivos alterados serão enviados, tornando o processo mais rápido e simples. Também evitamos que pessoas diferentes sobrescrevam as mudanças umas das outras.

Usei GitHub e GitHub Actions neste post, mas existem outras alternativas disponíveis se achar necessário. O processo de enviar arquivos para um servidor através do repositório é chamado de Continuous Delivery e faz parte do conjunto Continuous Integration, Delivery e Deployment, comumente abreviados como CI/CD.

Conclusão

Nesse post vimos um método para enviar arquivos para um servidor a partir de um repositório git.

Para acessar o servidor é preciso um par de chaves SSH. A chave pública é armazenada no servidor, a privada é guardada em um segredo no GitHub.

Também vimos como é fácil criar um workflow no GitHub: basta criar um arquivo .yml na pasta .github/workflows. Para restringir o acesso a informações sensíveis usamos os segredos do GitHub.

A sincronização dos arquivos é feita pelo comando rsync, que aceita vários parâmetros. Também é possível excluir arquivos da sincronização de formas diferentes: uma lista em um arquivo com o parâmetro --exclude-from ou várias chamadas para --exclude.

Este post é só o começo do que é possível com GitHub Actions. Também é possível usar ferramentas como o Composer ou NPM durante o processo.

Por fim, vimos porque essa forma de deployment é melhor que enviar arquivos individuais via SFTP.

Carregando publicação patrocinada...
1

Massa. Bem legal utilizar GitHub Actions para automatizar deploys.

Eu já fiz um conteúdo bem semelhante porém para subir no AWS S3 um Site com TailwindCSS.

Utilizo também o AWS Route 53, CloudFront e GitHub Actions.

São 9 vídeos e estão aqui nessa playlist.

No final também adiciono React, React Router e muito mais.

Aí você fica com um ambiente muito profissional e com custo de hospedagem praticamente zero.


Por sinal, todo esse conteúdo e muito mais faz parte do CodeFTW. Se tiver interesse se cadastra lá.

O CodeFTW é um projeto que tenho desde 2017 para ensinar desenvolvimento, é de graça, dá uma conferida nos cursos lá. Estou fazendo uma série passando por 100% da nova documentação do React e você pode ir marcando seu progresso pela plataforma do CodeFTW.

Temos também uma comunidade ativa no Discord e WhatsApp para você tirar dúvidas sempre que precisar, a gente responde 100% das dúvidas, assim você nunca fica travado.