diff --git a/lib/webInterface.js b/lib/webInterface.js
index 9620663..4285728 100644
--- a/lib/webInterface.js
+++ b/lib/webInterface.js
@@ -1,7 +1,5 @@
 'use strict';
 
-const DEFAULT_WEB_PORT = 8002; // port for web interface
-
 const express = require('express'),
   url = require('url'),
   bodyParser = require('body-parser'),
@@ -16,9 +14,13 @@ const express = require('express'),
   ip = require('ip'),
   compress = require('compression');
 
+const DEFAULT_WEB_PORT = 8002; // port for web interface
+
 const packageJson = require('../package.json');
 
 const MAX_CONTENT_SIZE = 1024 * 2000; // 2000kb
+
+const certFileTypes = ['crt', 'cer', 'pem', 'der'];
 /**
  *
  *
@@ -204,8 +206,9 @@ class webInterface extends events.EventEmitter {
       res.setHeader('Access-Control-Allow-Origin', '*');
       const _crtFilePath = certMgr.getRootCAFilePath();
       if (_crtFilePath) {
+        const fileType = certFileTypes.indexOf(req.query.type) !== -1 ? req.query.type : 'crt';
         res.setHeader('Content-Type', 'application/x-x509-ca-cert');
-        res.setHeader('Content-Disposition', 'attachment; filename="rootCA.crt"');
+        res.setHeader('Content-Disposition', `attachment; filename="rootCA.${fileType}"`);
         res.end(fs.readFileSync(_crtFilePath, { encoding: null }));
       } else {
         res.setHeader('Content-Type', 'text/html');
@@ -213,25 +216,12 @@ class webInterface extends events.EventEmitter {
       }
     });
 
-    //make qr code
-    app.get('/qr', (req, res) => {
-      res.setHeader('Access-Control-Allow-Origin', '*');
-      res.setHeader('Content-Type', 'text/html');
-
-      const qr = qrCode.qrcode(4, 'M');
-      const targetUrl = req.protocol + '://' + req.get('host');
-      qr.addData(targetUrl);
-      qr.make();
-      const qrImageTag = qr.createImgTag(4);
-      const resDom = '<a href="__url"> __img <br> click or scan qr code to start client </a>'.replace(/__url/, targetUrl).replace(/__img/, qrImageTag);
-      res.end(resDom);
-    });
-
     app.get('/api/getQrCode', (req, res) => {
       res.setHeader('Access-Control-Allow-Origin', '*');
 
+      const fileType = certFileTypes.indexOf(req.query.type) !== -1 ? req.query.type : 'crt';
       const qr = qrCode.qrcode(4, 'M');
-      const targetUrl = req.protocol + '://' + req.get('host') + '/fetchCrtFile';
+      const targetUrl = req.protocol + '://' + req.get('host') + '/fetchCrtFile?type=' + fileType;
       const isRootCAFileExists = certMgr.isRootCAFileExists();
 
       qr.addData(targetUrl);
diff --git a/test/spec_lib/webInterface.js b/test/spec_lib/webInterface.js
new file mode 100644
index 0000000..3eac176
--- /dev/null
+++ b/test/spec_lib/webInterface.js
@@ -0,0 +1,44 @@
+const WebInterface = require('../../lib/webInterface.js');
+const Recorder = require('../../lib/recorder');
+const { directGet } = require('../util/HttpUtil.js');
+
+describe('WebInterface server', () => {
+  let webServer = null;
+  let webHost = 'http://127.0.0.1:8002';
+
+  beforeAll(() => {
+    const recorder = new Recorder();
+    webServer = new WebInterface({
+      webPort: 8002,
+    }, recorder);
+  });
+
+  afterAll(() => {
+    webServer.close();
+  });
+
+  it('should support change CA extensions in /getQrCode', done => {
+    const certFileTypes = ['crt', 'cer', 'pem', 'der'];
+    const tasks = certFileTypes.map((type) => {
+      return directGet(`${webHost}/api/getQrCode`, { type })
+        .then(res => {
+          const body = JSON.parse(res.body);
+          expect(body.qrImgDom).toMatch('<img src="data:image/');
+          expect(body.url).toBe(`${webHost}/fetchCrtFile?type=${type}`);
+        });
+    });
+
+    Promise.all(tasks)
+      .then(done)
+      .catch(done);
+  });
+
+  it('should fallback to .crt file in /getQrCode', done => {
+    directGet(`${webHost}/api/getQrCode`, { type: 'unkonw' })
+      .then(res => {
+        expect(JSON.parse(res.body).url).toBe(`${webHost}/fetchCrtFile?type=crt`);
+        done();
+      })
+      .catch(done);
+  });
+});
\ No newline at end of file
diff --git a/web/src/component/download-root-ca.jsx b/web/src/component/download-root-ca.jsx
index 55d1322..ba63f57 100644
--- a/web/src/component/download-root-ca.jsx
+++ b/web/src/component/download-root-ca.jsx
@@ -5,26 +5,29 @@
 
 import React, { PropTypes } from 'react';
 import ReactDOM from 'react-dom';
-import ClassBind from 'classnames/bind';
 import { connect } from 'react-redux';
-import { message, Button, Spin } from 'antd';
+import { message, Button, Spin, Select } from 'antd';
 import ResizablePanel from 'component/resizable-panel';
 import { hideRootCA, updateIsRootCAExists } from 'action/globalStatusAction';
 import { MenuKeyMap } from 'common/Constant';
-import { getJSON, ajaxGet, postJSON } from 'common/ApiUtil';
+import { getJSON, postJSON } from 'common/ApiUtil';
 
 import Style from './download-root-ca.less';
 import CommonStyle from '../style/common.less';
 
+const certFileTypes = ['crt', 'cer', 'pem', 'der'];
+
 class DownloadRootCA extends React.Component {
     constructor () {
         super();
         this.state = {
             loadingCAQr: false,
-            generatingCA: false
+            generatingCA: false,
+            fileType: certFileTypes[0]
         };
 
         this.onClose = this.onClose.bind(this);
+        this.onFileTypeChange = this.onFileTypeChange.bind(this);
         this.getQrCodeContent = this.getQrCodeContent.bind(this);
     }
 
@@ -38,7 +41,7 @@ class DownloadRootCA extends React.Component {
             loadingCAQr: true
         });
 
-        getJSON('/api/getQrCode')
+        getJSON('/api/getQrCode', { type: this.state.fileType })
             .then((response) => {
                 this.setState({
                     loadingCAQr: false,
@@ -57,12 +60,33 @@ class DownloadRootCA extends React.Component {
         this.props.dispatch(hideRootCA());
     }
 
+    onFileTypeChange (value) {
+        this.setState({
+            fileType: value
+        }, () => {
+            this.fetchData();
+        });
+    }
+
     getQrCodeContent () {
         const imgDomContent = { __html: this.state.CAQrCodeImageDom };
         const content = (
             <div className={Style.qrCodeWrapper} >
                 <div dangerouslySetInnerHTML={imgDomContent} />
-                <span>Scan to download rootCA.crt to your Phone</span>
+                <div>Scan to download rootCA.{this.state.fileType} to your Phone</div>
+                <div>You can change the CA's file extension:
+                    <Select
+                        defaultValue={this.state.fileType}
+                        className={Style.fileSelect}
+                        onChange={this.onFileTypeChange}
+                    >
+                        {
+                            certFileTypes.map(key => (
+                                <Option key={key} value={key}>{key}</Option>
+                            ))
+                        }
+                    </Select>
+                </div>
             </div>
         );
 
@@ -71,7 +95,6 @@ class DownloadRootCA extends React.Component {
     }
 
     getGenerateRootCADiv () {
-
         const doToggleRemoteIntercept = () => {
             postJSON('/api/generateRootCA')
                 .then((result) => {
@@ -127,8 +150,8 @@ class DownloadRootCA extends React.Component {
                 </div>
 
                 <div className={Style.buttons} >
-                    <a href="/fetchCrtFile" target="_blank">
-                        <Button type="primary" size="large" > Download </Button>
+                    <a href={`/fetchCrtFile?type=${this.state.fileType}`} target="_blank">
+                        <Button type="primary" size="large" >Download</Button>
                     </a>
                     <span className={Style.tipSpan} >Or click the button to download.</span>
                 </div>
@@ -146,7 +169,6 @@ class DownloadRootCA extends React.Component {
         return (
             <ResizablePanel onClose={this.onClose} visible={panelVisible} >
                 {this.props.globalStatus.isRootCAFileExists ? this.getDownloadDiv() : this.getGenerateRootCADiv()}
-
             </ResizablePanel>
         );
     }
diff --git a/web/src/component/download-root-ca.less b/web/src/component/download-root-ca.less
index 8c9d1de..550227d 100644
--- a/web/src/component/download-root-ca.less
+++ b/web/src/component/download-root-ca.less
@@ -55,4 +55,9 @@
     margin-top: 18px;
     display: block;
   }
+}
+
+.fileSelect {
+  width: 60px;
+  margin-left: 8px;
 }
\ No newline at end of file