Secure SSH private key with passphrase

A good passphrase keeps SSH private key secured, even when the key is stolen. But maybe we don’t often use passphrase because we don’t want to enter it whenever logging into a server. Actually there’s a way to balance security and convenience in this situation, by using ssh-agent. ssh-agent is a program that runs on your computer. It stores unencrypted private key in memory. The idea is that we just need to enter the passphrase every time we load the key into ssh-agent, then everything else just works like normal.

We need to add passphrase to our key first:

Now the private key is protected with a passphrase. Next we load the key to memory:

To verify if the key is added to ssh-agent:

Now we should be able to log in to our servers as usual.

Rails development with Docker

I’ve been busy working on a personal side project recently. It’s an web application written in Ruby on Rails. I played around with Docker for times in the past, and now I want to apply Docker to my development workflow. Below are some useful things that I learned.


Docker engine does not run directly on OSX, so we need to run it on a virtual machine.
The last time I used Docker, I could get Docker up and running with some brew commands (brew install boot2docker, brew install docker…). Since then, some new things got introduced: Docker Machine, Docker Compose… I decided to install Docker as the official documentation recommends: using Docker Toolbox.
Docker Machine is used to create Docker hosts, on which the containers are run, on our machine or on cloud providers. After installing Docker Toolbox, it might already create a default Docker engine name default using VirtualBox. You can check this using this command:

We should now start this host:

Then we need to set environment variables so that Docker client can work with started Docker host:

Dockerize our Rails app

To Dockerize the Rails app, first we need a Dockerfile file, which specifies the necessary steps to put our app to a Docker image.

The above file is pretty simple: it inherits an image (which includes Ruby 2.2.0), then installs some packages required by our Rails app, creates a working directory /app and adds the source code to this folder. It finally installs gems specified in Gemfile.

At this point we can build our image:

(Remember to change my_app to your app’s name)

Docker Compose

The Rails app needs a PostgreSQL database for all the persistence stuffs. The Docker way to do this is to use a container which serves PostgreSQL service and links our web container to this. Docker has already supported this kind of link (Link Containers), something that we can make use of like this:

But if we introduce more services (such as Redis, Elastic Search, Sidekiq…) to our stack, this will be not a preferable way. We will have to build (or pull) and start each container manually. It’s time for a simple and automatic way to start our entire application (and define our application stack as well). That’s the reason for Docker Compose. That exactly what Docker Compose does. To get started with Docker Compose, we need a docker-compose.yml file in our application root directory:

The above file defines two containers: one for our web app, one for PostgreSQL service, which is an official image downloaded from Docker Hub. Every time we start our application with docker-compose up, Docker will check if the web container needs to be built and start it, along with database container db.

* Note: You may need to update the file config/database.yml so that Rails could “see” PostgreSQL on the database container:


So now our app has been started. It is reachable via the URL With is the IP of our Docker host (you can obtain this IP with this command: docker-machine ip default), and 3000 is the port we specified in docker-compose.yml that maps port 3000 on Docker host to port 3000 on web container.
Normally using docker-compose up is enough to start the app. But I find this difficult when I want to debug errors with byebug, or pry-rails, ’cause the console doesn’t show up. So I use this instead:

This brings up the linked containers (db so far) and starts the web server. The parameter -e TRUSTED_IP= is to pass a environment variable to Rails, so that I can use better_errors gem, to debug errors right on the error pages.

To run other Rails and Rake commands, we use docker-compose run. For examples:

Everytime I update Gemfile with a new gem, or remove old ones, I need to rebuild the web image with docker-compose build, and run docker-compose run web bundle install.

