2020-11-27

Mailgun 資源

mailgun 資源

以 mailgun 使用程式發信時,首先要有自己的 domain,個人是使用 godaddy 的網域。 Mailgun 官網是以 Cloudflare 為範例說明,來說明如何設定網域的驗證:Domain-Verification-Walkthrough。 設定的 domain 以 mg.mydomain.com 為例。

申請 Sending API Keys

到 Mailgun 官網登入後,在左側欄點選「Sending」>「Domain」,選擇你要使用的 domain 後,選「Domain Settings」,再點選「Sending API Keys」建立所需的發信 key。

使用 Node.js 發信

官方有出 Node.js package mailgun-js,先在專案中安裝。 參考這篇官方的文件 How To Send Transactional Email In A NodeJS App Using The Mailgun API。 我的 .env 設定大概是長這樣:

MAILGUN_API_KEY=my_secret_key MAILGUN_FROM_WHO=service@mg.mydomain.com MAILGUN_DOMAIN=mg.mydomain.com

測試發給自己信箱時,有可能會進到垃圾郵件,如果沒看到郵件,先到垃圾郵件找找找不到的話,再進行除錯。

官方會提供一個 postmaster@mg.mydomain.com 的帳號,可以在 Domain settings > SMTP credentials 那邊看到。 重設密碼後,應該可以使用 nodemailer 發信。有些人以 nodemailer 搭配 nodemailer-mailgun-transport 使用。

2020-11-21

在 ubuntu 使用 screen 背景執行

在 ubuntu 使用 screen 背景執行

通常終端機指令在其後下 & 就可以背景執行,不過很不方便。screen 用起來就方便多了。 尤其是使用 ssh 遠端登入,就算網路斷線或者筆電進入睡眠狀態,也不用擔心程式跑一半就斷了;同時又可以接回去原本的訊息畫面。

# 查看有沒有安裝 screen $ screen --version # 若沒有安裝,以 apt 安裝 $ sudo apt install screen # 查看背景執行的程式 $ screen -ls # 開始,直接下 screen 指令,然後按 Enter 進入即可 $ screen # 進入後像是進入另一個 shell 一樣,執行你要執行的指令後,可以關掉 terminal # 退出 screen $ exit

以下是查看的例子:

$ screen -ls There are screens on: 220648.pts-4.backup-sfo2-20201024 (11/20/20 11:05:38) (Detached) 210531.pts-0.backup-sfo2-20201024 (11/18/20 23:00:07) (Attached)

使用參數 -r 可以連接目前分離狀態 (Detached) 的 terminal

# id 打前面幾個字元按 tab 即可 $ screen -r 220648.pts-4.backup-sfo2-20201024

使用參數 -x 可以搶用目前不是在分離狀態 (Attached) 的 terminal

# id 打前面幾個字元按 tab 即可 $ screen -x 210531.pts-0.backup-sfo2-20201024

2020-11-20

在 ubuntu 建立磁碟交換區 swap

在 ubuntu 建立磁碟交換區 swap (暫存區)

本篇筆記參考How To Add Swap Space on Ubuntu 16.04。

文中警告,swap 可能會降低 SSD 硬碟的壽命!

# 查看是否有磁碟交換區 $ sudo swapon --show # 查看記憶體使用情況(亦會顯示交換區) $ free # 建立 swap 之前,先了解磁碟的使用狀況 $ df -h # 建立一個用來當做 swap 的檔案 swapfile(名稱可自己決定), # 大小為 4g,通常為實體記憶體的一半到相同大小,視情況而定 $ sudo fallocate -l 4G /swapfile # 變更為只有 root 能用 $ sudo chmod 600 /swapfile # 設定檔案為交換區 $ sudo mkswap /swapfile # 啟用檔案為交換區 $ sudo swapon /swapfile # 若要在下次重開機時,重新掛載 swap,需編輯 /etc/fstab # 先備份檔案,以免發生悲劇 $ sudo cp /etc/fstab /etc/fstab.bak # 將設定內容加入檔案,就全部完成 $ echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

2020-11-08

使用 docker-node 測試 nodejs 專案

使用 docker-node 測試 nodejs 專案

首先你的環境必須已經安裝 docker,參考「取得 docker」。

# 取得 nodejs,在此使用較舊版本 10 docker pull node:10

在專案中建立 docker-compose.yml 檔:

version: "2" services: node: image: "node:10" working_dir: /Users/shinder/Dropbox/my-nodejs-proj environment: - NODE_ENV=development volumes: - ./:/Users/shinder/Dropbox/my-nodejs-proj ports: - 3000:3000 command: "node ./src/index.js"

