「Ruby on Rails」カテゴリーアーカイブ

CentOS7でpassenger-configやpassenger-statusがエラーになる

CentOS7でpassenger-configやpassenger-statusがエラーになる。

  • CentOS Linux release 7.2.1511 (Core)
  • Apache/2.4.6 (CentOS)
  • Phusion Passenger 5.0.23 (passenger-install-apache2-moduleでインストール)
$ passenger-config restart-app
*** ERROR: Phusion Passenger doesn't seem to be running. If you are sure that it
is running, then the causes of this problem could be one of:

 1. You customized the instance registry directory using Apache's
    PassengerInstanceRegistryDir option, Nginx's
    passenger_instance_registry_dir option, or Phusion Passenger Standalone's
    --instance-registry-dir command line argument. If so, please set the
    environment variable PASSENGER_INSTANCE_REGISTRY_DIR to that directory
    and run this command again.
 2. The instance directory has been removed by an operating system background
    service. Please set a different instance registry directory using Apache's
    PassengerInstanceRegistryDir option, Nginx's passenger_instance_registry_dir
    option, or Phusion Passenger Standalone's --instance-registry-dir command
    line argument.

原因

Passengerのinstance registry directory(Apacheの場合はPassengerInstanceRegistryDir、Nginxの場合はpassenger_instance_registry_dir)が見つからないのが原因。
instance registry directoryを明示的に指定していない場合のデフォルトは/tmpなので、instance registry directoryは/tmp下に作成されるが、SystemdのPrivateTmpオプションがhttpdで有効になっている(デフォルト)ため、httpd専用の/tmp(実際には/tmp/systemd-private-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-httpd.service-XXXXXX/tmp)に作成される。このディレクトリが、別プロセスであるpassenger-configやpassenger-statusには見つけられないのだ。

SystemdのPrivateTmpによって発生する問題なので、RHEL7やAmazon Linux 2でも同様だろう。

解決方法1: PassengerInstanceRegistryDirを明示的に指定する

SystemdのPrivateTmpは有効にしたままで対処する方法。
Passengerのinstance registry directoryがhttpd専用の/tmpに作成されないように、明示的に指定する。

当初、PassengerInstanceRegistryDir を /var/run に作成するようにしていましたが、systemd-239 以降で以下のような警告が表示されるため、/run に作成するよう修正しました。
[/etc/tmpfiles.d/passenger.conf:1] Line references path below legacy directory /var/run/, updating /var/run/passenger-instreg → /run/passenger-instreg; please update the tmpfiles.d/ drop-in file accordingly.

Systemd logs warnings about the legacy tmpfile location /var/run - Red Hat Customer Portal

(Apacheの場合)
/etc/httpd/conf/httpd.conf

PassengerInstanceRegistryDir /run/passenger-instreg

/run に置くファイル、ディレクトリは、再起動すると削除されてしまうので、tmpfiles.dに設定が必要。
詳細は、man 5 tmpfiles.d を参照。

/etc/tmpfiles.d/passenger.conf

D /run/passenger-instreg 0755 root root

passenger-status、passenger-configを実行するユーザにPASSENGER_INSTANCE_REGISTRY_DIRの設定が必要。

~/.bash_profile

export PASSENGER_INSTANCE_REGISTRY_DIR=/run/passenger-instreg

capistrano-passengerを使用している場合は、デプロイ後のpassenger-config restart-appでPASSENGER_INSTANCE_REGISTRY_DIRの指定が必要なので、該当するステージのデプロイレシピに以下を追加する。

set :default_env, {
  ...(略)..,
  "PASSENGER_INSTANCE_REGISTRY_DIR" => "/run/passenger-instreg"
}

以上を設定したら、システムを再起動する。

解決方法2: httpd.serviceのPrivateTmpを無効にする

SystemdのPrivateTmpをhttpdで無効にしてしまう方法。

$ sudo systemctl edit httpd.service
[Service]
PrivateTmp=false

保存後、httpdを再起動する。

$ sudo systemctl restart httpd.service
/usr/lib/systemd/system/ 下のファイルを手動でコピーして編集するよりも、`systemctl edit`を使った方がよいので、修正しました。`systemctl edit`を使えば、systemdの設定ファイルの再読み込み(daemon-reload相当)は自動で行われます。

/usr/lib/systemd/system/httpd.service を /etc/systemd/system にコピーすると、/etc/systemd/system に置いたファイルが優先される。コピーしたhttpd.serviceのPrivateTmpをfalseに変更する。

/etc/systemd/system/httpd.service

...(略)
PrivateTmp=false
...(略)

変更後、

$ sudo systemctl daemon-reload
$ sudo systemctl restart httpd.service

情報源: CentOS 7 で Phusion Passenger の passenger-status を実行するとエラーとなる - Qiita
お前らもさっさとハマって泣くべきCentOS7の落とし穴4つ - Qiita
Handle systemd PrivateTmp #1475
Systemd入門(5) - PrivateTmpの実装を見る - めもめも

omniauth-google-oauth2はGoogle APIのContacts APIとGoogle+ APIを有効にする必要がある

