So when I'm locally testing things such as Ajax in apps I'm writing, I often like to add a delay in server side scripts using a sleep statement. It helps simulate slow connections etc.

Is there a way to specify a similar delay behaviour directly in Nginx config that would work for the flat HTML files it's serving?

I'm aware you can do a similar delay simulation at the network level (see here) but it seems pretty messy and has never worked very well for me.


8 Answers 8


You should try an echo module.

  • Brilliant. That's exactly what I needed :-) Knew there must be a way! Sep 8, 2013 at 22:09

Giving a more detailed explanation of how you might use the echo module:

If you're starting from a basic config, that loads static files and PHP files, with something like this:

location ~ \.php$ {
    include fastcgi.conf;
    fastcgi_pass php;

That can then be converted to something like this to add a delay to both static and PHP requests:

# Static files
location / {
    echo_sleep 5;
    echo_exec @default;
location @default {}

# PHP files
location ~ \.php$ {
    echo_sleep 5;
    echo_exec @php;
location @php {
    include fastcgi.conf;
    fastcgi_pass php;

This can obviously be modified for anything you want. Basically, move each location block into a named @location. Then use echo_sleep and echo_exec in the original location block.


I would like to add to astlock's answer that if you want to reply with a plain return then note that there's a caveat: you have to use echo, not a standard return directive, after echo_sleep to respond with a delay, like this:

location = /slow-reply {
  echo_sleep 5.0;
  #return 200 'this response would NOT be delayed!';      
  echo 'this text will come in response body with HTTP 200 after 5 seconds';

(Tested on openresty/


Hackish way of doing this without external modules:

You build a plain HTTP server serving the asset with bash, it can make use of pv -L to throttle down the rate at which it is read from disk thus delaying the response:



function asset_response() {
    asset_size=$(du -b $asset_path)

    echo "HTTP/1.1 200 OK
Server: fake_server/0.0.0
Content-Type: text/html
Content-Length: $asset_size

$(pv -L $bytes_second $asset_path)"

while [ 1 ]; do
    asset_response | nc -l $port


./fake_server.sh 500 8080 text/html index.html

Then you can just set Nginx up to proxy requests to that bash HTTP server:

    server {
           location /fake_proxy {
                    proxy_pass http://localhost:8080;
  • Tried this but the server never responds until I CTLR+C the script Aug 29, 2023 at 23:25
  • @SteveRobbins just tested it again, the terminal where the server starts "hangs" until you hit ctrl+c as the program takes control of it, you can run it in background mode. Yet, if you hit its endpoint (curl localhost:8080) you'll see output on that terminal and curl with get its response. Aug 30, 2023 at 9:38

The following python script worked well for me and IMHO worth sharing.

#!/usr/bin/env python

# Includes
import getopt
import sys
import os.path
import subprocess
from http.server import HTTPServer
from http.server import BaseHTTPRequestHandler
import socketserver
import time

########  Predefined variables #########
helpstring = """Usage: {scriptname} args...
    Where args are:
        -h, --help
            Show help
        -p PORTNUMBER
            Port number to run on
        -d delay-in-seconds
            How long to wait before responding

helpstring = helpstring.format(scriptname=sys.argv[0])

def beSlow(seconds):

########  Functions and classes #########
class SlowserverRequestHandler(BaseHTTPRequestHandler):
    def do_GET(s):
        if s.path == "/slow":
            # Check status
            # Assume fail
            code = 200
            status = ""

            # Be slow for a while

            s.send_header("Content-type", "text/html")
            s.wfile.write(b"I'm a slow response LOL\n")

            s.send_header("Content-type", "text/html")
            s.wfile.write(b"slowserver - reporting for duty. Slowly...\n")

# Parse args
    options, remainder = getopt.getopt(sys.argv[1:], "hp:d:", ['help'])
    print("Invalid args. Use -h or --help for help.")

for opt, arg in options:                                                  
    if opt in ('-h', '--help'):                                           
    elif opt in ('-p'):                                                   
        HTTPPORT = int(arg)                                               
    elif opt in ('-d'):                                                
        seconds = arg                                                  
# Start HTTP service                                                   
server_address = ('', HTTPPORT)                      
httpd = server_class(server_address, handler_class)
except KeyboardInterrupt:                          

Source (gist.github.com)


I had to simulate delays (to generate timeouts every now and then) and, although the result is not as constant as other answers, the following is a quick implementation.

In practice one uses limit_req or request limiting. For example with an allowance for 1 requests per minute, the first request will get through but then the rest will be either rejected or delayed. If one configures a proper burst one can achieve substaintial delays (that indeed easily result in connection timeouts). Setting the burst is important otherwise there is only rejection and no delay.

    limit_req_zone $binary_remote_addr zone=adddelay:2m rate=1r/m;

    server {
      listen 80;

      include /etc/nginx/conf.d/restricted_access.cnf;
      root    /usr/share/nginx/html/;

      location / {
        limit_req zone=adddelay burst=100; #up to 100 mins delay
        proxy_pass http://endpoint;

More info here: Limiting the Request Rate section.


you can set a backend server to receive the request, then delay to response in the server. Nginx proxy the request to the backend server.


There is no way (IHMO) to delay the response from nginx. You have to rework your application not your webserver to enable such feature.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .