How to get secure cookies working with Nginx

How to get secure cookies working with Nginx

Background

As I was setting up my Node server in a VPS, I got confused as to why my cookies weren't being set. After some time I figured out that it works in the development environment, but not in the production environment. I kept prodding around to find out that when I set the secure option to true the cookies weren't being sent.

Note: I'm using express-sessions my code roughly looks like this.

app.use(
  session({
    secret: process.env.SESSION_SECRET as string,
    resave: false,
    saveUninitialized: false,
    name: 'sid',
    store: new RedisStore({ client: redisClient }),
    proxy: process.env.NODE_ENV === 'production',
    cookie: {
      httpOnly: true,
      secure: process.env.NODE_ENV === 'production',
      maxAge: 1000 * 60 * 60 * 24 * 365, // 1 year
    },
  })
);

After hours of fiddling, researching, failing, and crying, I finally found the solution.

The Solution

Apparently, you need to add the directive proxy_set_header X-Forwarded-Proto https; to your Nginx file.

For example:

location / {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_set_header X-NginX-Proxy true;

    proxy_pass http://127.0.0.1:4000/;
    proxy_set_header X-Forwarded-Proto https;
}

And that's it! So much confusion just for one line.

Conclusion

I mainly wrote this article out of frustration with the hours spent, hoping someone else won't go through that.

As always you can follow me on Twitter, and I have a newsletter if you're into that.

Resources