No access to https through a new port

SYSTEM INFORMATION
OS type and version Rocky Linux 8.6
Webmin version 2.105
Virtualmin version 7.10.0
Related packages Python

Hello. I have a Linux server with 5 virtual servers, each with an SSL certificate installed. In one of them I have installed a private Python environment and installed an Angular web application. I have added to the FirewallD the port that the application asks for (9000), I have modified the application sources and compiled, and started the server with “gunicorn” but when I try to access it, I cannot do so through https:/ /111.222.333.444:9000 Only through http. How can i fix this? Thank you so much.

What error does your browser give and what errors are in your server logs? You did restart FirewallD?

Yes, I restarted the firewall.

After trying to connect for a while:
The connection has expired

An error occurred while connecting to 111.222.333.444:9000.

  •  The site may be temporarily unavailable or too busy. Please try again in a few moments.*
    
  •  If you cannot load any pages, check your computer's network connection.*
    
  •  If your computer or network is protected by a firewall or proxy, make sure Firefox has permission to access the web.*
    

What is the log that I should consult?

To test a port remotely, try:
curl 111.222.333.444:9000

Logs could be iffy on where to look depending on how far the request gets, so just try this first.

traceroute -p 9000 -T domain.tld

Also, does your provider have an upstream firewall?

I’m sorry, I don’t understand anything.

  • “Also, does your provider have an upstream firewall?” . . . ¿My provider? ¿What is an upstream firewall?

  • traceroute -p 9000 -T domain.tld:

traceroute: command not found

  • curl 111.222.333.444:9000 :
