- Knowledge
- technology
- OOP
- Tips
- Programming
- Tips
- Tutorial
- SEO
- Ranking
- Knowledge
- Special Day
- Seo
- Bug
- Data science
- Seo
- artificial intelligence
- Machine Learning
- Robotics
- happyNewYear2021
- newYearEve
- 2021
- Automation
- Smart Home
- Career
- Best Practices
- Git
- Logging
- Web Fundamentals
- DNS
- HTTPS
- Performance
- AI Tools
- ChatGPT
- Claude
- Gemini
- Laravel
- Eloquent
- MySQL
- HTTPS
- TLS
- Web Security
- Certificates
- Developer Life
- Debugging
- Docker
- DevOps
- Transactions
- Queues
- LLMs
- AI
- AI Coding
- Developer Tools
- React Native
- Expo
- Kate PMS
- Mobile Apps
- Laravel
- Authentication
- Sanctum
- Cookies
- API Design
- Payments
- Idempotency
- DeepSeek
- Open Source AI
- LLMs
- AI News
- Git
- Version Control
- AI Coding
- Prompting
- PHP
- Checklist
- MCP
- AI Agents
- OpenAI
- Architecture
- Microservices
- Modular Monolith
- Estimation
- Developer Life
- Project Planning
- Humour
- OAuth
- OpenID Connect
- Authentication
- Embeddings
- Vector Search
- RAG
- pgvector
- OpenAI
- GPT-4.1
- Codex CLI
- Events
- Testing
- Clean Code
- Maintainability
- Code Review
- Webhooks
- API
- Security
- Claude Code
- Workflow
- AI
- LLM
- Prompt Injection
- Mobile
- React
- Networking
- TCP
- UDP
- HTTP/3
- CLAUDE.md
- AWS
- Cloud Security
- Backups
- PHPUnit
- Software Engineering
- Leadership
- Communication
- RAG
- Embeddings
- AI Engineering
- IT Infrastructure
- Networking
- Access Control
- CI/CD
- GitHub Actions
- Gemini CLI
- Claude Code
- JavaScript
- Async/Await
- Node.js
- Promises
- Security
- Cryptography
- Passwords
- MySQL
- Database
- Vibe Coding
- Software Quality
- DNS
- Code Reading
- Onboarding
- Productivity
- Background Jobs
- Developer Humour
- Estimates
- Dev Life
- JWT
- o3-mini
- DeepSeek R1
- Rate Limiting
- Kate PMS
- E-Signing
- Audit Trail
- REST
- GraphQL
- API Design
- Laravel 12
- Upgrade Guide
- Open Source
- Self-Hosting
- Task Scheduling
- Cron
- Secrets
- CORS
- PHP
- PHP-FPM
- OPcache
- GitHub Copilot
- Software Architecture
- Engineering
- TypeScript
- JavaScript
- Type Safety
- AI Security
- React Native
- Product Design
- AI Agents
- Kiro
- Queues
- Redis
- RabbitMQ
- AWS SQS
- Nginx
- Apache
- GPT-5
- gpt-oss
- Clean Code
- Architecture
- Naming
- Documentation
- Career
- ADR
- Teamwork
- Supply Chain
- Kate HRM
- HR Software
- Permissions
- System Design
- Pagination
- SSH
- Linux
- Big O
- Databases
- Laravel Boost
- MCP
- Developer Skills
- Validation
- Databases
- Indexes
- Code Quality
- Deployment
- Developer Humour
- Feature Flags
- Code Review
- Pull Requests
- Docker
- Cursor
- Authorization
- RBAC
- Gemini
- Long Context
- PHP 8.4
- Caching
- Dependency Injection
- Web Performance
- Browser
- CSS
- Database
- Migrations
- ChatGPT
- AI for Developers
- Monitoring
- On-Call
- REST
- Backend
- SQL
- NoSQL
- Database Design
- Coding Agents
- Claude 4
- API Resources
- REST API
- Load Balancing
- Scaling
- AWS
- AI Tools
- Claude
- Sora 2
- CTE
- 2FA
- TOTP
- Programming Languages
- Prompts
- Developer Workflow
- API Gateway
- APIs
- Passport
- API Auth
- Learning
- Burnout
- Developer Growth
- Web Development
- SEO
- Kate Mall
- ChatGPT Atlas
- Agent Skills
- Middleware
- Laravel 12
- Collections
- Context Window
- Monitoring
- Commit Messages
- Self Review
- Growth
- Regex
- Programming Basics
- Text Processing
- Database Design
- Normalization
- Linux
- Server Security
- Linux Foundation
- Open Standards
- Legacy Code
- Documentation
- AI Workflow
- File Uploads
- Test Data
- Hashing
- Performance
- Caching
- Enums
- Scope Creep
- Estimation
- Codex
- Gemini CLI
- Timezones
- Carbon
- Bugs
- PHP 8.5
- Gemini 3
- GPT-5.1
- Data Integrity
- Event Loop
- Async
- Opus 4.5
- AI Models
- React
- Forms
- Frontend
- Backups
- AI Images
- DALL-E
- Midjourney
- Race Conditions
- Concurrency
- Legacy Code
- Refactoring
- Senior Engineer
- Scope
- LLM
- CDN
- Web
- Sub-Agents
- Soft Deletes
- Audit Log
- Concurrency
- AI Learning
- NestJS
- AI Evals
- Policies
- SPF DKIM DMARC
- Unicode
- UTF-8
- Knowledge Graph
- Value Objects
- Technical Debt
- Feature Flags
- Laravel Pennant
- Deployment
- Copilot
- Composer
- Dependencies
- Artisan
- Automation
- AWS S3
- Object Storage
- Cloud
- Small Language Models
- Ollama
- Production
- Sessions
- HTTP
- Mentoring
- SQL
- Virtual Machines
- Web Development
- HTTP/2
- QUIC
- Web Performance
- AI Integration
- LLM API
- SOLID
- OOP
- Hosting
- Serverless
- Merge Conflicts
- Temperature
- AI Development
- Reverse Proxy
- Nginx
- Infrastructure
- Verification
- Passkeys
- WebAuthn
- Teams
- Communication
- Stakeholders
- Monorepo
- CI/CD
- Versioning
- JSON Schema
- Livewire
- Inertia
- Meetings
- Distributed Systems
- Privacy
- Full-Stack
- T-Shaped Skills
- Money
- Notifications
- Web Security
- HTTP Headers
- CSP
- Function Calling
- Load Testing
- k6
- Data Extraction
- Debugging
- WebSockets
- SSE
- Real-Time
- Laravel Reverb
- Infrastructure as Code
- Terraform
- Side Projects
- Laravel Pint
- OpenAPI
- Swagger
- UX
- Multimodal
- Jest
- Pair Programming
- APIs
- Rate Limiting
- Resilience
- Dev Humour
- Design Tokens
- JWT
- API Keys
- Sessions
- PHPStan
- Rector
- Incidents
- Reporting
- Dashboards
- Zero Trust
- IAM
- Search
- Laravel Scout
- Junior Developers
- Mentoring
- Images
- WebP
- AVIF
- Bug Reports
- Let's Encrypt
- Design Docs
- Software Design
- Observers
- Replication
- Accountability
- Data Structures
- Reliability
- LLM Memory
- Error Handling
- Payments
- Payment Gateway
- Webhooks
- PCI DSS
- Observability
- OpenTelemetry
- Personal Brand
- Writing
- Conventions
- Dates
- Scheduling
- Disaster Recovery
- Compression
- Brotli
- Deadlines
- Developer Habits
- State Machines
- Tech Roles
- UUID
- ULID
- Horizon
- Planning
- Engineering Culture
- Ownership
- Soft Skills
- Socialite
- Cost Control
- Collations
- Unicode
- Octane
- PostgreSQL
What Is a Reverse Proxy? The Server in Front of Your Server
About Post
You deploy behind a load balancer and two strange things happen. Every visitor in your logs now has the same IP address, something like 10.0.0.12. And Laravel starts generating http:// links on a site that is definitely served over HTTPS, so the browser complains about mixed content and the login redirect goes in circles.
Nothing is wrong with your code. Your app just doesn't know that there's now another server standing between it and the world. That server is a reverse proxy, and once you understand what it does, both bugs take one line to fix.
What's the difference between a proxy and a reverse proxy?
Both sit in the middle of a conversation. The difference is whose side they're on.
- A forward proxy works for the client. A company network might send all employee traffic through one, to filter sites or cache downloads. The websites see the proxy, not the individual laptops.
- A reverse proxy works for the server. Visitors think they're talking to your site, but they're talking to the proxy, which passes requests to your app servers behind it.
Think of a hotel reception desk. Guests never walk into the kitchen or the laundry room. They talk to reception, and reception gets the right department to deal with it. The guests don't know (or need to know) how many people work in the back.
Nginx, HAProxy, Caddy and Traefik are common reverse proxies. So are AWS Application Load Balancers and CDNs like Cloudflare. You may have several in a row.
What does a reverse proxy actually do?
TLS termination
The proxy holds the certificate and handles HTTPS. Behind it, traffic to your app may be plain HTTP on a private network. One place to manage certificates, and your app servers don't spend effort on encryption.
Load balancing
With three app servers, the proxy spreads requests between them and stops sending traffic to a server that fails its health check. Deploys can take servers out one at a time without downtime.
Caching and compression
The proxy can serve static files and cached responses itself and compress responses, so many requests never reach PHP at all.
Routing
One domain, several services: /api goes to a Laravel app, /realtime to a Node.js WebSocket server, everything else to a frontend. Users see a single site.
Protection
Rate limiting, request size limits, blocking bad bots and hiding your real servers from direct access all happen at the front door, before a request costs you a database query.
What does it look like?
A minimal Nginx reverse proxy in front of an app listening on port 8000 (simplified, certificate lines left out):
server {
listen 443 ssl;
server_name app.example.com;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Those proxy_set_header lines are the key to the two bugs from the start.
Why does Laravel see the wrong IP and the wrong scheme?
From your app's point of view, every request now comes from the proxy. The TCP connection really does start at 10.0.0.12, and it really is plain HTTP. So $request->ip() returns the proxy's address, and url() builds http:// links.
The proxy passes the original details along in headers:
X-Forwarded-For: the original client IP, plus any proxies along the way.X-Forwarded-Proto: whether the visitor usedhttps.X-Forwarded-HostandX-Forwarded-Port: the host and port the visitor used.
But Laravel won't believe those headers by default, and that's a good thing. Anyone can send a request with X-Forwarded-For: 1.2.3.4. If your app trusted it blindly, an attacker could fake their IP to dodge rate limits or poison your audit logs.
How do I make Laravel trust the proxy safely?
You tell Laravel which proxies are allowed to set those headers. In Laravel 12 that lives in bootstrap/app.php:
->withMiddleware(function (Middleware $middleware): void {
$middleware->trustProxies(at: [
'10.0.0.0/8', // your load balancer's private network
]);
})
Now, when a request arrives from an address in that range, Laravel reads the forwarded headers. $request->ip() returns the real visitor, $request->secure() is true, and generated URLs use https.
You'll often see trustProxies(at: '*'). It's common with cloud load balancers whose IP addresses change, and it's acceptable only if your app servers can't be reached directly from the internet, for example because a security group only allows traffic from the load balancer. If someone can bypass the proxy and hit your server, '*' lets them write their own IP address.
The rule: trust forwarded headers only from proxies you control, and make sure nothing else can reach your app servers. Trusting '*' on a server that's publicly reachable is trusting every stranger's word about who they are.
Anything else that bites in production?
- Several layers. CDN in front of a load balancer in front of Nginx means a chain of IPs in
X-Forwarded-For. Each layer needs to be trusted for the real client IP to come through. - CDN-specific headers. Some CDNs send their own header with the visitor's IP (Cloudflare uses
CF-Connecting-IP). Know which one your setup relies on. - Timeouts. The proxy has its own timeout. A long report that PHP is happy to run for two minutes may be cut off by the proxy much earlier, returning a 504 that never appears in your Laravel logs. Long work belongs in a queue anyway.
- Upload limits. Nginx's
client_max_body_sizecan reject a large upload before PHP ever sees it, with a 413 error. Raisingupload_max_filesizein PHP won't help on its own. - Health checks. Give the load balancer a lightweight endpoint (Laravel 12 ships with
/up) so it knows when a server is really ready.
The short version
- A reverse proxy is the front door to your servers: TLS, load balancing, caching, routing and protection.
- Behind it, your app sees the proxy's IP and plain HTTP unless it trusts the forwarded headers.
- Trust only proxies you control, and keep app servers unreachable from anywhere else.
- When something fails with no trace in your app logs, check the proxy's logs and limits.
How many proxies sit in front of your main app right now? It's often one more than people think.

Be first to comment it...