在Vultr VPS上安装CentOS8+Rails 6+MySQL8+nginx,并使用Capistrano3进行部署

首先

在 CentOS7 文章之后,我也尝试了 CentOS8,并记录下来。

Vultr最便宜的10GB SSD计划在使用CentOS8时,磁盘空间会不足,建议使用25GB以上的空间。以下步骤中,虽然只有Ruby版本较旧,但这是因为本地应用程序在ruby 2.5.3上运行。我认为在2.7上步骤是相同的(未验证)。

在激安VPS提供商Vultr上通过介绍人的链接注册账户,您将获得100美元的信用额度。我尝试了各种组合,如CentOS7、8,MySQL 5.7、8等。由于不知道这个活动何时结束,所以如果您有兴趣,请通过以下链接注册账户。您将获得信用额度,而我也会获得一些信用额度,这是双赢的局面。

只需点击此链接,即可收到100美元。

スクリーンショット 2020-03-09 午後7.03.25.png
スクリーンショット 2020-03-09 午後7.17.41.png

0. 操作系统的基本配置

完成了在上一篇CentOS7文章中的1至6步骤,包括创建用户和设置交换空间等准备工作。

安装 MySQL 8

$ sudo su

Unistall MariaDB
# yum -y remove mariadb-libs
# rm -rf /var/lib/mysql/

Install MySQL 8
# yum -y install @mysql
# systemctl start mysqld
# systemctl enable --now mysqld
# systemctl status mysqld
# mysql_secure_installation

Securing the MySQL server deployment.

Connecting to MySQL using a blank password.

VALIDATE PASSWORD COMPONENT can be used to test passwords
and improve security. It checks the strength of password
and allows the users to set only those passwords which are
secure enough. Would you like to setup VALIDATE PASSWORD component?

Press y|Y for Yes, any other key for No: y

There are three levels of password validation policy:

LOW    Length >= 8
MEDIUM Length >= 8, numeric, mixed case, and special characters
STRONG Length >= 8, numeric, mixed case, special characters and dictionary                  file

Please enter 0 = LOW, 1 = MEDIUM and 2 = STRONG: 2
Please set the password for root here.

New password: 

Re-enter new password: 

Estimated strength of the password: 100 
Do you wish to continue with the password provided?(Press y|Y for Yes, any other key for No) : y
By default, a MySQL installation has an anonymous user,
allowing anyone to log into MySQL without having to have
a user account created for them. This is intended only for
testing, and to make the installation go a bit smoother.
You should remove them before moving into a production
environment.

Remove anonymous users? (Press y|Y for Yes, any other key for No) : y
Success.


Normally, root should only be allowed to connect from
'localhost'. This ensures that someone cannot guess at
the root password from the network.

Disallow root login remotely? (Press y|Y for Yes, any other key for No) : y
Success.

By default, MySQL comes with a database named 'test' that
anyone can access. This is also intended only for testing,
and should be removed before moving into a production
environment.


Remove test database and access to it? (Press y|Y for Yes, any other key for No) : y
 - Dropping test database...
Success.

 - Removing privileges on test database...
Success.

Reloading the privilege tables will ensure that all changes
made so far will take effect immediately.

Reload privilege tables now? (Press y|Y for Yes, any other key for No) : y
Success.

All done! 

安装 Ruby V2.5.3

# yum groupinstall "Development Tools"
# yum -y install libyaml-devel
# yum install -y openssl-devel readline-devel zlib-devel
# cd /usr/local
# git clone git://github.com/sstephenson/rbenv.git rbenv
# git clone git://github.com/sstephenson/ruby-build.git rbenv/plugins/ruby-build


# vi /etc/profile.d/rbenv.sh

> 以下を記述してパスを通しておく。
export RBENV_ROOT="/usr/local/rbenv"
export PATH="${RBENV_ROOT}/bin:${PATH}"
eval "$(rbenv init --no-rehash -)"

# source /etc/profile.d/rbenv.sh
# rbenv install 2.5.3  <=これが時間がかかる。
# rbenv global 2.5.3
# rbenv rehash

3. 安装 bundler 2.1.2

因为我的开发环境的Bundler是2.1.2,所以要与之匹配,但版本应根据开发环境进行调整。

# gem install bundler -v 2.1.2

4. 安装 Node.js

# yum install -y nodejs
# node --version
v10.19.0

5. 安装 yarn

# npm install -g yarn

6. 安装Nginx稳定版本的最新版

安装yum-utils。

# yum install yum-utils
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key

