Category Archives: Nginx

Renew Expired SSL Certification in Nginx Server

Each SSL Certification has its own valid date. When your server’s certification is expired, your website will be not visitable. In this case, you need to renew your expired certification. It is quite simple and easy. But Here I just write it down to record its steps.

Step1: check its valid date

openssl x509 -in domain.crt -noout -enddate

Step2: copy the new certificate files to your server

This step depends on your service, I mean which SSL service you get. For me, I get this service from Godaddy. I need to go to Godaddy to get new crt files. There are two crt files which you need to download.

And then you need to use SCP command to copy these files to your server. If you forget the target location, you just need to go to your Nginx’s conf file to check this parameter: ssl_certificate and you will know where to copy to.

Here is an example of SSL part in Nginx.

ssl on;
ssl_certificate /etc/ssl/domain.crt;
ssl_certificate_key /etc/ssl/domain.key;

Here ssl_certificate is your primary certificate; ssl_certificate_key should be the key file generated when you created the CSR.

Please note, this part is just to update expired SSL certificate so you don’t need to do anything on the key file.

Step3: concatenate the SSL certificate and intermediate certificate

In fact, you need to backup or remove the existing expired domain.crt first and the do concatenate. Just for safe.

cat 29393****.crt gd_bundle-g2-g1.crt >> domain.crt

Step4: restart Nginx

sudo nginx -s reload
Advertisements

Play Framework (1) – WebSocket

Even though Play uses async method to communicate with front-end and back-end. But sometimes, we still need to call third-party restful api to do something else. Especially, third-party restful api takes too long time to return data. In this case, it is wasteful to wait there and always ask whether it is ok or not. Good way to handle it is to make use of third-party callback and web socket to deal with this case.

So it is very clear that we have three sides: one is third-party api, the other is our back-end, another is our front-end.

What we need to do is that front-end builds a WebSocket with back-end. And then back-end requests data from third-party api. When third-party api returns data,  back-end sends data back to front-end.

  1. Build a web socket between front-end and back-end.
  2. front-end sends data to back-end
  3. back-end calls third-party api
  4. third-party api returns data back to back-end
  5. back-end returns data back to front-end by web socket