<!DOCTYPE html>
<html>
  <head>

    <title>MY API</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="icon" href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@latest/favicon-32x32.png">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@latest/swagger-ui.css">
    <style>
      html { box-sizing: border-box; overflow-y: scroll; }
      *, *:after, *:before { box-sizing: inherit; }
      body { background: #fafafa; margin: 0; }
    </style>

  </head>
  <body>

    <div id="swagger-ui"></div>
    <script src="https://cdn.jsdelivr.net/npm/swagger-ui-dist@latest/swagger-ui-bundle.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/swagger-ui-dist@latest/swagger-ui-standalone-preset.js"></script>

    <script>
    "use strict";

const swaggerSettings = {
  "deepLinking": true
};
const schemaAuthNames = [];
let schemaAuthFailed = false;
const plugins = [];

const reloadSchemaOnAuthChange = () => {
  return {
    statePlugins: {
      auth: {
        wrapActions: {
          authorize: (ori) => (...args) => {
            schemaAuthFailed = false;
            setTimeout(() => ui.specActions.download());
            return ori(...args);
          },
          logout: (ori) => (...args) => {
            schemaAuthFailed = false;
            setTimeout(() => ui.specActions.download());
            return ori(...args);
          },
        },
      },
    },
  };
};

if (schemaAuthNames.length > 0) {
  plugins.push(reloadSchemaOnAuthChange);
}

const uiInitialized = () => {
  try {
    ui;
    return true;
  } catch {
    return false;
  }
};

const isSchemaUrl = (url) => {
  if (!uiInitialized()) {
    return false;
  }
  return url === new URL(ui.getConfigs().url, document.baseURI).href;
};

const responseInterceptor = (response, ...args) => {
  if (!response.ok && isSchemaUrl(response.url)) {
    console.warn("schema request received '" + response.status + "'. disabling credentials for schema till logout.");
    if (!schemaAuthFailed) {
      // only retry once to prevent endless loop.
      schemaAuthFailed = true;
      setTimeout(() => ui.specActions.download());
    }
  }
  return response;
};

const injectAuthCredentials = (request) => {
  let authorized;
  if (uiInitialized()) {
    const state = ui.getState().get("auth").get("authorized");
    if (state !== undefined && Object.keys(state.toJS()).length !== 0) {
      authorized = state.toJS();
    }
  } else if (![undefined, "{}"].includes(localStorage.authorized)) {
    authorized = JSON.parse(localStorage.authorized);
  }
  if (authorized === undefined) {
    return;
  }
  for (const authName of schemaAuthNames) {
    const authDef = authorized[authName];
    if (authDef === undefined || authDef.schema === undefined) {
      continue;
    }
    if (authDef.schema.type === "http" && authDef.schema.scheme === "bearer") {
      request.headers["Authorization"] = "Bearer " + authDef.value;
      return;
    } else if (authDef.schema.type === "http" && authDef.schema.scheme === "basic") {
      request.headers["Authorization"] = "Basic " + btoa(authDef.value.username + ":" + authDef.value.password);
      return;
    } else if (authDef.schema.type === "apiKey" && authDef.schema.in === "header") {
      request.headers[authDef.schema.name] = authDef.value;
      return;
    } else if (authDef.schema.type === "oauth2" && authDef.token.token_type === "Bearer") {
      request.headers["Authorization"] = `Bearer ${authDef.token.access_token}`;
      return;
    }
  }
};

const requestInterceptor = (request, ...args) => {
  if (request.loadSpec && schemaAuthNames.length > 0 && !schemaAuthFailed) {
    try {
      injectAuthCredentials(request);
    } catch (e) {
      console.error("schema auth injection failed with error: ", e);
    }
  }
  // selectively omit adding headers to mitigate CORS issues.
  if (!["GET", undefined].includes(request.method) && request.credentials === "same-origin") {
    request.headers["X-CSRFTOKEN"] = "ewrger gregreg reg regre reg regre grere rererrere";
  }
  return request;
};

const ui = SwaggerUIBundle({
  url: "/schema/",
  dom_id: "#swagger-ui",
  presets: [SwaggerUIBundle.presets.apis],
  plugins,
  layout: "BaseLayout",
  requestInterceptor,
  responseInterceptor,
  ...swaggerSettings,
});

ui.initOAuth({});

    </script>


  </body>
</html>

It is a Linux command.

It seems curl worked? It pulled the page from port 9000. Are you using that port in your browser request or are you relying on some kind of redirect?

Looks like it needs installing, dnf install traceroute
There is tracepath.

http://111.222.333.444:9000 works
https://111.222.333.444:9000 doesn’t works

I have installed traceroute:

[] traceroute -p 9000 -T mydomain.com

traceroute to mydomain.com (111.222.333.444), 30 hops max, 60 byte packets
 1  myserver.eu (111.222.333.444)  0.014 ms  0.004 ms  0.003 ms

This is big mistake. There can only be one service per port. But https and http are two different services.

I just want it to work over https

Have your modifications to the original source caused the issue ? As this is not a webmin issue but an issue with the software you have installed a better course of action would be to reach out to the authors of the software you installed for a solution

No. The only address that the application takes is changing the destination URL (https://111.222.333.444:9000) in the settings. And it has been under the supervision of the manufacturer.

How you start gunicorn? With config file or only with commandline options?

With commandline options:

gunicorn --bind 0.0.0.0:9000 miapiwin.wsgi --workers 3 --daemon --timeout 5000

So you have to modify the source and recompile it to change a setting ? That sounds really old fashioned having hard coded settings, each to their own i guess. Using netstat or ss check to see what is actually listening on port 9000, it may give you a clue, but i would guess somewhere in the software you have installed there will be an option for it to listen in ssl mode rather than standard

And “–certfile=server.crt --keyfile=server.key” not need?

You don’t have TLS enabled on your server. It is not expected to be available via https, because it is not https.

You shouldn’t do it this way, anyway, in the general case. It’s recommended to run gunicorn (or any other app server) locally (either on a UNIX file socket or a local port) and proxy to it with your web server. That protects the app server from a variety of things and allows you to run everything on the usual web ports (80 and 443).

1 Like

Testing with https://www.ssllabs.com/, I get TLS 1.3 … YES.
Gunicorn is running in a private Python environment

Returning to this, I hope I have explained myself well:

I created a private Python environment, activated it, and ran:

python3 -m venv myfolder
source bin/activate

First I did a test:

python manage.py runserver

And this is the result:

(apiw-env) [myuser apiw-env]# python manage.py runserver
April 17, 2024 - 09:21:04
Django version 5.0.2, using settings 'apiwin4you.settings.development'
Starting development server at http://127.0.0.1:9000/
Quit the server with CONTROL-C.

Now I can access

http://111.222.333.444:9000

but I can’t access

https://111.222.333.444:9000

You wont access it via https as the server is running in http mode (as your screenshot shoows) you need to proxy to it or reach out to the developer to find out how to start the server with ssl enabled