[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx.org/keys/nginx_signing.key

(2) 安装

# cat /etc/redhat-release
CentOS Linux release 8.1.1911 (Core) 

# yum --disablerepo=AppStream install -y nginx

Basic認証を使いたいのでhttpd-toolsもインストール
# yum install httpd-tools

确认行动

nginx起動
$ sudo nginx

nginx自動起動設定
# systemctl enable nginx
Created symlink /etc/systemd/system/multi-user.target.wants/nginx.service → /usr/lib/systemd/system/nginx.service.

動作状態確認
# systemctl status nginx
● nginx.service - nginx - high performance web server
   Loaded: loaded (/usr/lib/systemd/system/nginx.service; disabled; vendor preset: disabled)
   Active: active (running) since Sun 2020-03-15 17:14:15 UTC; 5s ago
     Docs: http://nginx.org/en/docs/
  Process: 3413 ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf (code=exited, status=0/SUCCESS)
 Main PID: 3414 (nginx)
    Tasks: 2 (limit: 5066)
   Memory: 2.0M
   CGroup: /system.slice/nginx.service
           ├─3414 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
           └─3415 nginx: worker process

Mar 15 17:14:14 vultrguest systemd[1]: Starting nginx - high performance web server...
Mar 15 17:14:15 vultrguest systemd[1]: nginx.service: Can't open PID file /var/run/nginx.pid (yet?) after start: No such file or directory
Mar 15 17:14:15 vultrguest systemd[1]: Started nginx - high performance web server.

在浏览器中访问。

スクリーンショット 2020-03-15 午後1.17.53.png

7. 快照

因为已经完成了干净安装到这里,所以在进行其他任务之前先进行快照拍摄。

スクリーンショット 2020-03-15 午後1.21.40.png

安装 Rails 6

(1) 为了Rails6的准备工作

# yum install mysql-devel
# gem install mysql2 -v '0.5.3' --source 'https://rubygems.org/'
# gem install msgpack

安装Rails 6

# gem install rails -v 6.0.2.1
...
Done installing documentation for concurrent-ruby, i18n, thread_safe, tzinfo, zeitwerk, activesupport, rack, rack-test, mini_portile2, nokogiri, crass, loofah, rails-html-sanitizer, rails-dom-testing, builder, erubi, actionview, actionpack, activemodel, activerecord, globalid, activejob, mini_mime, mail, actionmailer, nio4r, websocket-extensions, websocket-driver, actioncable, mimemagic, marcel, activestorage, actionmailbox, actiontext, thor, method_source, railties, sprockets, sprockets-rails, rails after 87 seconds
40 gems installed

9. 测试Rails应用程序

创建一个适当的应用程序用于操作验证。如果使用Capistrano从本地环境进行部署,可以跳过此操作验证而不要紧。

(1) 目录准备

$ sudo su
[root@vultrguest var]# mkdir /var/www
[root@vultrguest var]# mkdir /var/www/myapp
[root@vultrguest var]# chown -R deploy.deploy /var/www

(2) Gemfile 准备工作

$ bundle init
Writing new Gemfile to /var/www/myapp/Gemfile

$ vi Gemfile
# frozen_string_literal: true

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem "rails"  <= remove "#" here

(3) 创建新的 Rails 项目

$ bundle install --path vendor/bundle
$ bundle exec rails new . -B -d mysql --skip-test
$ bundle install --path vendor/bundle
$ rails webpacker:install
...
Webpacker successfully installed ? ?

$ rails s
=> Booting Puma
=> Rails 6.0.2.1 application starting in development 
=> Run `rails server --help` for more startup options
Puma starting in single mode...
* Version 4.3.3 (ruby 2.5.3-p105), codename: Mysterious Traveller
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://127.0.0.1:3000
* Listening on tcp://[::1]:3000
Use Ctrl-C to stop

(4) 使用telnet进行确认

前提条件:确保端口3000已经打开。

$ yum list installed | grep telnet

もしtelnetがインストールされていなければインストール
$ sudo yum -y install telnet telnet-server
$ telnet 127.0.0.1 3000
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
GET / HTTP/1.1   <=Enterを2回押す事。

HTTP/1.1 403 Forbidden
Content-Type: text/html; charset=UTF-8
Content-Length: 3102

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <title>Action Controller: Exception caught</title>
  <style>
    body {
      background-color: #FAFAFA;
....
</body>
</html>
Connection closed by foreign host.

通过这个可以确认Puma已经在运行了。如果要从外部通过浏览器访问,需要进行与nginx的集成配置。

(5) 快照

一旦到这个阶段,我们将进行快照保存。

10. 使用Capistrano3进行部署。

我打算使用Capistrano3在本地开发环境部署我开发的应用程序。

前提条件 (Native Chinese)
前提 (Simplified Chinese)

    GitHubにSSH公開鍵でローカルからPushできていること。

(1) 準備在 Vultr VPS 上應用程式部署的目錄。

$ sudo su
# mkdir /var/www
# mkdir /var/www/myapp
# mkdir /var/www/myapp/shared
# mkdir /var/www/myapp/shared/config

# adduser www
# chown -R www:www /var/www
# chown -R deploy /var/www/myapp
# gpasswd -a deploy www
# gpasswd -a nginx www

(2) 复制指定为非部署对象的文件

$ scp -i ~/.ssh/vultr config/master.key deploy@SERVER_IP_ADDR:/var/www/myapp/shared/config/
$ scp -i ~/.ssh/vultr config/database.yml deploy@SERVER_IP_ADDR:/var/www/myapp/shared/config/

(3) 与Capistrano相关的配置

# Use Capistrano for deployment
group :development do
  gem 'capistrano'
  gem 'ed25519'
  gem 'bcrypt_pbkdf'
  gem 'capistrano-rbenv'
  gem 'capistrano-bundler'
  gem 'capistrano-rails'
  gem 'capistrano3-puma'
end

生成Capfile和config/deploy.rb文件。

$ bundle exec cap install STAGES=production

設定 Capfile和config/deploy.rb。

# Load DSL and set up stages
require "capistrano/setup"

# Include default deployment tasks
require "capistrano/deploy"

# Load the SCM plugin appropriate to your project:
#
# require "capistrano/scm/hg"
# install_plugin Capistrano::SCM::Hg
# or
# require "capistrano/scm/svn"
# install_plugin Capistrano::SCM::Svn
# or
require "capistrano/scm/git"
install_plugin Capistrano::SCM::Git

# Include tasks from other gems included in your Gemfile
# require "capistrano/rvm"
require "capistrano/rbenv"
# require "capistrano/chruby"
require "capistrano/bundler"
require "capistrano/rails/assets"
require "capistrano/rails/migrations"
# require "capistrano/passenger"
require 'capistrano/puma'
install_plugin Capistrano::Puma
install_plugin Capistrano::Puma::Nginx

# Load custom tasks from `lib/capistrano/tasks` if you have any defined
Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }
# config valid for current version and patch releases of Capistrano
lock "~> 3.12.1"

server 'Your Vultr IP ADDR', port: 22, roles: [:app, :web, :db], primary: true
set :application, 'myapp'
set :repo_url, 'git@github.YOU/myapp.git'
set :user,            'deploy'
set :ssh_options,     {
  forward_agent: true,
  user: fetch(:user),
  keys: %w(~/.ssh/vultr)
}

# Default branch is :master
# ask :branch, `git rev-parse --abbrev-ref HEAD`.chomp

# Default deploy_to directory is /var/www/my_app_name
# set :deploy_to, "/var/www/my_app_name"
set :deploy_to, "/var/www/myapp"

# Default value for :format is :airbrussh.
# set :format, :airbrussh

# You can configure the Airbrussh format using :format_options.
# These are the defaults.
# set :format_options, command_output: true, log_file: "log/capistrano.log", color: :auto, truncate: :auto

# Default value for :pty is false
# set :pty, true

# Default value for :linked_files is []
# append :linked_files, "config/database.yml"

# Default value for linked_dirs is []
# append :linked_dirs, "log", "tmp/pids", "tmp/cache", "tmp/sockets", "public/system"
append :linked_dirs, '.bundle'
append :linked_files, "config/master.key"
append :linked_files, "config/database.yml"
append :linked_dirs, "log", "tmp/pids", "tmp/cache", "tmp/sockets"

# Default value for default_env is {}
# set :default_env, { path: "/opt/ruby/bin:$PATH" }

# Default value for local_user is ENV['USER']
# set :local_user, -> { `git config user.name`.chomp }

# Default value for keep_releases is 5
# set :keep_releases, 5

# Uncomment the following to require manually verifying the host key before first deploy.
# set :ssh_options, verify_host_key: :secure

# rbenv
set :rbenv_type, :system
set :rbenv_ruby, File.read('.ruby-version').strip
set :rbenv_prefix, "RBENV_ROOT=#{fetch(:rbenv_path)} #{fetch(:rbenv_path)}/bin/rbenv exec"

set :bundle_jobs, 2      <=安いプランなので2Default4

# debug log level
set :log_level, :debug    <=設定作業中はデバッグモードにした。

(4) 预先部署 nginx-puma 的协作。

VPS预备工作

# mkdir /etc/nginx/sites-available
# mkdir /etc/nginx/sites-enabled
# chgrp www sites-available
# chgrp www sites-enabled

使用capistrano-puma插件自动生成配置文件。

使用这些命令可以在服务器上创建/etc/nginx/sites-available和shared/puma.rb的配置文件。

$ bundle exec cap production puma:nginx_config
00:00 puma:nginx_config
      Uploading /tmp/nginx_myapp_production 100.0%
      01 sudo mv /tmp/nginx_myapp_production /etc/nginx/sites-available/myapp_production
     01 deploy@Vultr_IP_ADDR 0.200s
      02 sudo ln -fs /etc/nginx/sites-available/myapp_production /etc/nginx/sites-enabled/myapp_production
     02 deploy@Vultr_IP_ADDR 0.223s
$ bundle exec cap production puma:config
00:00 puma:config
      Uploading /var/www/myapp/shared/puma.rb 100.0%

执行部署。

执行部署,确保成功启动 puma 直到正常结束。

$ bundle exec cap production deploy

提示1:
如果无法从Vultr服务器加载GitHub,请尝试使用以下命令将您在本地开发环境中用于GitHub的SSH密钥添加到SSH连接中,即可解决问题。如果在重新创建GitHub存储库时出现错误,建议尝试此方法。

ssh-add ~/.ssh/id_rsa

提示2:
如果出现OpenSSL错误,请检查是否部署了由config/master.key创建的config/credentials.yml.enc。如果在~/.bash_profile中存在export RAILS_MASTER_KEY=”abc0123456789xyz…”,将优先使用RAILS_MASTER_KEY,因此如果密钥不匹配,就会导致此错误。

 DEBUG [3b3d9306] 	rake aborted!
ActiveSupport::MessageEncryptor::InvalidMessage: ActiveSupport::MessageEncryptor::InvalidMessage
...
Caused by:
OpenSSL::Cipher::CipherError: 

(5) Nginx和Puma的配置集成

进行Nginx和Puma通过套接字进行协作的配置。

#user  nginx;
user  deploy; <=重要。NginxPumaは同じユーザーでプロセスを起動する。
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    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;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*; <=RailsアプリのConfigをここでインクルードしている。
}
upstream puma_myapp { 
  server unix:/var/www/myapp/shared/tmp/sockets/puma.sock fail_timeout=0;
}

