Using Docker for Node.js in Development

There’s an issue with npm have been stuck for a few days. It’s you have to build the node_modules at build time, otherwise it’s not accessible at runtime. And finally found a solution on

Here’s another best practice adjustment: Copy your package.json and package-lock.json before you copy your code into the container. Docker will cache installed node_modules as a separate layer, then, if you change your app code and execute the build command, the node_modules will not be installed again if you did not change package.json. Generally speaking, even if you forget to add those line, you will not encounter a lot of problems. Usually, you will need to run a docker build only when your package.json was changed, which leads you to install from scratch anyway. In other cases, you don’t run docker build too often after your initial build in the development environment.

In another word, Having

COPY package*.json ./
RUN npm install

in your Dockerfile to do the npm install. Then in the docker-compose.yml

build: .
- .:/usr/src/app
- /usr/src/app/node_modules
command: npm start

Set up Letsencrypt/Certbot with Nginx web server with webroot

The default certbot certonly –standalone is quite useful for a quick start to run a standalone server and get the SSL certificate. But nowadays everyone is running their own server. Which would cause the issue of binding port 80 fail. In order to fix this would be using –webroot instead.

Firstly, create a new folder for nginx to serve static file

mkdir -p /var/www/letsencrypt/.well-known/acme-challenge

Secondly, in each server config that you want to have SSL add the followings, E.g. inside into the server listen 80 block.

location ^~ /.well-known/acme-challenge/ {
root /var/www/letsencrypt;

It tells nginx when matching path /.well-known/acme-challenge/, go to /var/www/letsencrypt/.well-known/acme-challenge/ to find the file.

Thirdly, run nginx reload and

letsencrypt certonly --webroot -w /var/www/letsencrypt -d

Letsencrypt will put a text file inside /var/www/letsencrypt/.well-known/acme-challenge and fire a get request to achieve it in order to finish the justification. You can tail the nginx log to see the requests to debug.

Fourthly, you add the listen 443 block into your domain’s nginx config file

listen 443;
ssl on;
ssl_certificate /etc/letsencrypt/live/;
ssl_certificate_key /etc/letsencrypt/live/;
ssl_prefer_server_ciphers On;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

Lastly, create a cron job task file in /etc/cron.d/

@monthly root /bin/bash -c "/usr/bin/letsencrypt certonly --webroot -w /var/www/letsencrypt -d"

Hope that helps!

Action required: Let’s Encrypt certificate renewals

Just received email from to upgrade certbot as TLS-SNI-01 validation is reaching end-of-life.

By running

/usr/bin/letsencrypt --version
certbot 0.17.0

Following the instructions from needs to upgrade to 0.28 or higher.

$ sudo apt-get update
$ sudo apt-get install python-certbot-nginx
certbot --version
certbot 0.28.0

2.Remove any explicit references to tls-sni-01 in your renewal configuration:

sudo sh -c "sed -i.bak -e 's/^\(pref_challs.*\)tls-sni-01\(.*\)/\1http-01\2/g' /etc/letsencrypt/renewal/*; rm -f /etc/letsencrypt/renewal/*.bak"

3. Run sudo certbot renew –dry-run. Remember to turn off nginx before you run it as it will have fail to bind port error.

That’s it. Good Luck with your upgrade.

Regex in Ruby

# encoding: utf-8

Regex In Ruby – Capture Groups

Lecky Lao(@leckylao)

RORO 09-06-2015

Mongo BSON Injection: Ruby Regexps Strike Again

Jun 4, 2015 • Egor Homakov (@homakov)

Mongoid is an ODM(Object Document Mapper) Framework
for MongoDB written in Ruby

Mongoid uses more low-level adapter Moped which uses BSON-ruby

the vulnerability is in legal? method of BSON::ObjectId

  # /\nhi\n/ =~ /hi$/
  # /\nhi\n/ =~ /hi\Z/
  # /\nhi\n/ =~ /hi\z/

  # Vulnerable
  def legal?(string)
    # March 31 2013 to Apr 7 2013
    /\A\h{24}\Z/ === string.to_s
    # currently it thinks Mongo is down and pings it 39 more times with intervals.
    # In other words it keeps the worker busy for 5 seconds and makes x40 requests to Mongo DB
    # One way or another, it is Denial of Service.

    # Apr 7 2013 till now
    string.to_s =~ /^[0-9a-f]{24}$/i ? true : false
    # he attacker can send any data to the socket with something like
    # _id=Any binary data\naaaaaaaaaaaaaaaaaaaaaaaa\nAny binary data

  # Patch
  def ((defined?(Moped::BSON) ? Moped::BSON : BSON)::ObjectId).legal?(s)
    /\A\h{24}\z/ === s.to_s

—-Capturing Groups—-

    # What's the difference?

    /sat (in)/.match("The cat sat in the hat")

    "The cat sat in the hat" =~ /sat (in)/

The difference is

The operator =~ returns the index

of the first match (nil if no match)

and stores the MatchData

in the global variable $~

The method match returns

the MatchData itself (again, nil if no match)

Grouping with reference

    # What's the difference?


    "$3.67" =~ /\$(?\d+)\.(?\d+)/

    /\$(?\d+)\.(?\d+)/ =~ "$3.67"

The difference is

When named capture groups are used with a literal regexp

on the left-hand side of an expression and the =~ operator,

the captured text is also assigned to local variables

with corresponding names.


    # Is this correct?

"The cat sat in the hat".gsub(/(.*)cat(.*)/, "#{$1}black dog#{$2}")
"The cat sat in the hat".gsub(/(.*)cat(.*)/, "\1black dog\2")

"The cat sat in the hat".gsub(/(.*)cat(.*)/, '\1black dog\2')

"The cat sat in the hat".gsub(/(?<prefix>.*)cat(.*)/, '\k<prefix>black dog\2')

"The cat sat in the hat".gsub(/(?<prefix>.*)cat(?<suffix>.*)/, '\k<prefix>black dog\k<suffix>')

$1 and $2 only store after the execution, therefore
and use \\1 and \\2 instead

use '' instead of "" when using regex

A regexp can't use named backreferences
and numbered backreferences simultaneously.

That's all, thanks!

slide: – examples/regex_in_ruby.rb

slides made using tkn("