其中,比較要注意的是 ports,第一個 3000 是 host 使用的 port,第二個 3000 是 container 使用的 port。 執行使用 up,關閉使用 down:

# 啟動 docker-compose up # 在背景中啟動 docker-compose up -d # 關閉 docker-compose down # 查看正在執行的 containers docker ps

*** 在啟動專案的時候出錯了「invalid ELF header」,無法載入 bcrypt 模組。 問題出在,bcrypt 是平台相依性的,我的 host 是 MacOS,container 則是 Debian。

目前想到的解法是,重新建立 image 檔,將專案內的檔案(排除 node_modules)複製到 container,然後再重新 npm install 所有套件。要設定三個檔案:.dockerignore,Dockerfile,docker-compose.yml。

# .dockerignore node_modules
# Dockerfile FROM node:10 RUN npm install -g nodemon RUN mkdir -p /usr/src/app WORKDIR /usr/src/app COPY package.json /usr/src/app RUN npm install EXPOSE 3000
# docker-compose.yml version: "3" services: node: build: . working_dir: /usr/src/app environment: - NODE_ENV=development volumes: - ./:/usr/src/app - /usr/src/app/node_modules # 上式可以用 container 的路徑覆蓋原來 host 的 node_modules 目錄 ports: - 3000:3000 command: "npm run dev"

執行 docker-compose up 即可建立,若調整設定檔後要重建可使用 docker-compose build。 其它常用的指令:

# 連入 container 的 bash docker exec -it <container-id> /bin/bash # 列出所有 image 檔 docker image ls # 移除某個 image 檔 docker rmi <image-id>

2020-11-07

使用 mongoose 連線遠端 mongodb (ubuntu)

使用 mongoose 連線遠端 mongodb (ubuntu)

通常連線遠端的 Mongodb server,使用 connection string uri:

mongodb://[username:password@]host1[:port1][,...hostN[:portN]][/[defaultauthdb][?options]]

Admin 帳號設定方式同 這篇。但是在使用 mongoose 連線時,一般的 connection uri 設定一直無法正常連線。

爬了文才發現要在 mongoose 連線時,使用 auth, user, pass 三個另外的設定,uri 內就不用放帳號和密碼了。例如我的連線檔案 mongoose-connect.js:

const mongoose = require('mongoose'); mongoose.connect(process.env.MONGO_DSN, { useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true, useFindAndModify: false, "auth": { "authSource": "admin" }, "user": process.env.MONGO_USER, "pass": process.env.MONGO_PASS, }); const db = mongoose.connection; db.on('error', (error)=>{ console.log('Mongoose connection error:', error); console.log(`mongoose.connection.readyState: ${mongoose.connection.readyState}`); }); db.on('open', ()=>{ console.log('Mongoose connected ~'); }); module.exports = mongoose;

2020-11-03

ubuntu 備份 mysql

ubuntu 備份 mysql

一般使用 mysqldump 來備份 mysql 資料

# 只備份 schema mysqldump --no-data -u db_user -p'db_password' db_name > mybackup.sql

如果不想把 db_password 放在裡面,可以建立 ~/.my.cnf 輸入如下,並將檔案屬性設定為 600:

[mysqldump] user=db_user password=db_password

把要備份的檔案加上日期,將工作寫成 backup.sh:

#!/bin/bash today=`date +"%Y-%m-%d"` mysqldump --no-data db_name > "mybackup-${today}.sql"

搭配 crontab 使用,即可自動排程備份。以下是備份後複製到遠端主機,然後移除檔案:

#!/bin/bash today=`date +"%Y-%m-%d"` sqlFile="/root/db_bk/mydatabase-${today}-all.sql" mysqldump mydatabase > "${sqlFile}" scp -C "${sqlFile}" root@xxx.xxx.xxx.xxx:/mnt/volume_somewhere/db_bk/ rm "${sqlFile}" echo "ok"

2020-11-01

nginx + nodejs 使用 certbot

nginx + nodejs 使用 certbot

以下的設定參考 教學-申請Let’s Encrypt憑證與啟用https。

承上篇,在 nginx 設定中加入一個 server /etc/nginx/sites-enabled/www.shinder.cc,並設定為:

server { listen 80; server_name www.shinder.cc shinder.cc; location / { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Host $host; } }

啟動 node/express server,使用 port 3000。 然後測試 http://www.shinder.cc 是否可以看到 node/express 的執行內容。 安裝 certbot:

# 先加入 certbot 的 repo 資料 sudo add-apt-repository ppa:certbot/certbot # 更新 repo 並安裝 sudo apt update sudo apt install certbot

