I Deployed React + Laravel + MySQL on One Server
I recently deployed a full project:
React (frontend)
Laravel (API)
MySQL (database)
All on a single AWS server.
If you search online, everything looks clean and easy. In reality, it’s not. Small mistakes waste hours.
So instead of pretending it’s smooth, I’m just going to walk through what actually matters — setup, mistakes, and what you should do differently.
What I Wanted
Simple goal:
Open domain → React loads
Call
/api→ Laravel respondsLaravel → talks to MySQL
That’s it.
Basic Setup (Server)
I used an EC2 instance from Amazon Web Services.
First thing I installed:
sudo apt update
sudo apt install nginx git unzip curl -y
Nothing fancy here.
Node Setup (Don’t Use apt)
I first installed Node using apt.
Bad idea.
Version was outdated and caused weird issues in React.
So I switched to Node Version Manager:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
source ~/.bashrc
nvm install node
After that, React build worked properly.
React Setup
cd /var/www/html
git clone <your-react-repo> react-project
cd react-project
npm install
npm run build
This gives a dist/ folder — that’s what Nginx will serve.
Laravel Setup
cd /var/www/html
git clone <your-laravel-repo> laravel-api
cd laravel-api
composer install
cp .env.example .env
php artisan key:generate
At this point, Laravel exists but doesn’t fully work yet.
MySQL Setup
Install MySQL:
sudo apt install mysql-server -y
Secure it:
sudo mysql_secure_installation
Then create DB + user:
CREATE DATABASE laravel_api;
CREATE USER 'madin'@'localhost' IDENTIFIED BY 'StrongPassword123!';
GRANT ALL PRIVILEGES ON laravel_api.* TO 'madin'@'localhost';
FLUSH PRIVILEGES;
Connect Laravel to Database
Edit .env:
DB_DATABASE=laravel_api
DB_USERNAME=madin
DB_PASSWORD=StrongPassword123!
Run:
php artisan migrate
If this fails, don’t guess — check credentials.
The Biggest Confusion — Laravel “Working” But Not Really
I ran:
php artisan serve
API worked.
So I assumed backend is done.
Wrong.
That command is just for local testing. Nginx doesn’t use it.
Real fix was installing PHP-FPM:
php -v
sudo apt install php8.3-fpm
Without this, Laravel won’t work with Nginx at all.
Nginx Setup (Where Most Bugs Come From)
Created config:
server {
listen 80;
server_name madinapp.duckdns.org;
root /var/www/html/react-project/dist;
index index.html;
location / {
try_files $uri /index.html;
}
location ^~ /api/ {
root /var/www/html/laravel-api/public;
index index.php;
try_files \(uri \)uri/ /index.php?$query_string;
}
location ~ \.php$ {
root /var/www/html/laravel-api/public;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME \(document_root\)fastcgi_script_name;
}
}
This part took the most time to get right.
Mistakes That Cost Me Time
1. API returning React instead of JSON
Cause: wrong Nginx routing Fix: use ^~ /api/
2. Laravel not responding
Cause: PHP-FPM not installed Fix: install correct version
3. Node issues
Cause: installed via apt Fix: use NVM
4. Domain not opening
Cause: DNS not pointing correctly Used DuckDNS
5. “Connection refused”
Cause: port 80 not open Fix: allow in AWS security group
SSL Setup
Used Let's Encrypt:
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx
Also opened:
port 80
port 443
Final Setup Flow (Simple View)
Browser
↓
Nginx
↓
Laravel (PHP-FPM)
↓
MySQL
One Thing I Got Wrong Initially
I thought since both apps are on same server, API calls are internal.
They’re not.
Browser still sends request → server → response So yes, it uses bandwidth.
Final Thoughts
This setup works well for:
learning
small projects
personal apps
But the tricky part is not React or Laravel.
It’s understanding how everything connects.
If you skip that and just copy configs, you’ll get stuck.
That’s it.
No perfect tutorial — just what actually worked after fixing mistakes.