Proxying to node.js + express.js, session doesn't persist

I have Nginx set up to proxy_pass requests to location /api to
127.0.0.1:3000, where Node.js is listening.
Node.js is running a server written with Express.js.
In my previous project, I used request session in Express to track
users. In that project, I didn’t use Nginx.
In the current project, I can’t use session because it simply doesn’t
save. I can write and read cookies, but not the request session. I
verified that the issue is in Nginx by running exact same code without
Nginx and being able to use request session.
My nginx.conf is as follows:

http {
include mime.types;
default_type application/octet-stream;

sendfile        on;

keepalive_timeout  65;

gzip  on;

server {
    listen 80;
    server_name 173.203.105.235;

    root /home/project/public;
    location ^~ /api/ {
        proxy_pass_header Set-Cookie;
        proxy_pass_header P3P;
        proxy_pass http://127.0.0.1:3000;
    }
}

}

Posted at Nginx Forum:
http://forum.nginx.org/read.php?2,212747,212747#msg-212747

Hello!

On Thu, Jul 21, 2011 at 06:45:00AM -0400, ilya wrote:

I have Nginx set up to proxy_pass requests to location /api to
127.0.0.1:3000, where Node.js is listening.
Node.js is running a server written with Express.js.
In my previous project, I used request session in Express to track
users. In that project, I didn’t use Nginx.
In the current project, I can’t use session because it simply doesn’t
save. I can write and read cookies, but not the request session. I
verified that the issue is in Nginx by running exact same code without
Nginx and being able to use request session.

How cookies are set? I.e. please show Set-Cookie header from
nginx (or backend) response. I suspect domain attribute doesn’t
match hostname of your nginx server, and that’s why cookies are
rejected by browsers.

gzip  on;

server {
    listen 80;
    server_name 173.203.105.235;

    root /home/project/public;
    location ^~ /api/ {
        proxy_pass_header Set-Cookie;
        proxy_pass_header P3P;

Just a side note: these “proxy_pass_header” directives aren’t
needed.

        proxy_pass http://127.0.0.1:3000;
    }
}

}

Maxim D.

Here’s what I see in the browser
---------Logging in-------------

Request Headers
Host 173.203.105.235
User-Agent Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101
Firefox/5.0
Accept /
Accept-Language en-us,en;q=0.5
Accept-Encoding gzip, deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection keep-alive
Content-Type application/json; charset=UTF-8
X-Requested-With XMLHttpRequest
Referer http://173.208.105.235/api.html
Content-Length 87


Response Headers
Server nginx/1.0.4
Date Thu, 21 Jul 2011 14:55:06 GMT
Transfer-Encoding chunked
Connection keep-alive
X-Powered-By Express
Set-Cookie
wdialef51s00s=4edaae8b004e0c6d740968fd6b7f9c89c23b5a2a0d373de44a937605899127bc;
path=/; expires=Thu, 21 Jul 2011 15:10:06 GMT; httpOnly
connect.sid=L96yGUBwoDwrQLqm2xlhBsZB.XHduhuaqAHqocaN6%2F0gCKQG6uiZtPb1UsSdGRTFpxgM;
path=/; expires=Thu, 21 Jul 2011 15:05:11 GMT; httpOnly

Login successful. As you can see, connect.id cookie is set (this is what
Express.js session uses). Now, I make a request to resource where
session is checked:


Request Headers
Host 173.203.105.235
User-Agent Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101
Firefox/5.0
Accept /
Accept-Language en-us,en;q=0.5
Accept-Encoding gzip, deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection keep-alive
X-Requested-With XMLHttpRequest
Referer http://173.208.105.235/api.html
Cookie
wdialef51s00s=4edaae8b004e0c6d740968fd6b7f9c89c23b5a2a0d373de44a937605899127bc;
connect.sid=L96yGUBwoDwrQLqm2xlhBsZB.XHduhuaqAHqocaN6%2F0gCKQG6uiZtPb1UsSdGRTFpxgM


Response Headers
Server nginx/1.0.4
Date Thu, 21 Jul 2011 14:56:09 GMT
Transfer-Encoding chunked
Connection keep-alive
X-Powered-By Express
Set-Cookie
connect.sid=L96yGUBwoDwrQLqm2xlhBsZB.XHduhuaqAHqocaN6%2F0gCKQG6uiZtPb1UsSdGRTFpxgM;
path=/; expires=Thu, 21 Jul 2011 15:05:11 GMT; httpOnly


Now, I just stumbled upon something I didn’t notice yesterday: the
property that I save on request session - the one that I can’t get to
work - apparently DOES work sometimes. Basically, if I keep logging in
and requesting resource - it works on some attempts. However, if I keep
requesting the resource after successful attempt - it breaks after few
requests and session goes back to original state.

This is just bizarre.

Posted at Nginx Forum:
http://forum.nginx.org/read.php?2,212747,212763#msg-212763

Hello!

