5

I'm using Drupal 7, and have Pound running in front of Varnish for HTTPS. I can browse the site via HTTPS, but can't login - each time I do, the server returns a 403 forbidden error. Any ideas as to what is causing this? I'm guessing something may need to be changed in settings.php, but not sure.

Output from Firebug:

POST user

Response Headers

Accept-Ranges   bytes
Age 0
Cache-Control   no-cache, must-revalidate, post-check=0, pre-check=0
Connection  keep-alive
Content-Length  0
Content-Type    text/html; charset=UTF-8
Date    Tue, 09 Oct 2012 17:49:08 GMT
Etag    "1349804948"
Expires Sun, 19 Nov 1978 05:00:00 GMT
Last-Modified   Tue, 09 Oct 2012 17:49:08 +0000
Location    https://drupal.domain.com/user/2
Server  Apache
Set-Cookie SESSe15687525d17b8ec181665a71c88775c=EttXyyPvqESdU4RapW7xZkrRagGNHgRH5I9P6x0yRRE; expires=Thu, 01-Nov-2012 21:22:28 GMT; path=/; domain=.drupal.domain.com; httponly SSESSe15687525d17b8ec181665a71c88775c=mAdWa_a_OvcIIoWBuiVbLqFJzwyHiukfd_xBOVz_eaQ; expires=Thu, 01-Nov-2012 21:22:28 GMT; path=/; domain=.drupal.domain.com; secure; HttpOnly
Via 1.1 varnish
X-Drupal-Cache  MISS
X-Varnish   2081364495

Request Headers

Accept  text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding gzip, deflate
Accept-Language en-us,en;q=0.5
Connection  keep-alive
Cookie  has_js=1; __utma=194497400.1529654640.1349804906.1349804906.1349804906.1; __utmb=194497400.3.10.1349804906; __utmc=194497400; __utmz=194497400.1349804906.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)
DNT 1
Host    drupal.domain.com
Referer https://drupal.domain.com/user
User-Agent  Mozilla/5.0 (Windows NT 5.1; rv:15.0) Gecko/20100101 Firefox/15.0.1

GET 2

Response Headers

HTTP/1.1 403 Forbidden
Server: Apache
Expires: Sun, 19 Nov 1978 05:00:00 GMT
Last-Modified: Tue, 09 Oct 2012 17:49:08 +0000
Cache-Control: public, max-age=300
Etag: "1349804948-1"
Content-Language: en
X-Generator: Drupal 7 (http://drupal.org)
Set-Cookie: SSESSe15687525d17b8ec181665a71c88775c=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.drupal.domain.com; secure; httponly
SESSe15687525d17b8ec181665a71c88775c=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.drupal.domain.com; httponly
Vary: Cookie,Accept-Encoding
Content-Encoding: gzip
Content-Type: text/html; charset=utf-8
Content-Length: 8916
Accept-Ranges: bytes
Date: Tue, 09 Oct 2012 17:49:09 GMT
X-Varnish: 2081364496
Age: 0
Via: 1.1 varnish
Connection: keep-alive

Request Headers

GET /user/2 HTTP/1.1
Host: drupal.domain.com
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Connection: keep-alive
Referer: https://drupal.domain.com/user
Cookie: has_js=1; __utma=194497400.1529654640.1349804906.1349804906.1349804906.1; __utmb=194497400.3.10.1349804906; __utmc=194497400; __utmz=194497400.1349804906.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); SESSe15687525d17b8ec181665a71c88775c=EttXyyPvqESdU4RapW7xZkrRagGNHgRH5I9P6x0yRRE; SSESSe15687525d17b8ec181665a71c88775c=mAdWa_a_OvcIIoWBuiVbLqFJzwyHiukfd_xBOVz_eaQ
  • module rewrite of apache enabled? in the config files of drupal settings.php do you enable the cookie? I have a similar problem that my site broke but it was because I did not have the rewrite module enabled? do you have ssl enabled? – cayerdis Oct 9 '12 at 19:01
  • I am facing same problem... Did you get any solution? Please update... – Jilani Jidni Oct 31 '12 at 10:58
  • @JilaniJidni Pound passes along the client IP appropriately, but it needs to be set in Varnish. if (req.http.X-Forwarded-Proto !~ "https") { remove req.http.X-Forwarded-For; set req.http.X-Forwarded-For = client.ip; } – am4 Oct 31 '12 at 14:10
  • @am4 would you mind writing your solution and check your answer as the solution. It will help other people facing the same problem. – cayerdis Nov 22 '12 at 15:50
1

Pound passes along the client IP appropriately, but it needs to be forcibly set for non-https (http) requests to Varnish.

