asciinema / asciinema-server

Platform for hosting and sharing terminal session recordings
https://docs.asciinema.org/manual/server/
Apache License 2.0
2.31k stars 266 forks source link

Behind Apache httpd Proxy #345

Closed vikramkhatri closed 6 months ago

vikramkhatri commented 5 years ago

@sickill - First lots of thanks for Asciinema.

This is not an ideal case but this is what I have:

  1. A CentOS Linux server running some sites - ports 80 and 443 are in use by regular httpd server.
  2. I installed asciinema-server using docker-compose with following env vars in .env.production
    URL_SCHEME=http
    URL_HOST=localhost
    URL_PORT=18880
  3. docker-compose.yml - changed exposed port on host to 18880:
    ports:
      - "18880:80"
  4. Defined reverse proxy at httpd level at host:
    <VirtualHost *:80>
    ServerName www.markiv.us
    ServerAlias www.markiv.us
    DirectoryIndex index.php index.html
    SetOutputFilter SUBSTITUTE,DEFLATE
    ProxyPass / http://localhost:18880/
    ProxyPassReverse / http://localhost:18880/
    SetOutputFilter INFLATE;proxy-html;DEFLATE
    AddOutputFilterByType SUBSTITUTE text/html
    Substitute "s|http://localhost:18880/|https://www.markiv.us/|i"
    <Proxy *>
        Order deny,allow
        Allow from all
        Allow from localhost
    </Proxy>
    RewriteEngine on
    RewriteCond %{SERVER_NAME} =www.markiv.us
    RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
    </VirtualHost>
    <VirtualHost *:80>
    ServerName markiv.us
    RewriteEngine On
    RewriteCond %{HTTP_HOST} !^www\. [NC]
    RewriteRule ^(.*)$ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
    RewriteCond %{SERVER_NAME} =markiv.us
    RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
    </VirtualHost>

    In above -

    SetOutputFilter INFLATE;proxy-html;DEFLATE
    AddOutputFilterByType SUBSTITUTE text/html
    Substitute "s|http://localhost:18880/|https://www.markiv.us/|i"

I needed to add SetOutputFilter INFLATE;proxy-html;DEFLATE since it appeared that the response was compressed.

So - The site works fine as SSL termination is at the apache httpd level and not at the nginx.

Issue - 1

The issue is - when email comes after login - the url has http://localhost:18880.

Issue - 2

I tried using the following in .env.production

URL_SCHEME=http
URL_HOST=markiv.us
URL_PORT=80

The email that comes has above URL but asciinema player breaks it does not start.

Is there something that you can suggest for the config or env vars? I am close and thanks for your insight.

ku1ik commented 3 years ago

I guess it's too late but I'll try :)

This one seems correct to me:

URL_SCHEME=http
URL_HOST=markiv.us
URL_PORT=80

The port number here needs to be one to use for generating URLs, and given you're fronting it all with Apache on port 80 it should work like that.

What error do you get when the player doesn't start with these settings?

Ciberth commented 2 years ago

@sickill I am facing a similar issue. I'm not using apache but nginx instead. I have a Linux server that runs nginx as a reverse proxy, proxying multiple applications that each run on their own port (they may or may not run in docker containers). Because of that very use case doing rewrites (for the "/") is only possible once so this is a not a valid solution for my use case.

Is it possible to fix the source code instead to use relative paths instead of absolutes for all static/asset information?

This should be fixed at the application level not at a deployment level IMHO. This would fix the original issue with apache as well and no rewrites should be needed.

Big thank you in advance!

jiriks74 commented 6 months ago

Like @ku1ik said this seems wrong:

URL_SCHEME=http
URL_HOST=localhost
URL_PORT=18880

The URL_PORT controls the port inside the container so

    ports:
      - "18880:80"

doesn't work because the way it's now configured should have this in the docker-compose.yml:

    ports:
      - "18880:18880"

Just don't change the port using the variables at all and instead use docker to do it for you:

    ports:
      - "18880:4000"

Also you should change the host as localhost works only on your local PC. When you'll try to connect from another machine it will break as the server doesn't know it's hostname which you use for connections - that's why it's there. If you want to test it on the local network just set it to your server's hostname in the network. That way you can connect to the machine similarly to this, depending on your local DNS suffix: myserver.local

URL_HOST=myserver.local

I just set asciinema like so (using traefik but it should work the same way with apache):

URL_HOST=asciinema.myserver.com
URL_SCHEME=https
    labels:
      - traefik.http.routers.asciinema.rule=Host(`asciinema.myserver.com`)
      - traefik.http.routers.asciinema.entrypoints=websecure # Port 443
      - traefik.http.routers.asciinema.tls.certresolver=lets-encrypt # Enable SSL between proxy and internet
      - traefik.http.routers.asciinema.service=asciinema
      - traefik.http.services.asciinema.loadBalancer.server.port=4000 # What port to connect to in the container. You'll have to expose it like I said above

AFAIK the server doesn't care what you set the variables to. It uses it for generating urls, etc. You can run it on the default port (like I do) and then just use docker + apache to set a different port and proxy it. Also your proxy config seems overly complicated. Just point the proxy to the server and enable SSL, nothing else should be needed.

jiriks74 commented 6 months ago

@Ciberth

proxying multiple applications that each run on their own port ... Because of that very use case doing rewrites (for the "/") is only possible once so this is a not a valid solution for my use case.

Why don't you use a subdomain like asciinema.yourserver.com? It's easy to set up using nginx and it's more readable URL IMHO:

server {
    listen      80;
    listen      [::]:80;
    server_name asciinema.yourserver.com;

    # logging
    access_log  /var/log/nginx/access.log combined buffer=512k flush=1m;
    error_log   /var/log/nginx/error.log warn;

    # reverse proxy
    location / {
        proxy_pass            http://localhost:4000;
        proxy_set_header Host $host;
    }
}

It would be nice to have a subdir option as well but I've been using subdomains for almost everything and I find it more flexible and readable. For you it could be at least a temporary solution if you don't like the subdomain approach.

ku1ik commented 6 months ago

Is it possible to fix the source code instead to use relative paths instead of absolutes for all static/asset information?

I've just released new version of the server: https://github.com/asciinema/asciinema-server/releases/tag/v20240515

One related change in this release is changing of the URL used for fetching recordings in the player, from absolute URL to a local (absolute) path. This should help with any potential URL rewrites or cases where the URL_HOST and URL_PORT are misconfigured.

However, it's essential to configure URL_HOST properly for the whole installation to work anyway (https://docs.asciinema.org/manual/server/self-hosting/configuration/#base-url), and as @jiriks74 suggested, when deploying together with other services it's best to keep them on separate subdomains. The server assumes it runs at the root of a domain, and it's likely going to stay this way (supporting nesting under arbitrary paths is a PITA to maintain, sorry).

ku1ik commented 6 months ago

Given the last remaining asset (the recording file) is now served using a path instead of a full URL I think there's nothing more to fix on the code side, and I'm going to close this. If you'd like to discuss your setup further feel free to start a topic on asciinema forum. Thanks!