申請憑證:

sudo certbot certonly --webroot --webroot-path=/home/ubuntu/<express專案>/public/ -d www.shinder.cc -d shinder.cc

接著會有幾個詢問, email,是否同意授權,email是否要接收訊息等等。最後就是 key 所放的位置:

/etc/letsencrypt/live/www.shinder.cc/fullchain.pem /etc/letsencrypt/live/www.shinder.cc/privkey.pem

為了增加安全性產生一個2048-bit Diffie-Hellman的密碼組合:產生的 /etc/ssl/certs/dhparam.pem 之後會用到:

sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

更改 nginx 設定

建立設定檔 /etc/nginx/snippets/ssl-www.shinder.cc.conf:

ssl_certificate /etc/letsencrypt/live/www.shinder.cc/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/www.shinder.cc/privkey.pem;

建立另一個設定檔 /etc/nginx/snippets/ssl-params.conf:

ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH"; ssl_ecdh_curve secp384r1; ssl_session_cache shared:SSL:10m; ssl_session_tickets off; ssl_stapling on; ssl_stapling_verify on; resolver 8.8.8.8 8.8.4.4 valid=300s; resolver_timeout 5s; add_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff; ssl_dhparam /etc/ssl/certs/dhparam.pem;

最後修改 nginx 設定檔 /etc/nginx/sites-enabled/www.shinder.cc:

server { listen 443 ssl http2; listen [::]:443 ssl http2; include snippets/ssl-www.shinder.cc.conf; include snippets/ssl-params.conf; server_name www.shinder.cc shinder.cc; client_max_body_size 1G; location / { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Host $host; } } server { listen 80; server_name www.shinder.cc shinder.cc; return 301 https://$server_name$request_uri; }

nginx 重新載入設定就可以測試 https 了。

自動更新憑證

使用 crontab 排程:

# 進入編輯 sudo crontab –e

加入下行,每日早上七點更新:

10 7 * * * /usr/bin/certbot renew --quiet --renew-hook "/bin/systemctl reload nginx"

如果 web document root 變更了,可以在 /etc/letsencrypt/renewal/www.shinder.cc.conf 檔案內修改 webroot_map 。

在 AWS EC2 安裝 nginx

在 AWS EC2 安裝 nginx

安裝 nginx 和 php

前置的步驟:

  • 先登入 AWS console。
  • 選擇 EC2 console。
  • 啟用實體(instance)。
  • 選擇作業系統影像檔,我習慣用 ubuntu。
  • 選虛擬機器規格,一般用途選 t2 系列。
  • 啟動之前會詢問要使用已存在的 key pair 或者建立新的。若選建立新的,要保管好 key,不然無法登入實體。
  • 啟動後可以在 console 看到實體。

注意:記得到 instance console 的 security 分頁,設定 inbound rules,讓一般人都可以透過 http 和 https 拜訪。

登入主機:我自己是使用 Mac zsh,當然也可以使用 linux bash,若使用 Windows 建議用 git bash 來登入。

# 先將 key 檔權限設定為 400 chmod 400 my_ec2_key.pem # 使用 ssh 登入,ubuntu 為預設用戶 ssh -i /my_path/my_ec2_key.pem ubuntu@xxx.xxx.xxx.xxx

將本機的 ~/.ssh/id_rsa.pub 加到遠端 ~/.ssh/authorized_keys 內,之後就可以不需要 pem 檔登入。

# 登入後先更新系統 sudo apt update sudo apt upgrade
# 安裝 nginx sudo apt install nginx # 查看 nginx 狀態,應該會是啟動的狀態 service nginx status
# 利用 curl 測試是否可以正常訪問 curl -I http://xxx.xxx.xxx.xxx
# 安裝 PHP 相關套件 sudo apt install php php-cli php-fpm php-json php-pdo php-mysql php-zip php-gd php-mbstring php-curl php-xml php-pear php-bcmath # 安裝套件後會自動啟動 apache2,但由於未安裝 apache2 所以會看到啟動失敗的錯誤訊息 # 查看 php-fpm 的狀態,應該要為啟動的狀態 service php7.4-fpm status
# 查看 nginx 預設網站設定,原則上不需要變更 sudo nano /etc/nginx/sites-available/default

在 /var/www/ 建立「 網域同名資料夾」,例如 php.shinder.cc,用來服務 php.shinder.cc domain 的站台。 在 /etc/nginx/sites-available/ 新增一個設定檔(通常和你的網域同名),例如: php.shinder.cc。並設定內容如下:

server { listen 80; server_name php.shinder.cc; root /var/www/php.shinder.cc; index index.php index.html; location / { try_files $uri $uri/ =404; } location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; } location ~ /\.ht { deny all; } }
# 在 sites-enabled 內建立 link sudo ln -s /etc/nginx/sites-available/php.shinder.cc /etc/nginx/sites-enabled/
# 測試一下 nginx 的設定檔,看有沒有寫錯 sudo nginx -t
# 重啟 nginx sudo service nginx restart

