How to enable ssl on a drupal 7 site

We encourage users to post events happening in the community to the community events group on https://www.drupal.org.
mmncs's picture

Hi everybody,

I have a VPS which is running Ubuntu with NGINX.

I have just created a Drupal Commerce site where I would like to enable SSL for the checkout procedure. So I would like to enable SSL for this site and limit the secure pages to only those during checkout. I am using the PayPal WPP - credit card, payment method and any help would be much appreciated.

Thanks for your time.

Chris

Comments

That's not really secure

perusio's picture

mixed mode sites are vulnerable do MiTM attacks. You can't mark the cookies secure, for example. Anyway, do something like this:

At the http level define a map directive listing your secure pages:

map $uri $is_secure {
    default 0;
    ~^/secure 1; # all pages started with 'secure' are served over SSL.
}
# and one that complements it, i.e., non-secure pages.
map $is_secure $not_secure {
    1 0;
    0 1;
}

After that create your SSL host — you can check here for example. Then do:

On the non-SSL host:

server {
    ...
    ## Before any location.
    if ($is_secure) {
        return 301 https://www.example.com$request_uri; # adjust to your host
    }
   # server specific stuff below
}

on the SSL host.
server {
   ...
   ## Before any location.
   if ($not_secure) {
       return 301 http://www.example.com$request_uri; # adjust to your host
   }
  # server specific stuff below
}

That's it generically.

Is it less secure to have

Circlefusion1's picture

Is it less secure to have authenticated users use SSL while anonymous visitors do not?

Or do you mean having mixed modes for different pages after logging in?

I mean

perusio's picture

having mixed mode for any type of users.

Have a look at the Secure

wipeout_dude's picture

Have a look at the Secure Pages module ( http://drupal.org/project/securepages ).. Will probably be easier to let you choose which pages are secure and which aren't..

In your nginx server config make the server listen on both port 80 and 443 so you only have to manage one config..

Example:
server {
listen 80;
listen 178.79.128.229:443 ssl;
...
ssl_certificate /etc/ssl/private/your.crt;
ssl_certificate_key /etc/ssl/private/your.key;
...
other config
...

}

Also add this to your settings.php for your site so the session information is handled better..
$conf['https'] = TRUE;

Hope that helps..

That's not needed

perusio's picture

in Drupal 7. Since it sets that variable automatically if the scheme is https. Also on Nginx 1.1.11 it was introduced the variable $https_if_not_empty that should be set as a FCGI parameter: fastcgi_param HTTPS $https_if_not_empty. If using a version of Nginx that doesn't have this variable defined yet, and I've been told that the usual Ubuntu PPA doesn't have it, then define:

map $scheme $https_if_not_empty {
    default '';
    https on;
}

See this.

Take a look how it is done in

omega8cc's picture

Take a look how it is done in Barracuda-Octopus-Aegir stack (with local SSL proxy). It handles all required/expected stuff like secure cookies, disabling caching and extra IPs SSL enabled on the fly. It is much more reliable than Secure Pages module.

http://drupalcode.org/project/barracuda.git/blob/HEAD:/aegir/conf/overri...
http://drupalcode.org/project/barracuda.git/blob/HEAD:/aegir/conf/global...
http://drupalcode.org/project/barracuda.git/blob/HEAD:/docs/SSL.txt

SSL w/ Drupal 6 w/ nginx as reverse proxy

mesch's picture

Don't mean to hijack your thread, but this is nginx/Drupal/SSL-TLS related so it fits the security theme.

I'm developing a Drupal 6 site w/ SSL using nginx as a reverse proxy to apache which runs the php. I'm using perusio's config with a few tweaks.

My approach to SSL is as follows:
1. Add "proxy_set_header X-Forwarded-Proto $scheme;" to my nginx configuration (in "reverse_proxy.conf"). Then in "settings.php", add this:
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
$_SERVER['HTTPS'] = 'on';
}

