Running webserver by the side of Seatable enterprise

Hi everyone,
In addition to my last post, I encounter another problem while setting my own Enterprise Edition up : I’d like to run a webserver (actually a python tornado server) by the side of my Seatable Enterprise installation.
I started by installing Seatable and everything is ok (except the problem presented in my last post), but I can’t access to my webpage, wathever port I ask tornado to listen to. I’m gessing I missed something in the Seatable’s nginx configuration, but this is pretty unintelligible to me…
Do you have any idea on how to set this up ?
Thanks a lot !

Bests,
Benjamin

Here are some clarifications, just in case :
Here is a minimal version of the Tornado’s server.py file to see the configuration (the only notable thing is the port : 8443, and the mapping)

#! /usr/bin/python
import os.path
import tornado.httpserver
import tornado.websocket
import tornado.ioloop
import tornado.web
import asyncio
from tornado_request_mapping import request_mapping, Route

####### Serveur Tornado #######
PORT = 8443
settings = dict(
    template_path = os.path.join(os.path.dirname(__file__), "templates"),
    static_path = os.path.join(os.path.dirname(__file__), "static")
    )    

@request_mapping("/products")
class PainMainHandler(tornado.web.RequestHandler):
    @request_mapping("/order.html")
    def get(self):
        print("[HTTP](MainHandler) User Connected.")
        self.render("products/order.html")

@request_mapping("/ws")
class PainWSHandler(tornado.websocket.WebSocketHandler):
    def open(self):
        print('[WS] Connection was opened.')
 
    async def on_message(self, message):
        print('[WS] Incoming message:', message)

    def on_close(self):
        print('[WS] Connection was closed.')

if __name__ == "__main__":
    try:
        application = tornado.web.Application(**settings)
        route = Route(application)
        route.register(PainMainHandler)
        route.register(PainWSHandler)
        http_server = tornado.httpserver.HTTPServer(application)
        http_server.listen(PORT)
        main_loop = tornado.ioloop.IOLoop.instance()

        print("Tornado Server started")
        main_loop.start()
    
    except:
        print("Exception triggered - Tornado Server stopped.")

