準備
http://vps.sakura.ad.jp/
上にアクセスし、VPSに申し込みを済ませる。
今回メモリは2GB。ストレージの種類 SSD(50GB)。サーバー台数1台。
支払い情報を入力して、申し込み完了!
1、カスタムOSのインストール
OSを選択
今回はubuntu20を選択。
VNCコンソールを開き、インストール作業を開始。
Installを選択し、日本語を選択。
ホスト名、ドメイン名、rootパスワード、ユーザーアカウントを入力。
↓
ディスクパーティショニング ”ガイドーディスク全体を使う”→”全ての。。(初心者。。)”を選択→”パーティショニングの終了とディスクへの変更の書き込み”を選択
↓
完了したらxで閉じ、さくらのコンソールの緑の起動ボタンを押してサーバーを起動。
2、ターミナルでsshログインし、鍵認証でログインする方法
参考サイト
ssh鍵認証参考サイト
※windowsの場合はSSHクライアントソフトをインストールする必要がある。
ターミナルを開き以下のコマンドを入力
ssh 上で設定したuser名@IPアドレス
yesと上で設定したパスワードを入力し、sshログイン完了。
sshログイン先で以下のコマンドを実行
※手元で自分の公開鍵をコピーしておく。ない人は作成。
$ mkdir .ssh
$ chmod 700 .ssh
$ vi .ssh/authorized_keys
自分の公開鍵をcopy&paste
$ chmod 600 .ssh/authorized_keys
sshログインの設定が完了したので、一旦ログアウトし、もう一度ログインしてみて、パスワード入力も求められずにログインできたらOK。
sudoをインストール
sshログイン先で
$ su -
# apt-get install sudo
# usermod -G sudo [ユーザー名]
# su [ユーザー名]
パスワード認証によるsshアクセスを禁止する方法
$ sudo su
# vi /etc/ssh/sshd_config
PasswordAuthentication no
# service sshd restart
不要なポート番号を閉じる
さくらのパケットフィルターで簡単に設定可能になったようです。
こちらを参考に進める。
上記の通り実行したら以下のように変更。
-A INPUT -p tcp -m state --state NEW --dport 1234 -j ACCEPT
↓
-A INPUT -p tcp -m state --state NEW --dport 22 -j ACCEPT
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT
3、必要なものを諸々インストール
下記のコマンドをsshログイン先で実行。(必要、不要はご判断ください)
$ sudo apt-get update
$ sudo apt-get install vim git gcc g++ make nginx nodejs libssl-dev libreadline-dev zlib1g-dev
nginxのステータスを確認
$ sudo service nginx status
Active: active (running) since Sun 2017-08-27 16:18:48 JST; 35s ago
activeになっていればOK。
IPアドレスにアクセスしてみると、Welcome to nginx!の文字が。
(※さくらVPS パケットフィルタに注意)
4、rubyをrbenvでインストール
rbenvをインストール
$ git clone https://github.com/rbenv/rbenv.git ~/.rbenv
$ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
$ cd ~/.rbenv && src/configure && make -C src
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
一度ログインし直す。
$ ~/.rbenv/bin/rbenv init
rubyをインストール
$ rbenv install -l
インストールできるバージョンの一覧が表示される
$ rbenv install 2.4.1
$ rbenv global 2.4.1
$ rbenv exec gem install bundler
Mysql8.0をインストール
こちらを参考にUbuntu20にMysql8.0をインストール
Resolve dpkg status database is locked by another processエラー
インストール中にResolve dpkg status database is locked by another process
エラーが出る場合はこちらを参考に解決
bundle install中にエラー
bundle install中にパッケージ不足でエラーが出る場合はこちらを参考に解決
Capistranoの導入
手元での設定
Gemfile
group :development do
gem 'capistrano', '~> 3.9'
gem 'capistrano-rails'
gem 'capistrano-rbenv'
gem 'capistrano-bundler'
gem 'capistrano3-puma'
end
gem 'puma'
$ bundle install
$ bundle exec cap install
Capfile
require "capistrano/setup"
require "capistrano/deploy"
require 'capistrano/rails'
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'
require 'capistrano/rbenv'
require 'capistrano/bundler'
require 'capistrano/puma'
require 'whenever/capistrano' # wheneverを利用している場合
install_plugin Capistrano::Puma # Default puma tasks
install_plugin Capistrano::Puma::Systemd
require "capistrano/scm/git"
install_plugin Capistrano::SCM::Git
Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }
config/deploy.rb
# require 'whenever/capistrano'
lock "3.9.0"
set :application, "my_app_name" #自分のapp_nameに変更
set :repo_url, "git@example.com:me/my_repo.git" #自分のリポジトリURLに変更
set :deploy_to, '/var/www/my_app_name' #自分のapp_nameに変更
set :keep_releases, 3
set :rbenv_type, :user # or :system, depends on your rbenv setup
set :rbenv_ruby, '2.4.1'
set :rbenv_map_bins, %w{rake gem bundle ruby rails}
set :rbenv_roles, :all # default value
set :linked_dirs, %w{log tmp/backup tmp/pids tmp/cache tmp/sockets vendor/bundle}
set :linked_files, %w{config/credentials/production.key}
set :bundle_jobs, 4
namespace :deploy do
task :restart do
on roles(:web, :app, :db) do |host|
execute "source /etc/environment"
end
invoke 'puma:restart'
end
after :finishing, 'deploy:cleanup'
end
config/deploy/production.rb
set :branch, 'master'
role :app, %w{user_name@IPアドレス}
role :web, %w{user_name@IPアドレス}
role :db, %w{user_name@IPアドレス}
server 'IPアドレス', user: 'user_name', roles: %w{web app db}
config/puma/production.rbを新規作成
rails_root = "/var/www/my_app_name/current" #自分app_nameに変更
shared_path = "/var/www/my_app_name/shared" #自分app_nameに変更
worker_processes 4
working_directory rails_root
#listen "#{rails_root}/tmp/puma.sock"
#pid "#{rails_root}/tmp/puma.pid"
listen File.expand_path('tmp/sockets/puma.sock', shared_path)
pid File.expand_path('tmp/pids/puma.pid', shared_path)
stderr_path "#{rails_root}/log/puma_error.log"
stdout_path "#{rails_root}/log/puma.log"
preload_app true
before_fork do |server, worker|
ENV['BUNDLE_GEMFILE'] = File.expand_path('Gemfile', rails_root)
old_pid = "#{server.config[:pid]}.oldbin"
if File.exists?(old_pid) && server.pid != old_pid
begin
sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU
Process.kill(sig, 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|
defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
end
database.yml
default: &default
adapter: mysql2
encoding: utf8mb4
pool: 5
username: root
password:
socket: <%= ["/run/mysqld/mysqld5.6.sock",
"/tmp/mysqld.sock",
"/var/run/mysqld/mysqld.sock",
"/var/lib/mysql/mysql.sock",
"/opt/local/var/run/mysql5/mysqld.sock"].detect {|s| File.exist?(s) } %>
production:
adapter: mysql2
encoding: utf8mb4
pool: 5
database: my_app_name_production
username: <%= ENV["DB_USER"] %>
password: <%= ENV["DB_PASSWORD"] %>
config/initializers/ar_innodb_row_format.rbの作成
以下のファイルを作成。参考サイト
ActiveSupport.on_load :active_record do
module ActiveRecord::ConnectionAdapters
module CreateTableWithInnodbRowFormat
def create_table(table_name, options = {})
table_options = options.merge(options: 'ENGINE=InnoDB ROW_FORMAT=DYNAMIC')
super(table_name, table_options) do |td|
yield td if block_given?
end
end
end
class AbstractMysqlAdapter
prepend CreateTableWithInnodbRowFormat
end
end
end
上記作成後、migrate。
$ bundle exec rake db:migrate
deployする
$ bundle exec cap production deploy
puma.serviceの設置
新規ファイルとして作成。以下内容を記述。参考
/etc/systemd/system/puma.service
[Unit]
Description=Puma HTTP Server
After=network.target
[Service]
Type=simple
User=ubuntu
WorkingDirectory=/var/www/my_project_name/current
Environment=RAILS_ENV=production
Environment=USING_WEB_SERVER=true
ExecStart=/bin/bash -lc 'bundle exec puma -C config/puma/production.rb'
Restart=always
[Install]
WantedBy=sockets.target
ここで色々エラーを起こすと思いますが、エラー文に従って修正していけば完了。(投げやり
以下にエラーが出て追加で行ったことを記しておきます。
sshログイン後
yarnをinstall
こちらを参考にubuntu20にyarnをinstall
権限エラー
$ chown -R [ユーザー名]:[ユーザー名] /var/www/
nodeバージョンエラー
こちらを参考にnodenvをinstallし、nodeをバージョンアップ
バージョンアップ後、deploy時にnodeのバージョンが変わらない場合は以下を試す。
$ yarn config set ignore-engines true
master.key配置
こちらを参考にmaster.keyを設定。
mysqlにログインし、Database作成
こちらを参考にmysqlにログインできるようにしておく。
Rails7 Tailwindを利用している場合のエラー
以下のようなエラーが出た場合
TypeError: Object.fromEntries is not a function
$ sudo apt-get install npm
$ sudo npm i -g n
$ cd /var/www/my_project_name
$ n latest
$ mysql -u root
mysql> CREATE DATABASE my_app_name_production;
MariaDBに以下の設定を記載
$vi /etc/mysql/mariadb.conf.d/50-server.cnf
[mysqld] の中に以下を記載
innodb_file_per_table = 1
innodb_file_format = Barracuda
innodb_large_prefix = 1
innodb_default_row_format = DYNAMIC # >= 5.7.9
Letsencryptをインストール
デプロ完了後、SSL化対応。
AレコードでDNS設定を済ませておく。
Ubuntu20用
- ssh先でcertbotをinstall
$ sudo apt install certbot python3-certbot-nginx
- localでnginxファイルを管理可能にするため、nginxフォルダを作成。
$ mkdir config/nginx
$ touch config/nginx/nginx.conf
$ touch config/nginx/my_project_name.conf
user root;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
# multi_accept on;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# SSL Settings
##
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
# gzip_vary on;
# gzip_proxied any;
# gzip_comp_level 6;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
#mail {
# # See sample authentication script at:
# # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
#
# # auth_http localhost/auth.php;
# # pop3_capabilities "TOP" "USER";
# # imap_capabilities "IMAP4rev1" "UIDPLUS";
#
# server {
# listen localhost:110;
# protocol pop3;
# proxy on;
# }
#
# server {
# listen localhost:143;
# protocol imap;
# proxy on;
# }
#}
upstream puma {
server unix:/var/www/my_project_name/current/tmp/sockets/puma.sock;
}
server {
listen 80;
root /var/www/my_project_name/current/public;
server_name www.my_project_domain_name;
client_max_body_size 50M;
# For letsencrypt
location /.well-known/ {
alias /var/www/my_project_name/.well-known/;
}
location / {
return 301 https://my_project_domain_name$request_uri;
}
}
server {
listen 80;
root /var/www/my_project_name/current/public;
server_name my_project_domain_name;
client_max_body_size 50M;
# For letsencrypt
location /.well-known/ {
alias /var/www/my_project_name/.well-known/;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443;
server_name my_project_domain_name www.my_project_domain_name;
root /var/www/my_project_name/current/public;
client_max_body_size 50M;
if ($http_host = www.my_project_domain_name) {
rewrite (.*) https://my_project_domain_name$1;
}
ssl on;
ssl_certificate /etc/letsencrypt/live/my_project_domain_name/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/my_project_domain_name/privkey.pem;
ssl_session_timeout 5m;
# Use https always
add_header Strict-Transport-Security 'max-age=31536000;';
# # 1. 暗号方式の設定
# # (デフォルト) ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
# # 2. Logjam攻撃対策
# ssl_dhparam /etc/nginx/ssl/dhparam.pem;
# # 3. Enable OCSP (Online Certificate Status Protocol) Stapling
# ssl_stapling on;
# ssl_stapling_verify on;
# resolver 8.8.4.4 8.8.8.8 valid=300s;
# resolver_timeout 10s;
location ~ ^/sitemap.xml.gz {
root /var/www/my_project_name/current/public;
}
location ^~ /assets/ {
# to serve pre-gzipped version
gzip_static on;
# for CloudFlare
gzip_proxied any;
gzip_vary on;
expires 1y;
add_header Cache-Control public;
add_header ETag "";
add_header Access-Control-Allow-Origin *;
break;
}
location ~* \.(css|ico)$ {
expires 24h;
if ($args ~ [0-9]+) {
expires max;
}
#access_log off;
}
try_files $uri @app;
location @app {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_pass http://puma;
}
location ^~ /blog {
alias /var/www/wordpress;
index index.php index.html index.htm;
try_files try_files $uri $uri/ /blog/index.php;
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
}
set $spambot 0;
# リファラスパムボットそれぞれの判定
if ($http_referer ~* (4webmasters.org) ) {
set $spambot 1;
}
if ($http_referer ~* (76brighton.co.uk) ) {
set $spambot 1;
}
if ($http_referer ~* (7makemoneyonline.com) ) {
set $spambot 1;
}
if ($http_referer ~* (7secretsearch.com) ) {
set $spambot 1;
}
if ($http_referer ~* (acads.net) ) {
set $spambot 1;
}
if ($http_referer ~* (floating-share-buttons.com) ) {
set $spambot 1;
}
if ($http_referer ~* (forum.topic65617124.darodar.com) ) {
set $spambot 1;
}
if ($http_referer ~* (free-social-buttons.com) ) {
set $spambot 1;
}
if ($http_referer ~* (www.event-tracking.com) ) {
set $spambot 1;
}
if ($http_referer ~* (www.Get-Free-Traffic-Now.com) ) {
set $spambot 1;
}
if ($http_referer ~* (chinese-amezon.com) ) {
set $spambot 1;
}
if ($http_referer ~* (e-buyeasy.com) ) {
set $spambot 1;
}
if ($http_referer ~* (erot.co) ) {
set $spambot 1;
}
if ($http_referer ~* (sa-live.com) ) {
set $spambot 1;
}
if ($http_referer ~* (get-free-social-traffic.com) ) {
set $spambot 1;
}
if ($http_referer ~* (free-floating-buttons.com) ) {
set $spambot 1;
}
if ($http_referer ~* (darodar.com) ) {
set $spambot 1;
}
if ($http_referer ~* (snip.to) ) {
set $spambot 1;
}
if ($spambot = 1) {
return 403;
break;
}
}
git pushとデプロイを完了させる。
その後sshログイン先でシンボリックリンクを貼る。
$ sudo ln -sf /var/www/my_project_name/current/config/nginx/my_project_name.conf /etc/nginx/conf.d/my_project_name.conf
$ sudo ln -sf /var/www/my_project_name/current/config/nginx/nginx.conf /etc/nginx/nginx.conf
その後 my_project_name.conf
のssl on
からssl_session_timeout 5m;
までを一度コメントアウトし、nginxをリスタート
$ sudo systemctl restart nginx
一度以下--dry-run
コマンドでテストし、問題なければ--dry-run
オプションを外し、実行。
$ sudo certbot certonly --webroot -w /var/www/my_project_name/ -d my_project_domain_name -d www.my_project_domain_name --dry-run
成功したら、コメントアウトを元に戻し、nginxをrestartすれば完了。
puma.sock failed (111: Connection refused系のエラーが出た場合
SSL化対応後にNginxで502 bad gateway
が出てしまった場合に確認する箇所。
$ vim /etc/systemd/system/puma.service
$ sudo systemctl enable /etc/systemd/system/puma.service
# pumaとnginxを再起動
他参考
ubuntuでopenssl最新版ダウンロード方法
ubuntu22.04でnginxインストールする方法
ubuntu22.04でLet's Encryptインストール