Skip to content

build

Perfect! Let’s design a production-ready setup for multiple Node/Vite apps on a single EC2 instance using subdomains + Nginx + HTTPS + PM2. This will allow you to host multiple apps like op1.evolo.fr, op2.evolo.fr, etc., efficiently.


On your EC2 instance, create a structure like:

/home/ubuntu/apps/
├── op1
│ ├── dist/ # built Vite project
│ ├── package.json
│ └── ecosystem.config.js # PM2 config
├── op2
│ └── ...
  • Each app has its own folder.
  • Vite projects must be built first (npm run build) into dist/.

Terminal window
sudo npm install -g pm2
pm2 startup systemd
  • PM2 keeps Node apps alive after reboots.
  • You can manage apps individually:
Terminal window
pm2 start index.js --name op1
pm2 start index.js --name op2
pm2 save

Terminal window
sudo apt update
sudo apt install nginx -y
  • Nginx will serve multiple apps via subdomains.

4️⃣ Nginx config for multiple subdomains

Section titled “4️⃣ Nginx config for multiple subdomains”

Create a config file:

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

Example config:

# OP1
server {
listen 80;
server_name op1.evolo.fr;
root /home/ubuntu/apps/op1/dist;
index index.html;
location / {
try_files $uri /index.html;
}
}
# OP2
server {
listen 80;
server_name op2.evolo.fr;
root /home/ubuntu/apps/op2/dist;
index index.html;
location / {
try_files $uri /index.html;
}
}

Enable the site:

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

Install Certbot:

Terminal window
sudo apt install certbot python3-certbot-nginx -y

Run for each subdomain:

Terminal window
sudo certbot --nginx -d op1.evolo.fr
sudo certbot --nginx -d op2.evolo.fr
  • Certbot auto-configures Nginx for SSL.
  • Certificates auto-renew every 90 days.

If you have a Node.js backend (Express/Nest/etc.):

  • Run with PM2:
Terminal window
pm2 start server.js --name api-op1
pm2 save
  • Add reverse proxy in Nginx:
server {
listen 80;
server_name api.op1.evolo.fr;
location / {
proxy_pass http://localhost:3000; # Node API 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;
}
}
  • HTTPS via Certbot as above.

  1. Pull repo / sync files (rsync or git pull)
  2. Install dependencies (npm install)
  3. Build Vite app (npm run build)
  4. PM2 restart Node backend (if any)
  5. Nginx serves dist/ automatically

✅ Can also be scripted into a one-command deploy script.


  • Each subdomain points to a different folder
  • Frontend Vite apps go in dist/
  • Node backends run via PM2 on separate ports
  • Nginx handles HTTPS + routing
  • Optional CDN for static assets improves performance

I can make a full ready-to-use template including:

  • Folder structure
  • PM2 ecosystem.config.js for multiple apps
  • Nginx config with SSL for all subdomains
  • One-command deployment script

This would let you deploy and serve multiple Node/Vite apps on EC2 with HTTPS immediately.

Do you want me to create it?

Create the folder with sudo, then give ubuntu write access

Terminal window
sudo mkdir -p /var/www/test1
sudo chown -R ubuntu:ubuntu /var/www/test1
Terminal window
rsync -avz \
-e "ssh -i ~/.ssh/web1.pem" \
./dist/ \
ubuntu@op1.evolo.fr:/var/www/test1/ --rsync-path="sudo rsync"

enable site:

Terminal window
sudo ln -s /etc/nginx/sites-available/test1 /etc/nginx/sites-enabled/

restart

Terminal window
sudo nginx -t
sudo systemctl reload nginx

Ah — you want to “push” your local build to EC2, and avoid accidentally deleting or overwriting files in the destination that aren’t in your local folder.

By default, your command:

Terminal window
rsync -avz -e "ssh -i ~/.ssh/web1.pem" ./dist/ ubuntu@op1.evolo.fr:/var/www/test1/
  • Copies all files from ./dist/ to /var/www/test1/
  • Overwrites files with the same name
  • Does not delete extra files on the server

