DEV Community

Cover image for Seamless Nuxt 2 Deployment: A Step-by-Step Guide with GitLab CI/CD and DigitalOcean
Ivan Mykhavko
Ivan Mykhavko

Posted on

Seamless Nuxt 2 Deployment: A Step-by-Step Guide with GitLab CI/CD and DigitalOcean

1. Introduction

Deploying a web application can often feel like a daunting task, especially when striving for a seamless user experience. Nuxt 2, a popular framework for building Vue.js applications, is no exception. Ensuring a smooth deployment process with zero downtime is crucial for maintaining user trust and satisfaction. This guide walks you through deploying a Nuxt 2 application using GitLab CI/CD and DigitalOcean, ensuring efficiency and reliability.

GitLab CI/CD provides a robust and flexible platform for automating the deployment pipeline, while DigitalOcean offers scalable and straightforward hosting solutions. Combined with tools like PM2 for process management and Nginx for serving your application, you can achieve a production-ready deployment with zero downtime.

Whether you’re deploying for the first time or looking to refine your existing workflow, this guide will help you master the process step-by-step, from setting up your server to configuring continuous integration and deployment. By the end, your Nuxt 2 application will be live and running seamlessly on DigitalOcean, ready to handle production traffic.

2. Prerequisites

Before diving into the deployment process, ensure you have these essential components for successfully deploying your Nuxt 2 application using GitLab CI/CD and DigitalOcean.

2.1 Development Environment

  • Nuxt 2 Application: Production-ready with configured nuxt.config.js
  • Node.js and Package Manager:
    • Node.js 18.x LTS
    • Yarn or NPM for package management

2.2 GitLab Repository

  • GitLab repository with your Nuxt 2 project
  • CI/CD pipeline configuration access
  • Version control best practices implemented

2.3 DigitalOcean Account

  • Active DigitalOcean account
  • Droplet specifications:
    • Ubuntu 22.04 or 24.04 LTS
    • 1 vCPU, 1 GB RAM, 25 GB SSD
  • Optional: Registered domain name

2.4 Server Requirements

  • Operating System: Ubuntu 22.04 or 24.04 LTS
  • Minimum Hardware:
    • 1 vCPU
    • 1 GB RAM
    • 25 GB SSD storage

2.5 Essential Tools

  • Process Management: PM2 (v5.x recommended)
  • Web Server: Nginx (v1.18 or later)
  • Security:
    • SSH
    • Certbot for Let's Encrypt SSL

2.6 Required Knowledge

Helpful background in:

  • Basic Linux terminal commands
  • Git workflows
  • GitLab CI/CD concepts
  • Nuxt 2 application structure

With these prerequisites met, you're prepared to implement a professional deployment pipeline for your Nuxt 2 application.

3. Setting Up the DigitalOcean Server

Setting up a reliable server is the foundation for a seamless deployment process. Follow these steps to prepare your
DigitalOcean droplet:

3.1 Create a Droplet

  1. Log in to your DigitalOcean account and navigate to the Create menu.
  2. Select Droplets and choose Ubuntu 22/24.04 as the operating system.
  3. Select the appropriate plan for your application. A basic plan with 1 GB RAM and 1 vCPU is sufficient for small projects. Upgrade as needed for larger applications.
  4. Add your SSH key to enable secure access to the server. If you don’t have one, generate an SSH key pair using the following command on your local machine:
   ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
Enter fullscreen mode Exit fullscreen mode

Add the public key (~/.ssh/id_rsa.pub) to your droplet. Follow the instruction
from how to add SSH keys to Droplets.

   cat ~/.ssh/id_rsa.pub
Enter fullscreen mode Exit fullscreen mode

And copy content.
generate ssh key
add public ssh key

  1. Finalize and create the droplet. Name your DigitalOcean droplet based on its purpose, environment, and region for clarity, such as web-prod-nyc1 or db-staging-ams3. Use short, descriptive, and consistent names to make management easier. Avoid generic names like server1 to ensure quick identification. We called our droplet: demo-deploy-nuxt2-app. Take note of the droplet’s public IP address. copy public ip

