Sử dụng chung MongoDB database cho cả development và production
Tất nhiên đây chỉ là một trick không hề được khuyến khích áp dụng vào bất cứ một dự án Company nào (vốn đòi hỏi yêu cầu bảo mật và an toàn dữ liệu cực kì lớn). App của mình cũng nhỏ thôi, và mình thì... lười. Giả sử như có một bảng user, tất nhiên, user phải vượt qua màn đăng nhập mới được phép truy cập vào app. Và một quãng thời gian đen đủi xảy ra, bạn phải vác chính cái app của mình đi deploy hết từ máy này cho đến máy nọ, vì mất lap, vì chó ỉa lên bàn phím hay sao sao đó chẳng hạn thì việc phải tạo ra một cái DB nữa cho development server nó khiến bạn muốn chán sống đúng không?
Mấy cái chuyện như thế này vốn có nhiều cách giải quyết mà. Dump sẵn một database demo phía client cũng được. Tái sử dụng mongoDB database phía server như mình cũng là một lựa chọn. Chả cái nào hơn cái nào, về phía mình, chỉ là... mình không có nhiều thời gian đi nghiên cứu những cái gì khiến chuyện mình phải focus vào cái app trở nên khó kiểm soát thôi. Mình chỉ là một frontend developer kiêm fullstack developer cho một startup cỡ nhỏ, và bản thân mình nghèo kiết xác k có tiền túi để thuê đứa khác làm giùm mấy cái backend này.
Public port 27017
Cảnh báo cực mạnh: trong mọi trường hợp, đây là cách làm nguy hiểm, trừ khi bạn đã thiết lập chặt chẽ việc bảo mật quá trình kết nối đến MongoDB bằng auth và SSL/TLS hoặc mấy thứ tương tự.
Nói đến chuyện SSL/TLS, chừng nào mình nghiên cứu xong vụ này mình sẽ có một bài viết, đây là trò mình khá thích. Thiết lập Nginx như là một stream reverse-proxy cho MongoDB phía sau hoặc public cổng 27017 rồi cài đặt để bắt buộc sử dụng SSL/TLS khi kết nối chẳng hạn.
Trò này thì đơn giản thôi không khó. Mở file
mongod.conf
lên (thường thì nằm ở /etc/mongod.conf
vì server mình chạy CentOS), comment out dòng bind_ip
đi hoặc khai báo rõ nó như dưới đây# Listen to local interface only. Comment out to listen on all interfaces.
# bind_ip=127.0.0.1
bind_ip=0.0.0.0
Rồi khởi động lại Mongo là xong. Dưới development, sửa lại localhost thành IP của server, ví dụ
mongodb://user:password@aaa.bbb.ccc.ddd/database
SSH Tunnel
Về mặt hình thức thì trò này cũng tương tự như việc bạn sử dụng Robo3T hay mấy phần mềm MongoAdmin tương tự, cho phép kết nối đến mongo server thông qua SSH Tunnel. Kết nối từ máy local sẽ không đi thẳng đến mongo server mà thông qua SSH trước, bằng cách này, tất nhiên sẽ không cần phải public port 27017 nữa, vẫn đảm bảo tính an toàn cho dữ liệu bên trong MongoDB. Để giữ an toàn cho việc đọc/ghi dữ liệu, đừng quên thiết lập bảo mật cho SSH (ví dụ bắt buộc đăng nhập có mật khẩu hay sử dụng private key nhằm mã hoá kết nối SSH cũng như tránh việc bị thằng mấy dạy nào đó chôm được quyền đăng nhập vào server, nhất là tài khoản root, nói tới đây tự hiểu hậu quả nhe).
Bản thân NodeJS có một vài package cho phép hỗ trợ tunnel SSH kiểu này, mình thì ưa thích dùng package
tunnel-ssh
. Cách sử dụng tunnel-ssh
để kết nối đến mongoDB phía server được demo chi tiết trong đoạn code dưới đây// dev-tunnel.js
import tunnel from 'tunnel-ssh'
import fs from 'fs'
const devSSHTunnel = cb => {
const sshConfig = {
host: 'aaa.bbb.ccc.ddd',
username: 'root',
agent: process.env.SSH_AUTH_SOCK,
privateKey: fs.readFileSync(process.env.DEV_SSH_PRIVATE_KEY, 'utf-8'),
port: 22, // An toàn hơn nữa là đổi luôn cổng mặc định của SSH
dstPort: 27017
}
tunnel(sshConfig, (err, server) => {
if (err) {
console.error(err.message)
return
}
console.log('SSH connection successfully')
cb()
})
}
export default devSSHTunnel
// mongoose-connect.js
import mongoose from 'mongoose'
import devSSHTunnel from './dev-tunnel'
mongoose.Promise = global.Promise
const conf = {
useNewUrlParser: true,
// useMongoClient: true,
poolSize: 2,
promiseLibrary: global.Promise
}
function connectDevelopment() {
return new Promise(resolve => {
devSSHTunnel(() => {
const connectPromise = mongoose.connect(
'mongodb://user:pass@localhost/database',
conf
)
var db = mongoose.connection
db.on('error', console.error.bind(console, 'DB connection error:'))
db.once('open', function() {
console.log('DB connection successful')
})
resolve(connectPromise)
})
})
}
Mình chả biết viết linh tinh mấy cái này có giúp mình bớt gãy sau 14 tiếng liền ngủ vì cơ thể kiệt sức không chịu nổi. Nhưng thôi kệ, nevermind, anh em có cái để đọc để biết là được. Haha.