if (req.http.X-Forwarded-Proto !~ "https") {
  remove req.http.X-Forwarded-For;
  set req.http.X-Forwarded-For = client.ip;
}
0

I had the same issue when I have enabled such settings in my sites/default/settings.php file:

$base_url = 'https://shkodenko.com';  // NO trailing slash!
$conf['https'] = TRUE;

I have fixed this by adding .htaccess mod_rewrite rules:

# Force SSL for user login
RewriteCond %{REQUEST_URI} ^/user/login
RewriteCond %{SERVER_PORT} !443
RewriteRule (.*) https://%{HTTP_HOST}/$1 [R=301,L]
0

You may want to configure your Varnish 3 with Drupal 7 by checking this page: Configure Varnish 3 for Drupal 7.

Based on your 2nd GET response, the interesting part of it is the header which is:

Set-Cookie: SSESSe15687525d17b8ec181665a71c88775c=deleted

which means this cookie was deleted (most likely by Varnish), so you need to setup req.http.Cookie in your configuration to allow SESS/SSESS-like cookies, so they can remain for your session, otherwise other cookies may be removed (unset req.http.Cookie).

Here is the relevant part of .vcl config file to parse respond to incoming Drupal requests:

# Respond to incoming requests.
sub vcl_recv {
  # Use anonymous, cached pages if all backends are down.
  if (!req.backend.healthy) {
    unset req.http.Cookie;
  }

  # Allow the backend to serve up stale content if it is responding slowly.
  set req.grace = 6h;

  # Pipe these paths directly to Apache for streaming.
  #if (req.url ~ "^/admin/content/backup_migrate/export") {
  #  return (pipe);
  #}

  if (req.restarts == 0) {
    if (req.http.x-forwarded-for) {
      set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip;
    }
    else {
      set req.http.X-Forwarded-For = client.ip;
    }
  }

  # Do not cache these paths.
  if (req.url ~ "^/status\.php$" ||
      req.url ~ "^/update\.php$" ||
      req.url ~ "^/admin$" ||
      req.url ~ "^/admin/.*$" ||
      req.url ~ "^/flag/.*$" ||
      req.url ~ "^.*/ajax/.*$" ||
      req.url ~ "^.*/ahah/.*$") {
       return (pass);
  }

  # Do not allow outside access to cron.php or install.php.
  #if (req.url ~ "^/(cron|install)\.php$" && !client.ip ~ internal) {
    # Have Varnish throw the error directly.
  #  error 404 "Page not found.";
    # Use a custom error page that you've defined in Drupal at the path "404".
    # set req.url = "/404";
  #}

  # Always cache the following file types for all users. This list of extensions
  # appears twice, once here and again in vcl_fetch so make sure you edit both
  # and keep them equal.
  if (req.url ~ "(?i)\.(pdf|asc|dat|txt|doc|xls|ppt|tgz|csv|png|gif|jpeg|jpg|ico|swf|css|js)(\?.*)?$") {
    unset req.http.Cookie;
  }

  # Remove all cookies that Drupal doesn't need to know about. We explicitly
  # list the ones that Drupal does need, the SESS and NO_CACHE. If, after
  # running this code we find that either of these two cookies remains, we
  # will pass as the page cannot be cached.
  if (req.http.Cookie) {
    # 1. Append a semi-colon to the front of the cookie string.
    # 2. Remove all spaces that appear after semi-colons.
    # 3. Match the cookies we want to keep, adding the space we removed
    #    previously back. (\1) is first matching group in the regsuball.
    # 4. Remove all other cookies, identifying them by the fact that they have
    #    no space after the preceding semi-colon.
    # 5. Remove all spaces and semi-colons from the beginning and end of the
    #    cookie string.
    set req.http.Cookie = ";" + req.http.Cookie;
    set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";");   
    set req.http.Cookie = regsuball(req.http.Cookie, ";(SESS[a-z0-9]+|SSESS[a-z0-9]+|NO_CACHE)=", "; \1=");
    set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", "");
    set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", "");

    if (req.http.Cookie == "") {
      # If there are no remaining cookies, remove the cookie header. If there
      # aren't any cookie headers, Varnish's default behavior will be to cache
      # the page.
      unset req.http.Cookie;
    }
    else {
      # If there is any cookies left (a session or NO_CACHE cookie), do not
      # cache the page. Pass it on to Apache directly.
      return (pass);
    }
  }
}

If you're using other modules which defines alternative cookies (such as OpenAM), you need to modify the regex for Cookie pattern accordingly, e.g.

set req.http.Cookie = regsuball(req.http.Cookie, ";(_MYCOOKIE_[a-z]+_[a-z]+|SESS[a-z0-9]+|SSESS[a-z0-9]+|NO_CACHE)=", "; \1=");

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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