server {
  listen 80;
  server_name あなたのVultrサーバーのIPアドレス;
  root /var/www/myapp/current/public;
  try_files $uri/index.html $uri @puma_myapp_production;

  client_max_body_size 4G;
  keepalive_timeout 10;

  error_page 500 502 504 /500.html;
  error_page 503 @503;

  location @puma_myapp_production {
    proxy_http_version 1.1;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $host;
    proxy_redirect off;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_set_header X-Forwarded-Proto http;
    proxy_pass http://puma_myapp_production;
    # limit_req zone=one;
    access_log /var/www/myapp/shared/log/nginx.access.log;
    error_log /var/www/myapp/shared/log/nginx.error.log;

    # Basic認証
    auth_basic "Restricted"; <=テスト用のサーバーなのでBasic認証を付けた
    auth_basic_user_file /etc/nginx/sites-available/.htpasswd; <=テスト用のサーバーなのでBasic認証を付けた
  }

  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
  }

  location = /50x.html {
    root html;
  }

  location = /404.html {
    root html;
  }

  location @503 {
    error_page 405 = /system/maintenance.html;
    if (-f $document_root/system/maintenance.html) {
      rewrite ^(.*)$ /system/maintenance.html break;
    }
    rewrite ^(.*)$ /503.html break;
  }

  if ($request_method !~ ^(GET|HEAD|PUT|PATCH|POST|DELETE|OPTIONS)$ ){
    return 405;
  }

  if (-f $document_root/system/maintenance.html) {
    return 503;
  }
}

检查和加载nginx配置。

由于有很多关于Nginx的解释文章,所以我不会详细讨论。

$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

起動
$ sudo nginx

停止
$ sudo nginx -s stop

設定の再読み込み
$ sudo nginx -s reload

基本认证

$ sudo htpasswd -c /etc/nginx/sites-available/.htpasswd username
New password: password
Re-type new password: password
Adding password for user username

彪马的操作

起動
$ bundle exec cap production puma:start

停止
$ bundle exec cap production puma:stop

状態確認
$ bundle exec cap production puma:status

请使用浏览器确认

スクリーンショット 2020-03-14 午後5.58.51.png

请参阅相关文章。

如何在CentOS 8 / RHEL 8上安装MySQL 8.0
在CentOS 8上安装和更新最新版的Git的方法
在CentOS 8上安装最新版本的Nginx stable(官方软件源)
新建Rails项目的步骤总结
关于遇到capistrano无法连接到GitHub的解决方案

广告
将在 10 秒后关闭
bannerAds