Json-server: How to run json-server under HTTPS?

Created on 19 Oct 2016  路  10Comments  路  Source: typicode/json-server

Hi,

I have been working on a project using json-server on localhost. It worked well until I wanted it to serve JSON responses from an actual server. Now, I have hosted my front-end code in Apache (under HTTPS) and ran json-server as a background process using nohup in my server. After this, the front-end code is unable to access any response from json-server.

I see multiple issues here -

  • Apache is running on port 80 under HTTPS and json-server is running in localhost w.r.to the server on default port 3000
  • Chrome browser does not allow mixed content.
  • json-server always runs on localhost. I could not force it to run on HTTPS (I'm not sure if this can be done)

I could not find a solution for this. Any idea how I can run json-server under HTTPS on an actual server? Any help would be much appreciated.

PS. json-server is able to serve responses when the front-end is served from HTTP. However, I am using service workers in my project which need HTTPS to work.

Most helpful comment

A practical example of how to use hotel and and json-server with https is completely lacking on the internet it seems. Can anyone offer some steps on how to get it working?

All 10 comments

Hi @kranthilakum,

I guess there's many way to solve it, you can:

  • use --host and --port if you need to make it run on some other port/host
  • use --static to tell JSON Server to serve your static files, so there shouldn't be an issue with mixed content anymore https://github.com/typicode/json-server#static-file-server

You can also probably configure Apache to proxy requests to JSON Server or use some other tools to do this.

Personally, I would suggest using JSON Server's static file server and hotel if you need https.

@typicode Thank you for the response!

A practical example of how to use hotel and and json-server with https is completely lacking on the internet it seems. Can anyone offer some steps on how to get it working?

@Gribbs - See if this helps. I had the same issue and the following steps work for me. I am providing steps for windows, and steps on unix based OS should be the same, except variable representation ($ instead of % etc.).

  1. Setup json-server, as provided on the site. Do not start.
    a. Create directory "c:\json-server" or any name.
    b. Create db.json.
  2. Setup hotel, as provided on the site and start hotel.
  3. Setup localdomain as ".localhost". I setup on firefox with browser method and worked fine with steps provided.
  4. Now add json-server to hotel. This is where it was slightly tricky and wasn't clear at first.
    a. Go to directory, where you have created json.db file. e.g. cd c:\json-server
    b. Now execute the following command: hotel add "json-server db.json -p %PORT%"
    The tricky part is the %PORT%. Your app needs to listen on %PORT% so hotel can dynamically assign it a port.
  5. Now go to hotel https://hotel.localhost and start the app.
    a. App will be named "json-server" by default. Once it starts you will see the port it assigns by default.
  6. Now you can visit https enabled site "https://json-server.localhost/"
    a. Add exception when the browser suggests an invalid certificate because of the certificate being self-signed.

Hope this helps.

@typicode - Could these steps be added as a complete guide for setting up json-server and hotel to provide https. It wasn't clear at first and this could save a lot of time. Thanks!

I do use a custom server.js

Create your cert

openssl req -nodes -new -x509 -keyout server.key -out server.cert
// https-json-server.js
import jsonServer from 'json-server';
import https from 'https';
import path from 'path';
import fs from 'fs';

const server = jsonServer.create();

const keyFile = path.join(__dirname, 'server.key');
const certFile = path.join(__dirname, 'server.cert');

https
  .createServer(
    {
      key: fs.readFileSync(keyFile),
      cert: fs.readFileSync(certFile),
    },
    server
  )
  .listen(3000, () => {
    console.log(
      'Go to https://localhost:3000/'
    );
  });

And then start node https-json-server.js

Hi @luishdez, I don't have much js knowledge. I'm actually trying to migrate the https option to a docker container, but I can't make it work even with this js template you show.

Heres the file I created:

// https-json-server.js
import jsonServer from 'json-server';
import https from 'https';
import path from 'path';
import fs from 'fs';

const server = jsonServer.create();

const keyFile = path.join(/usr/src/app, 'server.key');
const certFile = path.join(/usr/src/app, 'server.cert');

https
  .createServer(
    {
      key: fs.readFileSync(keyFile),
      cert: fs.readFileSync(certFile),
    },
    server
  )
  .listen(3000, () => {
    console.log(
      'Go to https://localhost:3000/'
    );
  });

I ran

npm install -g json-server

then

node https-json-server.js

it gives me this error:

MAC:node_modules galiad$ cd json-server/
MAC:json-server galiad$ node https-json-server.js 
(node:57757) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
/usr/local/lib/node_modules/json-server/https-json-server.js:2
import jsonServer from 'json-server';
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at wrapSafe (internal/modules/cjs/loader.js:1060:16)
    at Module._compile (internal/modules/cjs/loader.js:1108:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1164:10)
    at Module.load (internal/modules/cjs/loader.js:993:32)
    at Function.Module._load (internal/modules/cjs/loader.js:892:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)
    at internal/main/run_main_module.js:17:47

Do you have any clues or a more detailed step how to run this?

The '__dirname' is the directory to my docker folder and I copied the certificates before running the commands, but it doesn't even import the jsonServer from json-server.
I'm running node version 13.6.0

Thank you and sorry for my lack ok knowledge on this area.

@adrianogalindo Check npm install was executed in the Dockerfile, check Node version and see if supports ES6 (import) if not use Babel to compile first.

@adrianogalindo To fix the module issue, use require instead of import.

Here is the code I ended up using that works for me:

// https-json-server.js
// Run with: node https-json-server.js

// Generate SSL keys: openssl req -nodes -new -x509 -keyout server.key -out server.cert

const jsonServer = require("json-server");
const https = require("https");
const path = require("path");
const fs = require("fs");
const pause = require('connect-pause'); // Install: npm install connect-pause

const server = jsonServer.create();
const router = jsonServer.router('db.json');
const middlewares = jsonServer.defaults();

server.use(middlewares);

// To handle POST, PUT and PATCH you need to use a body-parser
// You can use the one used by JSON Server
server.use(jsonServer.bodyParser)
server.use((req, res, next) => {
  if (req.method === 'POST') {
    req.body.createdAt = Date.now()
  }
  // Continue to JSON Server router
  next()
})

server.use(pause(2000));
server.use(router);

// If using custom routes
//var routes = JSON.parse(fs.readFileSync('routes.json'));
//server.use(jsonServer.rewriter(routes));

const keyFile = path.join(__dirname, 'server.key');
const certFile = path.join(__dirname, 'server.cert');

https
  .createServer(
    {
      key: fs.readFileSync(keyFile),
      cert: fs.readFileSync(certFile),
    },
    server
  )
  .listen(3001, () => {
    console.log(
      'Go to https://localhost:3001/'
    );
  });

In Chrome, you can use url chrome://flags/#allow-insecure-localhost to allow insecure localhost.

@adrianogalindo To fix the module issue, use require instead of import.

Here is the code I ended up using that works for me:

// https-json-server.js
// Run with: node https-json-server.js

// Generate SSL keys: openssl req -nodes -new -x509 -keyout server.key -out server.cert

const jsonServer = require("json-server");
const https = require("https");
const path = require("path");
const fs = require("fs");
const pause = require('connect-pause'); // Install: npm install connect-pause

const server = jsonServer.create();
const router = jsonServer.router('db.json');
const middlewares = jsonServer.defaults();

server.use(middlewares);

// To handle POST, PUT and PATCH you need to use a body-parser
// You can use the one used by JSON Server
server.use(jsonServer.bodyParser)
server.use((req, res, next) => {
  if (req.method === 'POST') {
    req.body.createdAt = Date.now()
  }
  // Continue to JSON Server router
  next()
})

server.use(pause(2000));
server.use(router);

// If using custom routes
//var routes = JSON.parse(fs.readFileSync('routes.json'));
//server.use(jsonServer.rewriter(routes));

const keyFile = path.join(__dirname, 'server.key');
const certFile = path.join(__dirname, 'server.cert');

https
  .createServer(
    {
      key: fs.readFileSync(keyFile),
      cert: fs.readFileSync(certFile),
    },
    server
  )
  .listen(3001, () => {
    console.log(
      'Go to https://localhost:3001/'
    );
  });

How to expose it to with --host option? I mean external IP?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

goldmont picture goldmont  路  3Comments

casvil picture casvil  路  4Comments

TXRRNT picture TXRRNT  路  4Comments

shikaan picture shikaan  路  3Comments

ashleydavis picture ashleydavis  路  3Comments