N:B Setup necessary VPC configurations, public and private subnet, provide necessary permission of your AWS access and secret key and more importantly the lambda security group outbound rules:
- 443 Outbound rules should be forwarded to 0.0.0.0/0
- Any 5432/Postgres Outbound rules should be forwarded be to postgres-security-group
- For Postgres security group inbound rule accepts incoming from Lamda security groups
Create Serverless yml in project root:
service: backend-api frameworkVersion: '^3.0.0' useDotenv: true configValidationMode: error provider: name: aws region: us-east-2 runtime: nodejs20.x stage: ${opt:stage, 'dev'} deploymentMethod: direct logRetentionInDays: 7 vpc: securityGroupIds: - sg-13f39e24a9d - sg-87037c0f81 subnetIds: - subnet-d40bc57 - subnet-45gf564g3454 ecr: scanOnPush: true images: backend-api-image: path: . file: Dockerfile environment: NODE_ENV: ${env:NODE_ENV} DATABASE_URL: ${env:DATABASE_URL} JWT_TOKEN_SECRET: ${env:JWT_TOKEN_SECRET} API_BACKEND_AWS_REGION: ${env:STUDY_BUDS_AWS_REGION} API_BACKEND_AWS_ACCESS_KEY: ${env:STUDY_BUDS_AWS_ACCESS_KEY} API_BACKEND_AWS_SECRETE_KEY: ${env:STUDY_BUDS_AWS_SECRETE_KEY} AWS_BUCKET_NAME: ${env:AWS_BUCKET_NAME} AWS_CLOUD_FRONT_URL: ${env:AWS_CLOUD_FRONT_URL} AWS_SMTP_HOST: ${env:AWS_SMTP_HOST} AWS_SMTP_USER: ${env:AWS_SMTP_USER} AWS_SMTP_PASS: ${env:AWS_SMTP_PASS} AWS_FROM_EMAIL: ${env:AWS_FROM_EMAIL} AI_BACKEND_URL: ${env:AI_BACKEND_URL} CORS_ALLOWED_HOSTS: ${env:CORS_ALLOWED_HOSTS} FRONTEND_BASE_URL: ${env:FRONTEND_BASE_URL} MAIL_HOST: ${env:MAIL_HOST} MAIL_USER: ${ env:MAIL_USER } MAIL_PASSWORD: ${env:MAIL_PASSWORD} MAIL_FROM_NAME: ${env:MAIL_FROM_NAME} MAIL_FROM_ADDRESS: ${env:MAIL_FROM_ADDRESS} apiGateway: binaryMediaTypes: - '*/*' custom: prune: automatic: true number: 2 functions: main: image: name: backend-api-image command: - dist/src/serverless.handler entryPoint: - '/lambda-entrypoint.sh' memorySize: 1024 timeout: 330 url: true provisionedConcurrency: 0 events: - http: method: ANY path: / - http: method: ANY path: '{proxy+}' Install below two packages:
npm i @codegenie/serverless-express npm i -D @types/aws-lambda Create serverless.ts inside src/serverless.ts
import { NestFactory, Reflector } from '@nestjs/core'; import { AppModule } from './app.module'; import serverlessExpress from '@codegenie/serverless-express'; import { Callback, Context, Handler } from 'aws-lambda'; import { RequestMethod, ValidationPipe } from '@nestjs/common'; import helmet from 'helmet'; import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; import { ResponseTransformInterceptor } from './common/interceptor/global-response-interceptor'; import { RolePermissionsSeederService } from './modules/v1/user/seed/role-permissions.seeder.service'; import { SeedService } from './modules/v1/character/seeder/seeder.service'; let server: Handler; async function bootstrap() { const app = await NestFactory.create(AppModule); const allowedHosts = (process.env.CORS_ALLOWED_HOSTS as string) || '*'; app.enableCors({ origin: allowedHosts.split(','), methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS', credentials: true, }); app.setGlobalPrefix('api/v1', { exclude: [{ path: '/', method: RequestMethod.GET }], }); app.use(helmet()); app.useGlobalPipes( new ValidationPipe({ transform: true, whitelist: true, }), ); const reflector = app.get(Reflector); app.useGlobalInterceptors(new ResponseTransformInterceptor(reflector)); //const rolePermissionsService = app.get(RolePermissionsSeederService); //await Promise.all([rolePermissionsService.insertRolePermissions()]); const rolePermissionsService = app.get(RolePermissionsSeederService); const seedsService = app.get(SeedService); const config = new DocumentBuilder() .setTitle('Backend api') .setDescription('Swagger docs for backend apis') .setVersion('1.0') .addBearerAuth() .build(); const document = SwaggerModule.createDocument(app, config); SwaggerModule.setup('/api-docs', app, document); await app.init(); const expressApp = app.getHttpAdapter().getInstance(); return serverlessExpress({ app: expressApp, }); } export const handler: Handler = async ( event: any, context: Context, callback: Callback, ) => { try { server = server ?? (await bootstrap()); return server(event, context, callback); } catch (error) { console.error('Error during Lambda execution:', error); return { statusCode: 500, body: JSON.stringify({ error: 'Internal Server Error', message: error.message, }), }; } }; Create Dockerfile inside root directory :
# Use the AWS Lambda base image for Node.js FROM public.ecr.aws/lambda/nodejs:22 # Set the working directory in the container WORKDIR ${LAMBDA_TASK_ROOT} # Copy only package files first for dependency installation COPY package*.json ${LAMBDA_TASK_ROOT}/ # Install dependencies (both production and development for the build phase) RUN npm install # Copy the rest of the application code (excluding files in .dockerignore) COPY . ${LAMBDA_TASK_ROOT}/ # Build the NestJS application RUN npm run build # Set the Lambda function handler CMD ["dist/src/serverless.handler"] Create .env.dev in project root
NODE_ENV=development PORT=8035 DATABASE_URL=postgresql://postgres:postgres@database_container:5432/nestjs REDIS_HOST=redis_container REDIS_PORT=6379 JWT_TOKEN_SECRET=dkfjkjdfkjdfkdfjkjdfkjkdkdfjk AWS_BUCKET_NAME=store-backend API_BACKEND_AWS_REGION=us-east-2 API_BACKEND_AWS_ACCESS_KEY=JKDIUENDIUEKNIUEIJKIWJKWJOUIW API_BACKEND_AWS_SECRETE_KEY=LKFLKORJKIJKUFKJFKJKFJKFKFJ AWS_CLOUD_FRONT_URL=https://your.cloudfront.net AWS_SMTP_HOST=email-smtp.ap-southeast-1.amazonaws.com AWS_SMTP_USER=AJKDIUENSDUJEHUSDJBUE AWS_SMTP_PASS=fkdjkjrtiu93j934jkjf98493ikjkjrjii4ju5 AWS_FROM_EMAIL=alamin.cse15@gmail.com AI_BACKEND_URL=https://aibackend.io/api/v2 CORS_ALLOWED_HOSTS='http://localhost:3000' FRONTEND_BASE_URL="http://localhost:3000" MAIL_HOST=smtp.gmail.com MAIL_USER=alamin.cse15@gmail.com MAIL_PASSWORD='sdjkdfjkdfkdfhjdfhdjfhj' MAIL_FROM_NAME=Shaikh MAIL_FROM_ADDRESS=alamin.cse15@gmail.com *Install serverless framework globally: *
npm i -g serverless@3.39.0 Setup AWS access and secret key using AWS CLI (setup in ubuntu):
**
Now navigate to project root and run **
sls deploy --stage dev Make sure you have .env.dev exists in your project root:
**CI/CD: Deploy from github actions:** name: Deploy Serverless App to Dev Environment on: push: branches: - dev pull_request: types: [closed] branches: - dev jobs: deploy: if: github.event.pull_request.merged == true || github.event_name == 'push' runs-on: ubuntu-latest steps: # 1. Checkout code - name: Checkout code uses: actions/checkout@v3 # 3. Configure AWS Credentials - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v3 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: us-east-2 # 4. Setup Node.js - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: 20.x - name: Clear Serverless Cache run: | rm -rf .serverless # 5. Map environment variables manually - name: Set Environment Variables run: | rm -f .env.dev touch .env.dev echo "NODE_ENV=${{ secrets.NODE_ENV }}" >> .env.dev echo "DATABASE_URL=${{ secrets.DEV_DATABASE_URL }}" >> .env.dev echo "JWT_TOKEN_SECRET=${{ secrets.DEV_JWT_TOKEN_SECRET }}" >> .env.dev echo "AWS_BUCKET_NAME=${{ secrets.DEV_AWS_BUCKET_NAME }}" >> .env.dev echo "BACKEND_AWS_REGION=${{ secrets.DEV_BACKEND_AWS_REGION }}" >> .env.dev echo "BACKEND_AWS_ACCESS_KEY=${{ secrets.BACKEND_AWS_ACCESS_KEY }}" >> .env.dev echo "BACKEND_AWS_SECRETE_KEY=${{ secrets.DEV_BACKEND_AWS_SECRETE_KEY }}" >> .env.dev echo "AWS_CLOUD_FRONT_URL=${{ secrets.DEV_AWS_CLOUD_FRONT_URL }}" >> .env.dev echo "AWS_SMTP_HOST=${{ secrets.AWS_SMTP_HOST }}" >> .env.dev echo "AWS_SMTP_USER=${{ secrets.AWS_SMTP_USER }}" >> .env.dev echo "AWS_SMTP_PASS=${{ secrets.AWS_SMTP_PASS }}" >> .env.dev echo "AWS_FROM_EMAIL=${{ secrets.AWS_FROM_EMAIL }}" >> .env.dev echo "AI_BACKEND_URL=${{ secrets.DEV_AI_BACKEND_URL }}" >> .env.dev echo "CORS_ALLOWED_HOSTS=${{ secrets.DEV_CORS_ALLOWED_HOSTS }}" >> .env.dev echo "FRONTEND_BASE_URL=${{ secrets.DEV_FRONTEND_BASE_URL }}" >> .env.dev echo "MAIL_HOST=${{ secrets.MAIL_HOST }}" >> .env.dev echo "MAIL_USER=${{ secrets.MAIL_USER }}" >> .env.dev echo "MAIL_PASSWORD=${{ secrets.MAIL_PASSWORD }}" >> .env.dev echo "MAIL_FROM_NAME=${{ secrets.MAIL_FROM_NAME }}" >> .env.dev echo "MAIL_FROM_ADDRESS=${{ secrets.MAIL_FROM_ADDRESS }}" >> .env.dev # 6. Install Serverless Framework v3 - name: Install Serverless Framework v3 run: npm i -g serverless@3.39.0 # 7. Deploy to the specified stage - name: Deploy to dev run: sls deploy --stage dev
Top comments (1)
If someone fails to set up the serverless, I can assist you