"Se um trabalhador quiser fazer bem o seu trabalho, ele deve primeiro afiar suas ferramentas." - Confúcio, "Os Analectos de Confúcio. Lu Linggong"
Primeira página > Programação > Implante NextJs e NestJs como um único aplicativo

Implante NextJs e NestJs como um único aplicativo

Publicado em 2024-11-08
Navegar:350

Ei! Estou animado em compartilhar como você pode configurar o NestJS para funcionar perfeitamente em um único host. Mas primeiro, deixe-me explicar por que essa configuração tem sido minha principal escolha para gerenciar front-end e back-end por tanto tempo.

Next.js é uma potência quando se trata de iniciar novos projetos. Ele vem com recursos como roteamento integrado, renderização no servidor (SSR) e cache que ajudam você a começar a trabalhar. Além disso, Next.js tem seus próprios recursos de API internos, permitindo gerenciar tarefas como cache e preparação de dados diretamente na estrutura. Isso significa que você pode se concentrar mais na construção do seu aplicativo e menos na configuração da infraestrutura.

Mas às vezes você precisa de algo mais poderoso para o servidor. É aí que entra o Nest.js. Essa estrutura é tão poderosa que pode lidar não apenas com as tarefas de middleware entre seu back-end e front-end, mas também pode atuar como uma solução de back-end robusta por conta própria. Portanto NestJS é uma boa adição ao Next.js neste caso, permitindo o uso de uma única linguagem de programação para frontend e backend.

Por que um único host?

Simplificando, é incrivelmente conveniente. Com apenas um git pull e um docker-compose up -d, você está pronto para começar. Não há necessidade de se preocupar com CORS ou malabarismo com portas. Além disso, agiliza o processo de entrega, fazendo com que tudo corra de maneira mais tranquila e eficiente. Como desvantagem, posso apontar que isso não é adequado para grandes projetos com alta carga.

1. Primeiro, vamos definir a estrutura de pastas do seu repositório

Deploy NextJs and NestJs as a single application

2. Vamos declarar um arquivo docker para o servidor

Arquivo: ./docker-compose.yml

services:
    nginx:
        image: nginx:alpine
        ports:
            - "80:80"
        volumes:
            - "./docker/nginx/conf.d:/etc/nginx/conf.d"
        depends_on:
            - frontend
            - backend
        networks:
            - internal-network
            - external-network

    frontend:
        image: ${FRONTEND_IMAGE}
        restart: always
        networks:
            - internal-network

    backend:
        image: ${BACKEND_IMAGE}
        environment:
            NODE_ENV: ${NODE_ENV}
            POSTGRES_HOST: ${POSTGRES_HOST}
            POSTGRES_USER: ${POSTGRES_USER}
            POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
            POSTGRES_DB: ${POSTGRES_DB}
        depends_on:
            - postgres
        restart: always
        networks:
            - internal-network

    postgres:
        image: postgres:12.1-alpine
        container_name: postgres
        volumes:
            - "./docker/postgres:/var/lib/postgresql/data"
        environment:
            POSTGRES_USER: ${POSTGRES_USER}
            POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
            POSTGRES_DB: ${POSTGRES_DB}
        ports:
            - "5432:5432"

networks:
    internal-network:
        driver: bridge

    external-network:
        driver: bridge

Simplificando, é incrivelmente conveniente. Com apenas um git pull e um docker-compose up -d, você está pronto para começar. Não há necessidade de se preocupar com CORS ou malabarismo com portas. Além disso, agiliza o processo de entrega, fazendo com que tudo corra de maneira mais tranquila e eficiente. Como desvantagem, posso apontar que isso não é adequado para grandes projetos com alta carga.

3. Outro arquivo docker para modo de desenvolvimento

Para o modo de desenvolvimento, não precisamos de serviço de contêiner para back-end e front-end porque iremos executá-los localmente.

Arquivo: ./docker-compose.dev.yml

version: '3'

services:
    nginx:
        image: nginx:alpine
        ports:
            - "80:80"
        volumes:
            - "./docker/nginx/conf.d:/etc/nginx/conf.d"

    postgres:
        image: postgres:12.1-alpine
        container_name: postgres
        volumes:
            - "./docker/postgres:/var/lib/postgresql/data"
        environment:
            POSTGRES_USER: postgres
            POSTGRES_PASSWORD: postgres
            POSTGRES_DB: postgres
        ports:
            - "5432:5432"

4. Arquivo Docker para back-end

Arquivo: ./backend/Dockerfile

FROM node:18-alpine AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app

COPY package.json package-lock.json ./
RUN  npm install

FROM node:18-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

ENV NEXT_TELEMETRY_DISABLED 1

RUN npm run build

FROM node:18-alpine AS runner
WORKDIR /app

