Skip to main content
FomiVIP
Tech Sharing

Nginx Reverse Proxy Configured — and the PHP Site Still 502'd Twice

Migrating a legacy PHP site to ECS behind Nginx with HTTPS, we hit five pitfalls in two days: backend not listening on 8080, 17 broken relative paths, a missing certificate intermediate, a 301 written as 302, and an upload limit buried in php.ini. Those five became our standing Nginx checklist.

May 9, 2016Reverse ProxySSL CertificatesPostmortem

Moving the corporate site from a shared virtual host to our own ECS happened in May 2016. The old site ran PHP 5.4 with MySQL on shared hosting — slow pages, and backend image uploads timing out constantly. The plan: put Nginx in front as a reverse proxy and add an HTTPS certificate while we were at it. Two days end to end; here are the pits we fell into.

1. upstream Pointed at 8080 — the Backend Wasn't Listening There

Our habit is PHP-FPM on 9000 with fastcgi_pass; this time, to keep it simple, we let Apache keep handling PHP, listening on 8080, with Nginx proxy_pass forwarding. Config written, reload done — every request 502. Half an hour later we found it: Apache's Listen was still 80, never changed to 8080.

Fixed that one line and the pages appeared — with all styles missing.

2. Static Assets Used Relative Paths

The old templates referenced css/style.css; behind the proxy the browser resolved it under the new domain's root — 404. We added a temporary location block in Nginx to forward requests, then simply changed all 17 relative paths in the templates to absolute paths starting with a slash. The count of 17 came from grep, not a guess.

3. The HTTPS Certificate Chain Was Missing a Level

Only the site certificate was deployed, without the intermediate. Chrome opened fine; Android's stock browser reported 'certificate not trusted.' We cat'd the intermediate onto the certificate file and restarted Nginx before it worked. Since then we verify with one command: openssl s_client, check that Verify return code is 0.

4. A 301 Written as a 302

The http-to-https redirect started as return 302. Tests passed; after launch someone warned that link equity might not carry over. We changed it to 301 — and the browser had cached the old redirect, so we spent half a day clearing caches before seeing the effect. That config now gets copied from a template, never hand-typed.

5. Upload Size Limits Live in Two Places

A 3 MB image upload in the admin returned 413. We raised Nginx's client_max_body_size to 8m — still 413. Then we remembered php.ini: upload_max_filesize was 2M, and post_max_size needed raising too. Both changed, php-fpm restarted, finally effective.

How the Checklist Grew

Five items became six. In 2017, on another site, we added 'first confirm which port the backend is listening on' — same species as item 1: Nginx was configured right, but someone had set Apache back to 80, pages 502'd all the same, and twenty minutes passed before anyone thought to run netstat. Same pit, different mask, fallen into again.

In 2019 we added one more: run nginx -t before reload. That time a missing semicolon meant the reload never actually took effect — the pages still ran the old config while we believed the change was live, and we waited out an afternoon for nothing. Same family as the certificate-chain incident: 'assuming it took effect.'

The checklist lives in the repo's deploy directory — one md file, six lines, one sentence each. When a new engineer configures Nginx, we have them walk the list first, then explain why each line exists. Most people ask 'what's a certificate chain?' at item 3 — the right moment to explain, far better than 2 AM.

The 502 screenshot is gone, but one line of the error log survived: upstream prematurely closed connection. Ugly handwriting, but it sticks after one read. Once, a client configuring on their own skipped client_max_body_size and hit 413 on a 3 MB upload again; their first words on the phone were 'I skipped item 5 on your checklist.' Fine — at least they knew which line they skipped.

One Thing Not on the List

None of the six items covers 'why Nginx and not something else.' That time there was no choice: the budget covered one ECS, Apache was already running, and a reverse proxy in front was the cheapest change. Other projects have used other solutions, but the checklist never got restructured — its pits are Nginx pits, and a different tool has different pits. The shortest item is No. 4, six words: redirects use 301. Written short because clearing those caches took half a day, and nobody wants to relive it.

Wrapping Up

The next afternoon we switched the DNS A record, TTL lowered to 600 a day ahead. The old host stayed up for two full weeks in case any form submissions landed in the old database. Two weeks on, the access logs still showed a trickle of POSTs — some visitor's browser holding an old bookmark.

From that project on, every Nginx setup we do starts from a checklist — five items, the five above. Nothing complicated, but walking it beat trusting memory every time.

Consulting · Free initial chat

Need advice for your scenario?

Tell us your business context and current systems, and we'll give an actionable approach.

Contact us

Mon–Fri 9:00–18:00 · We respond on business days within one business day.

WeChat (Business Only)
WeChat (Business Only)二维码

Scan and add our WeChat for consulting

Or fill out the requirements form