I also use ActionMailer to send emails, so it comes the need to see how the emails sent out look like. mailcatcher ( fits this perfectly, and fortunately, the community has already built a Docker image of it: I add another container to docker-compose.yml, update config/environments/development.rb to use the mail server at host mailcatcher and port 1025. Now docker-compose.yml looks like below:

From now on I can check the emails sent out by looking at Thanks to Docker, I don’t have to spend time set mailcatcher up manually.

Time for Tests

To apply continuous testing, I use Guard with Minitest. I add another container named test, which is almost the same as web:

I run docker-compose build to build the images, and start test container on a separate tmux pane:

This works as expected. Tests are run, with dots, errors and failures. However, it also adds a new problem…


Update: As of 20/01/2016, I finally could get rid of this problem completely on OSX. The solution is I’m not stick with VirtualBox anymore. Instead, I use xhyve to create the virtual machine that runs Docker. xhyve is even more lightweight and faster compare to VirtualBox. Details of installation xhyve for Docker can be found here:

The problem is that it takes so long for the tests to run, and the CPU fan of my Macbook works like the machine is under heavy load. I have a look at Activity Monitor and find out that VboxHeadless is consuming more than 160% of CPU:

VboxHeadless consumes more than 160% CPU

VboxHeadless consumes more than 160% CPU

Further research takes me to the conclusion that this relates to a wontfix bug of vboxsf (a filesystem implemented in VirtualBox). The bug causes the syncing of files from host machine (OSX) to guest machine (Docker host) very slow and consume a lot of resource. There’s no perfect way to get rid of this bug (as long as I’m stick with OSX and VirtualBox).
In my case, I decided to use docker-osx-dev, a tool by Yevgeniy Brikman who also tried a lot of solutions for this problem. The main idea of the tool is to use rsync, along with fswatch to sync files from local machine (host) to Docker host (guest).

This is much faster compare to vboxfs, but it also comes with a trade-off: it can only sync from host to guest, which means that files generated from containers are not synced back to OSX. We will not see those files on our text editors.

Docker-osx-dev says it will install Docker, Boot2Docker, Docker Compose, VirtualBox, fswatch, and the script docker-osx-dev itself. I don’t need to install all those except fswatch and the script, so I just install what I need:

Then I start a new tmux pane in my project directory with docker-osx-dev command, it automatically picks up the directories in docker-compose.yml file, asks me to disable shared folder on Docker host vm, I choose yes, and it starts to sync files.
When the files are synced, I start the test container again. This time it doesn’t surprise me! :-P


Docker helps save time to setup working environments and workflow. This means a lot in the context of a team working on a project. However it would be better to run Docker on a native Linux machine.

Nói với Thanh về sứ mệnh

Duy Thanh thân mến,

Có lần anh nói với em là anh biết “mission” của em đến với cuộc đời này là gì. Thực ra anh không biết. Anh chỉ tin thôi. (Anh cũng nói vậy với em hén : ). Anh tin là với những người thường băn khoăn tự hỏi mình từ đâu đến, tại sao mình có mặt trên cõi đời này, mình đến đây để làm gì (có thể khi đang ngồi một mình vào một buổi tối trời đầy sao, ngẫm về sự vô cùng của vũ trụ và sự nhỏ bé của con người, biết đâu được) đều có chung một câu trả lời.

Anh coi “How I met your mother”, có tập bạn Ted nói “Love is the best thing that we (human) do”. Nói với bạn Robin thì phải. Anh nghĩ là đúng. Không phải TV, điện thoại, laptop, thuốc men, vũ khí, chiến tranh, bánh mì, nước ngọt… là thứ mà con người làm tốt nhất, giỏi nhất, so với các loài khác hoặc là loài người với nhau, mà đó là Tình yêu. Em có thể hiểu là mọi thể loại tình yêu (kể cả đồng giới – đúng rồi :-p). Thử nghĩ mà xem có loài nào trên trái đất được ban nhiều ân huệ như con người: ngoài trí tuệ để suy xét còn có trái tim biết rung cảm, biết yêu thương. Nhờ có Tình yêu thương, con người có thể làm được nhiều điều lớn lao, vĩ đại. Nhờ có Tình yêu con người có thể hy sinh rất nhiều thứ kể cả chính bản thân cho đồng loại, cho người họ yêu thương… (Tuy cũng có những tình yêu mù quáng khiến người ta nhỏ nhen, đố kỵ, hoặc thậm chí hận thù hơn… nhưng đó không phải là thể loại anh đang muốn nói đến. Với lại, dù sao thì anh cũng tin là Tình yêu cuối cùng cũng chiến thắng Thù hận). Tình yêu làm trái tim và tâm hồn con người rộng mở. Tình yêu giúp con người và những người xung quanh họ cảm thấy đầy đủ hơn, an toàn hơn, lớn lao hơn, trách nhiệm hơn và sống tốt hơn. Hãy tưởng tượng một thế giới mọi người sống với nhau chỉ có Tình yêu, không còn nghi kỵ, thù hận, không còn chiến tranh, bi kịch,… thế giới đõ sẽ tốt đẹp biết chừng nào.

Vậy đó, “mission” của em là làm cuộc sống này tốt đẹp hơn, bằng điều mà chỉ có con người mới làm được và làm tốt nhất. Đó là Tình yêu. Vậy nên em cứ yêu đi. Yêu nhiều lên. Yêu cái gì đó cũng được. Yêu con gì đó cũng được. Yêu một ai đó cũng được. Hoặc yêu rất nhiều người nào đó cũng được luôn. Và kể cả khi yêu mà không được đáp lại cũng không sao. Hãy cứ làm việc mà em làm tốt nhất thôi : ) (Áp dụng luật hấp dẫn là em thu hút tình yêu thì tình yêu cũng sẽ đến với em :))