ENV NODE_ENV production
ENV NEXT_TELEMETRY_DISABLED 1

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --from=builder --chown=nextjs:nodejs /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json

RUN mkdir -p /app/backups && chown -R nextjs:nodejs /app/backups && chmod -R 777 /app/backups

USER nextjs

EXPOSE 3010

ENV PORT 3010

CMD ["node", "dist/src/main"]

## 5. Docker file for frontend
File: ./frontend/Dockerfile

FROM node:18-alpine AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app

COPY package.json package-lock.json ./
RUN  npm install

FROM node:18-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

ENV NEXT_TELEMETRY_DISABLED 1

RUN npm run build

FROM node:18-alpine AS runner
WORKDIR /app

ENV NODE_ENV production
ENV NEXT_TELEMETRY_DISABLED 1

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json

USER nextjs

EXPOSE 3000

ENV PORT 3000

CMD ["npm", "start"]

6. Configuração Ngnix

Nesta etapa, configuramos o Nginx para atuar como um proxy reverso para nosso frontend Next.js e backend Nest.js. A configuração do Nginx permite encaminhar solicitações perfeitamente entre o front-end e o back-end, ao mesmo tempo em que as atende no mesmo host.

Arquivo: /docker/nginx/conf.d/default.conf

server {
    listen 80;

    location / {
        proxy_pass http://host.docker.internal:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /api {
        proxy_pass http://host.docker.internal:3010;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Esta configuração escuta na porta 80 e roteia o tráfego geral para o frontend Next.js na porta 3000, enquanto quaisquer solicitações para /api são encaminhadas para o backend Nest.js na porta 3010.

7. Prefixo global da NestJs

Como usamos o mesmo host, precisamos que os NestJs estejam disponíveis em /apipath. Para fazer isso, precisamos setGlobalPrefix — API.

Arquivo: ./backend/src/main.js

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule, { cors: true  });
  app.setGlobalPrefix('api');
  await app.listen(3010);
}
bootstrap();

8. Interface

Nenhuma configuração é necessária no frontend, mas apenas levando em consideração que todas as solicitações do servidor devem ser chamadas em relação ao caminho /api.

9. Execute localmente

front-end do CD
npm executar desenvolvedor
cd ../backend
início de execução npm:dev
cd ../
docker-compose -f docker-compose.dev.yml up -d

Agora podemos verificar nosso site abrindo localhost no navegador. No exemplo temos 1 requisição no servidor e outra no cliente. Ambas as solicitações são chamadas de Next.Js e processadas por Nest.Js.

Deploy NextJs and NestJs as a single application

10. Implante e execute no servidor via GitHub

Este artigo explora como implantar um projeto em um servidor usando Docker Registry e GitHub Actions. O processo começa com a criação de imagens Docker para back-end e front-end no Docker Registry. Depois disso, você precisará configurar um repositório GitHub e configurar os segredos necessários para uma implantação perfeita:

DOCKERHUB_USERNAME
DOCKERHUB_TOKEN
DOCKER_FRONTEND_IMAGE
DOCKER_BACKEND_IMAGE
REMOTE_SERVER_HOST
REMOTE_SERVER_USERNAME
REMOTE_SERVER_SSH_KEY
REMOTE_SERVER_SSH_PORT

A desvantagem de usar um repositório para backend e frontend é que cada vez que você envia algo, ambas as imagens são reconstruídas. Para otimizá-lo, podemos usar estas condições:

if: contains(github.event_name, ‘push’) && !startsWith(github.event.head_commit.message, ‘frontend’)
if: contains(github.event_name, ‘push’) && !startsWith(github.event.head_commit.message, ‘backend’)

Torna possível reconstruir apenas a imagem que você atende especificando a mensagem de commit.

Arquivo: ./github/workflows/deploy.yml

name: deploy nextjs and nestjs to GITHUB

on:
  push:
    branches: [ "main" ]