On Thu, Jul 21, 2011 at 11:18:17AM -0400, ilya wrote:

[…]

Now, I just stumbled upon something I didn’t notice yesterday: the
property that I save on request session - the one that I can’t get to
work - apparently DOES work sometimes. Basically, if I keep logging in
and requesting resource - it works on some attempts. However, if I keep
requesting the resource after successful attempt - it breaks after few
requests and session goes back to original state.

Ok, so basically everything works fine but breaks sometimes,
right? It doesn’t looks like nginx issue for me, probably
something wrong with session storage on backend side.

Maxim D.

Well, not really, since this happens only when nginx is used.
I and other people use Express sessions and they work, but in my case
nginx somehow breaks them. The fact that session becomes flaky with
introduction of nginx doesn’t mean Express is broken, it means that
nginx introduces some change that affects session.
On the backend, sessions stored in Redis.

Looking at my config - does nginx pass all the headers from browser and
backend to each other? Maybe it modifies them somehow? Connect.session,
that Express uses
(https://github.com/senchalabs/connect/blob/master/lib/middleware/session.js)
uses this for fingerprinting:


function defaultFingerprint(req) {
var ua = req.headers[‘user-agent’] || ‘’;
return ua.replace(/;?\schromeframe/[\d.]+/, ‘’);
};

and gets existing session like so:

// get the sessionID from the cookie
req.sessionID = req.cookies[key];

So, can it be that nginx constantly modifies UA or filters out cookies?
Or anything else?

Posted at Nginx Forum:
http://forum.nginx.org/read.php?2,212747,212766#msg-212766

Are you see sessions not being flacky while working directly with
your backend?

Correct. I’ve tested backend standalone and this doesn’t happen. Notice,
that in requests above connect.sid is changing every request. That is
not supposed to happen - with standalone backend connect.sid value is
constant across requests and changes either when user re-logins or it
expires.

Can it be because nginx talks HTTP/1.0 to backend?.. Ugh.

Posted at Nginx Forum:
http://forum.nginx.org/read.php?2,212747,212768#msg-212768

Hello!

On Thu, Jul 21, 2011 at 12:28:39PM -0400, ilya wrote:

Are you see sessions not being flacky while working directly with
your backend?

Correct. I’ve tested backend standalone and this doesn’t happen. Notice,

So try to figure out what goes wrong. Dumping all of a session
requests till session break may be helpful, as well as dumping all
of the requests between nginx and your backend.

Instrumenting your backend’s code may be helpful as well (or even
easier).

that in requests above connect.sid is changing every request. That is
not supposed to happen - with standalone backend connect.sid value is
constant across requests and changes either when user re-logins or it
expires.

All of the requests you’ve provided have identical connect.sid as
far as I see.

Can it be because nginx talks HTTP/1.0 to backend?.. Ugh.

This may be a problem if e.g. your backend is multi-process, while
session store is local to process. With HTTP/1.1 and keepalive
you’ll be most likely talking to one process over established
connection (and everything seems to work ok), while though nginx
there will be new connection to your backend for each request and
you’ll be talking to many backend processes (and you’ll see
“flacky” sessions as described). This is a typical example of
“something wrong with session storage on backend side” as
mentioned in previous message.

Maxim D.

Hello!

On Thu, Jul 21, 2011 at 11:45:36AM -0400, ilya wrote:

Well, not really, since this happens only when nginx is used.
I and other people use Express sessions and they work, but in my case
nginx somehow breaks them. The fact that session becomes flaky with
introduction of nginx doesn’t mean Express is broken, it means that
nginx introduces some change that affects session.
On the backend, sessions stored in Redis.

Are you see sessions not being flacky while working directly with
your backend?

};

and gets existing session like so:

// get the sessionID from the cookie
req.sessionID = req.cookies[key];

So, can it be that nginx constantly modifies UA or filters out cookies?
Or anything else?

No, nginx doesn’t modify neither User-Agent nor Cookie headers
unless explicitly asked (with proxy_set_header directive).

Maxim D.

Was a solution to this problem ever found? I, too, am having similar
issues. Thanks!

Posted at Nginx Forum:
http://forum.nginx.org/read.php?2,212747,226251#msg-226251

All of the requests you’ve provided have identical
connect.sid as
far as I see.

Yeah, maybe the session lasted that long. I kept clicking and I saw
cookie change every few seconds, though.

you’ll be talking to many backend processes (and
you’ll see
“flacky” sessions as described). This is a
typical example of
“something wrong with session storage on backend
side” as
mentioned in previous message.

My backend is, in fact, multi-process - I use Cluster
(https://github.com/LearnBoost/cluster), which spawns 4 workers, one per
CPU core. I’m discussing this with Express/Cluster developer and he just
mentioned the same thing. If that’s the case - how would I fix that,
then?

Posted at Nginx Forum:
http://forum.nginx.org/read.php?2,212747,212779#msg-212779