Dagmar
Dagmar

Reputation: 3261

Issue with setting up SSL for a rails 4.2 site using apache and passenger

I am managing a Rails (4.2) site running on Ubuntu 14.04, using Apache (2.4.7) and Passenger 5.1.1. I am setting up SSL using a Cloudflare certificate.

The website appears to be working, and I'm not getting any SSL errors in my browser, but in my application log I am seeing loads of 404 (ActionController::RoutingError) errors for internal resources (generally in vendor or public).

I can't figure out what could be causing this error. I've tried setting "config.force_ssl = true" in my production.rb file, but from what I can understand, I should be able to manage this from Apache, or Cloudflare for that matter.

Can anyone help me, or even just give me some leads because at the moment, I'm at a loss.

Started GET "/example/vendor/bundle/ruby/2.3.0/gems/posix-spawn-0.3.12/test/" for xxx.xxx.xxx.xx at 2017-09-25 21:14:37 +0100

ActionController::RoutingError (No route matches [GET] "/mysite/vendor/bundle/ruby/2.3.0/gems/posix-spawn-0.3.12/test"):
  vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.0/lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call'
  vendor/bundle/ruby/2.3.0/gems/newrelic_rpm-3.17.1.326/lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.0/lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
  vendor/bundle/ruby/2.3.0/gems/newrelic_rpm-3.17.1.326/lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  vendor/bundle/ruby/2.3.0/gems/railties-4.2.0/lib/rails/rack/logger.rb:38:in `call_app'
  vendor/bundle/ruby/2.3.0/gems/railties-4.2.0/lib/rails/rack/logger.rb:20:in `block in call'
  vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.0/lib/active_support/tagged_logging.rb:68:in `block in tagged'
  vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.0/lib/active_support/tagged_logging.rb:26:in `tagged'
  vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.0/lib/active_support/tagged_logging.rb:68:in `tagged'
  vendor/bundle/ruby/2.3.0/gems/railties-4.2.0/lib/rails/rack/logger.rb:20:in `call'
  vendor/bundle/ruby/2.3.0/gems/newrelic_rpm-3.17.1.326/lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.0/lib/action_dispatch/middleware/request_id.rb:21:in `call'
  vendor/bundle/ruby/2.3.0/gems/newrelic_rpm-3.17.1.326/lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  vendor/bundle/ruby/2.3.0/gems/rack-1.6.5/lib/rack/methodoverride.rb:22:in `call'
  vendor/bundle/ruby/2.3.0/gems/newrelic_rpm-3.17.1.326/lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  vendor/bundle/ruby/2.3.0/gems/rack-1.6.5/lib/rack/runtime.rb:18:in `call'
  vendor/bundle/ruby/2.3.0/gems/newrelic_rpm-3.17.1.326/lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.0/lib/active_support/cache/strategy/local_cache_middleware.rb:28:in `call'
  vendor/bundle/ruby/2.3.0/gems/newrelic_rpm-3.17.1.326/lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  vendor/bundle/ruby/2.3.0/gems/rack-1.6.5/lib/rack/sendfile.rb:113:in `call'
  vendor/bundle/ruby/2.3.0/gems/newrelic_rpm-3.17.1.326/lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  vendor/bundle/ruby/2.3.0/gems/railties-4.2.0/lib/rails/engine.rb:518:in `call'
  vendor/bundle/ruby/2.3.0/gems/railties-4.2.0/lib/rails/application.rb:164:in `call'
  vendor/bundle/ruby/2.3.0/gems/railties-4.2.0/lib/rails/railtie.rb:194:in `public_send'
  vendor/bundle/ruby/2.3.0/gems/railties-4.2.0/lib/rails/railtie.rb:194:in `method_missing'
  vendor/bundle/ruby/2.3.0/gems/newrelic_rpm-3.17.1.326/lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  /home/mysite/.rvm/gems/[email protected]/gems/passenger-5.1.1/src/ruby_supportlib/phusion_passenger/rack/thread_handler_extension.rb:97:in `process_request'
  /home/mysite/.rvm/gems/[email protected]/gems/passenger-5.1.1/src/ruby_supportlib/phusion_passenger/request_handler/thread_handler.rb:152:in `accept_and_process_next_request'
  /home/mysite/.rvm/gems/[email protected]/gems/passenger-5.1.1/src/ruby_supportlib/phusion_passenger/request_handler/thread_handler.rb:113:in `main_loop'
  /home/mysite/.rvm/gems/[email protected]/gems/passenger-5.1.1/src/ruby_supportlib/phusion_passenger/request_handler.rb:416:in `block (3 levels) in start_threads'
  /home/mysite/.rvm/gems/[email protected]/gems/passenger-5.1.1/src/ruby_supportlib/phusion_passenger/utils.rb:113:in `block in create_thread_and_abort_on_exception'

My Apache config looks as follows:

<VirtualHost *:80>

  ServerName example.com

  RewriteEngine On
  RewriteCond %{HTTPS} off [OR]
  RewriteCond %{HTTP_HOST} !^www\. [NC]
  RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
  RewriteRule ^ https://www.%1%{REQUEST_URI} [L,NE,R=301]

</VirtualHost>

<VirtualHost *:80>

  ServerName www.example.com

  RewriteEngine On
  RewriteCond %{HTTPS} off [OR]
  RewriteCond %{HTTP_HOST} !^www\. [NC]
  RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
  RewriteRule ^ https://www.%1%{REQUEST_URI} [L,NE,R=301]

</VirtualHost>