jobs:
  build-and-push-frontend:
    runs-on: ubuntu-latest

    if: contains(github.event_name, 'push') && !startsWith(github.event.head_commit.message, 'backend')

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

      - name: Login to Docker Hub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Build and push frontend to Docker Hub
        uses: docker/build-push-action@v2
        with:
          context: frontend
          file: frontend/Dockerfile
          push: true
          tags: ${{ secrets.DOCKER_FRONTEND_IMAGE }}:latest

      - name: SSH into the remote server and deploy frontend
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.REMOTE_SERVER_HOST }}
          username: ${{ secrets.REMOTE_SERVER_USERNAME }}
          password: ${{ secrets.REMOTE_SERVER_SSH_KEY }}
          port: ${{ secrets.REMOTE_SERVER_SSH_PORT }}
          script: |
            cd website/
            docker rmi -f ${{ secrets.DOCKER_FRONTEND_IMAGE }}:latest
            docker-compose down
            docker-compose up -d

  build-and-push-backend:
    runs-on: ubuntu-latest

    if: contains(github.event_name, 'push') && !startsWith(github.event.head_commit.message, 'frontend')

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

      - name: Login to Docker Hub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Build and push backend to Docker Hub
        uses: docker/build-push-action@v2
        with:
          context: backend
          file: backend/Dockerfile
          push: true
          tags: ${{ secrets.DOCKER_BACKEND_IMAGE }}:latest

      - name: SSH into the remote server and deploy backend
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.REMOTE_SERVER_HOST }}
          username: ${{ secrets.REMOTE_SERVER_USERNAME }}
          password: ${{ secrets.REMOTE_SERVER_SSH_KEY }}
          port: ${{ secrets.REMOTE_SERVER_SSH_PORT }}
          script: |
            cd website/
            docker rmi -f ${{ secrets.DOCKER_BACKEND_IMAGE }}:latest
            docker-compose down
            docker-compose up -d=
empregos: front-end de construção e push: executado: ubuntu-mais recente if: contém(github.event_name, 'push') && !startsWith(github.event.head_commit.message, 'backend') passos: - nome: Check-out usa: ações/checkout@v3 - nome: Faça login no Docker Hub usa: docker/login-action@v1 com: nome de usuário: ${{ secrets.DOCKERHUB_USERNAME }} senha: ${{ secrets.DOCKERHUB_TOKEN }} - nome: Construa e envie o front-end para o Docker Hub usa: docker/build-push-action@v2 com: contexto: front-end arquivo: frontend/Dockerfile empurrar: verdadeiro tags: ${{secrets.DOCKER_FRONTEND_IMAGE }}:mais recentes - nome: SSH no servidor remoto e implantação do frontend usa: appleboy/ssh-action@master com: anfitrião: ${{ secrets.REMOTE_SERVER_HOST }} nome de usuário: ${{ secrets.REMOTE_SERVER_USERNAME }} senha: ${{ secrets.REMOTE_SERVER_SSH_KEY }} porta: ${{ secrets.REMOTE_SERVER_SSH_PORT }} roteiro: | site do CD/ docker rmi -f ${{secrets.DOCKER_FRONTEND_IMAGE }}:mais recentes docker-compose down docker-compose up -d construir e enviar back-end: executado: ubuntu-mais recente if: contém(github.event_name, 'push') && !startsWith(github.event.head_commit.message, 'frontend') passos: - nome: Check-out usa: ações/checkout@v3 - nome: Faça login no Docker Hub usa: docker/login-action@v1 com: nome de usuário: ${{ secrets.DOCKERHUB_USERNAME }} senha: ${{ secrets.DOCKERHUB_TOKEN }} - nome: Construa e envie back-end para Docker Hub usa: docker/build-push-action@v2 com: contexto: back-end arquivo: backend/Dockerfile empurrar: verdadeiro tags: ${{secrets.DOCKER_BACKEND_IMAGE }}:mais recentes - nome: SSH no servidor remoto e implantar back-end usa: appleboy/ssh-action@master com: anfitrião: ${{ secrets.REMOTE_SERVER_HOST }} nome de usuário: ${{ secrets.REMOTE_SERVER_USERNAME }} senha: ${{ secrets.REMOTE_SERVER_SSH_KEY }} porta: ${{ secrets.REMOTE_SERVER_SSH_PORT }} roteiro: | site do CD/ docker rmi -f ${{secrets.DOCKER_BACKEND_IMAGE }}:mais recentes docker-compose down docker-compose up -d=

Repositório: https://github.com/xvandevx/blog-examples/tree/main/nextjs-nestjs-deploy

Recapitular

Este artigo é um guia prático para implantar Next.js e Nest.js juntos em um único servidor, tornando-o uma solução ideal para desenvolvedores que desejam uma configuração simplificada. Combinando os pontos fortes do Next.js para frontend e Nest.js para backend, mostrei como gerenciar com eficiência ambas as partes do seu aplicativo usando Docker e GitHub Actions. Ele simplifica o processo de implantação, permitindo que você se concentre na construção do seu aplicativo, em vez de fazer malabarismos com várias configurações. Perfeito para quem deseja colocar um projeto full-stack em funcionamento rapidamente e com o mínimo de complicações.

Declaração de lançamento Este artigo foi reproduzido em: https://dev.to/xvandev/deploy-nextjs-and-nestjs-as-a-single-application-15mj?1 Se houver alguma violação, entre em contato com [email protected] para excluir isto
Tutorial mais recente Mais>

Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.

Copyright© 2022 湘ICP备2022001581号-3