Skip to main content

NGINX / Apache Tips

A reverse proxy in front of your provider's API server is the recommended setup. It gives you TLS termination, load balancing, and control over request buffering. The settings below unlock good upload speeds to your provider.

Why buffering matters

By default, NGINX buffers client request bodies (uploads) to a temporary file on disk before forwarding them to the upstream. For large file uploads this adds latency and disk I/O, and can stall the upload stream. Disabling request buffering makes NGINX stream the body straight to the provider as it arrives.

NGINX

Server block

In the server block for your provider's domain:

server {
listen 443 ssl;
server_name storage.example.com;

# --- Upload tuning ---
client_body_buffer_size 4m; # increase size of upload buffer segments in memory
client_body_temp_path off; # don't spill uploads to temp files
client_max_body_size 4G; # allow uploads up to the provider's max_upload_size

# TLS certificates
ssl_certificate /etc/letsencrypt/live/storage.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/storage.example.com/privkey.pem;
...
}

The three directives:

  • client_body_buffer_size 4m — bodies up to 4 MiB are buffered in memory instead of written to disk. On hardware that isn't a decade old, 4M is easy to handle.
  • client_body_temp_path off — prevents NGINX from spooling request bodies to temporary files, eliminating disk I/O from the upload path.
  • client_max_body_size 4G — must be at least the provider's api_config.max_upload_size (default 4 GiB), otherwise large uploads are rejected with 413 Request Entity Too Large.

Location / proxy block

In the location block that proxies to the provider (default port 3333):

location /api/v1/ {
proxy_pass http://127.0.0.1:3333;

# --- Streaming: don't buffer requests or responses ---
proxy_buffering off; # stream responses as they arrive
proxy_request_buffering off; # stream uploads straight to the provider
proxy_cache off; # never cache file data

# --- Headers ---
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;

# --- Timeouts for long uploads ---
proxy_connect_timeout 60s;
proxy_send_timeout 3600s;
proxy_read_timeout 3600s;

# --- Large uploads ---
client_body_timeout 3600s;
}
  • proxy_request_buffering off — the critical one for uploads: the request body streams directly to the provider instead of being fully buffered by NGINX first.
  • proxy_buffering off — responses (file downloads) stream straight to the client; no read-ahead caching.
  • proxy_cache off — file data must never be served from an NGINX cache, since providers serve by FID and the data changes.

Full example

server {
listen 443 ssl;
server_name storage.example.com;

ssl_certificate /etc/letsencrypt/live/storage.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/storage.example.com/privkey.pem;

client_body_buffer_size 4m;
client_body_temp_path off;
client_max_body_size 4G;

location /api/v1/ {
proxy_pass http://127.0.0.1:3333;

proxy_buffering off;
proxy_request_buffering off;
proxy_cache off;

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;

proxy_connect_timeout 60s;
proxy_send_timeout 3600s;
proxy_read_timeout 3600s;
client_body_timeout 3600s;
}
}

After editing, test the config and reload:

nginx -t
systemctl reload nginx

Apache

For Apache as a reverse proxy, the equivalent request-body streaming is handled with the mod_proxy and mod_proxy_http modules:

<VirtualHost *:443>
ServerName storage.example.com

SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/storage.example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/storage.example.com/privkey.pem

# Allow uploads up to the provider's max_upload_size
LimitRequestBody 4294967296

ProxyPreserveHost On
ProxyPass /api/v1/ http://127.0.0.1:3333/api/v1/ flushpackets=on
ProxyPassReverse /api/v1/ http://127.0.0.1:3333/api/v1/
</VirtualHost>

flushpackets=on enables chunked streaming of responses, which is the Apache equivalent of proxy_buffering off.

Verify

Check that uploads stream without buffering:

# Health check through the proxy
curl https://storage.example.com/api/v1/health

# Upload a test file and confirm it completes
curl -X POST https://storage.example.com/api/v1/upload \
-F fid=test-fid \
-F file=@/path/to/large-file.bin

If uploads stall or fail with 413 errors, check that client_max_body_size (NGINX) or LimitRequestBody (Apache) matches the provider's api_config.max_upload_size.