How to Add Artificial Delay for Assets in Nginx (Simulate Slow Connections)


2 views

When developing web applications that make AJAX calls or load critical assets, testing under simulated network conditions is crucial. While tools like Chrome DevTools offer network throttling, sometimes you need more precise server-side control - especially when testing API endpoints or static file delivery.

Nginx provides the limit_rate_after and limit_rate directives for bandwidth control, but for pure delay simulation, we can use a more elegant solution:

location /delayed-assets/ {
    echo_sleep 3; # Delay in seconds
    try_files $uri =404;
}

This requires the ngx_http_echo_module which is included in OpenResty or can be compiled manually.

For more sophisticated scenarios, use the Lua module:

location /api/ {
    access_by_lua_block {
        ngx.sleep(2.5) -- Delay in seconds
    }
    proxy_pass http://backend;
}

Always wrap delay configurations in environment detection:

# In nginx.conf
if ($environment = "development") {
    set $delay_enabled 1;
}

location /static/ {
    if ($delay_enabled) {
        access_by_lua_block { ngx.sleep(1) }
    }
    alias /var/www/static/;
}

For more realistic simulation, consider random delays:

location /simulate-network/ {
    access_by_lua_block {
        math.randomseed(ngx.time())
        local jitter = math.random() * 2 -- Random delay up to 2 seconds
        ngx.sleep(jitter)
    }
    try_files $uri =404;
}

Remember to test with various delay patterns to cover different network conditions your users might experience.


When developing web applications that rely on AJAX calls or dynamic content loading, it's crucial to test how the UI behaves under real-world network conditions. While tools like Chrome DevTools offer network throttling, sometimes you need more precise control at the server level.

Nginx provides a simple way to introduce artificial delays through the limit_rate_after and limit_rate directives, but these control bandwidth rather than initial latency. For true delay simulation, we'll use a different approach.

The most flexible solution involves using Nginx's Lua module (ngx_http_lua_module). First, ensure you have it installed:

# For Ubuntu/Debian
sudo apt-get install libnginx-mod-http-lua

# For CentOS/RHEL
sudo yum install nginx-mod-http-lua

Here's a simple configuration to add a 3-second delay to all static assets:

location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
    access_by_lua_block {
        ngx.sleep(3)  -- Delay in seconds
    }
}

You can create more sophisticated delay patterns:

location /static/ {
    access_by_lua_block {
        local uri = ngx.var.uri
        if string.match(uri, "%.js$") then
            ngx.sleep(2)  -- 2s delay for JS files
        elseif string.match(uri, "%.css$") then
            ngx.sleep(1)  -- 1s delay for CSS
        else
            ngx.sleep(0.5) -- 0.5s for other assets
        end
    }
}

For more realistic testing, implement random delays:

location / {
    access_by_lua_block {
        math.randomseed(os.time())
        local delay = math.random(100, 3000) / 1000  -- Random delay between 0.1-3s
        ngx.sleep(delay)
    }
}

Remember these important notes:

  • Delays tie up worker processes - don't use in production
  • For heavy testing, increase worker_connections in nginx.conf
  • Consider adding limit_except GET { deny all; } to delay only GET requests

If you can't use Lua, this hack works by proxying to a delayed backend:

location /delayed/ {
    proxy_pass http://127.0.0.1:81;
    proxy_set_header Host $host;
}

server {
    listen 81;
    location / {
        sleep 3;  # Requires custom module
        root /path/to/files;
    }
}

The best approach depends on your specific testing needs. For most development scenarios, the Lua method provides the best combination of flexibility and simplicity.