Standalone deployment tutorial

@Derk: We are very interested on your pdf tutorial. How can we get it? It is possible to post it here.

I think there is also a need for more detailed tutorials for deployment of Xojo web apps. For example we are very interesting to know how Xojo is running in Microsoft environments, because many of our customers only want to install web apps on a windows server with MS SQL.
Also we need more infos how to create standalone apps. We found only a very small description in the Xojo tutorials. I hope Xojo is working on it and in future we will get more step by step tuturials.

Thanks in advance!

If you are using Windows, build a Standalone app using 2013r1 or newer and run it as a service. You’ll have much more luck that way.

We tried it with the follow description, we found:

A Standalone web application is an application that you manually
run on your server. You have to start the application (usually from
the command line) and leave it running in order for people to
access the web app. In addition, a Standalone web application is
accessed through a port, which you specify when building the
app. Essentially, a standalone web application consists of both
the web server and your web application.
Standalone web apps also take advantage of WebSockets, a
feature that improves the performance of web applications by
providing a faster bi-directional communications channel.
A deployed standalone web app would be accessed with a URL
such as this:
http://www.mywebsite.com:8080

It didn’t work. We tested it with the following address: localhost:8080

Is there any more documentation? How can we determine the port? Is the generated executable file the file for a standalone app? Are there any possibilities to configure or monitor a standalone webapp? How to start it as window service?

There are several command-line options for overriding standalone apps:

  • –port=8080 lets you set the listening port
  • –SecurePort=8081 lets you set the secure listening port (for SSL, must be different than port)
  • –logging turns on apache style logging
  • –MaxSockets=200 lets you determine the maximum number of non-secure sockets
  • –MaxSecureSockets=200 lets you determine the maximum number of secure sockets (–secureport must be set)

As for Windows services, there are several programs out there for converting an app into a service, but my suggestion is to use an installer which sets up the service for you. Most of the Windows compatible installer creation apps will do this, including InnoSetup and AdvancedInstaller.

I found it now. I found the compiler settings in the left navigation bar, not in “settings” in the menu bar.
I choosed port 9000 and now it works.

With the Check in the backend of the HAproxy.cfg a new session is started every 2000ms,
which with the timeout settings I use, is giving me about 30 sessions per node even when I have no clients using the web app.
Should I add an “inter” parameter somewhere, or quit the session in HandleURL?
It seems not smart to have 30 sessions per node running by default.

You should be able to setup a check url that goes to the api url in xojo so that no session is started. You could also add some logic in the xojo side as well that could implement some sort of limiting algorithm. Say you have measured an app instance as handling 100 sessions. In your xojo code you could fail the check if you have 100 sessions and haproxy wouldn’t send any more connections to that instance.

There are downsides to this approach as well, but it seems like something that might be useful in high load applications.

[quote=208367:@Boudewijn Krijger]With the Check in the backend of the HAproxy.cfg a new session is started every 2000ms,
which with the timeout settings I use, is giving me about 30 sessions per node even when I have no clients using the web app.
Should I add an “inter” parameter somewhere, or quit the session in HandleURL?
It seems not smart to have 30 sessions per node running by default.[/quote]

You don’t need to use ‘option httpchk’ in the backend. If you leave it out HAproxy will do a TCP check that will not spawn a session but can still detect an app that has completely crashed. I have been using it this way for quite some time and it is working great. I use the following in my backend config:

backend myApp
        server node1 127.0.0.1:10001 check inter 3000 rise 2 fall 5
        server node2 127.0.0.1:10002 check inter 3000 rise 2 fall 5
        server node3 127.0.0.1:10003 check inter 3000 rise 2 fall 5

If you really want to check http, you can give that command a URL 'option httpchk ’ and you can point it to an address you catch with HandleSpecialURL and return whatever you want, as Kevin has stated above. A 2xx or 3xx response is considered OK by HAproxy.

@John Joyce : did you ever complete the tutorial you were talking about back in 2013? [I am also originally from Cleveland, if that gives you any incentive to answer]

@Charles Weger

Well - I wrote a couple of blog posts and have contribute to several discussions on this forum. I didn’t ever make a complete tutorial because the few with interest seemed to find that enough or just ask me the occasional question directly.

You can read my post on ha proxy here:
http://john-joyce.com/xojo-and-load-balancing-with-haproxy/

I am currently running a system similar to this post on haproxy 1.5 - works great!

If you have a question just ask - I will help if I can, or someone else will :slight_smile:

John

[quote=218546:@John Joyce]<…>
You can read my post on ha proxy here:
http://john-joyce.com/xojo-and-load-balancing-with-haproxy/
<…>[/quote]

I followed your tutorial and it did work great so far.