Để làm cuộc đời này tốt đẹp hơn, ngoài tình yêu thương còn cần một thứ khác là kiến thức và chia sẻ kiến thức. Nghĩa là em sẽ cần chia sẻ những gì em biết với mọi người để giúp họ trở nên hiểu biết hơn, thông minh hơn, giỏi giang hơn và có thể là giàu có hơn. Hãy tưởng tượng một thế giới mà mọi người đều cho đi những kiến thức quý báu mình tích lũy được (và nhiều thứ khác) một cách vô điều kiện. Mỗi con người trong thế giới đó sẽ là những cá nhân thông tuệ biết chừng nào. Con người sẽ không mất nhiều thời gian để tự đi tìm chân lý, mà thay vào đó, họ có thể tập trung làm rất nhiều thứ hay ho (hay hơn cả iPhone, iPad, Internet, Facebook, Google… đại loại vậy). Đồng thời cũng có thể giải quyết được nhiều vấn đề lớn của thế giới như đói nghèo, bệnh tật, chiến tranh, bất công, ô nhiễm môi trường…
Nghe vẫn có vẻ gì đó xa vời và có thể là khó làm đúng không? Nhưng cứ bắt đầu thôi. Với những điều nhỏ cũng được.
Khi con người được dẫn dắt bằng một trái tim trong sáng và nhân hậu (tình yêu) cùng với khả năng nhận biết thế giới một cách đúng đắn, phù hợp (kiến thức) thì họ sẽ không sợ bị lạc lối.
Để cho đi những gì chúng ta biết thì ta cũng phải tự trau dồi, học tập rất nhiều. Hãy đọc nhiều sách (càng nhiều thể loại, chủ đề càng tốt). Học những gì cần thiết cho mình. Hãy học như là em sống mãi ấy (Be a lifetime learner!). Với những kiến thức em học được chắn chắn sẽ làm cuộc sống của em tốt hơn (hoặc vui vẻ hơn, hii). Và nếu vậy thì nó cũng có thể làm cuộc sống của những người được em chia sẻ tốt hơn.

Em đến với cõi đời này để làm nó tốt đẹp hơn.

Anh tin là như vậy. Đó là sứ mệnh của em, của anh, của rất nhiều nhiều người khác nữa.
Hy vọng là anh có thể thuyết phục được em.

Chúc em vui.

* Cho Duy Thanh Xinh đẹp : )

Một số kinh nghiệm triển khai wifi tại Silicon Straits Saigon