3.2 Secure the Server

After creating the droplet, secure it to prevent unauthorized access:

  1. Connect to the droplet using SSH:
   ssh root@your_droplet_ip
Enter fullscreen mode Exit fullscreen mode
  1. Update the system packages:
   apt update && apt upgrade -y
Enter fullscreen mode Exit fullscreen mode
  1. Set up a basic firewall using UFW (Uncomplicated Firewall):
   ufw allow OpenSSH
   ufw enable
Enter fullscreen mode Exit fullscreen mode
  1. Create a dedicated deployment user with sudo privileges:
   adduser deployer
   usermod -aG sudo deployer
Enter fullscreen mode Exit fullscreen mode
  1. Disable root login and password-based authentication for SSH by editing the SSH configuration file:
   nano /etc/ssh/sshd_config
Enter fullscreen mode Exit fullscreen mode

Change the following lines:

   PermitRootLogin no
   PasswordAuthentication no
Enter fullscreen mode Exit fullscreen mode

Restart the SSH service:

   systemctl restart ssh
Enter fullscreen mode Exit fullscreen mode

3.3 Install Node.js and PM2

  1. Install Node.js (18 LTS version):
   curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
   apt install -y nodejs
Enter fullscreen mode Exit fullscreen mode
  1. Verify the installation:
   node -v
   npm -v
Enter fullscreen mode Exit fullscreen mode

node.js version

  1. Install PM2 globally to manage your Nuxt 2 application:
   npm install -g pm2
Enter fullscreen mode Exit fullscreen mode

pm2 version

3.4 Install and Configure Nginx

  1. Install Nginx:
   apt install nginx -y
Enter fullscreen mode Exit fullscreen mode
  1. Configure Nginx as a reverse proxy for your application. When naming Nginx configuration files, use lowercase letters and descriptive names for clarity, such as example-site.conf or api-backend.conf. For environment-specific files, add suffixes like -dev, -stg, or -prod (e.g., example-site-prod.conf). Shared or reusable configurations should have clear prefixes like shared-headers.conf. Avoid redundancy by omitting terms like "nginx" in file names and use .bak or .disabled for backups or inactive files. We name our config file like: demo-deploy-nuxt2-app-prod.
   nano /etc/nginx/sites-available/demo-deploy-nuxt2-app-prod
Enter fullscreen mode Exit fullscreen mode