在 /var/www/php.shinder.cc 放一個 phpinfo 的測試程式,就可以測試 php 了。

安裝 nodejs

# 目前從官方套件安裝,版本為 10.19 有點舊,不過應該可以應付大部份的需求 sudo apt install nodejs npm

2020-10-31

在 Digitalocean Spaces 使用 s3cmd

在 Digitalocean Spaces 使用 s3cmd

上一篇 基本上是廢文。 s3fs 好用,但只適合用在檔案數不多的情況下操作,而且不適合搭配 rsync 一起使用。

檔案數多時(我的狀況是有數百萬個檔案要上傳,或同步),就應該使用 s3cmd。

s3cmd 安裝方式可以參考 Digitalocean 官方的說明 Setting Up s3cmd 2.x with DigitalOcean Spaces。

s3cmd 基本用法也可以參考 Examples of s3cmd 2.x Usage with DigitalOcean Spaces。當然也可以用 s3cmd --help 查詢。

以下列出自己常用的部份:

# 上傳 my_path2 整個資料夾到 s3://my_bucket/my_path2,同時設定為 public s3cmd put --acl-public --recursive /my_path1/my_path2 s3://my_bucket/
# 同步 my_path2 資料夾到 s3://my_bucket/my_path2,同時設定為 public s3cmd sync --acl-public /my_path1/my_path2 s3://my_bucket/
# 設定 s3://my_bucket/my_path2 內所有檔案為 public s3cmd setacl --acl-public --recursive s3://my_bucket/my_path2/

2020-10-25

在 Digitalocean Spaces 和 Wasabi 上使用 s3fs 和 rsync

在 Digitalocean Spaces 和 Wasabi 上使用 s3fs 和 rsync

AWS S3 是個方便的雲端工具,唯一的缺點就是價格高了一些(消費者的缺點?) 剛好有客戶是用 digitalocean 的空間,就來試試 Spaces 吧(開始踩雷之旅)。

之前試用 S3,發現 s3fs 真是個好東西,掛上去之後就像使用一般磁碟一樣方便。

在 ubuntu 20.4 上安裝好 s3fs 後,Spaces 的設定一直搞不定,參考了這篇How to mount DigitalOcean Spaces on droplets with s3fs。

其中一點是 /etc/fuse.conf 裡的 user_allow_other 要開啟。 另外要開 debug mode 的設定,不然永遠都沒訊息,不管有沒有設定成功。

-o dbglevel=info -f -o curldbg

Digitalocean Spaces 以設定在 sfo2 為例子:

s3fs mySpacesName ${HOME}/s3/myMntFolder -o passwd_file=${HOME}/.passwd-do-spaces -o url=https://sfo2.digitaloceanspaces.com/ -o allow_other -o use_path_request_style -o dbglevel=info -f -o curldbg

上式中,mySpacesName 為 Spaces 名稱;${HOME}/s3/myMntFolder 為掛載的資料夾路徑;.passwd-do-spaces 為金鑰的設定檔。測試後,除錯的參數就可以拿掉了。

Wasabi Storage 的設定:

s3fs myBucketName ${HOME}/s3/myMntFolder -o passwd_file=${HOME}/.passwd-wasabi -o url=https://s3.us-west-1.wasabisys.com

Wasabi 要注意的是,url 的設定。官方說使用 https://s3.wasabisys.com 就可以了,但實際上會出錯(不知道是不是 s3fs 版本的問題)。應該直接使用 endpoint(雲端可用區域)的 url。

原以為掛上去之後就會帆風順,結果原本好用的 rsync 卻一直出狀況。同步上傳沒多少檔案就出錯罷工,之後常常看到隱藏檔的出現,但來源卻沒有這些檔案。

找了好一陣子才發現這篇 S3FS rsync recommendations,主要是針對 rsync 的特性和 S3 的特性做參數的校調。

例如:

rsync -avW --progress --inplace --size-only /mnt/volumes/my_copy_folder /target_folder

目前看來,似乎可以好好用 rsync。 還是有個問題:Digitalocean Spaces 和 Wasabi Storage 上傳的速度好慢...



備註:之後改用 s3cmd 上傳,速度快很多。

FB 留言