I implemented this solution based on this post (http://www.metaltoad.com/blog/running-drupal-secure-pages-behind-proxy) and others.

  1. Use securepages and securepages_prevent_hijack modules to secure the pages I want. I've set it up to automatically redirect pages to the proper protocol.

I've tested it with a self-signed certificate on my development environment and it seems to work just fine. But I'm far from an nginx expert... any thoughts from the community on this setup?

That's unnecessary

perusio's picture

Just proxy pass to https. No need to touch the settings.php file.

location = /index.php {
    internal;
    proxy_pass https://my_apache?q=$no_slash_uri&$args;
}

to use a snippet from my config.

Also: you're proxying to HTTPS? I think it more advisable to just use Nginx as an SSL terminator and force on the proxy config to use SSL on the pages you want. Nginx is much faster at SSL than Apache. If the backend is on a trusted network I see no upside on using https to backend. Of course you'll have to move your setup (locations that are secure and so on) to the proxy config. But the all thing is simpler, faster and smoother IMHO.

Thanks for the reply

mesch's picture

Thanks for the reply perusio.

I don't think I'm proxying to HTTPS; let me give a few more details as to the setup. As per your nginx "example.conf", I'm running two nginx servers: one for http, and one for https. My ssl_certificate info is included under the HTTPS server config. Both servers include "drupal6.conf", which proxies to http://phpapache when instructed. I don't have Apache2 mod_ssl enabled. So Apache doesn't know whether it's HTTP or HTTPS, but Drupal learns of it by having nginx add the custom header. Am I reading this right? Is it secure? (Yes, the backend is on a trusted network).

I thought of moving the location matching from Drupal to the nginx proxy, but thought it would be easier to administer the secure urls via the securepages module for now. I can definitely see how doing it with the proxy would be faster, as under the above setup requests have to pass all the way to the Drupal application for redirects to happen.

Well

perusio's picture

it's as secure as mixed mode. That's what secure_pages does. Yes using the header is a good way. Simpler and safer would be to keep all your logged in users over HTTPs. You can do that quite easily with Nginx. Leave as it is if you're happy with secure pages.

I think I'll stick with

mesch's picture

I think I'll stick with secure pages for now. securepages_prevent_hijack gives me the extra security I need to run securepages. I gather that running securepages w/o securepages_prevent_hijack by itself provides next to no security at all. Adding a second (secure!) cookie makes all the difference.

I am intrigued by the approach of keeping logged in users on HTTPS using nginx only, but I'm not sure how to go about it. I'm usually for anything that lets me cut down on the Drupal module count while still achieving my objectives.

Try something like this

perusio's picture

Have one SSL or I should say TLS since the current 1.1.x branch ships with TLS up to v1.3 info.

Then do at the http level:

map $http_cookie $is_secure {
    default 0;
    ~SESS 1;
}

map $not_secure $is_secure {
    1 0;
    0 1;
}

Now on the SSL host:
server {
   server_name ssl.example.com;
   #...
   if ($not_secure) {
      return 301 http://www.example.com$request_uri;
   }

   # usual stuff - locations etc.
}

On the non-SSL host:
server {
   server_name www.example.com;
   #...
   if ($is_secure) {
      return 301 https://ssl.example.com$request_uri;
   }
 
   # usual stuff - locations etc
}

I'm assuming you didn't set cookie.domain so that the session cookie gets a name started with SESS. If you did then adjust the map directive regex.

This should work. Of course it requires pressflow on Drupal 6. On Drupal 7 it works out of the box. The reason for pressflow is that D6 sends cookies for anon users. Alternatively for D6 use no_anon.

Hi perusio, omega8cc and

mmncs's picture

Hi perusio, omega8cc and wipeout_dude

Thanks a lot for the quick feedback!

I have decided to use wipeout_dudes solution since I'm quite new to NGINX and I don't want to drown my self in configuration, but thanks the other solutions I'm definitely going to look at those when I get a bit more comfortable with NGINX configuration. So I have now installed the securepages module and added ssl to the site configuration, but I'm not able to enable SSL in the securepages module and the server doesn't accept requests on https:

note*: I haven't added the patches to securepages module yet, since my thought was to first try if the server was even listening on 443. And now the Server isn't responding at all when I access it using https://test.artunika.dk

Thanks for your time, Chris

Here are the steps I have taken

The NGINX version is 1.0.5 and I have installed using standard package.

I have created a dummy cert using this guide: http://wiki.nginx.org/HttpSslModule

Here is my conf for the site:

server {
        server_name test.artunika.com test.artunika.dk;
        listen 80;
        listen 443;
        ssl on;

        ssl_certificate /usr/local/nginx/conf/server.crt;
        ssl_certificate_key /usr/local/nginx/conf/server.key;

        root /usr/share/nginx/www/artunika.test;

        location = /favicon.ico {
                log_not_found off;
                access_log off;
        }

        location = /robots.txt {
                allow all;
                log_not_found off;
                access_log off;
        }

        # This matters if you use drush
        location = /backup {
                deny all;
        }

        # Very rarely should these ever be accessed outside of your lan
        location ~* .(txt|log)$ {
                # allow 192.168.0.0/16;
                deny all;
        }

        location ~ ../..php$ {
                return 403;
        }


        location / {
                # This is cool because no php is touched for static content
                try_files $uri @rewrite;
        }

        location @rewrite {
                # Some modules enforce no slash (/) at the end of the URL
                # Else this rewrite block wouldn't be needed (GlobalRedirect)
                rewrite ^/(.)$ /index.php?q=$1;
        }

        location ~ .php$ {
                fastcgi_split_path_info ^(.+.php)(/.+)$;
                #NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
                include fastcgi_params;
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                fastcgi_intercept_errors on;
                fastcgi_pass php;
        }

        # Fighting with ImageCache? This little gem is amazing.
        location ~ ^/sites/.
/files/imagecache/ {
                try_files $uri @rewrite;
        }
        # Catch image styles for D7 too.
        location ~ ^/sites/./files/styles/ {
                try_files $uri @rewrite;
        }

        location ~
.(js|css|png|jpg|jpeg|gif|ico)$ {
                expires max;
                log_not_found off;
        }
}

Here is my fastcgi_params:

fastcgi_connect_timeout         60;
fastcgi_send_timeout            180;
fastcgi_read_timeout            180;
fastcgi_buffer_size             4k;
fastcgi_buffers                 64 4k;
#fastcgi_busy_buffers_size      256k;
#fastcgi_temp_file_write_size   256k;
#fastcgi_intercept_errors       on;

fastcgi_param   QUERY_STRING            $query_string;
fastcgi_param   REQUEST_METHOD          $request_method;
fastcgi_param   CONTENT_TYPE            $content_type;
fastcgi_param   CONTENT_LENGTH          $content_length;

fastcgi_param   SCRIPT_FILENAME         $request_filename;
fastcgi_param   SCRIPT_NAME             $fastcgi_script_name;
fastcgi_param   REQUEST_URI             $request_uri;
fastcgi_param   DOCUMENT_URI            $document_uri;
fastcgi_param   DOCUMENT_ROOT           $document_root;
fastcgi_param   SERVER_PROTOCOL         $server_protocol;

fastcgi_param   GATEWAY_INTERFACE       CGI/1.1;
fastcgi_param   SERVER_SOFTWARE         nginx/$nginx_version;

fastcgi_param   REMOTE_ADDR             $remote_addr;
fastcgi_param   REMOTE_PORT             $remote_port;
fastcgi_param   SERVER_ADDR             $server_addr;
fastcgi_param   SERVER_PORT             $server_port;
fastcgi_param   SERVER_NAME             $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param   REDIRECT_STATUS         200;

May not be the answer but try

wipeout_dude's picture

May not be the answer but try changing..

    listen 443;
    ssl on;

to

    listen your-server-ip:443 ssl;

and see if that helps.. Also use "netstat -tap" to make sure your server is listeining on port 443..

Finally make sure and check that your firewall allows port 443..

Ooops - thanks for the

mmncs's picture

Ooops - thanks for the reminder wipeout_dude FIREWALL its been a long time since I have been configuring the server...

Thanks guys

Don't

perusio's picture

forget to set cgi.fix_pathinfo to 0 in your PHP config (php.ini) or you're liable to get hacked quite easily. That config is really a mess.

@perusio - I do acknowledge

wipeout_dude's picture

@perusio - I do acknowledge that the config isn't the "most secure" but it is simple and usable for a general site installation..

I had a good look through the config you put together and while its incredibly comprehensive its also quite complicated to get to grips with for a beginner and is geared towards larger high load servers from what I can see..

You probably have the best knowledge of nginx compared to just about anyone else so what about creating a simple/minimal/basic drupal config that's as simple to implement as the one supplied on the nginx wiki? A single copy and paste or single include config that for the most part works using the nginx defaults just with the required drupal tweaks?? Essentially a stripped down small server, low volume version of your "super server" config..

Just a thought to make the newbies adoption of nginx simple like it is with the wiki config but addressing the most exploitable security vulnerabilities..

Nothing but a tinkerer

perusio's picture

that's what I am: tinkering Nginx + Drupal. I don't see how the config can be any simpler than it is. What it needs, definitely, is much better documentation IMO. The config tries to give you a section of most of the goodies that Nginx provides like open files cache, video streaming, AIO, &c.

It's on my plans to improve the docs. Let's see if I can get some quality time soon enough to do it...

I know we are hijacking this

wipeout_dude's picture

I know we are hijacking this thread a little.. Sorry!! :)

