I am setting up etherpad-lite in a subdirectory at this location.
Unfortunately the files in ‘static’ aren’t being loaded:
Clearly something is going on in my nginx, which (partially) looks like this:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
listen [::]:80;
server_name _
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name www.whitewaterwriters.com;
ssl_certificate /etc/letsencrypt/live/www.whitewaterwriters.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/www.whitewaterwriters.com/privkey.pem;
return 301 https://whitewaterwriters.com$request_uri;
}
server {
listen 443 ssl;
server_name whitewaterwriters.com;
ssl_certificate /etc/letsencrypt/live/whitewaterwriters.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/whitewaterwriters.com/privkey.pem;
root /usr/share/nginx/html;
index index.html index.php;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location ~ .php$ {
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~/watchtower/.*/live/pdfs/ {
autoindex on;
}
location /watchtower {
root /usr/share/nginx/html/;
}
location /etherpad {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
proxy_read_timeout 300;
proxy_pass http://localhost:9001/;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
location /{
root /usr/share/nginx/html/whitewaterwriters-site/_site/;
}
error_page 404 /404.html;
location = /404.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
# Settings for a TLS enabled server.
#
# server {
# listen 443 ssl http2;
# listen [::]:443 ssl http2;
# server_name _;
# root /usr/share/nginx/html;
#
# ssl_certificate "/etc/pki/nginx/server.crt";
# ssl_certificate_key "/etc/pki/nginx/private/server.key";
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 10m;
# ssl_ciphers PROFILE=SYSTEM;
# ssl_prefer_server_ciphers on;
#
# # Load configuration files for the default server block.
# include /etc/nginx/default.d/*.conf;
#
# error_page 404 /404.html;
# location = /40x.html {
# }
#
# error_page 500 502 503 504 /50x.html;
# location = /50x.html {
# }
# }
}
My question is: how do I configure nginx so that the missing files appear?
There are some other questions on this topic both in the github issues and SE, but they, in general, are solved by moving from etherpad to etherpad-lite, which I already use, or are both unanswered and approaching a decade old…
2
Answers
You can try to navigate the static content to the correct folder with:
since this is working: https://whitewaterwriters.com/etherpad/static/js/vendors/html10n.js?v=869d568c
Short answer: if you add a trailing slash to your prefixed location, everything would work as expected.
If you want
/etherpad
URI to work too, add the following location if you won’t get HTTP 301 redirect from/etherpad
to/etherpad/
with the above configuration:For me it wasn’t necessary, but it can depend on your server environment.
To preserve query string, if any, you can use
return 301 /etherpad/$is_args$args;
orrewrite ^ /etherpad/ permanent
instead.Long answer (and what happened undercover).
There are many question on SO about "how can I host a webapp under an URI prefix". Here is one on my answers and here is a ServerFault thread on the similar topic.
The only right way to do it is to made your proxied app request its assets via relative URIs only (consider
assets/script.js
instead of/assets/script.js
) or using the right URI prefix (/etherpad/assets/script.js
).Luckily, etherpad requests its assets using a relative paths (e.g.
<script src="static/js/index.js"></script>
) making it suitable to be hosted under any URI prefix. The problem is, when your origin URI is/etherpad
, browser considers the current remote web server directory as the root one, and requests above script from server asscheme://domain/static/js/index.js
. That request won’t even caught by yourlocation /etherpad { ... }
(since it isn’t starts with/etherpad
). On the other hand, when your origin URI is/etherpad/
, browser considers the current remote web server directory as the/etherpad/
and correctly requests above script from server asscheme://domain/etherpad/static/js/index.js
.Now let’s see what happened with the proxied request
/etherpad/<path>
using your original configuration. Since you are using a trailing slash after the upstream address (http://localhost
+/
), nginx cut the location/etherpad
prefix from the request URI and prepend it with that slash (or any other URI used in aproxy_pass
directive after the upstream name) resulting in//<path>
. You can read A little confused about trailing slash behavior in nginx or nginx and trailing slash with proxy pass SO threads for more details. Anyway that URI won’t served by etherpad giving youCannot GET //<path>
error.Changing
location /etherpad { ... }
to thelocation /etherpad/ { ... }
you’ll made both of the aforementioned problems gone.A few words about the etherpad wiki examples, especially this one.
Both
and
do the same string – stripping the
/etherpad
prefix from the request URI before passing it to the upstream. However the first one do it in a much more efficient way. It is a good practice to avoid regular expressions whenever possible. Usingis also more efficient than
Second and third location blocks from the above wiki example completely duplicate functionality from the first one. Moreover, that example breaks WebSocket support (whoever wrote it, he can at least add that support to the
location /pad/socket.io { ... }
block).And never do the thing used at this example:
Use exact matching location instead:
Here is one more configuration I’ve tested in order to check if I can serve etherpad static assets directly via nginx. It seems to be workable, although I didn’t tested it a lot. It uses an uncompressed js/css assets versions (which should not impact performance when you are using gzip or some other compression). It is also a good example of a configuration where you can’t avoid using
rewrite
directive to strip a prefix from the request URI.Update
As being suggested on the GitHub, URIs started with
/etherpad/static/plugins/
prefix should always be passed to the nodejs upstream since there are no corresponding assets would exists under the/path/to/etherpad/src/static/
directory. Despite there is already defined fallback to the nodejs upstream (try_files $uri @etherpad
), to eliminate an extrastat
system call produced by thetry_files
directive we can modify the above configuration to this one:(using negative lookahead regex, better readability) or to this one:
(only prefix locations, better performance). The repetitive part
and probably other optional headers (
X-Real-IP
,X-Forwarded-For
,X-Forwarded-Proto
) setup mentioned at the very beginning of the answer, can be used as a separate file, e.g.etherpad-proxy.conf
, and included into the main nginx config with theinclude
directive.