Optei por usar uma VPS principalmente pelo custo-benefício que ela proporciona. Com essa opção, tenho a chance de estudar e testar em um ambiente controlado, evitando surpresas financeiras no fim do mês. A flexibilidade para configurar e testar diversos cenários me permite replicar situações reais, facilitando o aprendizado e o desenvolvimento de habilidades de maneira prática e eficaz, tudo dentro de um orçamento previsível. Essa alternativa é perfeita para quem deseja explorar novas oportunidades sem gastar excessivamente.
1. Contrate um serviço de VPS para obter recursos dedicados.
Existem várias opções disponíveis, mas no meu caso, optei pelo serviço da Contabo por apenas 5 dólares mensais, oferecendo 4 cores de CPU, 6 GB de RAM, 400 GB de armazenamento SSD, 200 Mbit/s de velocidade de rede e 32 TB de tráfego mensal (com entrada ilimitada)
Realize o primeiro acesso ao servidor utilizando o protocolo SSH com o seguinte comando no terminal, utilizando o IP da máquina contratada:
ssh root@<IP-do-servidor>
Encontre o IP da sua máquina para configurar o DNS utilizando o comando
ip addr
Configure o DNS no serviço onde o domínio foi adquirido. Consulte a documentação oficial do provedor para orientações detalhadas sobre como realizar essa configuração.
2. Atualize os pacotes
sudo apt update && sudo apt upgrade -y
3. Criando um Novo Usuário
Trabalhar diretamente com o usuário root pode expor seu servidor a riscos desnecessários, a melhor pratica e criar um novo usurário com privilégios limitados.
adduser newuser
4. Concedendo permissões de sudo
Após a criação do usuário devemos adiciona-lo ao sudo group para que ele possa realizar comandos que exigem privilégios de nível elevado, sem a necessidade de utilizar diretamente o usuário root
usermod -aG sudo newuser
Agora podemos trocar para o novo usuário para darmos inicio a configuração do sistema
su - newuser
5. Removendo autenticação por senha do SSH
Para aumentar a segurança da conexão SSH, é recomendável desativar a autenticação por senha, isso elimina o risco de ataques de brute force baseado em senha.
Antes de desativarmos a autenticação de senha para o SSH, devemos criar um par de chaves SSH para garantir que ainda poderemos acessar o servidor
ssh-keygen -t ed25519 -C "useremail@email.com"
## -t ed25519: Especifica o tipo da chave a ser gerada.
## -C "seuemail@exemplo.com: Adiciona um comentário à chave Durante a execução do comando, você deverá escolher o local onde deseja salvar a chave ou optar pelo local padrão: `~/.ssh/chave`
Após a criação da chave devemos adicionar a chave SSH ao servidor
ssh-copy-id -i ~/.ssh/sshkey.pub newuser@serverip
- indica o caminho onde a sua chave esta localizado localmente -i ~/.ssh/sshkey.pub
- Esse comando copia a chave pública SSH para o arquivo
~/.ssh/authorized_keys
no servidor remoto, permitindo o acesso para o usuário com a chave criada
Agora tente acessar o servidor utilizado a chave SSH privada localizada no mesmo diretório da chave publica
ssh -p 22 -i ~/.ssh/sshkey newuser@serverip
- -p especifica a porta SSH definida no servidor
- -i ~/.ssh/sshkey especifica o caminho da chave privada
Se acesso utilizando a chave SSH der certo podemos remover a autenticação por senha do SSH.
Primeiro abra o arquivo de configuração SSH
sudo nano /etc/ssh/sshd_config
Localize e altere as seguintes linhas no arquivo
## HARDENING SSH CONECTION
PermitRootLogin no ## BLOQUEIA O LOGIN DIRETO COM ROOT
PasswordAuthentication no ## DESATIVA CONEXÃO POR SENHA
UsePAM no ## DESATIVA O USO DE PAM NO SSH
após alterar essas linhas salve e feche o arquivo de configuração e reinicie o serviço de SSH:
sudo systemctl reload ssh
para validar se as alterações estão funcionando tente se conectar
root@serverip # a resposta deve ser essa root@serverip Permission denied (publickey).
Conecte-se ao novo usuário utilizando o SSH.
6. Instale o docker e docker-compose
Para configurar o ambiente, prossiga com a instalação do Docker e do Docker Compose seguindo a documentação oficial:
https://docs.docker.com/engine/install/ubuntu/
https://docs.docker.com/compose/install/linux/
Após instalar o Docker, execute esta imagem para verificar se ele está funcionando corretamente.
docker run -p 80:80 -d nginxdemos/hello
sudo systemctl enable docker
sudo usermod -aG docker newuser
7. Configurar Firewall
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 80
sudo ufw allow 443
Para que o Docker respeite as regras do UFW, edite o arquivo de configuração do Docker
sudo nano /etc/docker/daemon.json
{
"iptables": false
}
Reinicie o docker
sudo systemctl restart docker
8. Configuração do Docker file para o Projeto
Crie o arquivo Dockerfile na raiz do seu projeto para a criação da imagem docker
# Stage 1: Construção da aplicação usando Node.js
FROM node:22 AS build
# Define o diretório de trabalho dentro do container para organizar os arquivos
WORKDIR /app
# Copia os arquivos de configuração do Node.js (package.json e package-lock.json) para o container
COPY package*.json ./
# Instala as dependências do projeto
RUN npm install
# Copia o restante dos arquivos do projeto para o container
COPY . .
# Executa o comando para construir a aplicação (adapte este comando conforme o projeto)
RUN npm run build
# Stage 2: Configuração do servidor Nginx para servir a aplicação
FROM nginx:alpine
# Define o diretório de trabalho do Nginx onde os arquivos estáticos serão armazenados
WORKDIR /usr/share/nginx/html
# Copia os arquivos da build gerada no estágio anterior para o diretório do Nginx
COPY --from=build /app/dist/codebyfernandes/browser .
# Copia o arquivo de configuração personalizado do Nginx (opcional, se necessário)
COPY default.conf /etc/nginx/conf.d/default.conf
# Expõe a porta 80 para o servidor
EXPOSE 80
# Define o comando padrão para iniciar o Nginx
CMD ["nginx", "-g", "daemon off;"]
Crie o arquivo default.conf na raiz do projeto:
server {
listen 80; # Porta onde o servidor vai escutar
server_name localhost; # Nome do servidor (pode ser substituído pelo domínio)
root /usr/share/nginx/html; # Diretório onde estão os arquivos da aplicação
index index.html; # Arquivo principal da aplicação
# Rota principal para servir o Angular
location / {
try_files $uri $uri/ /index.html; # Redireciona todas as rotas para o index.html
}
# Configuração de cache para arquivos estáticos
location ~* \.(?:ico|css|js|gif|jpe?g|png|woff2?|eot|ttf|svg|webmanifest)$ {
expires 6M; # Define o tempo de expiração para 6 meses
access_log off; # Desativa logs para esses arquivos
add_header Cache-Control "public"; # Permite cache público
}
error_page 404 /index.html; # Redireciona erros 404 para o index.html
# Logs personalizados
error_log /var/log/nginx/angular-error.log; # Registro de erros
access_log /var/log/nginx/angular-access.log; # Registro de acessos
}
Agora crie a imagem localmente e rode ela em seguida
docker build -t meu-app:1.0 .
docker run -p 80:80 -d meu-app:1.0
-
d
: Executa o container em segundo plano. -
p 80:80
: Mapeia a porta 80 do container para a porta 80 do host.
Se tudo estiver configurado corretamente, você poderá acessar seu projeto em: http://localhost
Agora envie sua imagem para o Docker Hub utilizando a documentação abaixo:
Docker Hub: Build and Push First Image
9. Configuração do docker compose
Crie o arquivo compose.yaml na raiz do seu projeto, primeiro vamos adicionar a imagem do seu web app
services:
# Define os serviços do projeto
webapp:
# Nome do serviço
image: fernandeeess/portfolio-app:prod
# Imagem do contêiner usada para o serviço (versão de produção)
Agora vamos configurar o reverse proxy para o seu projeto utilizando o Traefik, que simplifica a gestão ao configurar automaticamente o certificado SSL e ajustar o load balancer de acordo com os serviços criados.
services:
reverse-proxy:
# Define o serviço do reverse proxy
image: traefik:v3.1
# Especifica a imagem do Traefik que será usada
command:
# Ativa o provedor Docker
- "--providers.docker"
# Desativa a exposição automática de serviços no Traefik
- "--providers.docker.exposedbydefault=false"
# Configura a porta para HTTPS (websecure)
- "--entryPoints.websecure.address=:443"
# Configura o desafio TLS para emissão do certificado SSL
- "--certificatesresolvers.myresolver.acme.tlschallenge=true"
# Define o e-mail para registrar os certificados SSL
- "--certificatesresolvers.myresolver.acme.email=youremail"
# Define o local para armazenar os certificados SSL
- "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
# Configura a porta para HTTP (web)
- "--entrypoints.web.address=:80"
# Redireciona HTTP para HTTPS
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
ports:
# Mapeia as portas do host para o contêiner (HTTP e HTTPS)
- "80:80"
- "443:443"
volumes:
# Volume para armazenar certificados SSL
- letsencrypt:/letsencrypt
# Permite que o Traefik se comunique com o Docker para detectar serviços
- /var/run/docker.sock:/var/run/docker.sock
webapp:
# Define o serviço da aplicação web
image: fernandeeess/portfolio-app:prod
# Especifica a imagem do contêiner da aplicação
volumes:
letsencrypt:
# Volume para armazenar os dados do Let's Encrypt
Adicione as labels ao web app service
webapp:
# Define o serviço da aplicação web
image: fernandeeess/portfolio-app:prod
# Especifica a imagem do contêiner que será usada para o serviço
labels:
# Habilita o Traefik para este serviço
- "traefik.enable=true"
# Define a regra de roteamento baseada no domínio
- "traefik.http.routers.webapp.rule=Host(`yourdomain.com`)"
# Define o entrypoint como HTTPS (websecure)
- "traefik.http.routers.webapp.entrypoints=websecure"
# Configura o resolver de certificado SSL a ser usado
- "traefik.http.routers.webapp.tls.certresolver=myresolver"
# Define a porta interna do contêiner que será usada pelo load balancer
- "traefik.http.services.webapp.loadbalancer.server.port=80"
deploy:
# Configuração de implantação do serviço
mode: replicated
# Define o número de réplicas (instâncias) do serviço
replicas: 3
Configure o serviço do Watchtower para monitorar a imagem Docker com a tag prod
. Sempre que houver uma atualização, o Watchtower irá puxar as alterações e reiniciar os serviços automaticamente.
# Continuous Delivery/Deployment
watchtower:
image: containrrr/watchtower # Imagem do Watchtower.
command:
- "--label-enable" # Monitora apenas serviços com labels específicas.
- "--interval" # Define o intervalo de verificação.
- "30" # Verifica atualizações a cada 30 segundos.
- "--rolling-restart" # Reinicia os serviços de forma gradual.
volumes:
- /var/run/docker.sock:/var/run/docker.sock # Permite ao Watchtower gerenciar containers.
# Adicione esta label ao serviço "webapp" para que o Watchtower o monitore:
# - "com.centurylinklabs.watchtower.enable=true"
O arquivo final deve ficar assim:
services:
watchtower:
image: containrrr/watchtower
command:
- "--label-enable"
- "--interval"
- "30"
- "--rolling-restart"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
reverse-proxy:
image: traefik:v3.1
command:
- "--providers.docker"
- "--providers.docker.exposedbydefault=false"
- "--entryPoints.websecure.address=:443"
- "--certificatesresolvers.myresolver.acme.tlschallenge=true"
- "--certificatesresolvers.myresolver.acme.email=email@email.com"
- "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
- "--entrypoints.web.address=:80"
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
ports:
- "80:80"
- "443:443"
volumes:
- letsencrypt:/letsencrypt
- /var/run/docker.sock:/var/run/docker.sock
webapp:
image: fernandeeess/portfolio-app:prod
labels:
- "traefik.enable=true"
- "traefik.http.routers.webapp.rule=Host(`yourdomain.com`)"
- "traefik.http.routers.webapp.entrypoints=websecure"
- "traefik.http.routers.webapp.tls.certresolver=myresolver"
- "traefik.http.services.webapp.loadbalancer.server.port=80"
- "com.centurylinklabs.watchtower.enable=true"
deploy:
mode: replicated
replicas: 3
volumes:
letsencrypt:
Se tudo estiver configurado corretamente, você poderá acessar seu projeto no seu domínio configurado
10. Configure o CI utilizando o GitHub Actions
Automatize o processo de construção da imagem Docker e envio ao Docker Hub. Siga o tutorial disponível no link abaixo:
Automate Docker Image Builds and Push to Docker Hub Using GitHub Actions
Lembre-se de que a imagem deve estar com a tag "prod" para que o Watchtower possa puxar as alterações e reiniciar os serviços.
11. Links
- Portfolio
- Instalação e Configuração do Docker:
- Documentação e Conceitos do Docker:
- Recursos Adicionais e Ferramentas Relacionadas:
- Firewall e Práticas de Segurança:
Top comments (0)