Mobile Proxy Architecture at SoundCloud
Article Summary
SoundCloud's mobile team hit a wall: their API-first approach broke down when browsers couldn't handle CORS redirects properly. Their solution? A proxy architecture that evolved from nginx to Node.js.
Back in 2011, SoundCloud built their mobile web app to consume their public API directly. But browser limitations around CORS and same-origin policy forced them to rethink their approach. This article walks through their journey building a 'mountable proxy' architecture that sits between the mobile client and API.
Key Takeaways
- Reserved /_api namespace to proxy all API calls through their own domain
- Started with nginx proxy module, then moved to Node.js for OAuth2 credential handling
- Added HAProxy for better visibility after observing partial downtimes with Node cluster
- Hit HTTP 502 errors from premature socket closures on 304 responses over HTTPS
- Turned off nginx proxy buffering to pass data synchronously to Node processes
SoundCloud's proxy architecture let them ship fast without reimplementing API logic, though it meant sacrificing the pure client-side independence they originally wanted.
About This Article
SoundCloud's mobile app kept dropping connections and returning 502 errors when it received 304 responses over HTTPS. The issue traced back to Node.js Streams being closed too early during pipe operations.
The team borrowed a fix from Node.js issue #728 that corrected how Streams handled events. This ensured the end and close semantics worked properly when their Node backend proxied API responses.
Once they applied the Stream fix and turned off nginx proxy_buffering to pass data synchronously, SoundCloud stopped seeing the protocol violation errors that HAProxy was reporting with reason code SH.