Now I would like to do a similar thing with an SSL encrypted connection.

I have a test-webapp running unencrypted here:
http://lic.seminar.pro:9100

I would like to loadbalance it behind the haproxy
https://lic.seminar.pro:9101 (and more instances on more ports)

What would I have to add here, in order to allow this ssl connection?

My config file looks like this now:

[code]global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin
stats timeout 30s
user haproxy
group haproxy
daemon

# Default SSL material locations
ca-base /etc/ssl/certs
crt-base /etc/ssl/private

# Default ciphers to use on SSL-enabled listening sockets.
# For more information, see ciphers(1SSL). This list is from:
#  https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS
ssl-default-bind-options no-sslv3

defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http

frontend http-in
bind *:80
acl is_myapp1 hdr_end(host) -i www.verifier.ch
acl is_myapp1 hdr_end(host) -i verifier.ch
use_backend myapp1pool if is_myapp1
default_backend myapp1pool

backend myapp1pool
option httpchk OPTIONS /
option forwardfor
option http-server-close
cookie serverid insert indirect nocache
server node1 127.0.0.1:9000 check cookie node1
server node2 127.0.0.1:9010 check cookie node2
server node3 127.0.0.1:9020 check cookie node3
[/code]

I posted a link here that might be helpful for you Oliver.
https://forum.xojo.com/10913-load-balancing-web-standalone/p2#p167070

It is pretty easy to get HAproxy to be your SSL termination point. The main thing you have to change is the bind directive in the frontend. If you want both SSL and non-SSL connections that function the same, duplicate your front-end and bind it to :443 instead of :80 with the SSL cert like this

bind *:443 ssl crt /etc/ssl/private/example.com.pem
alternatively, if you want to ONLY accept SSL then you can just change the front-end above.

One thing that SSL complicates is ACLs - which control your routing. Since the data comes in encrypted HAproxy has to decrypt it before it can read it to apply the ACL. That is handled a little differently, like this:

use_backend somebackend if { ssl_fc_sni host.domain.com }

So a tweaked version of your complete frontend might look like this:


frontend http-in
        bind *:443  ssl crt /etc/ssl/private/example.com.pem
        use_backend myapp1pool if { ssl_fc_sni www.verifier.ch }
        use_backend myapp1pool if { ssl_fc_sni verifier.ch }
        default_backend myapp1pool

Note that all your configurations above point to the same backend. If it is your default, you don’t need any of the backend rules and you can just go with the default line. If you plan on actually routing things by domain you will need the SNI lines. So a simplified frontend without domain routing could be as little as this:


frontend http-in
        bind *:443  ssl crt /etc/ssl/private/example.com.pem
        default_backend myapp1pool

HAproxy has a lot of configuration power over the types of cyphers you will accept and forcing the SSL to higher levels, etc… These are great for mitigating some of the SSL downgrade vulnerabilities and hardening the SSL.

Good link @Albin Kiland - this one is also very informative https://serversforhackers.com/using-ssl-certificates-with-haproxy

Thank you guys, your help is very much appreciated!

@Oliver Osswald - You’re welcome. Let me know if anything doesn’t make sense or if you run into issues.

You might want to allow any and every cypher format with SSL until you are sure it is working (comment out your “ssl-default” directives). This can be problematic sometimes. I did a web service implementation with a client that was java based and the ssl cypher compatibility was a pain to troubleshoot. With regular/modern browsers, I doubt you will run into any problems but I would comment it out to start with and add it last.

Good luck.
J

So far it seems to work as I wish except for the remote IP address.

In Xojo I use Session.RemoteAddress to retrieve the IP address of the visitor.

In haproxy.cfg I have such a backend defined:

backend license_app option httpchk OPTIONS / option forwardfor option http-server-close cookie serverid insert indirect nocache balance leastconn server node1 127.0.0.1:9100 check cookie node1 server node2 127.0.0.1:9200 check cookie node2 server node3 127.0.0.1:9300 check cookie node3

But as soon as I use haproxy, then I no longer get an IP address from Session.RemoteAddress

Somewhere I read that behind a haproxy, for instance Apache logs need to look for X-Forwarded-For in order to report the correct IP address behind a haproxy.

How do I get the originial IP address of the visitor behind a haproxy? I need it for geolocation.

Any ideas? Thanks!

[quote=253243:@Oliver Osswald]<…>
In Xojo I use Session.RemoteAddress to retrieve the IP address of the visitor.<…>
[/quote]
I found this thread with a solution by Tobias Bussmann. Works fine for me, from behind the haproxy!
https://forum.xojo.com/15490-reverse-proxy-ip-and-ssl/p1#p128020

Sorry, I did not notice your post @Oliver Osswald but I am glad you found the solution.
J