Hello everyone! Long time no show… anyways, I set up my first baremetal deployment today. Followed the guide but ran into quite a few problems, so I created a cheatsheet for my future-self, and i figured this might help others.
Please give it a read, and let me know if you get stuck somewhere. or if anything doesn’t make sense/
This is a cheatsheet, it assumes you kind of know what you are doing. Or at least have read the amazing guide in the docs first.
NEW KVM from Scratch Setup Guide
This guide outlines how to set up a new KVM from scratch. It’s based on the RedwoodJS documentation but includes additional steps and explanations. This guide was tested on a fresh install of Ubuntu 20.04.3 LTS.
After following this guide, you’ll have a fully functional redwood app running on a KVM with NGINX as the server to handle the web requests. The API will be server by the redwood server and managed by PM2.
Prerequisites
Ensure you have SSH credentials for the server. Once connected, follow the steps below.
1. Update Your Linux KVM
Before installing anything, it’s essential to ensure your system is up to date.
-
Refresh the apt list and upgrade all installed packages:
sudo apt update sudo apt upgrade
-
Perform a full upgrade:
sudo apt full-upgrade
This command upgrades installed packages and removes obsolete ones.
-
Remove unnecessary dependencies:
sudo apt --purge autoremove
This will clean up any unused packages that were automatically installed.
-
Upgrade to a new release version (if available):
sudo do-release-upgrade
This ensures you’re on the latest release version of the OS.
2. Create a New Sudo User
-
Create a new user:
sudo adduser username
-
Grant the user sudo privileges:
sudo usermod -aG sudo username
-
Exit the root user:
exit
-
Reconnect as the new user:
ssh username@remote_host
3. Simplify SSH Login (if you have a key)
-
Copy your SSH key to the remote server:
On your local machinessh-copy-id username@remote_host
-
make sure the key is added to the ssh-agent:
eval "$(ssh-agent -s)" ssh-add ~/.ssh/id_ed25519
for MacOs, make sure you add it to your keychain
ssh-add --apple-use-keychain ~/.ssh/id_ed25519
-
Install Git:
Back on the serversudo apt install git
-
Set up agent forwarding for github.com:
Add the following lines to ~/.ssh/config
:
Host github.com
ForwardAgent yes
-
Ensure SSH access to GitHub:
ssh -T git@github.com
4. Install Node.js and NVM (Node Version Manager)
-
Install Node.js:
sudo apt install nodejs
-
Install Curl (required for NVM installation):
sudo apt install curl
-
Install NVM:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash source ~/.bashrc
-
Install and use the latest LTS version of Node.js:
nvm install --lts nvm use --lts
5. Install Yarn
-
Remove any existing Yarn installations:
sudo apt remove yarn
-
Use Corepack to manage Yarn:
corepack enable
-
Install Yarn 4:
corepack prepare yarn@4.0.0 --activate
6. Handle SSH and Non-Interactive Sessions
Some distributions may have restrictions that interfere with non-interactive sessions. You may need to update .bashrc
to handle this.
-
Edit the
.bashrc
file:nano ~/.bashrc
-
Comment out lines that prevent non-interactive behavior:
# case $- in # *i*) ;; # *) return;; # esac
7. Increase Node Memory Limit
If your server has limited RAM (e.g., 512MB), you can increase Node.js’ memory limit to prevent build failures.
-
Edit the
.bashrc
file:nano ~/.bashrc
-
Add the following line to increase the Node memory limit:
export NODE_OPTIONS="--max-old-space-size=460"
-
Reload the
.bashrc
file:source ~/.bashrc
8. Install PM2 (Process Manager for Node.js)
-
Install PM2 globally:
npm install pm2 -g
-
Configure PM2 to start on system boot:
pm2 startup
Follow the on-screen instructions to complete the setup (it will prompt you with a command to copy and paste).
-
Give Node.js permission to bind to low-numbered ports (if required):
sudo setcap CAP_NET_BIND_SERVICE=+eip $(which node)
9. Install and Configure NGINX
-
Install NGINX:
sudo apt install nginx
-
Enable and start NGINX:
sudo systemctl enable nginx sudo systemctl start nginx
-
Check NGINX status:
sudo systemctl status nginx
10. Set Up Firewall
-
Install UFW (Uncomplicated Firewall):
sudo apt install ufw
-
Allow SSH connections:
sudo ufw allow ssh
-
Allow HTTP/HTTPS traffic for NGINX:
sudo ufw allow 'Nginx Full'
-
Enable the firewall:
sudo ufw enable
-
Check firewall status:
sudo ufw status
11. Configure NGINX for Your Site
-
Create the application directory:
sudo mkdir /var/www/app sudo chown -R $USER:$USER /var/www/app sudo chmod -R 755 /var/www/app
-
Add the .env file:
sudo touch sudo nano /var/www/app/.env
Add the following content:
WEB_PORT=80 API_PORT=8911
-
Edit the NGINX configuration:
sudo nano /etc/nginx/sites-available/default
-
Configure NGINX for your app:
Replace the default content with the following configuration:upstream redwood_server { server 127.0.0.1:8911 fail_timeout=0; } server { root /var/www/app/current/web/dist; server_name your_domain.com; gzip on; gzip_min_length 1000; gzip_types application/json text/css application/javascript application/x-javascript; sendfile on; keepalive_timeout 65; error_page 404 /404.html; error_page 500 /500.html; location / { try_files $uri /200.html =404; } location ^~ /static/ { gzip_static on; expires max; add_header Cache-Control public; } location ~ /api(.*) { rewrite ^/api(.*) $1 break; proxy_pass http://redwood_server; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
12. Deploy the Redwood App
-
Set up the Baremetal deployment
yarn rw setup deploy baremetal
-
Update
deploy.toml
# See <https://redwoodjs.com/docs/deploy/baremetal> for more info [[production.servers]] host = "IP_ADDRESS" username = "e" privateKeyPath = "/users/user/.ssh/id_ed25519" agentForward = true sides = ["api","web"] packageManagerCommand = "yarn" monitorCommand = "pm2" path = "/var/www/app" processNames = ["api"] repo = "<git@github.com>:username/repo.git" branch = "main" keepReleases = 5
-
Update
redwood.toml
[web] title = "App Title" port = "${WEB_PORT:8910}" apiUrl = "/api" includeEnvironmentVariables = [ # Add any ENV vars that should be available to the web side to this array # See https://redwoodjs.com/docs/environment-variables#web ] [api] port = "${API_PORT:8911}" [browser] open = true [notifications] versionUpdates = ["latest"]
-
Update
ecosystem.config.js
module.exports = {
apps: [
{
name: 'api',
cwd: 'current',
script: 'node_modules/.bin/rw',
args: 'serve api',
instances: 'max',
exec_mode: 'cluster',
wait_ready: true,
listen_timeout: 10000,
},
],
};
-
Commit and push the changes
git add . git commit -m "Update deployment configuration" git push origin main
-
Deploy the app from your local machine:
yarn rw deploy baremetal production --first-run
-
On the server, restart the PM2 process:
pm2 restart api
Say good bye to somebody elses server! Say hello to managing your own nightmares!