Do SSL HTTPS requests on Localhost using a domain and SSL certificates pointing to your local environment.
https://<any subdomain>.backloop.dev/ → https://localhost/
Any subdomain of *.backloop.dev points to localhost!
Exception: backloop.dev, which points to a page where you can download the certificates.
backloop.dev solves mixed-content issues when developing a WebApp or Backend on local environment while accessing resources on remote HTTPS sources.
The issue is often raised by the same-origin policy mechanism that restricts the loading of resources from another origin unless this can be allowed by sending correct Cross-Origin Resource Sharing (CORS) headers.
Which anyway will fall back on the must-have "non-mixed-content" (no HTTP & HTTPS).
But making requests to HTTPS APIs from HTTP sites on localhost would not be possible without changing security options on your browser, which is why backloop.dev provides SSL certificates with a full loopback domain, to let anyone benefit from a signed certificate on localhost.
Certificates are not bundled with the npm package, but downloaded and updated from backloop.dev at installation and runtime, or manually with backloop.dev-update. To specify in which directory the certificates should be stored, set the environment variable BACKLOOP_DEV_CERTS_DIR.
If the certificates are outdated, they are checked and updated at boot.
npm install backloop.dev [-g]
Add -g to use backloop.dev and backloop.dev-proxy globally.
(Don't forget to prefix commands with npx if not installed globally.)
Serve the contents of a directory on https://whatever.backloop.dev:<port>/:
backloop.dev <path> [<port>]
Example:
backloop.dev ./dist 4443
# Server started on port 4443 serving files in './dist'
# Open https://myapp.backloop.dev:4443/Proxy requests from https://whatever.backloop.dev:<port>/ to a backend.
Supports http:// and https:// targets, with optional base path.
Note: adds x-forwarded-proto: https to headers for express-session and similar services.
backloop.dev-proxy <target> [<port>]
Where <target> can be:
http://host[:port][/path]https://host[:port][/path]host[:port](legacy format, defaults to http)
Examples:
# Proxy to a local dev server
backloop.dev-proxy localhost:3000
# Proxy to an https backend with a base path
backloop.dev-proxy https://localhost:8443/api 4443Serve multiple hostnames from a single instance, each with its own static files or proxy target:
backloop.dev --config=<config.json>
Config file format:
{
"port": 7654,
"hostnames": {
"app": { "path": "./dist" },
"api": { "proxy": "http://localhost:3000/v1" },
"admin": { "proxy": "https://anotherwebsite.com:8443" }
}
}This starts a single server on port 7654 where:
https://app.backloop.dev:7654/serves static files from./disthttps://api.backloop.dev:7654/proxies tohttp://localhost:3000/v1https://admin.backloop.dev:7654/proxies tohttps://anotherwebsite.com:8443
Paths are resolved relative to the config file location.
Path-based routing is also supported. Use hostname/path/ keys (trailing slash required) to route different URL prefixes to different handlers on the same hostname:
{
"port": 7654,
"hostnames": {
"tom/static/": { "path": "./public" },
"tom/": { "proxy": "http://localhost:3000" }
}
}Here https://tom.backloop.dev:7654/static/app.js serves ./public/app.js, while https://tom.backloop.dev:7654/api/users proxies to http://localhost:3000/api/users. The longest matching prefix wins.
Manually force update of the certificates:
backloop.dev-update
You can download the certificate files on backloop.dev for your own usage.
import httpsOptions from 'backloop.dev';
import https from 'https';
https.createServer(httpsOptions, (req, res) => {
res.writeHead(200);
res.end('hello world\n');
}).listen(8443);const https = require('https');
const httpsOptionsAsync = require('backloop.dev').httpsOptionsAsync;
httpsOptionsAsync(function (err, httpsOptions) {
https.createServer(httpsOptions, (req, res) => {
res.writeHead(200);
res.end('hello world\n');
}).listen(8443);
});Or with promises:
const https = require('https');
const httpsOptionsPromise = require('backloop.dev').httpsOptionsPromise;
(async () => {
const httpsOptions = await httpsOptionsPromise();
https.createServer(httpsOptions, (req, res) => {
res.writeHead(200);
res.end('hello world\n');
}).listen(8443);
})();The following is not recommended as it will crash your app if the certificates are expired. It will however refresh them for your next boot ;).
const https = require('https');
const options = require('backloop.dev').httpsOptions();
https.createServer(options, (req, res) => {
res.writeHead(200);
res.end('hello world\n');
}).listen(8443);const https = require('https');
const httpsOptionsAsync = require('backloop.dev').httpsOptionsAsync;
const express = require('express');
const app = express();
// ...your code...
httpsOptionsAsync(function (err, httpsOptions) {
https.createServer(httpsOptions, app).listen(8443);
});// consider `await require('backloop.dev').httpsOptionsPromise()`
const backloopHttpsOptions = require('backloop.dev').httpsOptions();
backloopHttpsOptions.https = true;
backloopHttpsOptions.host = 'whatever.backloop.dev';
module.exports = {
// ...your options...
devServer: backloopHttpsOptions
};Now vue-cli-service serve will be served on https://whatever.backloop.dev
File: vite.config.js
import { defineConfig } from 'vite';
import backloopHttpsOptions from 'backloop.dev';
export default defineConfig({
server: {
port: 4443,
host: 'whatever.backloop.dev',
https: backloopHttpsOptions
},
// ... //
});Now npm run dev will be served on https://whatever.backloop.dev
There is also a ViteJS plugin that does the same: vite-plugin-backloop.dev.
What if *.backloop.dev DNS A and AAAA entries are not pointing to 127.0.0.1 and ::1 but to another IP (malicious ones)?
Then your HTTPS requests will not end up on your machine, but on these malicious servers.
Even if this is very unlikely to happen, you may want to be on the safe side by adding <what you need>.backloop.dev in your /etc/hosts file.
127.0.0.1 localhost whatever.backloop.dev ...
::1 localhost whatever.backloop.dev ...
npm test
Uses Node.js built-in test runner (requires Node.js 18+).
npm run lint lints the code with neostandard.
Pull requests are welcome.
The code to generate, publish and renew the certificates is here on github