Trong hơn một năm từ lúc thành lập, tất cả việc trao đổi thông tin, liên lạc của khoảng 20 con người  tại Silicon Straits Saigon (SSS) đều được thực hiện thông qua 2 đường dây ADSL 8Mb/768Kb. Chúng tôi đã không thể lắp đặt được cáp quang. Bạn có tin được không? Một công ty hoạt động trong lĩnh vực công nghệ thông tin tại khu đô thị hiện đại Phú Mỹ Hưng (Quận 7, Tp. HCM) nhưng lại không kéo được cáp quang, chỉ vì đơn vị chủ quản tòa nhà Garden Court 2 không muốn làm thay đổi tới thiết kế, cấu trúc của tòa nhà >_<.
Cho đến tận năm ngoái, để đáp ứng nhu cầu đường truyền tốc độ cao hơn khi số lượng nhân viên tăng lên, SSS đã ký hợp đồng thuê một văn phòng phụ ở dãy nhà đối diện văn phòng hiện tại để… có được cáp quang 80Mb/80Mb. Và để đưa được Internet tốc độ cao về đến SSS, chúng tôi chỉ có một giải pháp khả thi là phát wifi qua khoảng cách khoảng 30m – 40m, ở giữa có một số cây xanh chắn ngang.

Lúc đầu khi còn dùng ADSL, SSS chỉ dùng 1 thiết bị phát wifi chính là Apple Airport Extreme với khả năng phục vụ khoảng 50 người dùng (theo như tài liệu của hãng). Sau khi “kéo” được đường cáp FTTH, chúng tôi dùng thêm 1 “cục” Airport Extreme tương tự mới để phát wifi từ bên văn phòng phụ, cục Airport cũ dùng để thu wifi bên văn phòng chính.
Việc cài đặt này rất đơn giản với chức năng Extend wireless network của Airport Extreme. Tuy nhiên tốc độ thu được cũng không ổn định theo thời điểm, thời tiết, và suy hao khá nhiều. Để hỗ trợ Airport Extreme, SSS còn gắn thêm 1 thiết bị chuyên dùng hơn cho doanh nghiệp là Unify AP AC phát wifi với SSID riêng, khả năng đáp ứng khoảng > 200 người dùng cùng lúc (theo tài liệu của hãng).

Nhưng với số lượng nhân viên tăng dần lên khoảng 40 người, rồi 50 người và thêm nữa. Mỗi người thường có 2 thiết bị là laptop và điện thoại kết nối vào hệ thống wifi nên Airport Extreme dần không đáp ứng nổi. Tình trạng “rớt mạng” thường hay diễn ra trong ngày, từ nhân viên đến sếp, từ sếp đến anh bảo vệ ai cũng nản.

Để khắc phục tình trạng đau khổ đó, chúng tôi đã thử rất nhiều cách và dưới đây là một số cách mà chúng tôi đã áp dụng:

1. Xóa hết những sóng wifi không cần thiết khác. SSS thường tổ chức nhiều sự kiện và chúng tôi thỉnh thoảng tạo mạng wifi riêng để người tham dự sự kiện đó sử dụng Internet. Ngoài ra cũng có một số mạng wifi riêng phục vụ cho các mục đích khác. Những mạng wifi này có thể gây ra tình trạng nhiễu sóng đối với mạng wifi chính của công ty (phát ở băng tần 2.4Ghz và 5Ghz) vì số kênh trên băng tần này khá giới hạn (12 kênh).
Ngoài ra xung quanh SSS cũng có khá nhiều hộ gia đình, công ty khác cũng phát wifi riêng nên mật độ sóng khá dày và chuyện nhiễu là hoàn toàn có thể. Thông tin từ Wifi Analyzer cho thấy điều này:

Các sóng Wifi bên cạnh SSS

Theo Wifi Analyzer thì kênh wifi của SSS trùng với kênh của nhiều sóng xung quanh, nên chúng tôi đã thử chuyển sang 1 kênh ít được sử dụng hơn (không sử dụng chế độ chọn kênh tự động của router wifi). Nhưng sau đó có ghi nhận một số máy sử dụng Windows (Asus) không thể thấy wifi nên chúng tôi đã để lại chế độ tự động.

SSS cũng sử dụng wifi ở băng tần 5Ghz, vì số lượng kênh trên băng tần này nhiều hơn nên chuyện nhiễu ít xảy ra. Ngoài ra, số lượng thiết bị xung quanh phát ở băng tần này không nhiều, và sóng 5Ghz không có khả năng “đâm xuyên” (tường, cây cối…) tốt như 2.4Ghz nên băng tần này hầu như không bị ảnh hưởng bởi các thiết bị của những người hàng xóm.