So, there are two routes, one is for web socket, another is for callback. The connection between the two is to store actorRef to keep the bridge. You also needs to ask callback to append special token back in order to figure out this actor.

  • Javascript code to send web socket to build connection between front-end and back-end.
  • var myWebSocket = new WebSocket("ws://<your_domain_name>/<your_ws_route>/");
    myWebSocket.onopen = function() { myWebSocket.send(<your_data>); }; 
    myWebSocket.onmessage = function(event) { alert(event.data); // to render data }; 
    myWebSocket.onclose = function() { console.log("wsconnect close."); };
  • Nginx configuration to build connection. Please note: Here if you don’t configure “

    proxy_read_timeout” attribute, your websocket default connection time is 60 seconds and then it is closed automatically. So here normally I set it as 1d.

  • location /daoApp/websocket/create/ {
      proxy_pass  http://<your_domain_name>;
      proxy_http_version 1.1;
      proxy_set_header Host $host;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
      proxy_read_timeout 1d;
    }
  • Play routes to accept web socket request and another one is to accept callback request
  • POST    /<your_callback_route>/ controllers.WebSocketApp.apiCallback
    GET     /<your_ws_route>/       controllers.WebSocketApp.create
  • And next I have one global variable to store actorRef for each connect between front-end and back-end. For each web socket request, I will store unique key combining the actorRef and trigger call to third-party api. For each callback request, I will to find its mapping actorRef to send data back to front-end.
  • object WebSocketApp extends Controller {
      // remember to build a map to store your actorRef
      // here we use ConcurrentHashMap which is to avoid memory leak in multiple cores device
      var channels = new ConcurrentHashMap[String, ChannelMsg]().asScala
      def apiCallback = Action {
        request =>
          val requestBody = request.body.asFormUrlEncoded
          requestBody match {
            case Some(s) =>
              if (s.contains("parentID")) {
                val parentID = s("parentID").head
                val channelInfo = channels.get(parentID)
                channelInfo match {
                  case Some(info) =>
                    val yourParsedData = <deal_with_data_from_api>
                    actorInfo match {
                      case Some(actor) =>
                        actor ! <your_parse_data>
                        channels.remove(parentID)
                      case None =>
                    }
                  case None =>
                }
              }
            case None =>
          }
          Ok
      }
    
      def create = WebSocket.acceptWithActor[String, String] { request => out =>
        Props(new DAOWSCreateActor(out, request))
      }
    }
    class DAOWSCreateActor(out: ActorRef, request: RequestHeader) extends Actor {
      override def receive = {
        case topicName: String =>
          val queryTokenInfo = <your_send_request_to_third_party>
          // remember to involve your actorRef to channelMsg which will be used to parse actor 
          valchannelMsg = <construct_your_channel_msg>
          // remember to involve your key to callback on post which will be used to find actor back to send data back to front-end
          WebSocketApp.channels.put(<your_key>, channelMsg)
        case _ =>
      }
    }

Nginx Configuration for HTTPS

Before we enter into how to configure Nginx for HTTPS, we need to know why we need HTTPS. We already have HTTP, which is an internet protocol for transferring  web content including images, css, js, etc. But it is not safe because web context can be modified or stoled. In this case, we need involve another layer, SSL into HTTP. Here we will give two cases, one is to use un-certified certification file by Openssl, another is to use certified certification file by Godaddy. The benefit of the first case is free, by contract, the second’s disadvantage is money-cost. Before giving out detailed solution, we introduce some basic concepts first, like SSL, HTTPS.

What is SSL?

SSL is a digital certification, which uses Secure Socket Layer protocol to build a safe channel between browser and web server. So that data message is encoded between client and server in order to avoid third party tapping. This layer is also called TLS(Transport Layer Security), or SSL/TLS.

What is HTTPS?

HTTPS adds SSL at the bottom of HTTP, whose target is to provide safe channel. Or HTTPS = HTTP over SSL/TLS. After simply understanding our purpose, let’s see how to implement our goal.

How to do?

Check Nginx configuration

>>nginx -V

Rebuid nginx to support SSL

If your Nginx doesn’t support SSL, you need rebuild Nginx. Sometimes, you might lack libssl-dev package, you can use “apt-get install libssl-dev” to add it. Others are as below.

>>cd nginxPath
>>./configuration --with-http_ssl_module
>>make
>>sudo make install
>>nginx -V
//nginx version:nginx/1.6.0
//built by gcc 4.6.3(Ubuntu/Linaro 4.6.3-1ubuntu5)
//TLS SNI support enabled
//configure arguments:--with-http_ssl_module

Case 1:

Create self-signature SSL certification

1. use openssl to build a private key for the server
>>sudo openssl genrsa -des3 -out server.key 4096
2. create certification of signature
>>sudo openssl req -new -key server.key -out server.csr
// note: Common name:if your website has domain name, for example www.####.com, here common name should be this domain name. If not, use localhost to set its value.
3. close Nginx password authentication
>>sudo cp server.key server.key.org
>>sudo openssl rsa -in server.key.org -out server.key

Use above private key and CSR to mark certification

>>sudo openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

Configure Nginx

server{
  listen 443 ssl;
  server_name  localhost;
  ssl_certificate  /usr/local/nginx/conf/server.crt;
  ssl_certificate_key  /usr/local/nginx/conf/server.key;
  ssl_ciphers  HIGH:!aNULL:!MD5;
  ssl_prefer_server_ciphers  on;
  ...
}

 Don’t forget restart Nginx.

Case 2:

Copy SSL certification from Godaddy.

  • download it from Godaddy. In fact, you will get one zip folder and then unzip it to see two .crt files, one starts by gd_bundle which is linked certification file; another is server’s certification. For Nginx, you need to merge the two to one.
    • cat ***.crt gd_bundle-***.crt > server.crt
    • Please note the order of the two file. If you mistake the two order, you might be get this error:
    • SSL_CTX_use_PrivateKey_file(" ... /www.example.com.key") failed (SSL: error:0B080074:x509 certificate routines: X509_check_private_key:key values mismatch)
  • you also need anther file: ***.key

The next step is the same with case 1 to configure Nginx configuration file to add .key and .crt file.

Support HTTP/HTTPS:

Until now, Nginx only supports HTTPS, not HTTPS.  What you need to do is quite simply, you just need to redirect request from http to https. Here is the additional code you need to add to Nginx configuration file:

server {
    listen 80;
    listen 443 ssl;
    # force https-redirects
    if ($scheme = http) {
        return 301 https://$server_name$request_uri;
    }
}

Problems:

After configuration and re-run Nginx, we also might meet some problems. Go to logs/error.log to see what’s happen. Here are some errors which I met.

1. the “ssl” parameter requires ngx_http_ssl_module

You can see that in the first step I already re-configured Nginx with “–with-http_ssl_module” and then use “nginx -V” to check nginx configuration which reminds that the Nginx is already configured with the ssl, but why here I still get this error. The main reason is that even though I use “sudo nginx -s reload” command to reload configuration file, the Nginx is still the old one, not the re-build one. Here I need to use “sudo nginx -s stop” to stop Nginx first and then restart it by “sudo nginx“. 

2. [blocked] The page at ‘https://<my-domain>/&#8217; was loaded over HTTPS, but ran insecure content from ‘http://<some-file-name>&#8217;: this content should also be loaded over HTTPS.

I remove “http:” prefix from that link.

old: iframe src="http://<some-file-name>"
new: iframe src="//<some-file-name>"

3. The identity of this website has not been verified. Server’s certificate does not match the URL. Server’s certificate is not trusted.

  1. Commands to check bug
# to check 442 port open or not
nmap 
# to try to obtain server
wget --no-check-certificate <you_server_name>