Skip to main content

Command Palette

Search for a command to run...

I Tried Deploying React + Laravel on One Server… and It Was Messier Than I Expected

Updated
4 min read

So I thought this would be easy.

React frontend. Laravel backend. One EC2 server. One domain. Done.

That was the plan.

Reality was very different.


The plan (which looked simple on paper)

  • React → UI

  • Laravel → API

  • Nginx → handle routing

So basically:

  • / → React

  • /api → Laravel

I’ve seen this setup before, so I thought I’d just follow the same idea and it’ll work.

Spoiler: it didn’t.


First confusion — Node setup

I installed Node using apt like this:

apt install nodejs npm

Seemed fine.

Then React started acting weird during build. Some packages didn’t behave properly.

Checked version — it was old.

At that point I realized: Default packages on Ubuntu are usually outdated.

Switched to NVM, installed latest Node — things immediately became stable.

That was my first “ok, this is not going to be straightforward” moment.


Then a random error: libatomic

Out of nowhere:

libatomic.so.1: cannot open shared object file

Looks scary. Sounds like something deep is broken.

Actual fix?

sudo apt install libatomic1

That’s it.

This taught me something important: Not every scary error is complicated. Sometimes it’s just one missing package.


Laravel “working”… but not really

I ran:

php artisan serve

Opened browser → API worked.

So I thought: “Backend is fine, move on.”

Wrong move.

Once I connected Nginx, Laravel stopped responding completely.

After wasting time, I realized:

👉 Nginx doesn’t use artisan serve 👉 It uses PHP-FPM

And I didn’t even have PHP-FPM installed.

Installed it:

php -v
sudo apt install php8.3-fpm

Only then Laravel actually became usable in real setup.

That was a big gap in understanding.


The most confusing bug — API returning React

This one took time.

I hit:

/api/posts

And instead of JSON, I got my React app.

At first I thought:

  • maybe route issue?

  • maybe Laravel problem?

No.

It was Nginx.

I had:

location /api {

Which I assumed was correct.

It wasn’t strict enough.

Changed it to:

location ^~ /api/ {

And suddenly everything started working.

That tiny change fixed the whole system.


Another mistake — using alias without understanding

I copied this from somewhere:

alias /var/www/backend/public;

It looked fine.

But it broke PHP execution in weird ways.

I didn’t fully understand how alias works with PHP.

So I removed it and used root instead.

Everything became predictable again.

Lesson: If you don’t understand something in Nginx, don’t blindly use it.


Domain issues (DuckDNS)

I used a free domain from DuckDNS.

Sometimes it worked, sometimes it didn’t.

Turned out the IP wasn’t updated properly.

So even though server was running fine, domain wasn’t pointing correctly.

Simple issue, but wasted time.


“Connection refused” — the classic trap

Site didn’t open at all.

No error page, just refused.

Problem?

Port 80 wasn’t open in AWS.

That’s it.

Opened ports → everything worked.


When things finally worked

After all this:

  • React loaded properly

  • Laravel API returned JSON

  • Routing worked (/api)

  • No more weird behavior

Then I added SSL using Let's Encrypt That part was actually smooth compared to everything else.


What I actually learned (not theory)

  • Most issues are not in React or Laravel → they are in server config

  • If something “should work” but doesn’t → assume config problem first

  • Don’t trust default installs → check versions

  • Nginx is powerful but unforgiving → small mistake = big problem


One thing I misunderstood earlier

I thought since both apps are on same server, API calls are internal.

Not true.

Browser still makes request over network → it counts as bandwidth.


Final thought

This setup works.

But it’s not “easy” unless you actually understand what’s happening.

If you just copy configs, you’ll get stuck.

If you debug step by step, it starts making sense.


That’s it.

No perfect guide. Just what actually happened.