<VirtualHost *:443>

  RequestHeader set X-Forwarded-Proto "https"
  SSLEngine      on
  SSLCertificateFile        /home/example/ssl/example.crt
  SSLCertificateKeyFile     /home/example/ssl/example.key

  ServerName example.com

  # Redirect / https://www.example.com/
  RewriteEngine On
  RewriteCond %{HTTPS} off [OR]
  RewriteCond %{HTTP_HOST} !^www\. [NC]
  RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
  RewriteRule ^ https://www.%1%{REQUEST_URI} [L,NE,R=301]

</VirtualHost>

<VirtualHost *:443>
  RequestHeader set X-Forwarded-Proto "https"
  SSLEngine      on
  SSLCertificateFile        /home/example/ssl/example.crt
  SSLCertificateKeyFile     /home/example/ssl/example.key

  ServerName www.example.com
  ServerAdmin [email protected] 
  DocumentRoot /var/www/example/public 
  ErrorLog /var/log/apache2/example/error.log 
  CustomLog /var/log/apache2/example/access.log common 

  <Directory /var/www/example/public>
    # This relaxes Apache security settings.
    AllowOverride all
    # MultiViews must be turned off.
    Options -MultiViews
  </Directory>

// etc

</VirtualHost>

Upvotes: 0

Views: 260

Answers (2)

Dagmar
Dagmar

Reputation: 3261

So this was a comedy of errors. I'd like to share my findings, so that perhaps I can save someone many hours of frustration.

Firstly, there wasn't much wrong with the setup above, although it's a little verbose.

This is the final conf file I used:

# avoids sending hackers too much info about the server
ServerTokens Prod

# Necessary if you have more than one domain served from this webserver
SSLStrictSNIVHostCheck off

RewriteEngine On

# redirects http to https and root domain to www
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.example.com%{REQUEST_URI} [L,NE,R=301]

# sets the HTTPS header for Wordpress
SetEnvIf X-Forwarded-Proto https HTTPS=on

<VirtualHost _default_:443>

  ServerName www.example.com
  ServerAdmin [email protected]

  ErrorLog /var/log/apache2/example/error.log
  CustomLog /var/log/apache2/example/access.log common

  DocumentRoot "/var/www/example/public"
  <Directory "/var/www/example/public">
    Options None
    Require all granted
  </Directory>

  PassengerAppEnv production
  PassengerAppRoot "/var/www/example"
  PassengerHighPerformance on

  SSLEngine      on
  SSLCertificateFile        /home/example/ssl/example.crt
  SSLCertificateKeyFile     /home/example/ssl/example.key

  ServerSignature off

  ProxyRequests Off
  ProxyPreserveHost On

  # blog reverse proxy which goes over http
  ProxyPass /blog http://www.example.com:8080/blog
  ProxyPassReverse /blog http://www.example.com:8080/blog

</VirtualHost>

Two webpages that I found super helpful to get the correct Apache configuration:

  1. https://simonecarletti.com/blog/2016/08/redirect-domain-http-https-www-apache/
  2. https://www.phusionpassenger.com/library/deploy/apache/prod_ssl.html

Cloudflare

Since I am using Cloudflare, I am also using Cloudflare Page Rules to redirect https://example.com/* to https://www.example.com. See this blog for more details. Note: I didn't need to purge cache to get this solution to work.

I am also using Cloudflare to manage the http to https redirection using a toggle on the "Cypro" setting page.

Finally, with respect to the issues I was struggling with...

Issues with internal URLs in my log files

This was caused (I assume) with a previous mis-configuration of Apache and these files were public and were indexed by Google (how embarrassing). I think it may have been the Apache PageSpeed mod that I was using.

I added a "gone" redirect to my VirtualHost definition above to avoid my log file being clogged up until the search engines stop indexing these files.

  Redirect gone /example/

Issues with redirecting http to https and root domain to www

This was a doozy... no matter what Apache configuration I used, I couldn't for the life of me get the root domain to redirect properly. I was getting security warnings in my browser, but when I was checking the domain using SSL checker sites, they were all saying the site was configured correctly. In the end I realised that I had put an entry in my /etc/hosts file (on my laptop) to the server URL to make it easy to SSH into the server because of the Cloudflare proxy... so when I was going to https://example.com it was hitting the server directly and not going via Cloudflare.

Issues with Wordpress on a reverse proxy

The Wordpress virtual host (which is running on 8080), does not need SSL because it is proxied behind the root domain, however you need to change the URLs in the dashboard to https://www.example.com/blog.

If you break your dashboard (like I did) before changing all the URLS to https, you will need to make URL changes manually

  1. In the database, in the table wp_options. This query will be helpful: select * from wp_options where option_value like 'http://www.example.com%';
  2. And in wp-config.php (see entries WP_HOME and WP_SITEURL).

You also need to make some changes to wp-config.php (well I did) to get the dashboard to work after the upgrade to SSL. I added this code at the end of wp-config.php:

define('FORCE_SSL_ADMIN', true);
// in some setups HTTP_X_FORWARDED_PROTO might contain 
// a comma-separated list e.g. http,https
// so check for https existence
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')
    $_SERVER['HTTPS'] = 'on';

Note, this line in the Apache config, which is also critical:

SetEnvIf X-Forwarded-Proto https HTTPS=on

Lessons learnt

  1. Keep lots of backups of your Apache configuration
  2. Ensure your /etc/hosts file is clean
  3. To avoid having to clear your browser cache, use Incognito and Private windows

Upvotes: 0

Camden Narzt
Camden Narzt

Reputation: 2003

Requests are being made that refer to paths that are not public. ie /example/vendor/bundle/ruby/2.3.0/gems/posix-spawn-0.3.12/test/ That's not an SSL problem. Check your access logs to see if the requests are coming in like that and if they are it's a problem with your app, and if not it's a problem with your redirects.

Upvotes: 0

Related Questions