Great — Caddy is excellent for hosting a Next.js or React (Node.js) project. You don’t need to replace your Node server — just let Caddy act as a reverse proxy in front of it, automatically handling SSL and routing.
Let’s say:
-
You run your Node server on
localhost:3000(Next.js default) -
You want:
yourdomain.com→ your Next.js app- Automatic HTTPS
- No need to mess with acme.sh or Certbot
yourdomain.com {
reverse_proxy localhost:3000
}That’s it.
-
Stop Nginx (if running):
sudo systemctl stop nginx sudo systemctl disable nginx
-
Install Caddy:
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list sudo apt update sudo apt install caddy
-
Edit your Caddyfile:
sudo nano /etc/caddy/Caddyfile
Paste:
yourdomain.com { reverse_proxy localhost:3000 }
-
Run or restart your Node server, e.g.:
npm run build && npm start -
Reload Caddy:
sudo systemctl reload caddy
Caddy will:
- Automatically issue a Let’s Encrypt cert
- Serve over HTTPS
- Renew the cert before expiry
- Forward requests to your Node backend
Perfect — keeping Cloudflare is a good choice for performance, DDoS protection, and caching. Here’s how to make sure Cloudflare works smoothly with your Caddy + Node.js setup:
- Go to Cloudflare Dashboard → SSL/TLS → Overview
- Set it to: Full (Strict)
This ensures:
- Cloudflare connects to your Caddy server using a valid HTTPS cert (issued by Let’s Encrypt)
- Avoids “redirect loops” or insecure fallback
In DNS tab, make sure:
Arecord formetacode.fun→ your server IP- The cloud icon is orange (proxied by Cloudflare)
Example:
| Type | Name | Value | Proxy Status |
|---|---|---|---|
| A | @ | 123.123.123.123 | Proxied |
You only need this:
metacode.fun {
reverse_proxy localhost:3000
}Caddy will:
- Issue and renew certs (Cloudflare forwards HTTPS requests)
- Serve your Next.js app through reverse proxy
Caddy does this automatically if port 80 is open.
Make sure:
sudo ufw allow 80
sudo ufw allow 443Try:
curl -I https://metacode.funYou should see:
server: cloudflare- Your actual app’s headers (e.g.,
x-powered-by, etc.)
Visit in browser — should be secure and fast.
- Add a
wwwversion:
metacode.fun, www.metacode.fun {
reverse_proxy localhost:3000
}- Redirect
wwwto non-www:
www.metacode.fun {
redir https://metacode.fun{uri}
}
metacode.fun {
reverse_proxy localhost:3000
}Let me know if you want help adding subdomains like api.metacode.fun or enabling cache headers.
Yes, you’ll need to install Node.js on your remote Ubuntu server before running your Next.js or React project.
Here’s the recommended quick setup for Ubuntu (works on Ubuntu 20.04/22.04/24.04):
ssh username@your.server.ipThis is the cleanest way and lets you manage versions easily:
# Install nvm (Node Version Manager)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
# Load nvm into shell (or re-login)
export NVM_DIR="$HOME/.nvm"
source "$NVM_DIR/nvm.sh"
# Install latest LTS version of Node.js
nvm install --lts
# Set default
nvm alias default lts/*You now have:
nodenpm- Easily upgradeable Node.js in the future
node -v
npm -vnpm install -g pm2Use it to start and keep your app running:
cd ~/my-project-folder
pm2 start npm --name "my-app" -- start
pm2 save
pm2 startupWould you like me to give you a full install + deploy shell script you can copy/paste?
To copy all project files (e.g., your Next.js/React app) to a remote Ubuntu server, use scp or rsync over SSH.
scp -r ./my-project-folder username@your.server.ip:/home/username/-r: Recursive (includes all files and subfolders)- Replace
usernamewith your Ubuntu username (e.g.ubuntu) - Replace
your.server.ipwith your server’s public IP - Destination path can be anywhere writable (e.g.
/var/www/,/home/ubuntu/)
rsync -avz ./my-project-folder/ username@your.server.ip:/home/username/my-project-folder/-a: Archive mode (preserves permissions, symlinks, etc.)-v: Verbose output-z: Compress during transfer
💡 If you rerun rsync, it only sends changed files — much faster for updates.
-
SSH into your server:
ssh username@your.server.ip
-
Go to the project directory:
cd ~/my-project-folder
-
Install dependencies and build:
npm install npm run build
-
Start the app:
npm start
💡 For production, consider using PM2 to keep the server running:
npm install -g pm2
pm2 start npm --name "my-app" -- start
pm2 save
pm2 startupWould you like a quick script that bundles rsync + SSH setup + PM2 launch?