When I was looking at nginx for the first time a little less than a month ago your config seems quite daunting.. So many files and directories and includes.. I know I was a little intimidated trying to find my feet..

Better docs would be a great help..

Just another idea, perhaps have all but the minimal config disabled so the user can enable features (video streaming for example) as and when they need it?

I run multiple sites on my server and have a single generic "drupal.conf" include and thats it.. So I create the vhost config file in /etc/nginx/sites-available symlink it to sites-enabled.. The the vhost file I have the server{...} specific stuff along with a single include of my common drupal.conf file.. So creating a new vhost is very quick and easy to find any issues because I only have to look in two files..

I think perusio's setup is

mesch's picture

I think perusio's setup is actually quite similar in that he also includes a drupal.conf file from all applicable vhost files.

I think there are two issues:
- He is trying to accomodate multiple different configurations in his docs. If you were to focus on one only, you could strip out a lot of lines from many of the files. Personally I appreciate this as it helps to educate me about nginx while letting me more easily configure the server just how I want it.

  • There are multiple files in his github that aren't necessary for a given configuration, which makes it appear somewhat more daunting then it really is.

Personally I found it best to start at the top of the file chain (nginx.conf) and work my way down, looking at the other files as they are included. Extra documentation could help, but you can also supplement the existing documentation with the actual nginx docs at nginx.org (documentation, wiki, etc.)

Nginx

Group organizers

Group notifications

This group offers an RSS feed. Or subscribe to these personalized, sitewide feeds: