Usando oracle cloud free tier como alternativa ao heroku [demonstração com a criação de chatbot do telegram]
Thiago Cavalcanti
Posted on January 27, 2023
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
- Configurando o bot no telegram
- Criando nossa aplicação node.js
- Criando, configurando e deployando nosso chatbot na oracle cloud free tier
Parte 1 - Configurando o bot no telegram
Premissas
- Você deve ter uma conta no telegram
Vamos lá
- Abra uma nova conversa no telegram com o BotFather
- Basta seguir o fluxo de mensagem abaixo para que seja criado um novo bot
- Armazene o token informado pois usaremos isso mais pra frente
Parte 2 - Criando nossa aplicação node.js
Premissas
- Conhecimento básico no ambiente de node.js
- Conhecimento básico em git
- (Somente para testes) Ter instalado o node.js
Vamos lá
Criando a base do nosso projeto
- Setup inicial
mkdir artigo_oracle_chatbot
cd artigo_oracle_chatbot
git init
npm init -y
- Adicione o fastify que irá funcionar como o servidor http
npm i fastify
- Adicione o dotenv para adicionarmos nosso token de forma segura
npm i dotenv
- Crie um arquivo
.gitignore
na raíz do projeto e adicione o seguinte
node_modules
.env
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
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)
})
Por fim adicione no seu package.json o script start:
...
"scripts": {
"start": "node index.js"
},
...
Testando
Vamos rodar o comando npm start
e esse é o resultado esperado:
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
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"'
Repare que:
- Na url é passado o path bot que é o token que obtivemos na conversa com o BotFather
- Usamos o form data em que:
- url: é o valor da base url gerada pelo ngrok + /telegram/message que é o path que definimos no nosso index.js
- 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:
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
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
- Crie/Faça login na oracle cloud
- Começe a criar uma nova instância com as seguintes configurações
- Na parte de "Add SSH keys" clique em "Save Private Key" para que seja possível acessar a sua instância via terminal
- Acesso as suas instâncias e aguarde "State" ficar como "Running".
- 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
Rodando nosso projeto node.js
- 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
O output deve ser uma versão 18+
- 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>
- 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
- Instale as dependências usando
npm i
- Rode
npm start
e veja se o servidor é inicializado com sucesso
Configurando nginx para fazer o proxy para o nosso serviço
- Em um novo terminal Instale o nginx
sudo dnf install nginx -y
- 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
- 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;
}
}
- 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
- Caso você não apresente erro, significa que ocorreu tudo bem
Configurando firewall e liberando https
- 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
- Adicione uma nova "Ingress Rule", colocando os seguintes valores
- Por fim, libere o firewall rodando o seguinte comando
sudo firewall-cmd --zone=public --add-service=https
Último passo - Configurando o webhook do telegram
- Copie o conteúdo da sua chave pública criada anteriormente. Você pode obter rodando
sudo nano /etc/nginx/public.key
- Crie um novo arquivo local e coloque o conteúdo copiado anteriormente e salve como 'public.key' também
- 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>"'
- [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
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 :)
Posted on January 27, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.