目的
privateなgemサーバーを構築したい。
geminaboxやgemirroがよく使われているらしい。
ここではgeminaboxを使う。
構築環境
- CentOS 7.2(vagrant bento)
- geminabox
- puma
- nginx(yum package)
設置手順
rubyが設置されてない場合はyumやrbenvで設置する。この説明は割愛する。
bundlerの設置
gem install bundler
アプリケーションのディレクトリを生成する。
mkdir gembox
cd gembox
bundle init
アプリケーションサーバーとしてpumaを使う。
bundle initで生成されたGemfileを下記のように編集する。
# frozen_string_literal: true
source "https://rubygems.org"
# gem "rails"
gem "geminabox"
gem "puma"
別にglobalのruby環境やsystemのruby環境で設置しても構わない。
共通的なものだけglobalのruby環境に設置するのが自己ルールであるだけだ。
bundle install --path vendor/bundle
config.ruを生成する。
require "rubygems"
require "geminabox"
Geminabox.data = "./data" # ... or wherever
run Geminabox::Server
data、config、tmpディレクトリを生成する。
dataはgemファイルの保管箱である。
unixソケットを使うので、socketsディレクトリも作ろう。
mkdir data
mkdir config
mkdir -p tmp/pids
mkdir tmp/sockets
puma.rbを生成する。
mkdir config
vi config/puma.rb
app_root = "#{File.expand_path("../..", __FILE__)}"
pidfile "#{app_root}/tmp/pids/puma.pid"
state_path "#{app_root}/tmp/pids/puma.state"
bind "unix://#{app_root}/tmp/sockets/puma.sock"
directory app_root
threads 5,5
workers 2
environment 'production'
daemonize true
daemon化したいと思い、daemonize trueにしたがこのせいでsystemdで動けなくなり、とても苦労した。
あとで説明する。今は必要なので、そのままおいて。
bundle execは面倒だからpumaコマンドは生成しておく。
bundle binstubs puma
binディレクトリが生成されpumaやpumactlコマンドが生成されているはずだ。
ここまでするとプロジェクトの中身はこうなる。
.
├── Gemfile
├── Gemfile.lock
├── bin
│ ├── puma
│ ├── pumactl
│ └── rackup
├── config
│ └── puma.rb
├── config.ru
├── data
├── tmp
│ ├── pids
│ └── sockets
└── vendor
└── bundle
pumaの起動・終了
bin/pumactl -F config/puma.rb start
bin/pumactl -F config/puma.rb stop
nginxの設置
epelが設置されていない場合は先に設置する。
yumリポジトリを登録ではなくyumパッケージで設置する。
sudo yum install epel-release -y
sudo yum install nginx -y
nginx.confファイルを下記のように編集する。
sudo vi /etc/nginx/nginx.conf
# For more information on configuration, see:
# * Official English Documentation: http://nginx.org/en/docs/
# * Official Russian Documentation: http://nginx.org/ru/docs/
user vagrant;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
# Load dynamic modules. See /usr/share/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
include /etc/nginx/conf.d/*.conf;
server {
listen 80;
listen [::]:80;
server_name gembox;
client_max_body_size 100M;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
}
}
vagrantユーザでpumaが実行されるので、nginxのworkerプロセスもvagrantで実行される必要がある。
そうしないと502 Bad Gatewayエラーが発生する。
そのときのエラーログはこうだ。
cat /var/log/nginx/error.log
...
2017/04/07 01:43:53 [crit] 13203#0: *1 connect() to unix:/home/vagrant/gembox/tmp/sockets/puma.sock failed (13: Permission denied) while connecting to upstream, client: 192.168.33.1, server: _, request: "GET / HTTP/1.1", upstream: "http://unix:/home/vagrant/gembox/tmp/sockets/puma.sock:/", host: "gembox"
...
- serverの設定
- include /etc/nginx/conf.d/gembox_server.conf
upstream gembox {
server unix:/home/vagrant/gembox/tmp/sockets/puma.sock;
}
- locationの設定
- include /etc/nginx/default.d/gembox_server.conf
location / {
proxy_pass http://gembox;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
nginxの起動・終了・状態・リロード
sudo systemctl start nginx.service
sudo systemctl stop nginx.service
sudo systemctl status nginx.service
sudo systemctl reload nginx.service
おまけにsystemdについて
ここまでするとちゃんとgeminaboxのページが表示されるはずだが、もし表示されなかった場合は80ポートLISTENされているのか、確認する。
firewalld含めて確認する必要がある。
geminaboxページが表示されたら、gemファイルを1個選んでアップロードしてみよう。
必ずアップロードするんだ。アップロードするとgem保管箱の仕組みが作られるみたい。
空いていたdataディレクトリにファイルやディレクトリが生成される。
data
├── _cache
├── _temp
├── gems
├── latest_specs.4.8
├── latest_specs.4.8.gz
├── prerelease_specs.4.8
├── prerelease_specs.4.8.gz
├── quick
├── specs.4.8
└── specs.4.8.gz
gemファイル1個だけアップロードする場合はこれでも悪くないが、複数のgemをアップロードするにはコマンドが便利。
mac(ホスト) - vagrant(ゲスト、geminaboxサーバー)
vi /private/etc/hosts
192.168.33.10 gembox
ホストからゲストへ複数のgemファイルをアップロードしてみよう。
gem inabox *.gem -g http://gembox
500エラーが発生した。
Pushing yard-0.9.8.gem to http://gembox/...
ERROR: Error (500 received)
<html>
<head><title>500 Internal Server Error</title></head>
<body bgcolor="white">
<center><h1>500 Internal Server Error</h1></center>
<hr><center>nginx/1.10.2</center>
</body>
</html>
nginxのworkerプロセスはvagrantなので、「/var/lib/nginx」をownerがvagrantではないとgemファイルのアップロードができない。
そのときのエラーログはこうだ。
2017/04/07 10:58:21 [crit] 4488#0: *15 open() "/var/lib/nginx/tmp/client_body/0000000001" failed (13: Permission denied), client: 192.168.33.1, server: gembox, request: "POST /upload HTTP/1.1", host: "gembox"
ownerをvagrantに変更する。(vagrant、ゲスト側)
sudo chown -R vagrant /var/lib/nginx
もう一度やってみる。
アップロードファイルのサイズが大きい場合はエラーが発生する。
Pushing nokogiri-1.7.0.1.gem to http://gembox/...
ERROR: Error (413 received)
<html>
<head><title>413 Request Entity Too Large</title></head>
<body bgcolor="white">
<center><h1>413 Request Entity Too Large</h1></center>
<hr><center>nginx/1.10.2</center>
</body>
</html>
そのときのエラーログはこうだ。(vagrant、ゲスト側)
2017/04/07 11:50:52 [error] 4488#0: *70 client intended to send too large body: 9148319 bytes, client: 192.168.33.1, server: gembox, request: "POST /upload HTTP/1.1", host: "gembox"
このようなときは、nginx.confファイルの中でclient_max_body_sizeを適当に大きいサイズで変更しよう。
もう一度やってみる。
アップロードしたgemファイルが表示されるはずだ。
http://gembox
これでおわり!
ではない。
pumaをsystemdのサービスに登録して使う。
sudo vi /etc/systemd/system/puma.service
[Unit]
Description=Puma HTTP Server
After=network.target
[Service]
Type=simple
User=vagrant
Group=vagrant
PIDFile=/home/vagrant/gembox/tmp/pids/puma.pid
WorkingDirectory=/home/vagrant/gembox
ExecStart=/usr/bin/bash -lc 'bin/pumactl -F config/puma.rb start'
ExecReload=/bin/kill -s USR1 $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
TimeoutSec=300
Restart=always
[Install]
WantedBy=multi-user.target
systemdの詳細は割愛する。
Software Design 2015年2月号のLinux systemd入門を参考
おまけにpuma関連signal
ExecStartがサービスをstartするとき実行されるコマンドだが、「/usr/bin/bash -lc 'puma起動コマンド'」で実行しないといけない。
そうしないとvagrantではないrootユーザーのログインシェルで実行される。
puma.rbファイルからdaemonize trueの設定を消す!
systemdのサービスがdaemon化してくれることだから要らないし、むしろこれのせいでサービスがずっとfailedになってしまう。
おしまい。