Skip to content

astro SSR deployemnt

Deploying a dynamic (SSR) Astro site to an EC2 instance with Nginx is different from a static deployment. For SSR, Astro must run as a Node server (or another adapter like Deno/Cloudflare), and Nginx acts as a reverse proxy.

Below is the correct, production-ready guide for Ubuntu EC2 + Nginx + Astro SSR (Node adapter).


STEP 1 — Build your Astro project for SSR

Section titled “✅ STEP 1 — Build your Astro project for SSR”

In astro.config.mjs you must use:

import node from "@astrojs/node";
export default {
output: "server",
adapter: node({
mode: "standalone", // recommended on servers
}),
};

Then build:

Terminal window
npm install
npm run build

This produces a server-ready folder:

/dist
└── server.mjs
└── package.json
└── node_modules (light version)

STEP 2 — Upload your dist folder to the EC2 instance

Section titled “✅ STEP 2 — Upload your dist folder to the EC2 instance”

From your machine:

Terminal window
rsync -avz dist/ ubuntu@your-ec2:/var/www/myastro

Or via Git pull directly on EC2.


STEP 3 — Install dependencies on the EC2 server

Section titled “✅ STEP 3 — Install dependencies on the EC2 server”

SSH into EC2:

Terminal window
ssh ubuntu@your-ec2
cd /var/www/myastro
npm install --production

⚠️ If you used mode: "standalone", the server bundle already includes dependencies, and you don’t need npm install.


Test manually:

Terminal window
node ./server.mjs

It usually runs on port 3000, unless configured otherwise.

Check it’s working: http://your-ec2:3000


STEP 5 — Create a PM2 service for Astro

Section titled “✅ STEP 5 — Create a PM2 service for Astro”

Install PM2:

Terminal window
sudo npm i -g pm2

Start the Astro server:

Terminal window
pm2 start server.mjs --name astro-site
pm2 save
pm2 startup

This ensures your Astro server runs permanently after reboot.


STEP 6 — Configure Nginx as a reverse proxy

Section titled “✅ STEP 6 — Configure Nginx as a reverse proxy”

Create your site config:

Terminal window
sudo nano /etc/nginx/sites-available/astro

Paste:

server {
listen 80;
server_name your-domain.com;
location / {
proxy_pass http://127.0.0.1:3000;
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;
}
}

Enable it:

Terminal window
sudo ln -s /etc/nginx/sites-available/astro /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

STEP 7 — (Optional but recommended) Install HTTPS with Certbot

Section titled “✅ STEP 7 — (Optional but recommended) Install HTTPS with Certbot”
Terminal window
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.com

🚀 Your Astro SSR site is now live behind Nginx!

Section titled “🚀 Your Astro SSR site is now live behind Nginx!”

Terminal window
curl -I http://localhost

You should get:

HTTP/1.1 200 OK
server: nginx

ComponentRole
Astro SSRRuns as Node server (PM2)
Port 3000Internal server port
NginxReverse proxy in front
HTTPSManaged by Certbot

If you want, I can prepare a complete ready-to-copy server config, a deployment bash script, or help you fix errors (proxy, permissions, PM2, Nginx).

Perfect — here is Option A: a full ready-to-copy deployment script that installs everything on a fresh Ubuntu EC2 instance and deploys an Astro SSR (Node) site behind Nginx + PM2.


🚀 FULL DEPLOYMENT SCRIPT FOR ASTRO SSR ON UBUNTU + NGINX + PM2

Section titled “🚀 FULL DEPLOYMENT SCRIPT FOR ASTRO SSR ON UBUNTU + NGINX + PM2”

Replace the variables:

  • your_domain.com
  • /var/www/myastro
  • 3000 (if you use another port)

📦 DEPLOYMENT SCRIPT (copy & paste in EC2)

Section titled “📦 DEPLOYMENT SCRIPT (copy & paste in EC2)”
#!/bin/bash
# -----------------------------
# CONFIG - CHANGE THESE VALUES
# -----------------------------
DOMAIN="your_domain.com"
PROJECT_DIR="/var/www/myastro"
ASTRO_PORT=3000
NODE_VERSION="20"
# -----------------------------
# UPDATE SYSTEM
# -----------------------------
sudo apt update && sudo apt upgrade -y
# -----------------------------
# INSTALL NODE
# -----------------------------
curl -fsSL https://deb.nodesource.com/setup_$NODE_VERSION.x | sudo -E bash -
sudo apt install -y nodejs
# -----------------------------
# INSTALL NGINX
# -----------------------------
sudo apt install -y nginx
sudo systemctl enable nginx
sudo systemctl start nginx
# -----------------------------
# INSTALL PM2
# -----------------------------
sudo npm install -g pm2
# -----------------------------
# CREATE PROJECT DIRECTORY
# -----------------------------
sudo mkdir -p $PROJECT_DIR
sudo chown -R $USER:$USER $PROJECT_DIR
# -----------------------------
# PULL OR COPY YOUR ASTRO BUILD
# (You must rsync or git clone before running PM2)
# -----------------------------
echo "⚠️ Make sure your Astro 'dist/' folder is inside $PROJECT_DIR"
# -----------------------------
# START ASTRO SSR SERVER
# -----------------------------
cd $PROJECT_DIR
pm2 stop astro-site || true
pm2 delete astro-site || true
pm2 start server.mjs --name astro-site
pm2 save
pm2 startup -u $USER --hp $HOME
# -----------------------------
# CREATE NGINX REVERSE PROXY
# -----------------------------
sudo bash -c "cat >/etc/nginx/sites-available/astro <<EOF
server {
listen 80;
server_name $DOMAIN;
location / {
proxy_pass http://127.0.0.1:$ASTRO_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;
}
}
EOF"
sudo ln -sf /etc/nginx/sites-available/astro /etc/nginx/sites-enabled/astro
sudo nginx -t && sudo systemctl reload nginx
echo "---------------------------------------------------"
echo "🚀 Deployment done. Your Astro SSR app should be live."
echo "🌐 http://$DOMAIN"
echo "---------------------------------------------------"
# OPTIONAL ---------------------
# ENABLE HTTPS USING CERTBOT
# -----------------------------
echo ""
echo "To enable HTTPS, run:"
echo "sudo apt install certbot python3-certbot-nginx -y"
echo "sudo certbot --nginx -d $DOMAIN"

1️⃣ Upload your Astro build to the server:

Section titled “1️⃣ Upload your Astro build to the server:”

From your local machine:

Terminal window
rsync -avz dist/ ubuntu@YOUR_SERVER:/var/www/myastro
Terminal window
cd /var/www/myastro
pm2 restart astro-site
Terminal window
curl -I http://localhost

You should get:

HTTP/1.1 200 OK

export default {
output: 'server',
adapter: node({ mode: 'standalone' }),
};

✔️ Your server.mjs is generated inside /dist

Section titled “✔️ Your server.mjs is generated inside /dist”

✔️ Nginx does NOT serve Astro files directly in SSR mode

Section titled “✔️ Nginx does NOT serve Astro files directly in SSR mode”

It only proxies to the Node server.


Want the script customized to your domain + folder + EC2 setup?

Section titled “Want the script customized to your domain + folder + EC2 setup?”

Tell me:

  • Your domain
  • Your project folder
  • Your adapter mode
  • Your EC2 Linux version (probably Ubuntu 22.04)

I will generate a tailored deployment script.