Setup HTTPS on localhost

Many of us are encountering issues with ERR_CLEARTEXT_NOT_PERMITTED when working with Android locally. This request is to enable SSL on the local servers we use, so we do not have to find workarounds to develop our Android apps locally.

Good point indeed, we will investigate if we can also run the local servers with https @patrick

3 Likes

Which server are you referring to, is it Server Connect or the Live Web Server of Wappler for previews?

I think for most of us it’s running an API server/project for development with our app/mobile project, so the Server Connect server.

I’m running docker/node.js for my API server and Capacitor for the desktop/mobile project.
image

1 Like

@George,
May I suggest that one of your team builds a web app, using Capacitor, Security Provider, F7 etc and try running on iOS android etc.

It doesn’t need to be anything complex but I think it would be a good exercise to see how mobile app building is not quite full-developed yet.

5 Likes

Good idea. And even if it doesn’t end up it in direct fixes/changes, it could help to give some guidance / a short tutorial for those who looking for solutions.

3 Likes

The only way to get ssl on localhost is to use a self-signed certificate, not sure if android webview will trust that.

You can experiment with a ssl proxy, that way you can test if serf-signed certificates would work and we can look for a way to implement it.

1 Like

Are you regering specifically to the security provider and login to external api site? As those are indeed tricky due to special cookies expiration and credentials handling on mobile.

As for just simple f7 mobile apps, we do those all the time to test f7 and capacitor on Mac and android as well.

Or do you means something else in particular?

1 Like

I mean building a mobile app, using a web Wappler project as the source for security provider etc. I think there’s potential for the process to be made smoother in Wappler. Not just for running in a browser, but in IOS simulator or Android

2 Likes

mkcert seems like a relatively easy option, but I’m not sure I’m setting it up properly in server.js because testing with one of my server APIs (e.g. https://localhost/api/v1/activities) is not working.

https://web.dev/how-to-use-local-https/

Details for node npm version

Is the https.createServer correct? Not sure since I’m not setting it as a const like you’re doing for http.

if (process.env.NODE_ENV !== 'production') {
    require('dotenv').config();
}

process.on('uncaughtException', (e) => {
    // prevent errors from killing the server and just log them
    console.error(e);
});

const config = require('./setup/config');
const debug = require('debug')('server-connect:server');
const redis = require('./setup/redis');
const routes = require('./setup/routes');
const sockets = require('./setup/sockets');
const upload = require('./setup/upload');
const cron = require('./setup/cron');
const http = require('http');
//added for wappler https test
const https = require('https');
const fs = require('fs');
const options = {
  key: fs.readFileSync('./app/cert.key'),
  cert: fs.readFileSync('./app/cert.crt'),
};
// end adds for wappler https test
const express = require('express');
const endmw = require('express-end');
const cookieParser = require('cookie-parser');
const session = require('./setup/session'); //require('express-session')(Object.assign({ secret: config.secret }, config.session));
const cors = require('cors');
const app = express();

app.set('trust proxy', true);
app.set('view engine', 'ejs');
app.set('view options', { root: 'views', async: true });

app.disable('x-powered-by')

if (config.compression) {
    const compression = require('compression');
    app.use(compression());
}

if (config.abortOnDisconnect) {
    app.use((req, res, next) => {
        req.isDisconnected = false;
        req.on('close', () => {
            req.isDisconnected = true;
        });

        next();
    });
}

app.use(cors(config.cors));
app.use(express.static('public', config.static));
app.use(express.urlencoded({ extended: true }));
app.use(express.json({
    verify: (req, res, buf) => {
        req.rawBody = buf.toString()
    }
}));
app.use(cookieParser(config.secret));
app.use(session);
app.use(endmw);

upload(app);
routes(app);

const server = http.createServer(app);
const io = sockets(server, session);

//added for wappler https test
https.createServer(options, app).listen(443);
// end add for wappler https test

// Make sockets global available
global.io = io;

module.exports = {
    server, app, io,
    start: function(port) {
        // We add the 404 and 500 routes as last
        app.use((req, res) => {
            res.status(404).json({
                status: '404',
                message: `${req.url} not found.`
            });
        });
        
        app.use((err, req, res, next) => {
            debug(`Got error? %O`, err);
            res.status(500).json({
                status: '500',
                code: config.debug ? err.code : undefined,
                message: config.debug ? err.message || err : 'A server error occured, to see the error enable the DEBUG flag.',
                stack: config.debug ? err.stack : undefined,
            });
        });
        
        cron.start();

        server.listen(port || config.port, () => {
            console.log(`App listening at http://localhost:${config.port}`);
        });
    }
};

super agree with this suggestion!

Not sure if helpful for you, but I’m using a CF Argo Tunnel for local development if I need a real-world SSL cert or receive webhooks on a static endpoint. It’s better than ngrok as well since you don’t need to pay for a static custom URL as long as you bring your own domain. https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/tunnel-guide/local/

1 Like

Or use ngrok for tunnelling?

(Doesn’t Wappler comes with ngrok internally?)

1 Like

How would we connect that to Android/iOS/Electron apps?

ngrok runs on your machine and creates a tunel for your localhost and exposes your local API server via a ngrok: url (http and https) to the public (reverse proxy). You use this URL in your app to access the server. Like a production app would do.

e.g.
ngrok http 65442 exposes your Wappler web service, running on localhost and port 65442, you can access now via https://84c5df439d74.ngrok.io (example).

Like the port number on Wappler, the subdomain on ngrok changes with each launch, except you have a paid product, where you can “reserve” subdomains or name them.

But how do we set that up in the Android app when clicking “Run on Connected Device or Emulate”?

image

I think I have misunderstood your requirement.
The app uses a url to connect to the API, instead of http://localhost:<port> the https:-URL from ngrok should be used. But as I said, I might have misunderstood you.

We have a local API server project running on node/express at http://localhost:8100. This is what you’re saying ngrok can be setup on.

We also have another project for the mobile app we’re developing that connects to the API server project for various actions (authentication, GET and POST requests, etc.). When you emulate the mobile app it’s trying to connect to http://localhost:8100 for all of the server actions.

So how could we easily change all server actions from localhost:port to ngrok:port?