So in rsync terms, this is already a “push”, not a full sync.


If you want to ensure no files are deleted on the server

Section titled “✅ If you want to ensure no files are deleted on the server”
  • Do NOT use --delete
  • Your current command is fine:
Terminal window
rsync -avz -e "ssh -i ~/.ssh/web1.pem" ./dist/ ubuntu@op1.evolo.fr:/var/www/test1/

This pushes your local files but keeps existing files on the server.


To be extra safe, you can see what would happen without actually copying:

Terminal window
rsync -avzn -e "ssh -i ~/.ssh/web1.pem" ./dist/ ubuntu@op1.evolo.fr:/var/www/test1/
  • -n → dry run
  • You can check the output, then run the command without -n to actually push.

  1. Use a trailing slash on local folder ./dist/ → copies contents, not the folder itself.
  2. Always check permissions on the server after pushing:
Terminal window
sudo chown -R www-data:www-data /var/www/test1
sudo chmod -R 755 /var/www/test1

This ensures NGINX can serve the files.

1️⃣ sudo chown -R www-data:www-data /var/www/test1

Section titled “1️⃣ sudo chown -R www-data:www-data /var/www/test1”
  • sudo: Runs the command as the superuser (root), which is required to modify files owned by other users.

  • chown: Stands for change owner. It changes the owner and group of a file or directory.

  • -R: Means recursive, so the command applies to /var/www/test1 and everything inside it.

  • www-data:www-data:

    • The first www-data is the user owner.
    • The second www-data is the group owner.
    • www-data is the typical user/group used by web servers like Apache or Nginx.
  • /var/www/test1: The target directory whose ownership you want to change.

Effect: All files and directories under /var/www/test1 will now be owned by the www-data user and group. This is essential for a web server to read/write files safely.


  • chmod: Stands for change mode. It modifies file permissions.
  • -R: Recursive, applies to the directory and all its contents.
  • 755: A numeric representation of permissions:
DigitMeaningExample
7Owner can read, write, execute (4+2+1)rwx
5Group can read and execute (4+0+1)r-x
5Others can read and execute (4+0+1)r-x
  • /var/www/test1: Target directory.

Effect:

  • Owner (www-data) can read/write/execute.
  • Group and others can read and execute, but cannot modify files.
  • This is a common setting for web directories so the server can serve files, but users can’t modify them.

  1. chown → sets who owns the files (user & group).
  2. chmod → sets what permissions everyone has.

These two commands together make /var/www/test1 owned by the web server and readable/executable for it and visitors, but only writable by the server.


You can check both the owner and permissions of a file or directory using the ls command. Here’s how:


Terminal window
ls -l /var/www/test1

Example output:

drwxr-xr-x 5 www-data www-data 4096 Nov 16 17:00 test1

Breaking it down:

PartMeaning
drwxr-xr-xFile type & permissions (d = directory, rwx = read/write/execute for owner, r-x = read/execute for group and others)
5Number of hard links
www-dataOwner of the file/directory
www-dataGroup of the file/directory
4096Size in bytes
Nov 16 17:00Last modification date
test1File/directory name

2️⃣ Check recursively (all files inside)

Section titled “2️⃣ Check recursively (all files inside)”
Terminal window
ls -lR /var/www/test1

This will list all files and folders inside test1 with their owners and permissions.


Terminal window
stat /var/www/test1

Example output:

File: /var/www/test1
Size: 4096 Blocks: 8 IO Block: 4096 directory
Device: 802h/2050d Inode: 123456 Links: 5
Access: (0755/drwxr-xr-x) Uid: ( 1001/www-data) Gid: ( 1001/www-data)
Access: 2025-11-16 17:00:00.000000000
Modify: 2025-11-16 17:00:00.000000000
Change: 2025-11-16 17:00:00.000000000
  • Uid = Owner
  • Gid = Group
  • Access = Permissions in octal and symbolic (0755 / drwxr-xr-x)

If you want, I can also show a super quick one-liner to see just owner and permissions for all files under /var/www/test1 in a readable format.

Do you want me to do that?