Replace the contents with the following configuration:

    server {
        listen 80;
        server_name your_domain.com;

        # Disable server tokens for security
        server_tokens off;

        # Basic security headers
        add_header X-Frame-Options "SAMEORIGIN";
        add_header X-XSS-Protection "1; mode=block";
        add_header X-Content-Type-Options "nosniff";

        location / {
            proxy_pass http://localhost:PORT;
            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_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
Enter fullscreen mode Exit fullscreen mode
  1. Enable config file, test the configuration and reload Nginx:
   sudo ln -s /etc/nginx/sites-available/demo-deploy-nuxt2-app-prod /etc/nginx/sites-enabled/
   nginx -t
   systemctl restart nginx
Enter fullscreen mode Exit fullscreen mode

Nginx configuration

Server setup complete! You're now ready to deploy your Nuxt 2 application with enhanced security and performance.

4. Configuring GitLab CI/CD

This section outlines the steps to configure GitLab CI/CD for deploying a Nuxt 2 application to staging and production
environments. The .gitlab-ci.yml file and ecosystem.config.js facilitate automated deployment using Node.js and PM2.

4.1 Define CI/CD Variables

Navigate to Settings > CI/CD > Variables in GitLab. Add these variables to securely store sensitive data:

  • STAGING_SSH_PRIVATE_KEY: Private SSH key for the staging server.
  • PRODUCTION_SSH_PRIVATE_KEY: Private SSH key for the production server.

Ensure these keys match those configured for your DEPLOY_USER on the respective servers.

4.2 Overview of .gitlab-ci.yml

This file defines the pipeline with the following stages:

  • Test: Runs tests to validate the application.
  • Build: Compiles the application for deployment.
  • Deploy to Staging: Deploys the build to staging.
  • Deploy to Production: Deploys the build to production.
image: node:18

stages:
  - test
  - build
  - deploy-production

variables:
  PRODUCTION_SERVER: staging-server-ip
  DEPLOY_USER: deployer
  PRODUCTION_APP_NAME: demo-deploy-nuxt2-app-production
  PRODUCTION_PORT: 3200
  PRODUCTION_APP_PATH: /var/www/production
  DEPLOY_FILES: ".nuxt static nuxt.config.js package.json yarn.lock ecosystem.config.js"

cache:
  paths:
    - node_modules/
    - .yarn-cache/

before_script:
  - yarn config set cache-folder .yarn-cache
  - yarn install --frozen-lockfile

test:
  stage: test
  script:
    - yarn test

build:
  stage: build
  script:
    - yarn build
  artifacts:
    paths:
      - .nuxt/
      - static/
      - nuxt.config.js
      - package.json
      - yarn.lock
      - ecosystem.config.js
    expire_in: 1 hour

deploy-production:
  stage: deploy-production
  environment:
    name: production
    url: https://yourdomain.com
  script:
    - apt-get update -qy
    - apt-get install -y openssh-client
    - mkdir -p ~/.ssh
    - echo "$PRODUCTION_SSH_PRIVATE_KEY" | tr -d '\r' > ~/.ssh/id_rsa
    - chmod 600 ~/.ssh/id_rsa
    - ssh-keyscan -H $PRODUCTION_SERVER >> ~/.ssh/known_hosts

    # Create new release directory
    - export RELEASE_DIR=$(date +%Y%m%d%H%M%S)
    - |
      ssh $DEPLOY_USER@$PRODUCTION_SERVER "
      mkdir -p $PRODUCTION_APP_PATH/releases/$RELEASE_DIR;
      "

    # Copy built artifacts
    - scp -r $DEPLOY_FILES $DEPLOY_USER@$PRODUCTION_SERVER:$PRODUCTION_APP_PATH/releases/$RELEASE_DIR/

    # Update symlinks and restart application
    - |
      ssh $DEPLOY_USER@$PRODUCTION_SERVER "
      cd $PRODUCTION_APP_PATH;
      if [ -L current ]; then mv current previous; fi;
      ln -s releases/$RELEASE_DIR current;
      cd current;
      yarn install --frozen-lockfile --production;
      export APP_NAME=$PRODUCTION_APP_NAME;
      export NODE_ENV=production;
      export PORT=$PRODUCTION_PORT;
      export APP_PATH=$PRODUCTION_APP_PATH/current;
      pm2 startOrGracefulReload ecosystem.config.js --update-env;
      pm2 save;

      # Cleanup old releases (keep last 5)
      cd releases;
      ls -1dt */ | tail -n +6 | xargs rm -rf;
      "
  only:
    - main
Enter fullscreen mode Exit fullscreen mode
Key Highlights
  1. Caching:
   cache:
     key: ${CI_COMMIT_REF_SLUG}
     paths:
       - node_modules/
       - .yarn-cache/
Enter fullscreen mode Exit fullscreen mode

Speeds up pipelines by caching dependencies.

  1. Artifacts: Artifacts from the build stage are stored temporarily for deployment.
   artifacts:
     paths:
       - .nuxt/
       - static/
       - nuxt.config.js
       - package.json
       - yarn.lock
       - ecosystem.config.js
     expire_in: 1 hour
Enter fullscreen mode Exit fullscreen mode
  1. Deployment Scripts: Deployment involves creating a release directory, transferring files, updating symlinks, and restarting the app using PM2.

4.3 Server Configurations

Ensure these server configurations:

  • DEPLOY_USER has access to /var/www/staging and /var/www/production.
  • PM2 is installed and properly set up.

4.4 ecosystem.config.js Customization

The ecosystem.config.js file specifies PM2 settings:

module.exports = {
    apps: [
        {
            name: `demo-deploy-nuxt2-app-${process.env.NODE_ENV}`,
            script: './node_modules/nuxt/bin/nuxt.js',
            args: 'start',
            cwd: process.env.APP_PATH || '/var/www/staging/current',
            instances: 'max',
            exec_mode: 'cluster',
            env: {
                NODE_ENV: process.env.NODE_ENV,
                PORT: process.env.PORT || 3100,
            },
            max_memory_restart: '1G',
            error_file: `/var/log/pm2/${process.env.APP_NAME || 'staging'}-error.log`,
            out_file: `/var/log/pm2/${process.env.APP_NAME || 'staging'}-out.log`
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode

Adjust paths and variables as necessary.

4.5 Set Up the Pipeline

Commit the .gitlab-ci.yml and ecosystem.config.js files to your repository and push changes to trigger the pipeline.

Workflow
  • Staging Deployment: Automatically deploys from the staging branch.
  • Production Deployment: Automatically deploys from the main branch.

4.6 Testing and Troubleshooting

  1. Push code changes to staging and verify deployment at https://staging.yourdomain.com.
  2. Merge changes to main to test production deployment at https://yourdomain.com.
  3. For issues:
    • Check GitLab pipeline logs for errors.
    • Inspect PM2 logs (/var/log/pm2) on the server.
    • Verify SSH keys and configurations.

This configuration ensures a streamlined deployment process for your Nuxt 2 application.

5. Enabling HTTPS with Let’s Encrypt

Secure your application with HTTPS by setting up Let’s Encrypt:

  1. Install Certbot:
   apt install certbot python3-certbot-nginx -y
Enter fullscreen mode Exit fullscreen mode
  1. Obtain an SSL certificate:
   certbot --nginx -d your_domain
Enter fullscreen mode Exit fullscreen mode
  1. Test the renewal process:
   certbot renew --dry-run
Enter fullscreen mode Exit fullscreen mode
  1. Reload Nginx:
   systemctl reload nginx
Enter fullscreen mode Exit fullscreen mode

6. Results and Repository Access

By following this guide, you now have a fully functional pipeline that automates the deployment of your Nuxt 2
application to a DigitalOcean Droplet using GitLab CI/CD. Here's a quick summary of what we accomplished:

  • Continuous Integration: Each commit triggers a pipeline that installs dependencies, builds the Nuxt 2 project, and runs necessary tests.
  • Continuous Deployment: Successful builds are deployed automatically to your DigitalOcean Droplet.
  • Reliable Environment: Your application runs in a secure and scalable production environment.

Final Results

After deployment, you should observe the following:

  1. Live Application: Your Nuxt 2 app is accessible via your DigitalOcean server's IP address or domain.
  2. Automated Workflow: Every push to the main branch seamlessly updates your production environment without manual intervention.
  3. Error Logs and Monitoring: Logs and CI/CD pipelines provide detailed insights for troubleshooting and performance tracking.

app
pipelines

Access the Repository

To explore the full configuration files and pipeline setup, you can access the repository here:

GitLab Repository Link

7. Conclusion

Congratulations! By following this guide, you’ve successfully deployed a Nuxt 2 application with zero downtime using
GitLab CI/CD and DigitalOcean. This setup not only automates repetitive deployment tasks but also ensures a reliable and
scalable environment for your application. As your app grows, you can easily monitor, optimize, and scale to meet
increasing demands.

Take pride in achieving a seamless deployment! As a next step, consider exploring advanced performance tuning,
integrating monitoring tools, or further automating your workflows. The possibilities are endless—happy building!

Let me know if you'd like additional tweaks!

Top comments (0)