devise + omniauth-google-oauth2でGoogleアカウントでのログインを実装しているRailsアプリケーションで bundle updateしたら、omniauth-google-oauth2 が0.2.2から0.2.4になり、Googleアカウントでのログインで、invalid credentials が発生するようになった。
0.2.3から、Google APIのContacts APIとGoogle+ APIを有効にしないといけなくなったようだ。

https://github.com/zquestz/omniauth-google-oauth2#google-api-setup

cronでRVMのRubyを使う

RVMで複数のRuby環境がある場合に、Railsアプリケーションのためのcronをどうするか? Rubyのパスはフルパス指定すればいいが、gemがRVMのgemを見に行かないのが問題。RVM環境でcronを実行する必要がある。

RVM: Ruby Version Manager - Using Cron with RVM

cron用のシェルスクリプト内で使用するRVM環境をロードするには以下のようにする。

まず、環境ファイルのパスを確認

$ rvm env --path -- ruby-version[@gemset-name]

実行例

$ rvm env --path -- 1.8.7-p371
/Users/pistolfly/.rvm/environments/ruby-1.8.7-p371

cron用のシェルスクリプトで環境ファイルを読み込む

source /Users/pistolfly/.rvm/environments/ruby-1.8.7-p371

/home/pistolfly/app_dir
ruby script/runner -e production "ActiveRecord::SessionStore::Session.delete_all(['sessions.updated_at < ?', 6.hours.ago])"

CapistranoでPATH等の環境変数を設定する

Capfileに

load 'deploy/assets'

を追加すると、デプロイ時にassets:precompileを実行できるが、assets:precompile実行時に、

/usr/bin/env:
ruby
: そのようなファイルやディレクトリはありません

というエラーになってしまった。
ssh経由でのshellの実行時にPATHが通っていないのが原因と思われる。

解決方法

CapistranoでPATH等の環境変数を設定するには、:default_environmentを使う。

set :default_environment, {
  'PATH' => "/opt/ruby-enterprise-1.8.7-2011.03/bin:$PATH"
}

Change PATH environment with Rails and Capistrano - pastbedti.me
How do I configure capistrano to use my rvm version of Ruby - Stack Overflow
プリコンパイルする場合、config/environments/production.rbで、

config.assets.compile = false

にするが、assetsにapplication.js, application.css以外のjs、cssを使う場合は、以下のようにconfig.assets.precompileに追加する必要がある。追加しないと、smart_phone.css isn't precompiled のようなエラーになる。
config/environments/production.rb

config.assets.compile = false
# Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
config.assets.precompile += %w( smart_phone.css web_app_theme.css )

Rails3のActionMailerでOpenSSL::SSL::SSLError (hostname was not match with the server certificate)

Rails3でメールを送信したところ、送信できなかった。
ActionMailerの設定は、
config/initializers/02_action_mailer.rb

ActionMailer::Base.delivery_method = :smtp
ActionMailer::Base.smtp_settings = {
  :address        => "mail.example.com",
  :port           => "587",
  :domain         => "example.com",
  :user_name      => "username",
  :password       => "password",
  :authentication => :cram_md5
}

のようにしている。
同じ設定で、Rails2では送信できている。

原因

ActionMailer::Base.raise_delivery_errors = true

を追加して実行したところ、

OpenSSL::SSL::SSLError (hostname was not match with the server certificate)

となり、SSL証明書の検証で例外が発生しているらしいことが分かった。
また、メールサーバのログでも、

connect from xxxxx
setting up TLS connection from xxxxx
TLS connection established from xxxxx
lost connection after STARTTLS from xxxxx
disconnect from xxxxx

という状態だった。
このメールサーバはテスト用のpostfixで、
smtpd_tls_security_level = may
にしており、
smtpd_tls_cert_file、smtpd_tls_key_file には、自己署名証明書を設定していた。
Rails3では、STARTTLSがデフォルトで有効になっているためTLSで接続しようとするが、このメールサーバの証明書がテスト用の自己証明書だったので検証に失敗していたのが原因らしい。

解決方法

証明書を正当なものにすればよいと思われるが、テスト環境なのでとりあえず今は自己署名証明書を使いたい。
そのためには、ActionMailer::Base.smtp_settingsの設定で、STARTTLSを無効にするか証明書の検証を無効にする。

ActionMailer::Base.smtp_settings = {
  :address        => "mail.example.com",
  :port           => "587",
  :domain         => "example.com",
  :user_name      => "username",
  :password       => "password",
  :authentication => :cram_md5,
  :enable_starttls_auto => true,  # STARTTLSを無効にする場合はfalseにする
  :openssl_verify_mode => 'none'  # STARTTLSを有効にしつつ、不正な証明書もOKにしたい場合は、証明書の検証を無効にする
}

証明書の検証を無効にするのは本当はよくないけど、テスト環境等で自己署名証明書でもOKにしたい場合は、とりあえず上記のようにすれば、TLSでメールが送信できます。
OpenWebOps
email - Postfix & Rails 3.0 ActionMailer: lost connection after STARTTLS - Stack Overflow