Two guides in one place:
| Guide | For | Jump to |
|---|---|---|
| 🖥️ Desktop Setup | A new development machine (laptop / workstation) | Go → |
| ☁️ VPS / Server Setup | A fresh cloud server you will deploy apps to | Go → |
Tip
Run commands one block at a time and read the note above each block before pasting. Don't paste the whole file blindly.
Set up a fresh Ubuntu desktop as a development machine.
Update the system and install the essentials.
sudo apt-get update && sudo apt-get upgrade -ysudo apt-get install -y git curl wget g++ build-essential gnome-tweaks| Package | Why |
|---|---|
git |
Version control |
curl / wget |
Download files & install scripts |
g++ / build-essential |
C / C++ compiler + build tools |
gnome-tweaks |
Extra desktop settings |
✅ Done — system updated and base tools installed.
Set your identity (used on every commit).
git config --global user.name "Your Name"
git config --global user.email "your@email.com"
git config --global init.defaultBranch mainVerify:
git config --global --list✅ Done — Git knows who you are.
Note
Modern guidance recommends the Ed25519 key type — it's faster and more secure than the old RSA default.
1. Generate the key
ssh-keygen -t ed25519 -C "your@email.com"- Press Enter to accept the default location (
~/.ssh/id_ed25519). - Enter a passphrase (recommended) or press Enter twice to leave it blank.
2. Copy the public key
cat ~/.ssh/id_ed25519.pubCopy the entire output (starts with ssh-ed25519 ...).
3. Add it to GitHub
- Open GitHub → profile picture → Settings.
- Go to SSH and GPG keys.
- Click New SSH key.
- Give it a title (e.g. My Laptop) and paste the key.
- Click Add SSH key.
4. Test the connection
ssh -T git@github.comYou should see: "Hi username! You've successfully authenticated…"
✅ Done — you can now push/pull over SSH.
sudo snap install --classic code| Extension | Purpose |
|---|---|
| C/C++ | IntelliSense & debugging |
| Code Runner | Run snippets in one click |
| C/C++ Themes | Better C/C++ syntax colors |
| CMake | CMake project support |
| Markdown Preview Enhanced | Rich Markdown preview |
| Markdown All in One | Markdown shortcuts & TOC |
Install from the Extensions panel (Ctrl+Shift+X), or from the terminal:
code --install-extension ms-vscode.cpptools \
--install-extension formulahendry.code-runner \
--install-extension ms-vscode.cmake-tools \
--install-extension shd101wyy.markdown-preview-enhanced \
--install-extension yzhang.markdown-all-in-one- Auto Save:
File → Auto Save - Run in terminal:
Settings → Extensions → Run Code → ✔ Run In Terminal
✅ Done — VS Code ready.
1. Install zsh
sudo apt-get install -y zsh2. Install Oh My Zsh
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"3. Make zsh your default shell
chsh -s $(which zsh)Log out and back in for the change to take effect.
✅ Done — zsh + Oh My Zsh installed.
1. Clone the theme
git clone --depth=1 https://github.com/romkatv/powerlevel10k.git \
${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k2. Set it in ~/.zshrc
nano ~/.zshrcFind the ZSH_THEME line and change it to:
ZSH_THEME="powerlevel10k/powerlevel10k"Save with
Ctrl+O→Enter, exit withCtrl+X.
3. Apply the changes
source ~/.zshrcThe Powerlevel10k configuration wizard starts automatically. To re-run it anytime:
p10k configure✅ Done — your terminal looks 🔥.
🎉 Desktop setup complete. Reboot once and you're ready to build.
Take a fresh cloud server (DigitalOcean, Hetzner, AWS, etc.) from zero to deploying web apps with Nginx, SSL and PM2.
Warning
Run these as you SSH into the server. Steps 1–2 are security basics — don't skip them. Servers running as root with no firewall get compromised fast.
Working as root is risky. Create a dedicated user with sudo rights.
# 1. Create the user (you'll be prompted for a password)
adduser memo
# 2. Grant sudo privileges
usermod -aG sudo memo
# 3. Switch to the new user
su - memoReplace
memowith your chosen username throughout this guide.
✅ Done — you now have a safer, non-root account.
Allow only what you need, then enable the firewall.
sudo apt update && sudo apt install -y ufw
sudo ufw allow OpenSSH # keep SSH open — don't lock yourself out!
sudo ufw allow 'Nginx Full' # HTTP (80) + HTTPS (443)
sudo ufw enable
sudo ufw statusCaution
Always allow OpenSSH before running ufw enable, or you'll be locked out of the server.
✅ Done — firewall active.
Install the latest LTS release straight from NodeSource.
sudo apt update && sudo apt install -y curl
# Add the NodeSource LTS repository
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt install -y nodejsVerify:
node -v
npm -v✅ Done — Node.js + npm installed.
Follow the official instructions (kept current by Docker):
- Docker Engine: https://docs.docker.com/engine/install/ubuntu/
- Docker Compose: https://docs.docker.com/compose/install/standalone/
Note
Use sudo when installing Docker Compose.
Run Docker without sudo:
sudo usermod -aG docker memoLog out and back in for the group change to take effect.
Verify:
docker --version
docker compose version # or: docker-compose version✅ Done — Docker ready.
sudo apt update
sudo apt install -y nginx
sudo systemctl enable nginx # start on boot
sudo systemctl start nginx
sudo systemctl status nginxIf you didn't already do this in step 2:
sudo ufw allow 'Nginx Full'Visit http://your-server-ip — you should see the Nginx welcome page.
✅ Done — Nginx is serving.
Install Certbot and the Nginx plugin:
sudo apt install -y certbot python3-certbot-nginxIssue a certificate for each domain (point your DNS A record at the server first):
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.comCertbot auto-configures Nginx and sets up auto-renewal. Test renewal with:
sudo certbot renew --dry-run✅ Done — HTTPS enabled and auto-renewing. 🔒
PM2 keeps your app running and restarts it on crash or reboot.
sudo npm install -g serve pm2Serve a built static app (e.g. a Vite dist/ folder):
pm2 start serve --name memo-landing -- -s dist -l 3000Other common patterns:
# Static site on a custom port
pm2 start "npx serve -s dist -l 3000" --name arayees-front-client-3000
# Another static app
pm2 start "npx serve -s dist -l 2233" --name hola-dashboard-2233
# A Next.js app
pm2 start "npx next start -p 2233" --name hola-dashboardMake PM2 survive reboots:
pm2 save
pm2 startup # run the command it printsUseful PM2 commands:
pm2 list # show all processes
pm2 logs # tail logs
pm2 restart <name> # restart an app
pm2 delete <name> # stop & remove an app✅ Done — your app stays up.
Point a domain at a local PM2 app (e.g. dashboard.memo.com → localhost:3001).
1. Create the site config
sudo nano /etc/nginx/sites-available/dashboard.memo.com2. Paste this (adjust domain + port):
server {
listen 80;
server_name dashboard.memo.com;
location / {
proxy_pass http://localhost:3001; # your app's 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;
}
}3. Enable the site, test, reload
sudo ln -s /etc/nginx/sites-available/dashboard.memo.com /etc/nginx/sites-enabled/
sudo nginx -t # test the config
sudo systemctl reload nginx4. Add SSL for it
sudo certbot --nginx -d dashboard.memo.com✅ Done — domain live over HTTPS, proxied to your app.
🚀 Server ready. Repeat steps 7–8 for each app you deploy.
| Task | Command |
|---|---|
| Update system | sudo apt update && sudo apt upgrade -y |
| Test GitHub SSH | ssh -T git@github.com |
| List PM2 apps | pm2 list |
| Tail PM2 logs | pm2 logs |
| Test Nginx config | sudo nginx -t |
| Reload Nginx | sudo systemctl reload nginx |
| Firewall status | sudo ufw status |
| Renew SSL (dry run) | sudo certbot renew --dry-run |
Made with ☕ by Mustafa — happy hacking!