Trying this locally, everything works fine (I see the content of my order.html page using the address http://localhost:8443/products/order.html).

I then uploaded these files on my VPS to run the tornado’s webserver by the side of the nginx server from the Seatable Docker image but whatever I tried in the nginx.conf of the Seatable Docker image, I’m still getting an error (400 or 414 or 512 or the custom 404 page from Seatable).
Here is a part of the nginx.conf file provided by Seatable :

server {
    if ($host = myserver.vps.ovh.net) {
        return 301 https://$host$request_uri;
    }
    listen 80;
    server_name myserver.vps.ovh.net;
    return 404;
}

server {
    server_name myserver.vps.ovh.net;
    listen 443 ssl;

    ssl_certificate /shared/ssl/fullchain.pem;
    ssl_certificate_key /shared/ssl/privkey.pem;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    # for letsencrypt
    location /.well-known/acme-challenge/ {
        alias /var/www/challenges/;
        try_files $uri =404;
    }

    proxy_set_header X-Forwarded-For $remote_addr;

    location / {
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
        add_header Access-Control-Allow-Headers "deviceType,token, authorization, content-type";
        if ($request_method = 'OPTIONS') {
            add_header Access-Control-Allow-Origin *;
            add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
            add_header Access-Control-Allow-Headers "deviceType,token, authorization, content-type";
            return 204;
        }
        proxy_pass         http://127.0.0.1:8000;
        proxy_set_header   Host $host;
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header   X-Forwarded-Host $server_name;
        proxy_read_timeout  1200s;

        # used for view/edit office file via Office Online Server
        client_max_body_size 0;

        access_log      /opt/nginx-logs/dtable-web.access.log seatableformat;
        error_log       /opt/nginx-logs/dtable-web.error.log;
    }

I tried adding a new server configuration like

server {
        listen 8443;
        server_name myserver.vps.ovh.net;
        location /pain {
                proxy_pass      http://127.0.0.1:8443/products/order.html;
                proxy_redirect  off;
                access_log      /opt/nginx-logs/products.access.log;
                error_log       /opt/nginx-logs/products.error.log;
        }
}

with proxy_pass http://127.0.0.1:8443/products/order.html; or proxy_pass http://127.0.0.1:8443/;
I also tried to add a new location in the second server configuration like

server {
    server_name myserver.vps.ovh.net;
    listen 443 ssl;
    listen 8443;

    ssl_certificate /shared/ssl/fullchain.pem;
    ssl_certificate_key /shared/ssl/privkey.pem;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    # for letsencrypt
    location /.well-known/acme-challenge/ {
        alias /var/www/challenges/;
        try_files $uri =404;
    }

    proxy_set_header X-Forwarded-For $remote_addr;

    location / {
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
        add_header Access-Control-Allow-Headers "deviceType,token, authorization, content-type";
        if ($request_method = 'OPTIONS') {
            add_header Access-Control-Allow-Origin *;
            add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
            add_header Access-Control-Allow-Headers "deviceType,token, authorization, content-type";
            return 204;
        }
        proxy_pass         http://127.0.0.1:8000;
        proxy_set_header   Host $host;
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header   X-Forwarded-Host $server_name;
        proxy_read_timeout  1200s;

        # used for view/edit office file via Office Online Server
        client_max_body_size 0;

        access_log      /opt/nginx-logs/dtable-web.access.log seatableformat;
        error_log       /opt/nginx-logs/dtable-web.error.log;
    }
    location /products {
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
        add_header Access-Control-Allow-Headers "deviceType,token, authorization, content-type";
        if ($request_method = 'OPTIONS') {
            add_header Access-Control-Allow-Origin *;
            add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
            add_header Access-Control-Allow-Headers "deviceType,token, authorization, content-type";
            return 204;
        }
        proxy_pass         http://127.0.0.1:8443/products/order.html;
        proxy_set_header   Host $host;
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header   X-Forwarded-Host $server_name;
        proxy_read_timeout  1200s;

        # used for view/edit office file via Office Online Server
        client_max_body_size 0;

        access_log      /opt/nginx-logs/products.access.log;
        error_log       /opt/nginx-logs/products.error.log;
    }

with the same two proxy_pass variants as before, but nothing worked. I’m sure I miss something…
By the way, I can’t write an http block in the nginx.conf file from Seatable, I get an error :frowning:

Thanks a lot,

Benjamin

Hi everyone,
Just in case someone encounter the same problem, I finally found a (not completely satisfying) solution : just adding a new location in my current server block listening to 443 ssl :

location /products {
      proxy_pass https://127.0.0.1:8443/;
      proxy_redirect off;
      proxy_set_header Host $host;
      access_log    /opt/nginx-logs/products.access.log;
      error_log     /opt/nginx-logs/products.error.log;
}

I can then access my order.html page at the address myserver.vps.ovh.net:8443/products/order.html
I’d rather not need the port number in the URL, but at least, it’s working !

Sorry, a bit too fast : this solution was OK for version 4.2, but is not working anymore for version 4.3… :expressionless:

Hey Ben,
this topic is not that easy because you are touching many topics. Let me get you some basics.

  • a port can only be assigned to one application. You can not tell nginx to listen to port 8443 and then route to the port 8443. That will not work.
  • Webservers can be chained. With the new technic in 4.3 you first have caddy, then you have nginx. If you set something up in nginx, it must match also in caddy.
  • Even if the ports match, you have to make sure that the networks (host/docker/…) is correct. I mean 127.0.0.1 is not necessarly the same for the host and a docker container…

Now back to your problem:

  • you have a custom application running at port 8443. This is totally fine. Is this application running in the host system or inside a docker container?
  • now you have multiple options how to reach this application:
    • other url → proxy to 8443
    • other port → proxy to 8443
    • subfolder → proxy to 8443 (this is typically not working, because applications expect to be at the root level)
  • which webserver should do the proxying. Caddy at the beginning or nginx inside seatable?

For sure we will find a solution, but this is definately not a SeaTable problem, it is a general networking/webserver issue.

Best regards,
Christoph

Hi @cdb ,
Thank you for your answer! And sorry, I realized I posted my last message a bit too fast, but the doc and your message helped me understand that you added caddy on top of the nginx server in the last SeaTable version.
And you’re absolutely right, this is not a SeaTable problem, so thank you even more than usual for your help :pray: :pray: :pray:.

Now, to answer your questions :

  • my app is currently running in the host system. It would probably be cleaner and easier to deploy to run it in a docker container, but unfortunately I don’t have enough knowledge about Docker to be able to do that: I’ll have to take the time to look into it, but in the meantime I’ll continue to run my application on the host
  • I previously managed to reach my application at https://myserver.vps.ovh.net:8443/products/order.html, https://myserver.vps.ovh.net being the address to reach SeaTable. Ideally, I’d like to be able to reach my app using https://myserver.vps.ovh.net/products/order.html
  • I don’t really care which server is proxying to my app (and to be completely honnest, I don’t really understand the pros and cons of proxying directly with carry or with nginx). As far as I understand, nginx was previously proxying as it was the only web server, now that we have caddy on top (so reached first), proxying with caddy should be “enough” right ?

Once again, thanks a lot for your help!!

Bests,
Benjamin

Hey Ben,

You should proxy with the web server you feel more comfortable with.
I would recommend that you use caddy and here is how I would do it…

Step 1: create a custom yml file

You to create a custom yml file for your Seatable Server and add another redirect to it. Here is how I would do it:

cd /opt/seatable-compose
cp seatable-server.yml custom-seatable.server.yml

Step 2: Change the custom file according to your needs

In this custom-seatable-server.yml file you will find a section with labels. Here you can add additional directories.

# This is the original configuration
labels:
  caddy: ${SEATABLE_SERVER_HOSTNAME:?Variable is not set or empty}
  caddy.reverse_proxy: "{{upstreams 80}}"

Change it to this, if you want to reach your application via subfolder.

# configuration with an additional proxy directory
labels:
  caddy: ${SEATABLE_SERVER_HOSTNAME:?Variable is not set or empty}
  caddy.0_reverse_proxy: "{{upstreams 80}}"
  caddy.1_reverse_proxy: /products "127.0.0.1 8443"

As you can see, you have to add these .0_ to the existing line and then add the second line.

Step 3: change the yml file in your .env file.

In the .env file you have the variable COMPOSE_FILE. Replace here seatable-server.yml with custom-seatable-server.yml.

Step 4: restart all containers.

Don’t forget to restart all containers (SeaTable Server and Caddy).

In the last post I explained how to route a subdirectory. Here is the explanation how you can define another subdomain or custom port to reach your application:

As before start, that you make a copy of your seatable-server.yml and make all changes in your custom-seatable-server.yml.

Important: indentation is important in yml files. Make sure not to break the files.

Option 1: Other domain/subdomain

# change all rows starting with caddy.xxx to caddy_0.xxx
# then add the following

caddy_1: sub2.example.com
caddy_1.reverse_proxy: "{{upstreams 8443}}"

Option 2: Custom port

You also have to open up the port in caddy.

# have a look at collabora.yml to get a felling how to do, but you have to add another port
services:
  caddy:
    ports:
      - 9999:9999

# change all rows starting with caddy.xxx to caddy_0.xxx
# then add the following

caddy_1: ${SEATABLE_SERVER_HOSTNAME}:9999
caddy_1.reverse_proxy: "{{upstreams 8443}}"

Then also update your .env file and restart the containers.

More documentation

More details about the caddy docker container we use, can be found here:

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.