丹哥的技術培養皿

A blogging framework for hackers.

Octopress Multi Dev Env Setting Step

| Comments

如何在不同的電腦上面重新安裝已經發布過的 Octopress

[Deploy] 在其他電腦部署己存在的 octopress

1
2
3
4
5
6
7
8
git clone -b source git@github.com:dangjlin/dangjlin.github.com.git dangjlin.github.io
cd dangjlin.github.io
echo "2.5.1" >> .ruby-version
gem install bundler
bundle install          (才能使用 rake new_post['xxx'] 指令)
git clone git@github.com:dangjlin/dangjlin.github.com.git _deploy
rake generate
rake deploy

[Deploy] 同步不同電腦的 octopress

1
2
3
git pull origin source      ( 同步 source 的 branch
cd _deploy
git pull origin master      ( 同步 _deploy 目錄的內容

ps1: master branch 只存在 deploy 目錄內 ps2: deploy 目錄內一定要有一個 CNAME file ,這樣才可以使用自訂的 domain name 所以 rakefile 裡面在做 deploy 的時候,會自動 copy 一個 CNAME file from source branch to _deploy 目錄

如何使用 Mina & Puma & Nginx 部署 Rails - Deploy Rails App With Mina & Puma & Nginx

| Comments

從provision VM 到自動安裝軟體、到使用 mina 自動化部署 Rails App

provision 一台新 ubuntu server

自動裝機 script , 分兩段:

1- 第一段自動裝軟體 , curl -L https://gist.githubusercontent.com/dangjlin/2dd09f80d114e54b54be89ce8b9c6336/raw/d94cfd5eb92905c45899cb41a86c64b9f868efb5/init_install.sh | sh

gist file: (https://gist.github.com/dangjlin/2dd09f80d114e54b54be89ce8b9c6336)[https://gist.github.com/dangjlin/2dd09f80d114e54b54be89ce8b9c6336]

很重要的是: 裝完之後需手動 source ~/.bashrc 重新載入環境變數 才可以再繼續run 第二段

2- 一段自動裝 rbenv & 安裝 ruby 2.3.0 curl -L https://gist.githubusercontent.com/dangjlin/f57d8713352bfc8b0d35c31327658790/raw/efe262d3c030fa32d479b2eb9d852b41edc736d8/rbenv_init.sh | sh

gist file: (https://gist.github.com/dangjlin/f57d8713352bfc8b0d35c31327658790)[https://gist.github.com/dangjlin/f57d8713352bfc8b0d35c31327658790]

如果VPS都永遠在 AWS 或 Digital Ocean or Linode , 建議裝好之後自己 create 一個 image file, 以後就用這個image 去 provision new server

接著我會使用 chef-solo , knife-solo 自動安裝

cookbook 準備了 user , nginx, postgres sql 等自動安裝及自動設定 config template.

補充 knife-solo 的安裝 (摘錄 from Gogojimmy 網頁說明 在我們的本機,我們先安裝好knife,針對我們所使用的是Chef-Solo,因此我們要安裝的是Knife-Solo gem install knife-solo 裝好了knife-solo以後,讓我們使用knife solo init 來開啟一個新專案 knife solo init knife-solo-demo 再來我們進行下一步之前我們先產生一個chef的設定檔 knife configure -r . --defaults

在 knife-solo-demo/node 目錄裡面要 create 一個 xx.xx.xx.xx.json 檔案 這個就是待會 knife-solo 會參照的檔案

往下設定 config 之前請先完成這幾個動作

  1. 把local端的 ~/.ssh/id_rsa.pub 檔案 copy 到server端的 ~/.ssh/authorized_keys 裡面
  2. 把server端的 ~/.ssh/id_rsa.pub 檔案登記到 github 上面,這樣server 端才可以到github拉檔案

啟動 knife-solo ,使其對 server 端開啟自動 chef 的自動化腳本安裝

這邊有兩種情境 一種就是一般的 ssh 登入的方式,例如 digital ocean , linode 之類的 這種就照原本knife-solo的做法就可以 knife solo bootstrap server-user-name@xx.xx.xx.xx

一種就是 AWS 那種要登入到 ec2 instance 的時候,我們的 local 的環境要有一把 xxxx.pem 檔案的私鑰 這一種就要打這個指令才有辦法讓 knife-solo 去免帳號密碼 遠端驅動 server site 執行 chef-solo solo bootstrap xx.xx.xx.xx(server_ip) --ssh-user ubuntu -i ~/.ssh/your-pem-file-name.pem --node-name xx.xxx.xx.xx

接著請手動調整下列三個 config file

nginx config file, put it in the site-enable/default file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
upstream app {
    # Path to Puma SOCK file, as defined previously
    server unix:/home/ubuntu/site/app/app-name/current/shared/sockets/puma.sock fail_timeout=0;
}

server {
    listen 80;
    server_name localhost;

    root /home/ubuntu/site/app/app-name/current/public;

    try_files $uri/index.html $uri @app;

    location @app {
        proxy_pass http://app;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
    }

    error_page 500 502 503 504 /500.html;
    client_max_body_size 4G;
    keepalive_timeout 10;
}

puma config file in config/puma_production.rb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
environment 'production'
threads 2, 64
workers 2   #depends on how many cores of server CPU

application_path = File.expand_path('..', __dir__)
directory application_path

pidfile "#{application_path}/shared/pids/puma.pid"
state_path "#{application_path}/shared/sockets/puma.state"
stdout_redirect "#{application_path}/shared/log/puma.stdout.log", "#{application_path}/shared/log/puma.stderr.log"
bind "unix://#{application_path}/shared/sockets/puma.sock"
activate_control_app "unix://#{application_path}/shared/sockets/pumactl.sock"

daemonize true
preload_app!

Mina Setup 步驟執行之後注意事項

有三件事情要做: 1- 因為有兩個 config 檔案我們是做 symbolic link 到 shared folder “ shared/config ” 目錄裡面 所以記得要server 上手動增加 database.yml , secret.yml 檔案 2- 另外還有環境變數也記得手動到server去增加,以利後續 Rails production server 要讀取&啟動 3- 在 postgresql 手動 create production 的 database.

mina config file in config/deploy.rb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
require 'mina/bundler'
require 'mina/rails'
require 'mina/git'
require 'mina/rbenv'
require 'mina/puma'

# Basic settings:
#   domain       - The hostname to SSH to.
#   deploy_to    - Path to deploy into.
#   repository   - Git repo to clone from. (needed by mina/git)
#   branch       - Branch name to deploy. (needed by mina/git)

set :application_name, 'production_app'
set :domain, '192.168.99.99'
set :user, 'ubuntu' # Username in the server to SSH to.
set :deploy_to, "/home/#{fetch(:user)}/site/app/#{fetch(:application_name)}"
set :repository, 'git@github.com:abcdefg/xyz.git'
set :branch, 'master'
set :rbenv_path, "$HOME/.rbenv"
set :database, 'name_of_production'

# shared dirs and files will be symlinked into the app-folder by the 'deploy:link_shared_paths' step.
set :shared_files, fetch(:shared_files, []).push('config/database.yml', 'config/secrets.yml')
set :shared_dirs, fetch(:shared_dirs, []).push('shared/log', 'tmp/cache', 'shared/pids', 'shared/sockets', 'public', 'vendor')

# This task is the environment that is loaded for all remote run commands, such as
# `mina deploy` or `mina rake`.
task :environment do
    invoke :'rbenv:load'
end

task :setup do

end

desc "Deploys the current version to the server."
task :deploy do
  deploy do
    # Put things that will set up an empty directory into a fully set-up
    # instance of your project.
    invoke :'git:clone'
    invoke :'deploy:link_shared_paths'
    invoke :'bundle:install'
    invoke :'rails:db_migrate'
    invoke :'rails:assets_precompile'
    invoke :'deploy:cleanup'

    on :launch do
        in_path(fetch(:current_path)) do
        command %{mkdir -p tmp/}
        command %{touch tmp/restart.txt}
        invoke :'puma_restart'
        end
    end
  end
  # you can use `run :local` to run tasks on local machine before of after the deploy scripts
  # run(:local){ say 'done' }
end

task puma_restart: :environment do
  puma_pid = "#{fetch(:current_path)}/shared/pids/puma.pid"
  command %[
    if [ -e '#{puma_pid}' ]; then
      bundle exec pumactl -F config/puma_production.rb stop
      bundle exec pumactl -F config/puma_production.rb start
    else
      bundle exec pumactl -F config/puma_production.rb start
    fi
  ]
end

# For help in making your deploy script, see the Mina documentation:
#  - https://github.com/mina-deploy/mina/tree/master/docs

參考網站: (http://gogojimmy.net/2013/06/01/Chef-Solo-Basic-with-Vagrant/)[http://gogojimmy.net/2013/06/01/Chef-Solo-Basic-with-Vagrant/] (https://ruchee.com/notes/2016/deploy_rails_use_ubuntu_nginx_puma_mina.html)[https://ruchee.com/notes/2016/deploy_rails_use_ubuntu_nginx_puma_mina.html]

如何寫出clean Code 的參考資料

| Comments

如何設計好的程式架構跟安排,寫出clean code

這是在臉書上徵詢請教大大的筆記資料

thanks TaiAn suggestions:

Leetcode 主要還是演算法 如果是 OO (Objective Oriented) 的話, 0. Confident Ruby 1. Practical Object oriented design in ruby 2. Implementation pattern 3. The art of readable code

我記得後三本都有中文。如果不是 ruby 的話,第 0 本可以省略。也有人推薦 code complete 2,但是實在很厚,語氣也有點教條。

https://sourcemaking.com/refactoring

thanks Scott Tsai suggestions:

  1. 閱讀某篇 coding style 規範 (e.g. Google 的) 思考辯證其中規則 (e.g. 命名,變數長度與可見範圍)
  2. 閱讀某高品質的 open source 專案的程式,或可從 http://aosabook.org/en/index.html 找個目標。 500 lines or less 的程式也頗適合。

附註:Leetcode 只求解出演算法題目,會鼓勵實作快速、執行也夠快的程式碼,與寫出 “clean code” 的目標應是背道而馳。

thank unknow friend

一本聖經叫clean code

thanks Jason

裝rubocop,養成每次git commit 之前跑檢查,把檢查出的錯誤堅持修掉,然後隨經驗的累積調整 rubocop 的設定

Rails Using AWS SES Send Mail Service

| Comments

Ruby on Rails 如何使用AWS SES 的寄送MAIL服務

網站可以 send mail 了 , 感謝 AWS SES service.

有幾個小坑要注意一下:

  1. 使用 devise gem 時, initializers 目錄裡面的 devise.rb 這一行請不要亂打,AWS會驗證是不是已 verified domain , 否則會拒絕,不讓你寄信. config.mailer_sender = ‘service@aaa.bbb.ccc

  2. username & password 要在 SES 的管理頁面 「SMTP Settings」那邊有一個 create SMTP credentials ,才可以產生 SMTP 的 user & password , 不是自己跑去 IAM 生一組。

  3. 測試的時候,請先在SES 管理頁面,左邊有一個 「Email Addresses」先把要測試的收信的 mail address 打進去並且經過驗證,否則填入未經驗證的收信信箱,測試的時候SES也不讓你寄。

  4. 其餘的話就是在 environment/production.rb 把下面內容設定好

config.action_mailer.delivery_method = :smtp config.action_mailer.default_url_options = { :host => ‘http://aaa.bbb.ccc/’}

config.action_mailer.smtp_settings = { :address => ‘email-smtp.us-west-2.amazonaws.com’, :port => 465, :authentication => :login, :user_name => ENV[‘AWS_SES_USER’], :password => ENV[‘AWS_SES_PASS’], :domain => “aaa.bbb.ccc”, :ssl => true, :tls => true, :enable_starttls_auto => true }

  1. 確定沒問題之後,要離開 sandbox 到正式環境使用時,就在SES的介面填申請表,AWS會審核開通。

Redmine 串 AWS S3 遇到的問題 Hack Workaround

| Comments

整個安裝的步驟,請參考 sdlong 大的文章:

但是一直做到要把 file upload 串到 AWS S3 的時候,我們使用了 gem redmine_s3

其中 bundle install 的時候會有一個 error 說重複命名的問題 然後就開始追 code , 發現是 htmlentities 這個 gem 命名 inodot 變數的時候跟另外一個gem 的命名重複了 雖然人家 htmlentities 在 4.3.4 的時候修正了變數命名重複的問題, BUT 偏偏 redmine_3 的 dependency 又只能綁到 4.3.1 作者有回應說,我沒辦法綁到 4.3.4喔 因為 bulabulabula (省略一百字)

我剛好想到一個方式去 hack 這件事情 預設的 gemfile 會使用 bundler 去讀 rubygems.org 上面的檔案 所以所有的 code & dependency 都會依照 rubygems.org 上面的code所記載的內容運行

我想到我能做的是,我 clone 一份 htmlentities 4.3.1 的 code 回來自己的 github 然後把 lib/htmlentities/mappings/expanded.rb 檔案裡面的重複的 inotod 刪掉~ push 到自己的github.

然後我在 gemfile 裡面去指定 gem ‘htmlentities’ 的路徑是要去找我的 github 這樣被裝到 system library 的 code 就會被改正的了!

` gem “htmlentities”, github: “dangjlin/htmlentities”, branch: “fix-inodot-problem”

Rails 串 Stripe 付款的寫 Code 幾個步驟(摘要)

| Comments

Rails & Stripe

先摘要筆記下來,細節有機會再來補. 好好的付款動作,為什麼要跟註冊頁面綁在一起啊~ 然後這個註冊頁面還要跟 multi-tenancy design 綁在一起。 難度上升十倍. 範例也弄太難了吧~ (昏倒狀態) 筆記一下串 Stripe 第三方付款要做哪些動作.

  1. 設計 view , 定義好 class
  2. 設計 javascript , 該綁定的 , 該防止user誤觸的 ,該跳 error的
  3. 設定 secret key 放到 environment variable 或丟去變數管理
  4. 寫 model method , 付款動作
  5. 寫 controller , 創造 instance variable , call method , redirect .
  6. 檢查 strong parameter , 有 whitelist 的話要加上去

Bitnami Wordpress Apache Subdomain Virtual Host 設定

| Comments

bitnami wordpress apache subdomain & virtual host 設定

因為最近要把一個本來住在別的地方還是以 windows server 為 base 的 wordpress 搬家到 AWS 為了省去還要自己安裝 php , mysql , wordpress , 搞各種設定檔很麻煩的過繁瑣事務 看到 AWS 上面有 bitnami 出的 AMI 檔裡面已經有了基本的 LAMP + Wordpress. 很開心的就用了,結果是個小惡夢

對熟悉的人來說可能還好,但我太久沒有設定 apache 了,明明印象當中 subdomain 就是放到 virtual host 檔案裡面指定好目錄就好啦,但因為這個 AMI 是 Bitnami 綁了 wordpress 包出來的,他把 apache 的設定檔變成了一層包一層

然後又因為我是綁了 wordpress 的關係,現在有幾個設定檔可以設定呢?

/opt/bitnami/apache2/conf/httpd.conf /opt/bitnami/apache2/conf/bitnami/bitnami.conf /opt/bitnami/apache2/conf/bitnami/httpd.conf (這個這次不用改 可以忽視他) /opt/bitnami/apache2/conf/bitnami/bitnami-apps-prefix.conf /opt/bitnami/apache2/conf/bitnami/bitnami-apps-vhosts.conf

你以為這樣就沒了嗎?在 bitnami 所謂的 apps 裡面還有 apache 要讀的設定檔勒 /opt/bitnami/apps/wordpress/conf/httpd-app.conf /opt/bitnami/apps/wordpress/conf/httpd-prefix.conf /opt/bitnami/apps/wordpress/conf/httpd-vhosts.conf

我的情境是這樣 我的主網站放置的地方是 www.example.com /opt/bitnami/apps/wordpress/htdocs/MAINSITE 副站放置的地方是 /opt/bitnami/apps/wordpress/htdocs/OTHER-A /opt/bitnami/apps/wordpress/htdocs/OTHER-B

所以怎麼做?

bitnami apache wordpress virtual host 修改步驟

1.打開 /opt/bitnami/apache2/conf/bitnami/bitnami.conf 把下面這行註解掉

1
# Include "/opt/bitnami/apps/wordpress/conf/httpd-prefix.conf"

2.apache 本來會把主站的根目錄指去這裡 /opt/bitnami/apps/wordpress/htdocs/ 因為我們註解掉了之後, 他所謂的 prefix 模式就沒了,所以他變成去讀這個檔案 /opt/bitnami/apache2/conf/bitnami/bitnami.conf 裡面寫的根目錄路徑 /opt/bitnami/apache2/htdocs 所以我要把他換掉 換成 /opt/bitnami/apps/wordpress/htdocs/MAINSITE

3.然後去打開這個檔案 /opt/bitnami/apache2/conf/bitnami/bitnami-apps-vhosts.conf 加上下面這一行

1
 Include "/opt/bitnami/apps/wordpress/conf/httpd-vhosts.conf"

4.最後,就是我們要編輯 subdomain 副站的目的地了 打開 /opt/bitnami/apps/wordpress/conf/httpd-vhosts.conf 把 subdomain 放進去。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<VirtualHost *:80>
  ServerName Other-A.example.com
  DocumentRoot "/opt/bitnami/apps/wordpress/htdocs/OTHER-A"
  <Directory "/opt/bitnami/apps/wordpress/htdocs/OTHER-A">
    Options FollowSymLinks MultiViews
    LanguagePriority en
    ForceLanguagePriority Prefer Fallback

    AllowOverride All
    <IfVersion < 2.3 >
      Order allow,deny
      Allow from all
    </IfVersion>
    <IfVersion >= 2.3 >
      Require all granted
    </IfVersion>
  </Directory>
</VirtualHost>

Other B 一樣啦,就不寫了。 另外 DNS 那邊也要把 subdomain 的 cname給設定好喔!

以下是官網上的wiki document

How To Create A Virtual Host? Using a Virtual Host allows you to access an application at (for example) http://SERVER-IP/ or http://APPNAME.SERVER-IP instead of http://SERVER-IP/APPNAME.

This example shows how to configure WordPress to be accessible from http://wordpress.example.com. Follow these steps:

Comment out the line that includes the prefix configuration file in the /opt/bitnami/apache2/conf/bitnami/bitnami-apps-prefix.conf file:

# Include “/opt/bitnami/apps/wordpress/conf/httpd-prefix.conf” Include the virtual host configuration file for WordPress in the /opt/bitnami/apache2/conf/bitnami/bitnami-apps-vhosts.conf file:

Include “/opt/bitnami/apps/wordpress/conf/httpd-vhosts.conf” Update the URL in the application if necessary.

Restart the Apache server:

sudo /opt/bitnami/ctlscript.sh restart apache

AWS SES ( Simple Email Service) 服務使用

| Comments

很快地做一個筆記

  1. AWS SES 服務目前只有三個 Region (美東 Virginia , 美西 Orggan , 愛爾蘭) 可以用,但是不用擔心,我們開在不同Region的ec2是可調用的 (像我的主機放在東京,上面跑 wordpress ,去呼叫美東的 smtp server 是OK的。

  2. 要使用 AWS SES 服務有幾個動作要做

  3. 你要發出去的 sender 要經過驗證,其實這個很簡單,就是去登記 sender mail address 然後去這個mail 收信點驗證LINK
  4. 如果是要認證整個 domain 也可以,就是 dns 那邊要做驗證。
  5. 很重要!你要記得去 support center 開一張票,申請 ses mail service increase limitation. 這個很簡單就是幾個問題勾一勾(主要就是問你有沒有讀過使用規定,會不會遵守不寄發垃圾信的規定,會不會處理退信) 以及文字說明為什麼要增加 limitation , 我很簡單寫了需要啟用的原因是 電子商務網站註冊及寄發系統通知使用(當然是要用英文寫) , 其實這封mail 不只是增加 limitation 更是把服務從 sandbox 移到 production 啟用的重要步驟。
  6. 在 SES裡面 create 一組 IAM User,這個時候會產生一組 user name & password 很重要,請記錄下來。 這是後面要拿去 wordpress 做 smtp authentication 用的! 我一開始傻傻的拿 key id 跟 secret key 去當作帳號密碼一直認證不過~後來才知道是要在 SES 產生一組 user name & password , key and secret key 應該是 for REST API 調用的時候要寫到 code裡面的。

  7. 還有一個小坑, 我在 wordpress 那邊設定 sender email 舉例: “ Daniel@gmail.com ” , 但是我在 SES裡面認證過的是 ” daniel@gmail.com “ , 只是因為第一個字母的大小寫不一樣,這樣也會寄信失敗,要注意要一模一樣喔!

其實還有很多別的選擇啦,例如使用 mailchimp , mailgun 等等的 SaaS service. 未來有機會再來比較。

如何在windows 裡面自動定時螢幕截圖存檔 (Command Line)

| Comments

目前每天都讓 aws 上面 windows server 自動十二點半開機,然後一點啟動模型下單程式,收盤前會下單,機器兩點關機。 為了要做一個紀錄,我希望可以在每天收盤之後,讓電腦拍一下螢幕快照做歷史紀錄,否則每天自動關機,都沒有留下紀錄,到時候要回來追蹤的時候都毫無辦法。

很幸運的,老早就有人把windows裡面要做的動作,做成command line tool ,我們要使用 nircmd 這個小軟體 然後指令如下,下面這個是官方舉的例子,意思是 Save 10 screenshots in a loop, and wait 60 seconds between the screenshot save calls. The filenames of the screenshot will contain the time and date of the saved screenshot.

1
nircmd.exe loop 10 60000 savescreenshot c:\temp\scr~$currdate.MM_dd_yyyy$-~$currtime.HH_mm_ss$.png

但因為我只需要在收盤之後把畫面拍下來,然後放到 dropbox 的目錄裡面,這樣一同步之後,我在家裡就可以看到當天的數據紀錄了。我們來改一點點參數,變成這樣:

1
nircmd.exe savescreenshot c:\dropbox\Hmodel_~$currdate.yyyy_MM_dd$-~$currtime.HH_mm_ss$.png