Standalone app listening on multiple ports?

I know we can configure the two ports (one secure and one non-secure) that the app listens on for connections–it can be done in the IDE and also in the App’s Open event…

…but is there any way to listen on more than one secure port and/or more than one non-secure port?

Also, can the port(s) be changed programmatically after the app has launched and the Open event has already finished?

I’ve thought about these questions before, but don’t think I’ve ever asked about it online (and didn’t find anything with a quick search), so apologies if this has been asked before…

Not with Xojo Web. You don’t have underlying access to the ServerSocket that Xojo Web uses to serve.

You could in theory add your own ServerSocket and proxy any ports to your built-in Xojo Web ports however.

Another option might be to use something like NGINX configured as a reverse proxy to your Xojo Web app. You could then route traffic coming in on multiple ports, domain names, etc to a single instance of your app. You can also configure NGINX to handle the certificates.

Here’s documentation on how to set up NGINX as a proxy server:
https://www.nginx.com/resources/admin-guide/reverse-proxy/

And here’s some info on configuring the SSL termination:
https://www.nginx.com/resources/admin-guide/nginx-ssl-termination/

  • Tim

I use multiple instances of a webapp and each runs on its own port. In front of it i use a HAProxy loadbalancer which distributes the incoming requests to them.

This is the right way to do this (doesn’t have to be HAProxy, you could use Apache or Nginx as well). Otherwise you’d have to spin up another ServerSocket within the app and you’re stuck with the same scenario you have now… a battle for resources.

what do we need to do with nginx in order to use multiple port etc?

if someone that has done with with Xojo Standalone apps could write up a “how to”, I know many people would be appreciative to it.

for some of us it would just be educational. for others it would be useful for what we are doing.

Maybe it should have been a separate post, but what about the other question: Changing the port(s) after the app.open event has already completed?

You can’t. The ServerSocket is already up and accepting connections at that point. Your best bet would be to write the new port to a config file and restart the app.

I tried nginx back in 2012 and it worked about 95% of the time. However, there were issues with some connections due to the way it handled (or didnt handle ) “sticky sessions”. After changing to HA Proxy, everything has been smooth. Just out of curiosity, does nginx work as a reverse proxy “properly” for xojo?

Here is a tutorial for HA Proxy: http://john-joyce.com/xojo-and-load-balancing-with-haproxy/

Link seems to be broken.

http://john-joyce.com/xojo-and-load-balancing-with-haproxy/

[quote=348971:@Seth Ober]I know we can configure the two ports (one secure and one non-secure) that the app listens on for connections–it can be done in the IDE and also in the App’s Open event…

…but is there any way to listen on more than one secure port and/or more than one non-secure port?

Also, can the port(s) be changed programmatically after the app has launched and the Open event has already finished?

I’ve thought about these questions before, but don’t think I’ve ever asked about it online (and didn’t find anything with a quick search), so apologies if this has been asked before…[/quote]

Not sure if I am totally understanding the intent of the OP - but, following the proxy approach: You can set up HAproxy to listen on whatever ports you want using multiple ‘bind’ commands in the front end. They can all be grouped together and routed to the same back-end (which can be one or more xojo apps or even different physical servers) or they can be routed to different backends using the port the request was received on using the “dst_port” ACL filter. You could also rewrite a HAproxy config file and restart HAproxy when you want to change the configuration.

Abbreviated example:


frontend http-in
        bind *:8081
        bind *:8082
        acl is_myapp1 dst_port 8081
        acl is_myapp2 dst_port 8082
        use_backend myapp1pool if is_myapp1
        use_backend myapp2pool if is_myapp2

backend myapp1pool
        ...

backend myapp2pool
        ...

I’ve been using Docker a lot recently which gives you a lot of flexibility, such as being able to spin up the same app image as multiple containers with different local ports mapped to the same internal app ports.

Currently playing with Rancher as orchestration for a stack of services (bundle of services/apps that work together), includes stacks for load balancing etc. So far, very impressed.

@Richard Duke / @scott boss :

If there’s enough interest, then perhaps we could give a presentation on NGINX as part of a future VXUG meeting. In the meantime, here’s a quick overview…

Let’s suppose that you’re running your Xojo standalone Web app on the server using port 64000, like this:

./my-xojo-app --port=64000 &

And suppose that you want the app to be available externally via ports 8081 and 8082. In your NGINX config file, you could setup a server block like this:

server { listen 8081; listen 8082; location / { proxy_pass http://127.0.0.1:64000; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; proxy_pass_request_headers on; } }

This tells NGINX to listen for requests on ports 8081 and 8082, and pass them to http://127.0.0.1:64000, along with the host info, any HTTP headers that were specified, and the remote IP address (as a header named “X-Forwarded-For”).

So that single instance of the Xojo Web app, which internally is listening on port 64000, will be available externally on ports 8081 and 8082. You could, of course, configure NGINX to listen on additional ports if you’d like, as well as host names.

Another nice feature of NGINX is that you can have it handle redirects from http to https, and SSL termination as well. For example…

[code]server {
server_name my-domain-name.com;
listen 80;
return 301 https://$server_name$request_uri;
}

server {
server_name my-domain-name.com;
listen 443 ssl;
ssl_certificate /home/ec2-user/meh/certificate/chained.my-domain-name.com.crt;
ssl_certificate_key /home/ec2-user/meh/certificate/my-domain-name.com.key;
location / {
proxy_pass http://127.0.0.1:64010;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_pass_request_headers on;
}
}[/code]

The first server block tells NGINX to listen for requests for my-domain-name.com on port 80, and returns a 301 response, indicating that the client should send the request to the secure URL instead.

The second server block tells NGINX to listen for requests for my-domain-name.com on port 443. It also specifies the SSL certificate and key files. And it passes the request to an app listening internally on port 64010.

There’s a lot more that NGINX can do, but I think this covers some of the more commonly used features - and things that Xojo developers might be interested in.

Anyway, I hope this helps. And if you are interested in learning more, let me know.

  • Tim

Thanks all–lots of good information here from a variety of different angles!

@Ian Jones …would you mind showing what a typical Docker file might look like for a standalone webapp? Thanks!

Here’s one I use @David Swenson …

[code]FROM debian:jessie

MAINTAINER Byte Pixie hello@bytepixie.com

RUN apt-get update \
#
# Install dependencies and curl (for geting release).
&& apt-get install -y --no-install-recommends \
libglib2.0-0 \
libicu52 \
ca-certificates \
libssl1.0.0 \
logrotate \
curl \
#
# Install dumb-init (to handle PID 1 correctly).
# https://github.com/Yelp/dumb-init
&& curl -L https://github.com/Yelp/dumb-init/releases/download/v1.1.3/dumb-init_1.1.3_amd64.deb -o /tmp/dumb-init.deb \
&& dpkg -i /tmp/dumb-init.deb \
#
# Clean up temp stuff.
&& apt-get purge --auto-remove -y \
curl \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/*

Open up ports

EXPOSE 80 443 8080 8888

Set up built Xojo app (standalone web app).

VOLUME /opt/app/

Comment out during development and mount on volume instead for quick feedback loop.

COPY [“Builds - gm-admin.xojo_project/Linux 64 bit/gm-admin/”,"/opt/app/"]

Use dumb-init to make sure app is not running as PID 1.

ENTRYPOINT [“dumb-init”]
CMD ["/opt/app/gm-admin"][/code]

@Ian Jones … thanks very much…that was just the help I needed to get Docker working with my app.

I’m using ubuntu, so in case this helps anyone else, here’s the Dockerfile I got to work:

[code]FROM ubuntu:zesty

RUN apt-get update \
#
# Install dependencies.
&& apt-get install -y --no-install-recommends \
libglib2.0-0

Create app directory

WORKDIR /usr/src/[/code](my working dir)[code]

#copy build files to docker container folder
COPY ["./(dir with build)/","/usr/src/[/code](my working dir)[code]/"]

#port build listens on
EXPOSE 9090

#make standalone app executable
RUN [“chmod”,"+x","/usr/src/[/code](my working dir)/(my executable)"]

CMD ["/usr/src/

The latest version of Docker supports the --init flag (which reportedly addresses the PID 1 problem)

i.e.:

 sudo docker run --init -d -p  [/code] [i](external port)[/i][code]:9090

Other tips that helped me:

sudo docker exec -it (containerID)  /bin/bash

dropped me into the shell of the container, where I could run ps and nmap to confirm my webapp was running and on what port (turns out i had an old copy of the build that wasn’t running on the port I expected it on…wasted a few hours on that problem)

Also removed the “Call Daemonize” line from the open event of the App

Thanks again Ian, I’m a noob to xojo web and even noobier on docker.