hackmdio / codimd

CodiMD - Realtime collaborative markdown notes on all platforms.
https://hackmd.io/c/codimd-documentation
GNU Affero General Public License v3.0
9.3k stars 1.06k forks source link

docker image config to serve web files from subdir instead of root #1440

Open aleqx opened 4 years ago

aleqx commented 4 years ago

I want to use the Docker installation rather than manual installation (docker-compose image works fine, no problem accessing it under port 3000) but I want to change CodiMD's web installation folder from root to a subdir, i.e. from  http://localhost:3000/  to  http://localhost:3000/codimd -- is that possible? Any pointers?

Right now I notice the html content points to absolute urls such as  <img src="/screenshot.png" /> .

I take it I'd need to edit the docker image to change the internal web server's config to serve the static files at the /codimd url instead of at /, and then also set CMD_URL_PATH=codimd in the docker env variables.

I'd be grateful for some more exact pointers on how to do this.

The end goal is to put the CodiMD docker under a proxypass such that mydomain.com/codimd proxy-passes to localhost:3000/codimd (I can do a few things by rewriting html output, but that's not cutting it, as some CSS would also need to, it would be just cleaner to have CodiMD installed in a web subdir)

a60814billy commented 4 years ago

Hi @aleqx, sorry for late reply.

Thanks for you reported this issue about sub-folder deployment. We found some resource path not follow CMD_URL_PATH (config file and fonts)and we're going to fix this problem on the next version (v2.0.1).

Before we release next version, we provide a workaround setting in apache to fix this problem. (please tell me if you use others web server, I can test it)

But it has some limits:

  1. You didn't used route https://md.example.com/config on root directory.
  2. You didn't used any files under https://md.example.com/build/ and https://md.example.com/fonts/.

Workaround

The workaround setup CodiMD on https://md.example.com/internal-codimd/, and proxy all request to backend CodiMD server http://172.16.30.24:3000/.

1. CodiMD Server

CodiMD server is setup by docker and host on 172.16.30.24. The docker-compose config is shown as below.

version: "3"
services:
  database:
    image: postgres:11.6-alpine
    environment:
      - POSTGRES_USER=codimd
      - POSTGRES_PASSWORD=change_password
      - POSTGRES_DB=codimd
    volumes:
      - "database-data:/var/lib/postgresql/data"
    restart: always
  codimd:
    # you can use image or custom build below
    image: nabo.codimd.dev/hackmdio/hackmd:2.0.0
    environment:
      - CMD_DB_URL=postgres://codimd:change_password@database/codimd
      - CMD_USECDN=false
      - CMD_DOMAIN=md.example.com
      - CMD_URL_PATH=internal-codimd
      - CMD_PROTOCOL_USESSL=true
    depends_on:
      - database
    ports:
      - "3000:3000"
    volumes:
      - upload-data:/home/hackmd/app/public/uploads
    restart: always
volumes:
  database-data: {}
  upload-data: {}

2. Apache config

The apache requires these modules to apply the config shown as below

# Redirect http to https
<VirtualHost *:80>
    # ServerName md.example.com
    Redirect permanent / https://md.example.com/
</VirtualHost>

# https
<IfModule mod_ssl.c>
    <VirtualHost *:443>
        ServerName md.example.com

        # SSL Config
        SSLEngine on
        SSLCertificateKeyFile /usr/local/apache2/certs/md.example.com/cert-key.pem
        SSLCertificateFile /usr/local/apache2/certs/md.example.com/cert.pem

        RewriteEngine on
        RewriteCond %{REQUEST_URI} ^/internal-codimd/socket.io             [NC]
        RewriteCond %{QUERY_STRING} transport=websocket    [NC]
        RewriteRule /internal-codimd/(.*)  ws://172.16.30.24:3000/$1          [P,L]

        ProxyPass /internal-codimd/ http://172.16.30.24:3000/

        # temporary workaround for /confg, /build/* and /fonts/*
        ProxyPass /config http://172.16.30.24:3000/config
        ProxyPass /build http://172.16.30.24:3000/build
        ProxyPass /fonts http://172.16.30.24:3000/fonts
    </VirtualHost>
</IfModule>

Finally, I create a repository for demostraction (https://github.com/a60814billy/codimd-subdir-workaround), you can see more detailed configuration in the repo.

nmaas87 commented 4 years ago

I can confirm this error is still present in 2.0.1. It can be resolved in the same manner as descibred above, hosting on docker with a proxy on domain.example/codimd and exposing the config file, as well as the build and fonts folder on domain.example/

aleqx commented 4 years ago

That's not a workaround for me. It already works on a subdomain (e.g. md.example.com) but that's not what I want. What I want is example.com/md.

nmaas87 commented 4 years ago

Its definitly a bug and without the possibilty to host parts of the running containers in the root directory, its not possible to get it working.

aleqx commented 4 years ago

Its definitly a bug and without the possibilty to host parts of the running containers in the root directory, its not possible to get it working.

Not sure I understand that correctly. I don't care where the container hosts its parts locally in localhost (i'm happy to make the container host in any manner needed) ... i just want the public url to be https://example.com/md (i do not want a subdomain https://md.example.com).

Is the above possible or not?

It woould be possible if the localhost docker serves files correctly from localhost:3000/md (which is the bug i reported) so i can proxypass to it. Otherwise css/js/etc files inside the served html will still point to / instead of /md. It doesn't seem like the bug I reported was fixed despite the claim it's fixed in 2.0.1

nmaas87 commented 4 years ago

You're right. Its not fixed. To get it working in its current situation, you would need to do three things: 1.) with your docker container running, go to the correct path, i.e. example.com/md/config - it will show the config file, which it tries to find normally in example.com/config. Save this file and make it available on example.com 2.) get into your running docker container and copy the whole /home/hackmd/app/public/build out of the container (i.e. via the uploads folder?) and make it available on example.com/build 3.) do the same for the fonts folder ( /home/hackmd/app/public/fonts).

With that, your container should be working, so going to https://example.com/md should work, as the required files (config file, build folder and fonts folder) are searched in https://example.com/ and are now available to load at this place.

Yes, its a really dirty workaround and basically the same as descibred by https://github.com/hackmdio/codimd/issues/1440#issuecomment-595397057 - only expressed in other wording and mines a lot more dirty....

No, this issue here has not been resolved in 2.0.1 and it still needs fxing.

tarlety commented 4 years ago

I found that codimd/server has solutions for this issue.

I tried codimd/container 1.6.0, nginx as reverse proxy, and to serve codimd on /codimd subpath.

The sample docker-compose.yml:

version: "3"
services:
  database:
    image: postgres:11.6-alpine
    environment:
      - POSTGRES_USER=codimd
      - POSTGRES_PASSWORD=badpassword
      - POSTGRES_DB=codimd
    volumes:
      - "database-data:/var/lib/postgresql/data"
    restart: always
  codimd:
    image: quay.io/codimd/server:1.6.0-alpine
    environment:
      - CMD_DB_URL=postgres://codimd:badpassword@database/codimd
      - CMD_USECDN=false
      - CMD_URL_PATH=hackmd
      - CMD_PORT=3000
    depends_on:
      - database
    volumes:
      - upload-data:/home/hackmd/app/public/uploads
    restart: always
  nginx:
    image: nginx:1.18.0-alpine
    environment:
      - NGINX_HOST=localhost
      - NGINX_PORT=80
    depends_on:
      - codimd
    ports:
      - "80:80"
    volumes:
      - './nginx-default.conf:/etc/nginx/conf.d/default.conf'
volumes:
  database-data: {}
  upload-data: {}

The sample nginx-default.conf:

  listen 80 default_server;
  server_name localhost;

  #charset koi8-r;
  #access_log  /var/log/nginx/host.access.log  main;

  location / {
    root   /usr/share/nginx/html;
    index  index.html index.htm;
  }

  error_page   500 502 503 504  /50x.html;
  location = /50x.html {
    root   /usr/share/nginx/html;
  }

  location ^~ /hackmd/ {
    proxy_pass http://codimd:3000/;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
  }
}

These fixes work like a charm:

Screenshot from 2020-05-20 11-49-38

tarlety commented 4 years ago

@aleqx

Is this deployment case as expected?

If yes, I can help to port code and file PR for this issue.

yzx9 commented 1 year ago

Hello, is there any update here?

maxbeer99 commented 2 months ago

I still have the same issue. Using email auth immediately breaks as the webform points to localhost/login statically, independent of what is set in CMD_URL_PATH.