Usando oracle cloud free tier como alternativa ao heroku [demonstração com a criação de chatbot do telegram]

thiagocavalcanti

Thiago Cavalcanti

Posted on January 27, 2023

Usando oracle cloud free tier como alternativa ao heroku [demonstração com a criação de chatbot do telegram]

Introdução

Olá!

Decidi criar esse post para ajudar a quem está buscando formas de realizar deploy de aplicações de forma gratuita para fins de POC, estudo, etc. Com o anúncio que o heroku não terá mais free tier iremos explorar a alternativa que a oracle cloud fornece como free tier.

Objetivo

Iremos criar uma aplicação em node.js, iremos colocar ela na instância free tier da oracle cloud e iremos configurar nginx e certificados https para utilizar ela como bot do telegram

Como

Irei separar em 3 partes, assim você consegue ver tudo ou somente aquilo que te interessa. Lembrando que o foco é na parte da infraestrutura. O chatbot vai basicamente só responder o id do usuário, independente do input, somente para fins de teste

  1. Configurando o bot no telegram
  2. Criando nossa aplicação node.js
  3. Criando, configurando e deployando nosso chatbot na oracle cloud free tier

Parte 1 - Configurando o bot no telegram

Premissas

  1. Você deve ter uma conta no telegram

Vamos lá

  1. Abra uma nova conversa no telegram com o BotFather
  2. Basta seguir o fluxo de mensagem abaixo para que seja criado um novo bot Fluxo de conversa no telegram para criação de um Bot
  3. Armazene o token informado pois usaremos isso mais pra frente

Parte 2 - Criando nossa aplicação node.js

Premissas

  1. Conhecimento básico no ambiente de node.js
  2. Conhecimento básico em git
  3. (Somente para testes) Ter instalado o node.js

Vamos lá

Criando a base do nosso projeto

  1. Setup inicial
mkdir artigo_oracle_chatbot
cd artigo_oracle_chatbot
git init
npm init -y
Enter fullscreen mode Exit fullscreen mode
  1. Adicione o fastify que irá funcionar como o servidor http
npm i fastify
Enter fullscreen mode Exit fullscreen mode
  1. Adicione o dotenv para adicionarmos nosso token de forma segura
npm i dotenv
Enter fullscreen mode Exit fullscreen mode
  1. Crie um arquivo .gitignore na raíz do projeto e adicione o seguinte
node_modules
.env
Enter fullscreen mode Exit fullscreen mode

Codando

Crie um arquivo .env também na raíz e coloque o valor do seu token, além de uma secret (não pode ter símbolo) que você pode gerar usando LastPassword que iremos usar mais pra frente

TELEGRAM_API_TOKEN=93818281:nu1b31byb1i13bi13bi13
TELEGRAM_SECRET=tI5cfFVBW7DrvtHQoXit18r1sVapWWdqKImzymMxbaN33694gD
Enter fullscreen mode Exit fullscreen mode

Depois crie um arquivo index.js com seguinte código:

// 1 - Importa as dependências
const fastify = require("fastify")
require('dotenv').config()
const https = require("https")

// 2 - Cria função que envia mensagem para o telegram via API rest
const sendMessage = ({ chatId, message }) => {
    const req = https.request(`https://api.telegram.org/bot${process.env.TELEGRAM_API_TOKEN}/sendMessage`, {
        method: "POST", headers: {
            "content-type": "application/json"
        }
    })
    req.end(JSON.stringify({
        chat_id: chatId,
        text: message
    }))
}

// 3 - Cria http server, disponibilizando endpoint que servirá como webhook
const server = fastify()
server.post("/telegram/message", (req, res) => {
    const secret = req.headers["x-telegram-bot-api-secret-token"]
    const chatId = req.body.message.chat.id
    if (process.env.TELEGRAM_SECRET !== secret) {
        sendMessage({ chatId, message: "Foi tentado acessar o bot sem autorização!" })
        return res.status(200).send({})
    }
    const idUser = req.body.message.from.id;
    const message = req.body.message.text;
    sendMessage({ chatId, message: `O seu id é ${idUser} e você mandou a mensagem: ${message}` })
    res.status(200).send({})
})

