1

I am building an Express.js app locally. In order to test this in something other than localhost, I added the following entry to my hosts file:

127.0.0.1       mynewapp.dev

Without even starting the app, I accidentally tried http://mynewapp.dev:3000 (this is where I intended the app to run), in Chrome. To my surprise Chrome redirected me to https://mynewapp.dev:3000.

Headers in the browser's console show:

General:

  • Request URL: http://mynewapp.dev:3000/
  • Request Method: GET
  • Status Code: 307 Internal Redirect
  • Referrer Policy: no-referrer-when-downgrade

Response Headers:

  • Location: https://mynewapp.dev:3000/
  • Non-Authoritative-Reason: HSTS

Request Headers:

  • Provisional headers are shown
  • Upgrade-Insecure-Requests: 1
  • User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like
  • Gecko) Chrome/68.0.3440.106 Safari/537.36
  • X-DevTools-Emulate-Network-Conditions-Client-Id: 23A0CBD658A51DF4CA3B25A263078DA4

How did this happen? I have got no software redirecting the request, and my app isn't even running!

I am using:

  • Chrome Version 68.0.3440.106 (Official Build) (64-bit)
  • Windows 10 Enterprise

However this does not happen in:

  • Microsoft Edge 40.15063.674.0 (Shows Error Code: INET_E_RESOURCE_NOT_FOUND)
  • IE 11 (Shows Error Code: INET_E_RESOURCE_NOT_FOUND)

To answer the comments:

  • curl -I http://mynewapp.dev:3000 gets stuck and shows nothing.
  • I also tried chrome://net-internals/#events, and found the request. This is what I saw:

    100382: URL_REQUEST
    http://mynewapp.dev:3000/
    Start Time: 2018-08-17 07:32:03.853
    
    t=16751 [st=   0] +REQUEST_ALIVE  [dt=1007]
                       --> priority = "HIGHEST"
                       --> url = "http://mynewapp.dev:3000/"
    t=16751 [st=   0]   +URL_REQUEST_DELEGATE  [dt=1]
    t=16751 [st=   0]      DELEGATE_INFO  [dt=1]
                           --> delegate_blocked_by = "extension AdBlock"
    t=16752 [st=   1]   -URL_REQUEST_DELEGATE
    t=16752 [st=   1]   +URL_REQUEST_START_JOB  [dt=6]
                         --> load_flags = 18432 (MAIN_FRAME_DEPRECATED | MAYBE_USER_GESTURE)
                         --> method = "GET"
                         --> url = "http://mynewapp.dev:3000/"
    t=16752 [st=   1]      URL_REQUEST_REDIRECT_JOB
                           --> reason = "HSTS"
    t=16752 [st=   1]      URL_REQUEST_FAKE_RESPONSE_HEADERS_CREATED
                           --> HTTP/1.1 307 Internal Redirect
                               Location: https://mynewapp.dev:3000/
                               Non-Authoritative-Reason: HSTS
    t=16752 [st=   1]     +URL_REQUEST_DELEGATE  [dt=6]
    t=16752 [st=   1]        DELEGATE_INFO  [dt=6]
                             --> delegate_blocked_by = "MojoAsyncResourceHandler"
    t=16758 [st=   7]     -URL_REQUEST_DELEGATE
    t=16758 [st=   7]      URL_REQUEST_REDIRECTED
                           --> location = "https://mynewapp.dev:3000/"
    t=16758 [st=   7]   -URL_REQUEST_START_JOB
    t=16758 [st=   7]   +URL_REQUEST_DELEGATE  [dt=0]
    t=16758 [st=   7]      DELEGATE_INFO  [dt=0]
                           --> delegate_blocked_by = "extension AdBlock"
    t=16758 [st=   7]   -URL_REQUEST_DELEGATE
    t=16758 [st=   7]   +URL_REQUEST_START_JOB  [dt=1000]
                         --> load_flags = 18432 (MAIN_FRAME_DEPRECATED | MAYBE_USER_GESTURE)
                         --> method = "GET"
                         --> url = "https://mynewapp.dev:3000/"
    t=16759 [st=   8]      URL_REQUEST_DELEGATE  [dt=0]
    t=16759 [st=   8]      HTTP_CACHE_GET_BACKEND  [dt=0]
    t=16759 [st=   8]      HTTP_CACHE_OPEN_ENTRY  [dt=0]
                           --> net_error = -2 (ERR_FAILED)
    t=16759 [st=   8]      HTTP_CACHE_CREATE_ENTRY  [dt=0]
    t=16759 [st=   8]      HTTP_CACHE_ADD_TO_ENTRY  [dt=0]
    t=16759 [st=   8]     +HTTP_STREAM_REQUEST  [dt=999]
    t=16759 [st=   8]        HTTP_STREAM_JOB_CONTROLLER_BOUND
                             --> source_dependency = 100392 (HTTP_STREAM_JOB_CONTROLLER)
    t=17758 [st=1007]        HTTP_STREAM_REQUEST_BOUND_TO_JOB
                             --> source_dependency = 100393 (HTTP_STREAM_JOB)
    t=17758 [st=1007]     -HTTP_STREAM_REQUEST
    t=17758 [st=1007]   -URL_REQUEST_START_JOB
                         --> net_error = -102 (ERR_CONNECTION_REFUSED)
    t=17758 [st=1007]    URL_REQUEST_DELEGATE  [dt=0]
    t=17758 [st=1007] -REQUEST_ALIVE
                       --> net_error = -102 (ERR_CONNECTION_REFUSED)
    
  • Cleared the host cache from chrome://net-internals/#dns. Did not work.
  • Stopped all Chrome extensions. No change in behavior.
2

Beginning in 2018 Chrome and Firefox now forces HSTS for the .dev top level domain.

As explained in this blog post, while desktop developers have been using locally redirected (via hosts) .dev since almost forever, there apparently is now (as of May 2018) a legitimate .dev generic top level domain (gTLD) owned by Google. And there is this Chromium commit from Jan 4, 2018 that explicitly states:

Preload HSTS for the .dev gTLD.

What fun! Additionally, as of July 2018 Firefox does this as well.

The simplest and most practical solution—for anyone who doesn’t want to set up HTTPS for local development—is to use another suffix such as .localhost or even .local or honestly anything in the world such as *.foobar and such.

But the long and short of this is in 2018, using *.dev suffix for local development will only cause more inadvertent headaches and confusion than anything else.

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.