Set up a nginx aws general purpose web server for my next.js app

Set up a nginx aws general purpose web server for my next.js app

set up a nginx aws general purpose web server for my next.js app in /var/www/myapp and run it as a process with pm2 systemctl https, all that stuff so this web server is ready to deploy my we

Published: Today5 views1 likesAuthor: ComputerScienceX

1 total likes

Below is a solid “general-purpose” AWS EC2 setup for a Next.js app in /var/www/myapp, fronted by Nginx, running as a PM2-managed systemd service, with HTTPS (Let’s Encrypt). This is the standard production pattern: Nginx (80/443) → localhost:3000 (Next.js).

Assumptions: Ubuntu 22.04/24.04 on EC2, you have a domain (recommended), and you can SSH in.

  1. AWS prerequisites (security group + DNS)

Security Group inbound rules

TCP 22 from your IP (SSH)

TCP 80 from 0.0.0.0/0 (HTTP)

TCP 443 from 0.0.0.0/0 (HTTPS)

DNS

Create an A record: yourdomain.com → your EC2 public IPv4

Optional: www.yourdomain.com → same

  1. Base packages + firewall sudo apt update sudo apt -y upgrade

sudo apt -y install nginx ufw git curl build-essential

sudo ufw allow OpenSSH sudo ufw allow 'Nginx Full' sudo ufw --force enable

sudo systemctl enable --now nginx

Check Nginx:

curl -I http://localhost 2) Create a deploy user (optional but recommended)

If you’re currently using ubuntu user, that’s fine. The important part is: don’t run your app as root.

sudo adduser deploy sudo usermod -aG sudo deploy

Then (optional) let deploy manage /var/www/myapp:

sudo mkdir -p /var/www/myapp sudo chown -R deploy:deploy /var/www/myapp sudo chmod -R 755 /var/www

Log in as deploy:

sudo su - deploy 3) Install Node.js LTS (via NodeSource)

(Use current LTS line; this installs a modern Node suitable for Next.js.)

curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - sudo apt -y install nodejs node -v npm -v 4) Put your Next.js app in /var/www/myapp

If you already have it there, skip. Otherwise:

cd /var/www/myapp

either git clone into it OR copy files here

Example:

git clone <your_repo_url> .

Install deps:

cd /var/www/myapp npm ci

Create/adjust production env:

nano /var/www/myapp/.env.production

Build:

npm run build

Quick local test:

npm run start -- -p 3000

CTRL+C

  1. Install PM2 and run the app

Install PM2 globally:

sudo npm i -g pm2 pm2 -v Option A (simple): run npm start cd /var/www/myapp pm2 start npm --name myapp -- start -- -p 3000 pm2 save pm2 status Option B (recommended): ecosystem file (supports multiple processes cleanly)

Create ecosystem.config.cjs:

cd /var/www/myapp cat > ecosystem.config.cjs <<'EOF' module.exports = { apps: [ { name: "myapp", cwd: "/var/www/myapp", script: "node_modules/next/dist/bin/next", args: "start -p 3000", env: { NODE_ENV: "production" }, // If you use .env.production, Next loads it automatically in production, // but you can also use env_file if you prefer: // env_file: "/var/www/myapp/.env.production", autorestart: true, max_restarts: 10 } ] }; EOF

Start it:

pm2 start ecosystem.config.cjs pm2 save 6) Make PM2 a systemd service (auto-start on reboot)

Run this as the user that runs PM2 (e.g., deploy):

pm2 startup systemd

PM2 will print a command that starts with sudo env PATH=... pm2 startup systemd -u deploy --hp /home/deploy. Copy/paste that exact command.

Then:

pm2 save sudo systemctl status pm2-deploy

Now your app will come back after reboot.

  1. Configure Nginx reverse proxy (HTTP → localhost:3000)

Create a server block:

sudo nano /etc/nginx/sites-available/myapp

Paste (replace yourdomain.com):

server { listen 80; listen [::]:80;

server_name yourdomain.com www.yourdomain.com;

# Optional: increase body size for uploads
client_max_body_size 25m;

# Basic security headers (safe defaults)
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options DENY always;
add_header Referrer-Policy strict-origin-when-cross-origin always;

location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_http_version 1.1;

    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;

    # WebSockets / upgrade (useful if you add them later)
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

    proxy_read_timeout 60s;
    proxy_send_timeout 60s;
}

}

Enable it:

sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/myapp

sudo nginx -t sudo systemctl reload nginx

Test from server:

curl -I http://yourdomain.com 8) Add HTTPS with Let’s Encrypt (Certbot)

Install certbot:

sudo apt -y install certbot python3-certbot-nginx

Issue cert + auto-edit Nginx:

sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

Verify renewal timer:

sudo systemctl status certbot.timer sudo certbot renew --dry-run

At this point you have:

HTTPS on 443

HTTP redirected to HTTPS (if you chose that option in Certbot)

  1. Operational checks & common admin commands App health pm2 status pm2 logs myapp curl -I http://127.0.0.1:3000 curl -I https://yourdomain.com Nginx logs sudo tail -f /var/log/nginx/access.log sudo tail -f /var/log/nginx/error.log Restart flows pm2 restart myapp sudo systemctl reload nginx After deploying new code

Typical flow:

cd /var/www/myapp git pull npm ci npm run build pm2 restart myapp 10) “General purpose” extras you’ll likely want A) Provide a standard place for shared env/secrets

Keep app env in: /var/www/myapp/.env.production

Set permissions:

sudo chown deploy:deploy /var/www/myapp/.env.production sudo chmod 600 /var/www/myapp/.env.production B) Enable swap on small instances (helps builds)

For t2/t3 small instances, building Next.js can OOM. Example 2GB swap:

sudo fallocate -l 2G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab free -h C) Multiple processes behind Nginx

Run additional services on other localhost ports (e.g., API on 4000) using PM2.

Add more location blocks or separate subdomains in Nginx.

Minimal “ready-to-deploy” summary

You now have:

Nginx running on 80/443

HTTPS via Certbot

Next.js served by PM2 on localhost:3000

systemd auto-start for PM2 on reboot