226

I have configured Apache to send back a 200 response without serving any file with this configuration line

Redirect 200 /hello

Can I do this with Nginx? I don't want to serve a file, I just want the server to respond with a 200 (I'm just logging the request).

I know I can add an index file and achieve the same thing, but doing it in the config means there's one less thing that can go wrong.

Theo
  • 2,505
  • 2
  • 18
  • 10
  • 2
    One could argue that if you don't serve a "file" or any content, you should return 204 No Content, as opposed to 200. – amn Aug 06 '20 at 13:21

6 Answers6

442

Yes, you can

location / {
    return 200 'gangnam style!';
    # because default content-type is application/octet-stream,
    # browser will offer to "save the file"...
    # if you want to see reply in browser, uncomment next line 
    # add_header Content-Type text/plain;
}
cadmi
  • 6,858
  • 1
  • 16
  • 22
  • 4
    how do I add a newline to the response? `gangnam\nstyle`? – tback Dec 28 '15 at 13:52
  • 4
    @tback of course, right you are – cadmi Mar 09 '16 at 09:10
  • Just add the newline! Nginx configuration directives are not bound to single lines, they are ended by semicolon. – Emil Vikström May 03 '16 at 19:26
  • 11
    add_header doesn't work for me as it adds another header instead of replacing the old 'Content-type'. In my response I have 2 'Content-type' headers:$ curl -v localhost/healthcheck/h1_pio > GET /healthcheck/h1_pio HTTP/1.1 > User-Agent: curl/7.38.0 > Host: localhost > Accept: */* > < HTTP/1.1 200 OK < Date: Tue, 11 Oct 2016 13:27:53 GMT < Content-Type: application/octet-stream < Content-Length: 25 < Connection: keep-alive < Content-Type: application/json – jmcollin92 Oct 11 '16 at 13:30
  • 2
    @jmcollin92 your comment has nothing to do with the question that was asked and to which the answer was given. because you obviously have some sort of proxy_pass, fascgi_pass, whatever... but I still answer location /healthcheck/h1_pio { # proxy_pass blablabla what you need; proxy_hide_header Content-Type; add_header Content-Type application/json; } in the future, ask your question correctly and in the proper location – cadmi Oct 12 '16 at 23:43
  • 10
    @jmcollin92 that can happen if you have an existing default_type declared somewhere else. You can override it by using `default_type text/plain;` inside of the location block in place of the `add_header` directive. – tjb1982 May 23 '17 at 17:55
  • This is awesome for adding health checks to a dedicated reverse proxy instance! `location /health { add_header Content-Type text/plain; return 200 'healthy'; }` – Bruno Bronosky Feb 13 '19 at 19:22
  • 3
    Hint: use `add_header Content-Type text/plain always;` to force plain text if you're not returning a "successful" code. – Tugzrida Mar 15 '19 at 13:25
  • 1
    If you have authentication enabled, take care that this doesn't bypass it: https://stackoverflow.com/questions/40447376/auth-basic-within-location-block-doesnt-work-when-return-is-specified – Eric Jun 04 '20 at 03:29
  • Worth to mention this post: http://www.nginxer.com/records/how-to-configure-nginx-to-return-text-or-json/ – ivanleoncz Jun 20 '20 at 02:43
  • This will return a unformatted text. If that is the point of the answer, ok. But if the objective is to return a formatted html page, this doesn't work. An edit was not accepted for the answer, regarding such improvement, so I provided a different answer, with a broader scenario. – ivanleoncz Jul 01 '20 at 16:23
  • In case you need to return a custom 404 page with a custom `Content-Type` header but can only append part of the Nginx configuration (Kubernetes ingress-nginx controller configuration), please see my answer below. – Vedran Vidovic May 11 '21 at 10:24
33

If you want to return a formatted HTML text, without serving a HTML file:

location / {
    default_type text/html;
    return 200 "<!DOCTYPE html><h2>gangnam style!</h2>\n";
}

If you want to return a text without html format, as the answer points:

location / {
    add_header Content-Type text/plain;
    return 200 'gangnam style!';
}

And if you just simply wants to return 200:

location / {
    return 200;
}

Just to remember: location blocks go inside server blocks. Here's a doc for more information about the topic.

P.S.: I have similar configuration (formatted html) running on plenty of servers.

ivanleoncz
  • 1,433
  • 4
  • 18
  • 32
32

You do need to use a 204 as Nginx will not allow a 200 with no response body. To send a 204 you simply use the return directive to return 204; in the appropriate location.

Martin Fjordvald
  • 7,589
  • 1
  • 28
  • 35
  • 1
    If you try to view this through a browser, it will look like it did nothing. that's intentional. You served nothing (204), it displays nothing. To prove you served a 204, use `curl`. – jnovack Mar 19 '19 at 18:23
8

To complete @Martin Fjordval's answer, be careful if you're using such a configuration to do a healthcheck.

While a 204 HTTP code is semantically perfect for a healthcheck (success indication with no content), some services do not consider it a success.

Namely, I had the issue with Google Cloud Load-balancers.

toadjaune
  • 391
  • 3
  • 4
  • Exactly. Google Cloud Load Balancer **requires** a 200 response code to consider the instance healthy, no matter the body. Any other code (even 2xx codes) will make the health check fail. – maganap Mar 18 '20 at 14:56
6

As per status code definitions, I believe you want it to be a 204, and not 200. 200's need to be with a resource in the response, or I'd suspect most sane browsers would get confused by this. The other one you can use is 304, which is for cached content.

http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

sandroid
  • 1,724
  • 12
  • 16
  • Sure, make it a 204, how do I do it? Although I very much doubt any browser will be confused by an empty body. – Theo Nov 01 '10 at 15:55
  • 2
    an empty body is still a response, with an object, such as a blank index.html. What you asked is to provide a 200 response with no resource attached to it (no file served). As for how exactly to do it on nginx, I need to look it up myself, I've only once done this on apache, and I can't remember off hand. – sandroid Nov 01 '10 at 20:05
  • 304 seems like it would send all the wrong signals for things like debugging and temporary returns. – Kzqai Feb 05 '16 at 20:18
2

Expanding on the @cadmi answer for a specific case of Kubernetes ingress-nginx controller configuration.

In my case, I could only append the small part of the Nginx configuration inside the location directive.

I wanted to add a custom 404 error JSON message for a specific if directive. Since default_type is not allowed inside the if directive I came up with adding the "blank" default_type outside the if directive and add_header inside the if directive:

http {
    default_type text/html; # can't change this
    ...
    server {
        ...
        location / {
            ...
            # This part of configuration is something I can change (generated by ingress-nginx controller `ingress.kubernetes.io/configuration-snippet` annotation)
            default_type "";
            # Custom 404 JSON page returned for the call to my.specific.host
            if ($host = my.specific.host) {
                return 404 '{\n  "status": "404",\n  "message": "Not Found",\n  "details": "Please call other hosts."\n}\n';
                add_header Content-Type "application/json" always;
            }
        }
    }
}

Without the default_type ""; an add_header directive was adding the second Content-Type header instead of changing the default one.

  • If you have `nginx-extras`, `openresty` or similar, you don't need `default_type "";` - just use `more_set_headers 'Content-Type: text/plain';` - plus `return 900 'blubbi'`. – uav Aug 05 '21 at 11:57