// 4 - Inicializa servidor http
server.listen({ port: 3000, host: '0.0.0.0' })
    .then(_ => console.info('Server started at 3000'))
    .catch(e => {
        console.log(e.message)
        process.exit(1)
    })
Enter fullscreen mode Exit fullscreen mode

Por fim adicione no seu package.json o script start:

...
  "scripts": {
    "start": "node index.js"
  },
...
Enter fullscreen mode Exit fullscreen mode

Testando

Vamos rodar o comando npm start e esse é o resultado esperado:
npm rodando

Vamos agora testar a integração com telegram. Para isso, instale o ngrok, que serve como proxy reverso, em que vai fazer uma das suas portas ficar pública através de um domínio deles próprio

Após instalar rode ngrok http 3000 e anote o link gerado
ngrok rodando

Por fim, vamos cadastrar o nosso webhook no telegram, usando a api do telegram:

curl --location --request POST 'https://api.telegram.org/bot93818281:nu1b31byb1i13bi13bi13/setWebhook' \
--form 'url="https://85ec-2804-14d-5483-9658-51ed-100d-c05b-b1bd.sa.ngrok.io/telegram/message"' \
--form 'secret_token="tI5cfFVBW7DrvtHQoXit18r1sVapWWdqKImzymMxbaN33694gD"'
Enter fullscreen mode Exit fullscreen mode

Repare que:

  1. Na url é passado o path bot que é o token que obtivemos na conversa com o BotFather
  2. Usamos o form data em que:
  3. url: é o valor da base url gerada pelo ngrok + /telegram/message que é o path que definimos no nosso index.js
  4. secret_token: é o secret token que definimos usando o LastPassword. Esse token o telegram vai enviar no cabeçalho x-telegram-bot-api-secret-token

Vamos mandar uma mensagem para nosso bot e ver se tudo funciona como esperado:

Sucesso :)

Commitando

Crie um repositório no github privado, commite e faça o push no repositório

git remote add origin <link_git>
git add .
git commit -m "artigo oracle cloud"
git push --set-upstream origin main
Enter fullscreen mode Exit fullscreen mode

Parte 3 - Criando, configurando e deployando nosso chatbot na oracle cloud free tier

Agora vem a parte que é o objetivo de todo esse artigo. Vamos lá :)

Criando a instância

  1. Crie/Faça login na oracle cloud
  2. Começe a criar uma nova instância com as seguintes configurações Configuração da instância da oracle
  3. Na parte de "Add SSH keys" clique em "Save Private Key" para que seja possível acessar a sua instância via terminal Botão de download da chave ssh privada
  4. Acesso as suas instâncias e aguarde "State" ficar como "Running".
  5. Anote o Ip público, pois iremos usar mais pra frente.

Configurando a instância

Caso não seja dito, todos os terminais para os fluxos abaixos, devem ser abertos acessando a sua instância via SSH:

chmod 600 <caminho_para_chave>
ssh -i <caminho_para_chave_privada> opc@<ip_publico>
# Exemplo 
# ssh -i ./my_secret.key opc@129.393.293.42
Enter fullscreen mode Exit fullscreen mode

Rodando nosso projeto node.js

  1. Vamos instalar as ferramentas que vamos utilizar
 sudo dnf install git -y
 sudo dnf module enable nodejs:18 -y
 sudo dnf module install nodejs:18 -y
 node -v 
Enter fullscreen mode Exit fullscreen mode

O output deve ser uma versão 18+

  1. No github, gere um novo token. Com esse token, vamos fazer o clone do repositório (no momento que o git pedir a senha, você passa ele). Em "Repository access" selecione "Only selected repositories", escolha o seu repositorio, e em "Repository Permission", selecione "Read Only" em "Contents"
git clone <link_repositorio>
Enter fullscreen mode Exit fullscreen mode
  1. Vamos adicionar a nossas secrets criando o arquivo .env
cd <nome_repositorio>
sudo nano .env
# Copie o conteúdo do seu .env local e salve apertando ctrl x
Enter fullscreen mode Exit fullscreen mode
  1. Instale as dependências usando npm i
  2. Rode npm start e veja se o servidor é inicializado com sucesso

Configurando nginx para fazer o proxy para o nosso serviço

  1. Em um novo terminal Instale o nginx
sudo dnf install nginx -y
Enter fullscreen mode Exit fullscreen mode
  1. Crie os certificados openssl (veja que possui alguns parametros para ajustar quando for rodar ai)
sudo openssl req -newkey rsa:2048 -sha256 -nodes -keyout private.key -x509 -days 365 -out public.key -subj "/C=BR/ST=<Seu estado>/L=<Sua cidade>/O=<Nome da sua empresa>/CN=<O ip da máquina>"
sudo mv public.key /etc/nginx
sudo mv private.key /etc/nginx
sudo chmod 600 /etc/nginx/public.key
sudo chmod 600 /etc/nginx/private.key
Enter fullscreen mode Exit fullscreen mode
  1. Edite o arquivo /etc/nginx/nginx.conf removendo o objeto server atual e colocando o abaixo:
server {
  listen       80;
  server_name  localhost;

  location / {
    proxy_pass http://localhost:3000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
    proxy_redirect https:// http://;
  }
}

    server {
    listen 443 ssl;
    server_name localhost;

    ssl_certificate "/etc/nginx/public.key";
    ssl_certificate_key "/etc/nginx/private.key";

     location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
     }
    }
Enter fullscreen mode Exit fullscreen mode
  1. Rode os seguintes comandos (o primeiro comando é devido a isso)
sudo setsebool -P httpd_can_network_connect 1
sudo restorecon -v -R /etc/nginx
sudo systemctl restart nginx.service
Enter fullscreen mode Exit fullscreen mode
  1. Caso você não apresente erro, significa que ocorreu tudo bem

Configurando firewall e liberando https

  1. Precisamos habilitar na cloud da Oracle para permitir requisições https para a máquina. Para isso, vá na lista de instancias, clique na sua instancia. Depois em "Instance details" clique na sua "Virtual cloud network". Depois nas "Subnets", clique na "Sub rede pública". Depois em "Security Lists" clique em "Default Security List...". Você cair no "Ingress Rules" no final
  2. Adicione uma nova "Ingress Rule", colocando os seguintes valores Ingress Rule
  3. Por fim, libere o firewall rodando o seguinte comando
sudo firewall-cmd --zone=public --add-service=https
Enter fullscreen mode Exit fullscreen mode

Último passo - Configurando o webhook do telegram

  1. Copie o conteúdo da sua chave pública criada anteriormente. Você pode obter rodando sudo nano /etc/nginx/public.key
  2. Crie um novo arquivo local e coloque o conteúdo copiado anteriormente e salve como 'public.key' também
  3. Faça a seguinte chamada para configurar o webhook:
curl --location --request POST 'https://api.telegram.org/bot<telegram_api_token>/setWebhook' \
--form 'url="https://<instancia_ip_publico>/telegram/message"' \
--form 'secret_token="<secret_token_gerado_lastPassword>"' \
--form 'certificate=@"<caminho_para_chave_publica>"'
Enter fullscreen mode Exit fullscreen mode
  1. [Opcional] Instale screen para conseguir deixar um terminal da máquina rodando a aplicação
wget https://yum.oracle.com/repo/OracleLinux/OL8/developer/EPEL/x86_64/getPackage/screen-4.6.2-12.el8.x86_64.rpm
sudo rpm -i screen-4.6.2-12.el8.x86_64.rpm
sudo dnf localinstall screen-4.6.2-12.el8.x86_64.rpm

Enter fullscreen mode Exit fullscreen mode

Testando!

Mande uma nova mensagem para o bot e caso ele responda significa que deu tudo certo! Se quiser, desligue o seu computador e teste para ver que não tem nada local :)

💖 💪 🙅 🚩
thiagocavalcanti
Thiago Cavalcanti

Posted on January 27, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related