2. Với mô hình Extend wireless network từ 2 thiết bị Apple Airport Extreme, chạy DHCP cấp phát cho 2 Router wifi (Unify AP AC và Unify AP Pro). Cả hai router này đều chạy ở chế độ cầu nối (brigde mode) do đặc điểm của dòng Unify, nên Airport Extreme có thể trở thành 1 nút nghẽn khi lượng người dùng trong mạng wifi tăng lên nhiều. Tài liệu của Apple chỉ cho biết Airport Extreme có khả năng chịu khoảng 50 người dùng cùng lúc. Với một nhân viên tại SSS, mở nhiều ứng dụng, trình duyệt…, số lượng connection này trong khoảng 130 (có thể làm tròn thành 150 :D):

Vậy lượng kết nối mà Airport Extreme có thể chịu ở thời điểm bận rộn: 150 * 50 = 7.500. Đây là một số khá khiêm tốn với 1 router. Vì vậy để tránh bị nghẽn ở đây, chúng tôi cho Airport Extreme chạy ở chế độ cầu nối (brigde mode) thay vì DHCP. Lúc này Airport Extreme chỉ còn nhiệm vụ luân chuyển gói tin mà không cần phải “track” kết nối từ IP nào đến IP nào.

Lúc này, gánh nặng sẽ thuộc về router chính.

Đường cáp quang của SSS được FPT cung cấp và hỗ trợ sẵn 1 router là TL-R480T+. Theo như tài liệu kỹ thuật, khả năng của router này vào khoảng 30.000 kết nối cùng một lúc. Nếu cũng sử dụng cách tính trên thì router này có thể phục vụ cho khoảng 200 người.
Tuy nhiên tình trạng chập chờn mạng vẫn còn nên chúng tôi quyết định thay router Tp Link này bằng 1 router có sẵn trong kho của SSS là Draytek Vigor V300b với khả năng hỗ trợ khoảng 80.000 kết nối. Sau khi chuyển sang router mới, việc “rớt mạng” (mất kết nối wifi hoặc limited connectivity) ở công ty có vẻ tạm ổn, tuy nhiên…

3. Vài ngày sau đó, chúng tôi lại tiếp tục nghe bài ca “trả mạng cho ta” léo nhéo và ai oán vào một buổi trưa mùa hè nóng nực. Thôi thì nhận trách nhiệm rồi phải ráng giải quyết. Sau những lần phân tích giằng xé, đánh giá nhức óc, thử nghiệm rã rời thân xác các kiểu… (cũng không đến mức như vậy lắm, nhưng bạn hiểu đúng ý rồi đấy) ấy vậy mà vấn đề vẫn chưa được giải quyết dứt điểm. Lần này chúng tôi quyết định thử một giải pháp tốn kém hơn là thay thế 2 cục Airport hiện tại bằng thiết bị khác chuyên phát và thu wifi ngoài trời.

Có nhiều lý do để Airport Extreme không phù hợp để được sử dụng như cách nó đang được dùng tại SSS. Hai điều quan trọng trong số đó là nhiệt độ (ở ngoài trới có khi lên đến 70º) và khoảng cách (30m – 40m). Thiết bị chúng tôi chọn để thay thế Airport Extreme là Unify Nanostation locoM5. Chuyên dùng ngoài trời (chịu đựng nắng nóng, mưa gió) và khoảng cách phủ sóng khoảng hơn 10Km, quá nhiều so với nhu cầu thực tế. Nói là tốn kém nhưng chi phí cho 2 thiết bị locoM5 này cũng khá rẻ, tổng cộng chưa đến 3.000.000đ khoảng 5.000.000đ. Điều quan trọng khi sử dụng thiết bị này là chúng phát ở băng tần 5Ghz với công suất lớn, nên ít (hoặc hầu như không) bị ảnh hưởng bởi rất nhiều sóng wifi xung quanh văn phòng phụ (vốn chủ yếu phát ở băng tần 2.4Ghz).

