Tyler DeWitt
Tyler DeWitt

Reputation: 23576

Start Unicorn Without sudo

I'm trying to start my unicorn process without using sudo. I've written a script that has been symlinked to /etc/init.d/unicorn_arcsite.sh.

If I run service unicorn_arcsite start my script says it starts fine, but my server does not handle http requests. Looking at the unicorn log I see this:

E, [2013-09-24T13:21:39.111308 #16879] ERROR -- : reaped #<Process::Status: pid 26117 exit 1> worker=7
E, [2013-09-24T13:21:39.112981 #26120] ERROR -- : Operation not permitted (Errno::EPERM)
/home/deployer/.rvm/gems/ruby-2.0.0-p195@arcsite_mysql/gems/unicorn-4.6.2/lib/unicorn/worker.rb:83:in `initgroups'
/home/deployer/.rvm/gems/ruby-2.0.0-p195@arcsite_mysql/gems/unicorn-4.6.2/lib/unicorn/worker.rb:83:in `user'
/home/deployer/.rvm/gems/ruby-2.0.0-p195@arcsite_mysql/gems/unicorn-4.6.2/lib/unicorn/http_server.rb:592:in `init_worker_process'
/home/deployer/.rvm/gems/ruby-2.0.0-p195@arcsite_mysql/gems/unicorn-4.6.2/lib/unicorn/http_server.rb:615:in `worker_loop'
/home/deployer/.rvm/gems/ruby-2.0.0-p195@arcsite_mysql/gems/unicorn-4.6.2/lib/unicorn/http_server.rb:500:in `spawn_missing_workers'
/home/deployer/.rvm/gems/ruby-2.0.0-p195@arcsite_mysql/gems/unicorn-4.6.2/lib/unicorn/http_server.rb:511:in `maintain_worker_count'
/home/deployer/.rvm/gems/ruby-2.0.0-p195@arcsite_mysql/gems/unicorn-4.6.2/lib/unicorn/http_server.rb:277:in `join'
/home/deployer/.rvm/gems/ruby-2.0.0-p195@arcsite_mysql/gems/unicorn-4.6.2/bin/unicorn:126:in `<top (required)>'
/home/deployer/.rvm/gems/ruby-2.0.0-p195@arcsite_mysql/bin/unicorn:23:in `load'
/home/deployer/.rvm/gems/ruby-2.0.0-p195@arcsite_mysql/bin/unicorn:23:in `<main>'

Running sudo service unicorn_arcsite start works fine.

I'm running on top of nginx, and nginx and unicorn communicate over a socket at /tmp/unicorn.arcsite.sock.

Permissions

deployer@arcsite:~/apps/arcsite/current$ service unicorn_arcsite start
/home/deployer/apps/arcsite/current: 
Starting - OK

deployer@arcsite:~/apps/arcsite/current$ ls -ld /tmp/unicorn.arcsite.sock 
srwxrwxrwx 1 deployer sudo 0 Sep 24 13:50 /tmp/unicorn.arcsite.sock

deployer@arcsite:~/apps/arcsite/current$ ls -l tmp/pids/unicorn.pid 
-rw-r--r-- 1 deployer sudo 6 Sep 24 13:50 tmp/pids/unicorn.pid

deployer@arcsite:~/apps/arcsite/current$ id
uid=1000(deployer) gid=27(sudo) groups=27(sudo)

Files

unicorn.rb

# RAILS_ROOT/config/unicorn.rb
# Search for "# SET ME!" and replace these with your own settings!.

# Set environment to development unless something else is specified
env = ENV["RAILS_ENV"] || "development"
ROOT = "<app_root>"


ENV['BUNDLE_GEMFILE'] = File.expand_path('../Gemfile', File.dirname(__FILE__))
require 'bundler/setup'

pid "#{ROOT}/tmp/pids/unicorn.pid"

# See http://unicorn.bogomips.org/Unicorn/Configurator.html for complete
# documentation.
worker_processes 10 # SET ME!

# listen on both a Unix domain socket and a TCP port,
# we use a shorter backlog for quicker failover when busy
listen "/tmp/unicorn.arcsite.sock", :backlog => 1024 # SET ME!

# Preload our app for more speed
preload_app true

GC.respond_to?(:copy_on_write_friendly=) and
    GC.copy_on_write_friendly = true

# nuke workers after 30 seconds instead of 60 seconds (the default)
timeout 30

# Production specific settings
if env == "production"
  # Help ensure your application will always spawn in the symlinked
  # "current" directory that Capistrano sets up.
  working_directory ROOT

  # feel free to point this anywhere accessible on the filesystem
  user 'deployer', 'staff'
  shared_path = "<shared_path>"

  stderr_path "#{shared_path}/log/unicorn.log"
  stdout_path "#{shared_path}/log/unicorn.log"
end

before_fork do |server, worker|
  # the following is highly recomended for Rails + "preload_app true"
  # as there's no need for the master process to hold a connection
  if defined?(ActiveRecord::Base)
    ActiveRecord::Base.connection.disconnect!
  end

  # Before forking, kill the master process that belongs to the .oldbin PID.
  # This enables 0 downtime deploys.
  old_pid = "#{ROOT}/tmp/pids/unicorn.pid.oldbin"
  if File.exists?(old_pid) && server.pid != old_pid
    begin
      Process.kill("QUIT", File.read(old_pid).to_i)
    rescue Errno::ENOENT, Errno::ESRCH
      # someone else did our job for us
    end
  end
end

after_fork do |server, worker|
  # the following is *required* for Rails + "preload_app true",
  if defined?(ActiveRecord::Base)
    ActiveRecord::Base.establish_connection
  end

  # if preload_app is true, then you may also want to check and
  # restart any other shared sockets/descriptors such as Memcached,
  # and Redis.  TokyoCabinet file handles are safe to reuse
  # between any number of forked children (assuming your kernel
  # correctly implements pread()/pwrite() system calls)
end

Upvotes: 0

Views: 1691

Answers (1)

kik
kik

Reputation: 7937

The line that fails is the one where unicorn try to change group :

if gid && Process.egid != gid
  Process.initgroups(user, gid)
  Process::GID.change_privilege(gid)
end

From your config file, I would say that the "deployer" user is not permitted to change to "staff" group. You should either change the group in your unicorn config or add your user to this group.

Upvotes: 1

Related Questions