Unify NanoStation locoM5

Unify NanoStation locoM5

Việc cài đặt để 2 thiết bị này làm việc với nhau không khó và mất thời gian. Chỉ trong một buổi là xong. Việc còn lại là lấy thang chạy qua lại giữa 2 bên văn phòng để gỡ Airport Extreme và gắn locoM5 vào, tốn thêm 1 buổi nữa. Và đây là thành quả chúng tôi gặt được:

So sánh tốc độ trước và sau khi tối ưu

So sánh tốc độ trước và sau khi tối ưu

Tốc độ trước khi tiến hành các biện pháp tối ưu hóa cũng không đến nỗi tệ lắm, có lúc đo được khoảng 40Mbs hoặc 50Mbs, có thể tùy từng thời điểm, thời điểm chúng tôi chạy Speedtest thì chỉ có 8.23Mb/s, tuy nhiên sự thay đổi sau khi sử dụng locoM5 là rất rõ rệt.

Có thêm hai điều chúng tôi rút ra được trong quá trình tìm hiểu và khắc phục những vấn đề với mạng wifi của SSS là:

1. Có thể sử dụng SSID (tên mạng wifi) duy nhất với thông tin password, chế độ mã hóa… như nhau ở mỗi Access Point. Miễn là chúng không trùng kênh. Điều này sẽ giúp người sử dụng truy cập vào mạng wifi một cách thông suốt trong công ty mà không phải tự chuyển qua mạng wifi khác khi ở địa điểm khác. Máy tính (hoặc thiết bị di động) sẽ tự động kết nối với BSSID có tín hiệu tốt hơn. Đây là cách mà Unify AP AC và Unify AP Pro áp dụng.

2. Ubiquity (hãng cung cấp Unify AP AC/Pro) hỗ trợ việc quản lý thiết bị thông qua cloud (của nhà phân phối hoặc tự cài đặt). Do đó việc cài đặt, quản lý và theo dõi thiết bị rất tiện lợi thông qua trang dashboard này. Điều này giúp việc “scale” lên khá dễ dàng: khi có nhu cầu mở rộng tầm phủ sóng wifi hoặc phục vụ cho nhiều người dùng hơn, chỉ cần gắn thêm 1 thiết bị Unify vào hệ thống mạng và thao tác từ trang quản lý này.

Trang theo dõi tình trạng của Ubiquiti cho các thiết bị Unify

Trang theo dõi tình trạng của Ubiquiti cho các thiết bị Unify

Thực tế sau nhiều tháng sử dụng, ngoại trừ một số lần hệ thống mạng từ nhà cung cấp FPT bị trục trặc thì hệ thống wifi của SSS đã ổn định hơn rất nhiều. Thỉnh thoảng thiết bị Unify có bị “down” và phải restart lại nhưng vẫn ở trong mức chấp nhận được.
Lắp đặt hệ thống wifi cho nhiều người cùng sử dụng là điều không dễ dàng. Với một doanh nghiệp từ nhỏ thành không phải vừa, và tự tin là mình có thể làm được (nhiều thứ) như SSS thì cũng tốn kha khá thời gian và công sức để tối ưu hệ thống wifi. Nhưng bù lại những bài học mà chúng tôi học được cũng rất giá trị và thú vị. :-P

Simple trick to migrate Laravel passwords to Rails

Months ago (maybe even months, months ago) a colleague and I had to rewrite a Laravel 4 backend app to a Rails 4 one. At the near final stage of the project, I took responsibility for migrating the old database so that our new app can work with. Everything was fine, except for the passwords. Laravel and Devise (a popular authentication solution for Rails) use different kinds of hash for passwords. It took me a day to dig into the problem but it turned out that the solution was quite simple, ridiculously. I thought of writing a custom encryptor for Devise, but actually I just needed to update the old passwords like this:

Both Laravel and Devise use Bcrypt to encrypt the password, but Laravel seems to use a newer version of the algorithm (2y) compare to Devise’s (2a). But it’s luckily that the only difference between a 2a and a 2y password are their prefixes ($2y$10 and $2a$10). That’s why the above solution works.