Published
Correct the NginX proxy pages and the Tomcat proxy-headers page
Follow-up to Correct the HTTP Reverse Proxy hub and the Apache proxy configuration pages, now merged. That change was deliberately scoped to the Apache subtree, and its technical review found two claims that the NginX and Tomcat pages carry as well: forwarded headers a reader can forge, and "the Servlet Container has to trust the headers or the wiki's links stay http". Those are fixed here, together with the defects found while testing these three pages. Three pages, none created, none deleted, none renamed.
Everything below was verified against NginX 1.24.0 proxying a live XWiki 18.4.3, and the Tomcat items against Tomcat 11.0.21, with the block and the valve taken verbatim out of the proposed pages. Two harnesses, neither of which touches a system NginX or a system Tomcat: nginxcheck.sh records the defects of the pages as they are today, nginxverify.sh runs the exact block this change ships and reproduces each item of the second pass below.
Configurations that do not work as documented
- proxy_pass was given a path, which silently opens the wrong page. With
proxy_pass http://localhost:8080/xwiki;NginX forwards the normalized path, so the encoded slash an XWiki page name may contain is decoded on the way: a request for/xwiki/bin/view/Main/A%2FBreaches XWiki as Main.A.B, answers 200, and shows a different page than the one asked for. Written without the path,proxy_pass http://localhost:8080;, the same request arrives as Main.A/B. It is the NginX counterpart of the nocanon and AllowEncodedSlashes NoDecode pair the Apache pages document, and neither NginX page mentioned the problem. - proxy_set_header X-Forwarded-Proto http hard-coded the protocol, on the procedure page and in the reference table. Served over HTTPS through that block, the wiki reports
http://wiki.example.com/xwiki/bin/view/Main/as its own absolute URL, so every link it builds is plain HTTP: exactly the failure the Tomcat proxy-headers page exists to prevent. It becomes $scheme, which is http or https according to what the reader actually used, and the reference row now says why a literal value cannot work. - Nothing stopped a reader from forging the forwarded headers. NginX passes headers it does not set on untouched, and XWiki builds its URLs from the first value it finds, so through the documented block a request carrying
X-Forwarded-Host: evil.example.commade the wiki return https://evil.example.com/… as its absolute URL, and a Forwarded header chose the scheme too. The block now sets X-Forwarded-Host to $host and empties Forwarded, an empty value being how NginX is told to send a header not at all. - Connection "upgrade" was hard-coded on every request. It does work, both the handshake and ordinary pages were tested, but it labels as an upgrade every request that upgrades nothing, and it rules out the connection reuse an upstream block declaring keepalive brings. It is now driven by the map the NginX documentation uses for this, which belongs at http level, above the server block, and the reference table says so.
- The root redirect dropped the trailing slash.
return 301 /xwikimakes XWiki answer a second redirect to add it; the Apache pages already redirect to /xwiki/. - The Tomcat valve's result step promised what the valve does not do. It asked the reader to verify that "HTTPS URLs are generated correctly" and that "redirects use HTTPS", which is true before the valve is added: XWiki reads the forwarded headers itself. The step now names what the valve does change, the address in Tomcat's own access log, and the page opens by saying which of the two views of the request it is about.
- The reference table's proxy_pass row did not render as a directive. It put a URL inside ##…##, which the autolinker breaks, and the row ended in a stray ####. Every directive is in a code macro now, the same fix the Apache table got.
Found by a second technical pass
Six more items, each reproduced by nginxverify.sh before and after the fix.
- $host silently drops the port, so the wiki emits addresses that lead nowhere. NginX normalizes $host without the port, XWiki appends what it reads to scheme://, and neither page listened on anything but 80, which is what hid it. Proxying the same wiki on port 8081, the block reported
http://127.0.0.1/xwiki/bin/view/Main/as its absolute URL and answered "Edit" withLocation: http://127.0.0.1/xwiki/bin/login/XWiki/XWikiLogin: a reader who is not logged in leaves for port 80. Both Host and X-Forwarded-Host now send $http_host, the header as the reader sent it, and both addresses come back with :8081. Sending nothing is still the answer for a client that sends no Host at all: NginX omits a header whose value is empty, so nothing forgeable gets through. - The Windows instruction produced the stock welcome page. conf/nginx.conf already ships a server block listening on 80 for localhost, and the step said to add the wiki's next to it. Two blocks with the same name and port are not an error: NginX keeps the first, ignores the second with a [warn] line, and nginx -t still answers "test is successful", so the reader gets the welcome page at every URL with nothing to explain it. The step now says to put the block in place of that one, and says why.
- X-Forwarded-For is not evidence of who sent the request, and the page implied the header work made it so. $proxy_add_x_forwarded_for appends the proxy's address to whatever the client already sent, and XWiki reads the first value: through the shipped block, a request carrying
X-Forwarded-For: 1.2.3.4reaches the container as1.2.3.4, 127.0.0.1. The row says so, and names $remote_addr as the value to send where this proxy is the only one in front of the wiki. - requestAttributesEnabled was on the wrong element. It defaults to true on RemoteIpValve (Tomcat 10.1 and 11 alike) and to false on AccessLogValve. With the valve reduced to className alone and the attribute written out only on the access log, a request forwarded as 203.0.113.9 is logged as 203.0.113.9; drop it from the access log and the same request is logged as 127.0.0.1.
- internalProxies is version-dependent, and it replaces the default rather than adding to it. Tomcat 10.1 reads it as a regular expression; Tomcat 11 also accepts CIDR blocks and deprecates the regular expression, which Tomcat 12 will drop. Overriding it with an address that is not the proxy's silently turns the valve off, which is what the step now warns about.
- The Tomcat result step asked for a request over HTTPS, although the NginX procedure it sends the reader to serves plain HTTP. The valve's effect on the access log is visible either way, so the step no longer requires it.
Guideline work
- The Tomcat valve is reduced to what it needs, which is className and nothing else. Four of the five attributes it was given are Tomcat's own defaults (remoteIpHeader, protocolHeader, protocolHeaderHttpsValue, and requestAttributesEnabled, which is true on the valve in both Tomcat 10.1 and Tomcat 11), and internalProxies="127\.0\.[0-1]\.1" replaced a default that already covers the loopback and the private ranges, so it only narrowed it, silently, for anyone whose proxy is not on the same host. The internalProxies case becomes a step of its own and the rest FAQ, including the two attributes that really do default to nothing: hostHeader and portHeader.
- Three WIP banners are removed, one of them an author's note to the reader ("WIP: create a separate tutorial for Windows OS"). That question is real and is raised below rather than left in the page.
- The custom-domain FAQ answer on the NginX page was an Apache answer. It told the reader to replace ServerName localhost, a directive NginX does not have; it is server_name. This was the third copy of that answer: the other two moved to the Apache reference page in the previous change, and this one is now NginX-specific.
- The two NginX pages and the Tomcat page had no intro paragraph, opening straight on the numbered list, and the Tomcat page had no faq and no related at all. The reference page had no per-directive links to the NginX documentation although its table column promised the "official Nginx documentation meaning"; each row now links the directive it documents.
- The reference table mixed the server block with the location block, so nothing said where a row belonged; it is two tables under level-2 headings, matching the two blocks, and the row for the map says it goes above both.
- related carried a bare JIRA URL (XWIKI-13963), which is a transient resource rather than documentation, and two links were missing their doc: prefix.
- Smaller ones: the procedure's first step pointed at
http://localhost:8080/rather than at the wiki; an unclosed parenthesis; the two trailing "test in browser" and "test proxy behavior" steps duplicated the result step, so the log paths they carried became a FAQ answer instead of being dropped; and the shipped block is indented consistently.
What was added
- The two limits behind a failed import, as one FAQ answer on the reference page: 413 is client_max_body_size, 1m by default and set to 0 in the block, while a 504 after about a minute is proxy_read_timeout, 60s by default, expiring while the container is still working. The Apache reference page got the same answer for ProxyTimeout in the previous change.
- "Do I need this for the wiki to generate HTTPS links?" on the Tomcat page, answered no, with the causes to check instead (the proxy not sending the header, or xwiki.home and xwiki.url.protocol naming http).
- "Is the same configuration needed on Jetty?", answered no: XWiki's Jetty distributions enable Jetty's forwarded module, which processes the Forwarded header and its X-Forwarded-* predecessors. Checked in the distribution itself, where the xwiki Jetty module depends on forwarded.
- Why enabling a site is a separate step, kept from the page and extended with what the two NginX directories are for, and where NginX writes its logs, which is the first place to look when the wiki answers on port 8080 but not through the proxy.
Deliberately left alone
set-nginx stays type=tutorial and keeps its dual-OS shape: by the letter of Diataxis it is a How-to, but its Apache siblings are Tutorials too, and splitting Linux and Windows into two pages, as the removed banner suggested, is a page-creation decision rather than a correction. client_max_body_size 0 is kept: an unlimited body is what XAR imports and attachment uploads need. No HTTPS section is added on the NginX side although the Apache subtree has a whole page for it, because that is a new page rather than a fix; it is raised below. Technical ID stays empty on all three, these being installation pages. No number, path or directive value was changed other than the ones listed above.
Follow-ups, not in this change
- An HTTPS page for NginX, mirroring Configure HTTPS for the Apache HTTP Proxy Server. The NginX subtree stops at plain HTTP, so a reader who follows it to the end is served over port 80 with no path forward.
- Decide whether a separate Windows procedure is wanted, per the banner removed above. The page currently carries the Windows variant of every step, which is why it reads twice as long as its Apache counterparts.
- Rename the Apache HTTPS page from configurations to configure-https. It cannot travel in a change request: the application has file changes for creation, edition and deletion only, so a page move has to be done on the wiki itself. The ordering worry that came with this follow-up turned out not to apply, the tree already listing the three Apache children as Linux, Windows, HTTPS.
- A platform issue for the header handling: HttpServletUtils.getFirstHeaderValue takes the first value of X-Forwarded-* while a proxy appends its own value last, and there is no trusted-proxy count, so documentation can only tell administrators to overwrite those headers at the proxy, which both subtrees now do.
- ssh-tunneling opens a
group in its first FAQ answer and closes it at the end of the second, so the two answers render inside one box; and it describes a two-hop path in prose where a diagram would carry it.
-
Eleni Cojocariu created this Change Request with changes for NginX Server Key Configurations
3 weeks ago
-
Eleni Cojocariu added a new change for Set up NginX Proxy Server
3 weeks ago
-
Eleni Cojocariu added a new change for Configure Tomcat to Find Proxy Headers
3 weeks ago
-
Eleni Cojocariu added a new change for NginX Server Key Configurations
3 weeks ago
-
Eleni Cojocariu added a new change for Set up NginX Proxy Server
3 weeks ago
-
Eleni Cojocariu added a new change for Configure Tomcat to Find Proxy Headers
3 weeks ago
-
Eleni Cojocariu edited the description or the title of the Change Request
3 weeks ago
-
Eleni Cojocariu added a new approval review
3 weeks ago
-
Eleni Cojocariu changed the status of the Change Request from ready for review
to ready for publication
3 weeks ago
-
Eleni Cojocariu changed the status of the Change Request from ready for publication
to published
3 weeks ago
All changes
Summary
-
Page properties (1 modified, 0 added, 0 removed)
-
Objects (1 modified, 0 added, 0 removed)
Details
- Page properties
-
- Content
-
... ... @@ -1,23 +1,29 @@ 1 -{{warning}} 2 -WIP 3 -{{/warning}} 1 +[[NginX>>https://nginx.org/]] forwards requests to XWiki with the ##proxy_pass## directive of its [[proxy module>>https://nginx.org/en/docs/http/ngx_http_proxy_module.html]]. The directives below are the ones a wiki needs, and [[Set up NginX Proxy Server>>doc:documentation.xs.admin.installation.http-reverse-proxy.nginx-key-configurations.set-nginx.WebHome]] assembles them into a complete ##server## block. The [[Apache Server Key Configurations>>doc:documentation.xs.admin.installation.http-reverse-proxy.apache-key-configurations.WebHome]] page documents the equivalent Apache HTTP Server directives. 4 4 5 - NginXis a widely used open-source web server,often utilized as a reverse proxy to forwardclient requests to backendapplications likeXWiki. The followingconfiguration keysensure proper communication between NginX and XWiki:3 +== Server Block Directives == 6 6 7 -|=Configuration line|=Description / Official Nginx documentation meaning 8 -|##listen 80##|Specifies the port Nginx listens on. Port 80 is the default for HTTP traffic. 9 -|##server_name localhost##|Defines the domain name(s) this server block responds to (e.g., localhost or example.com). 10 -|##client_max_body_size 0##|Defines the maximum allowed size of the client request body. A value of 0 disables the size limit, allowing unlimited upload size. 11 -|##access_log /var/log/nginx/xwiki-access.log##|Path to the file where all successful client requests are logged. 12 -|##error_log /var/log/nginx/xwiki-error.log##|Path to the file where Nginx logs errors (configuration issues, backend failures). 13 -|##location /xwiki { ... }##|Matches requests with URI starting with /xwiki and applies the enclosed configuration. 14 -|##proxy_pass http://localhost:8080/xwiki/####|Forwards incoming requests to a backend server (reverse proxy). Here, to XWiki running on port 8080. 15 -|##proxy_set_header Host $host##|Passes the original Host header from the client request to the backend server. 16 -|##proxy_set_header X-Real-IP $remote_addr##|Sends the real client IP address to the backend. 17 -|##proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for##|Adds the client IP to the X-Forwarded-For chain (used when multiple proxies exist). 18 -|##proxy_set_header X-Forwarded-Proto http##|Indicates whether the original request was HTTP or HTTPS. 19 -|##proxy_http_version 1.1##|Forces HTTP/1.1, required for WebSocket connections. 20 -|##proxy_set_header Upgrade $http_upgrade##|Allows protocol upgrade (needed for WebSockets). 21 -|##proxy_set_header Connection "upgrade"##|Ensures connection header allows upgrade to WebSocket. 22 -|##proxy_redirect off##|Disables automatic rewriting of redirect URLs from the backend. 23 -|##location = / { return 301 /xwiki; }##|Exact match for root URL ("/"), redirects permanently to /xwiki. 5 +These go in the ##server## block that serves the wiki. 6 + 7 +|=Directive|=What it does 8 +|##listen 80##|The port this server block answers on, ##80## being the default for plain ##HTTP##. See [[listen>>https://nginx.org/en/docs/http/ngx_http_core_module.html#listen]]. 9 +|##server_name localhost##|The host name this block answers for. Set it to the wiki's public domain, for example {{code language="none"}}server_name wiki.example.com;{{/code}}. A request whose ##Host## header matches no ##server_name## reaches the server's default site instead, which is what answers with NginX's welcome page. See [[server_name>>https://nginx.org/en/docs/http/ngx_http_core_module.html#server_name]]. 10 +|{{code language="none"}}access_log /var/log/nginx/xwiki-access.log;{{/code}} and {{code language="none"}}error_log /var/log/nginx/xwiki-error.log;{{/code}}|Optional per-wiki log files, so that proxy problems can be told apart from the rest of the server's traffic. See [[access_log>>https://nginx.org/en/docs/http/ngx_http_log_module.html#access_log]]. 11 +|##client_max_body_size 0##|Removes the limit on the size of a request body, ##1m## by default, which otherwise makes NginX answer ##413## for an attachment upload or a XAR import larger than that. See [[client_max_body_size>>https://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size]]. 12 +|{{code language="none"}}location = / { return 301 /xwiki/; }{{/code}}|Redirects the root URL to the wiki, so that {{code language="none"}}http://localhost{{/code}} reaches XWiki without ##/xwiki## being typed. The trailing slash matters: without it XWiki answers a second redirect to add it. See [[return>>https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#return]]. 13 +|{{code language="none"}}location /xwiki { ... }{{/code}}|Matches every request whose path starts with ##/xwiki## and applies the proxy directives below. See [[location>>https://nginx.org/en/docs/http/ngx_http_core_module.html#location]]. 14 + 15 +== Proxy Directives == 16 + 17 +These go inside the ##location /xwiki## block, except the ##map##, which belongs at ##http## level. 18 + 19 +|=Directive|=What it does 20 +|{{code language="none"}}proxy_pass http://localhost:8080;{{/code}}|Forwards the request to the Servlet Container. It is deliberately given **no path**: with one, for example {{code language="none"}}proxy_pass http://localhost:8080/xwiki;{{/code}}, NginX forwards the normalized path instead of the original one, so a page name containing an encoded slash (##%2F##), which XWiki page names can, silently reaches a different page. See [[proxy_pass>>https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass]]. 21 +|##proxy_set_header Host $http_host##|Passes the client's ##Host## header on, so that XWiki builds URLs for the public domain rather than for ##localhost##. It has to be ##$http_host##, the header as the reader sent it, and not ##$host##, which NginX strips the port from: on a proxy listening anywhere other than ##80## or ##443##, ##$host## makes the wiki emit its own address without the port, and the redirects it answers with lead nowhere. See [[proxy_set_header>>https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_set_header]]. 22 +|##proxy_set_header X-Real-IP $remote_addr##|Sends the address NginX sees the request coming from, which a Servlet Container can be configured to log instead of the proxy's own address. 23 +|##proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for##|Appends that address to the ##X-Forwarded-For## chain, so a request that already crossed another proxy keeps its history. NginX does not check what the client put in that chain and XWiki reads its first value, so it is not evidence of who sent the request; where this proxy is the only one in front of the wiki, send ##$remote_addr## instead. 24 +|##proxy_set_header X-Forwarded-Proto $scheme##|Tells XWiki which protocol the reader used. It has to be the ##$scheme## variable and not a hard-coded ##http##: with the latter a wiki served over ##HTTPS## reports plain ##HTTP##, and XWiki builds every link with it. 25 +|##proxy_set_header X-Forwarded-Host $http_host##|Replaces the ##X-Forwarded-Host## header a client may have sent with the real one, port included. NginX passes headers it does not set through untouched, and XWiki reads this one before anything else to build its URLs, so without this line a reader can choose the host of every link the wiki emits. 26 +|{{code language="none"}}proxy_set_header Forwarded "";{{/code}}|Drops the ##Forwarded## header for the same reason: an empty value makes NginX send nothing at all, and it is the standard header XWiki looks at first. 27 +|##proxy_http_version 1.1##|Uses ##HTTP/1.1## towards the container, which the WebSocket upgrade needs. See [[proxy_http_version>>https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_http_version]]. 28 +|{{code language="none"}}map $http_upgrade $connection_upgrade { default upgrade; "" ""; }{{/code}} with ##proxy_set_header Upgrade $http_upgrade## and ##proxy_set_header Connection $connection_upgrade##|Tunnels the WebSocket connections that realtime editing uses. The ##map## belongs at ##http## level, outside the ##server## block, and is what keeps ##Connection: upgrade## for the handshakes only: hard-coded, that header goes out on every request, including the ones upgrading nothing, and it rules out the connection reuse an ##upstream## block declaring ##keepalive## would otherwise bring. See [[map>>https://nginx.org/en/docs/http/ngx_http_map_module.html#map]]. 29 +|##proxy_redirect off##|Leaves the ##Location## header of the container's redirects alone, which is what is wanted here: ##Host## is forwarded unchanged, so XWiki already redirects to the public address. See [[proxy_redirect>>https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect]].
- DocApp.Code.DocumentationClass[0]
-
- FAQ
-
... ... @@ -1,0 +1,19 @@ 1 +== How can I check whether NginX is running? == 2 + 3 +Open {{code language="none"}}http://localhost{{/code}} in a browser, or run {{code language="none"}}curl http://localhost{{/code}}: NginX's own welcome page means the server is running but is not forwarding to XWiki yet. 4 + 5 +== Why does a page whose name contains a slash open a different page? == 6 + 7 +Because ##proxy_pass## was given a path. NginX then forwards the normalized request path, which decodes the ##%2F## an XWiki page name can contain, so a link to a page named ##A/B## opens the page ##A.B## instead. Write {{code language="none"}}proxy_pass http://localhost:8080;{{/code}} without the ##/xwiki## suffix, and NginX passes the original path on unchanged. 8 + 9 +== Why does the wiki answer 404 through the proxy while port 8080 still works? == 10 + 11 +The proxied path does not match the wiki's context path: the ##location## block has to use the same ##/xwiki## prefix as the Servlet Container. 12 + 13 +== Why does realtime editing not work through the proxy? == 14 + 15 +Its WebSocket connection is not being tunnelled: the ##location## block needs ##proxy_http_version 1.1## together with the ##Upgrade## and ##Connection## headers above. 16 + 17 +== Why does importing a large XAR or uploading a large attachment fail? == 18 + 19 +Two different limits. A ##413## answer is NginX's ##client_max_body_size##, ##1m## by default, which the block above sets to ##0##. A ##504## after about a minute is ##proxy_read_timeout##, ##60s## by default, expiring while the container is still working; raise it for the wiki, for example {{code language="none"}}proxy_read_timeout 600s;{{/code}}. - Related
-
... ... @@ -1,3 +1,4 @@ 1 -* [[NginX documentation>>https://nginx.org/en/docs/]]. 2 -* [[https://jira.xwiki.org/browse/XWIKI-13963]]. 3 -* [[Configure Tomcat to Find Proxy Headers>>documentation.xs.admin.installation.methods.install-xwiki-war.configure-servlet-container.configure-tomcat.find-proxy-headers.WebHome]]. 1 +* [[Apache Server Key Configurations>>doc:documentation.xs.admin.installation.http-reverse-proxy.apache-key-configurations.WebHome]]. 2 +* [[Configure Tomcat to Find Proxy Headers>>doc:documentation.xs.admin.installation.methods.install-xwiki-war.configure-servlet-container.configure-tomcat.find-proxy-headers.WebHome]]. 3 +* [[NginX proxy module>>https://nginx.org/en/docs/http/ngx_http_proxy_module.html]]. 4 +* [[NginX beginner's guide>>https://nginx.org/en/docs/beginners_guide.html]].
Summary
-
Page properties (5 modified, 0 added, 0 removed)
-
Objects (0 modified, 2 added, 0 removed)
Details
- Page properties
-
- Title
-
... ... @@ -1,0 +1,1 @@ 1 +Set up NginX Proxy Server - Parent
-
... ... @@ -1,0 +1,1 @@ 1 +documentation.xs.admin.installation.http-reverse-proxy.nginx-key-configurations.WebHome - Author
-
... ... @@ -1,1 +1,1 @@ 1 -XWiki. XWikiGuest1 +XWiki.elenicojocariu - Default language
-
... ... @@ -1,0 +1,1 @@ 1 +en - Content
-
... ... @@ -1,0 +1,47 @@ 1 +NginX forwards requests to the XWiki [[Servlet Container>>doc:documentation.xs.admin.installation.methods.install-xwiki-war.configure-servlet-container.WebHome]], using the [[directives XWiki needs>>doc:documentation.xs.admin.installation.http-reverse-proxy.nginx-key-configurations.WebHome]]. This procedure serves the wiki over plain ##HTTP## on port ##80##. The commands are those of a Debian-based distribution, with the Windows equivalent given where it differs. 2 + 3 +1. Make sure your wiki is running and reachable locally, for example at {{code language="none"}}http://localhost:8080/xwiki{{/code}}. 4 +1. [[Install NginX>>https://nginx.org/en/docs/install.html]]. 5 +1. Create the file ##/etc/nginx/sites-available/xwiki## with the following content. On Windows there is no such directory: put the same content inside the ##http## section of ##C:\nginx\conf\nginx.conf##, in place of the ##server## block that file already has, and use Windows paths for the two log files. Leaving that block in is not reported as an error: two ##server## blocks listening on port ##80## for the same name only earn a warning, NginX keeps the first, and the stock welcome page answers instead of the wiki.((( 6 +{{code language="nginx"}} 7 +map $http_upgrade $connection_upgrade { 8 + default upgrade; 9 + "" ""; 10 +} 11 + 12 +server { 13 + listen 80; 14 + server_name localhost; 15 + 16 + access_log /var/log/nginx/xwiki-access.log; 17 + error_log /var/log/nginx/xwiki-error.log; 18 + 19 + client_max_body_size 0; 20 + 21 + location = / { 22 + return 301 /xwiki/; 23 + } 24 + 25 + location /xwiki { 26 + proxy_pass http://localhost:8080; 27 + 28 + proxy_set_header Host $http_host; 29 + proxy_set_header X-Real-IP $remote_addr; 30 + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 31 + proxy_set_header X-Forwarded-Proto $scheme; 32 + proxy_set_header X-Forwarded-Host $http_host; 33 + proxy_set_header Forwarded ""; 34 + 35 + proxy_http_version 1.1; 36 + proxy_set_header Upgrade $http_upgrade; 37 + proxy_set_header Connection $connection_upgrade; 38 + 39 + proxy_redirect off; 40 + } 41 +} 42 +{{/code}} 43 +))) 44 +1. Enable the site: {{code language="none"}}sudo ln -s /etc/nginx/sites-available/xwiki /etc/nginx/sites-enabled/{{/code}}. On Windows the block is already in ##nginx.conf##, so there is nothing to enable. 45 +1. Check the configuration: {{code language="none"}}sudo nginx -t{{/code}}, or {{code language="none"}}nginx -t{{/code}} on Windows. 46 +1. Reload NginX: {{code language="none"}}sudo systemctl reload nginx{{/code}}, or {{code language="none"}}nginx -s reload{{/code}} on Windows. 47 +1. Open {{code language="none"}}http://localhost{{/code}} in a browser. NginX redirects to {{code language="none"}}http://localhost/xwiki/{{/code}} and the wiki loads through port ##80##, with no port number in the address.
- DocApp.Code.DocumentationClass[0]
-
- FAQ
-
... ... @@ -1,0 +1,11 @@ 1 +== Why does the configuration file have to be enabled separately? == 2 + 3 +The ##nginx.conf## the Debian packages ship includes ##/etc/nginx/sites-enabled/##, and nothing else, so the symbolic link created above is what makes NginX read the file written in ##sites-available##. Keeping the two directories apart is what lets a site be disabled without deleting its configuration, and it is also why the Windows package, which has neither directory, is configured in ##nginx.conf## itself. 4 + 5 +== How do I serve the wiki on my own domain instead of localhost? == 6 + 7 +Set ##server_name## to that domain, for example {{code language="none"}}server_name wiki.example.com;{{/code}}, and make sure the name resolves: a name that is not published in DNS has to be added to the ##hosts## file of every machine that uses it, for example {{code language="none"}}127.0.0.1 wiki.example.local{{/code}}. 8 + 9 +== Where does NginX write its logs? == 10 + 11 +In the two files named by the block above, ##/var/log/nginx/xwiki-access.log## and ##/var/log/nginx/xwiki-error.log##; on Windows, under ##C:\nginx\logs##. The access log is where to look first when the wiki answers through port ##8080## but not through the proxy, since it records the path NginX actually forwarded. - Related
-
... ... @@ -1,0 +1,3 @@ 1 +* [[Configure Apache HTTP Server as a Proxy on a Linux OS>>doc:documentation.xs.admin.installation.http-reverse-proxy.apache-key-configurations.configure-apache-server-linux.WebHome]]. 2 +* [[Configure Tomcat to Find Proxy Headers>>doc:documentation.xs.admin.installation.methods.install-xwiki-war.configure-servlet-container.configure-tomcat.find-proxy-headers.WebHome]]. 3 +* [[NginX beginner's guide>>https://nginx.org/en/docs/beginners_guide.html]]. - Target
-
... ... @@ -1,0 +1,1 @@ 1 +administrator - Type
-
... ... @@ -1,0 +1,1 @@ 1 +tutorial
- DocApp.Code.DocumentationExtensionClass[0]
-
Summary
-
Page properties (1 modified, 0 added, 0 removed)
-
Objects (1 modified, 0 added, 0 removed)
Details
- Page properties
-
- Content
-
... ... @@ -1,35 +1,17 @@ 1 -{{warning}} 2 -WIP 3 -{{/warning}} 1 +Behind a [[reverse proxy>>doc:documentation.xs.admin.installation.http-reverse-proxy.WebHome]], every request reaches Tomcat from the proxy over plain ##HTTP##, so that is what Tomcat reports: the proxy's address as the client address, and ##http## as the protocol. Tomcat's ##RemoteIpValve## makes it read the headers the proxy adds instead, and report what the reader actually sent. XWiki does not depend on it, since it reads those same headers itself when it builds URLs, but everything that asks the container rather than XWiki does: Tomcat's own access log, and any code calling ##getRemoteAddr##, ##getScheme## or ##isSecure##. 4 4 5 -To make Tomcat read the client IP address and protocol forwarded by an [[Nginx>>documentation.xs.admin.installation.http-reverse-proxy.nginx-key-configurations.WebHome]] or [[Apache HTTP Server>>documentation.xs.admin.installation.http-reverse-proxy.apache-key-configurations.WebHome]] reverse proxy: 6 - 3 +1. Set up a reverse proxy that sends the forwarded headers, following [[Configure Apache HTTP Server as a Proxy on a Linux OS>>doc:documentation.xs.admin.installation.http-reverse-proxy.apache-key-configurations.configure-apache-server-linux.WebHome]] or [[Set up NginX Proxy Server>>doc:documentation.xs.admin.installation.http-reverse-proxy.nginx-key-configurations.set-nginx.WebHome]]. 7 7 1. Open the ##TOMCAT_HOME/conf/server.xml## file. 8 -1. Locatethefollowing##<Engine>## element:(((9 -{{code language=" none"}}5 +1. Add the valve directly inside the ##Engine## element:((( 6 +{{code language="xml"}} 10 10 <Engine name="Catalina" defaultHost="localhost"> 11 -{{/code}} 12 -))) 13 -1. Add the following ##RemoteIpValve## configuration directly inside the ##<Engine>## element:((( 14 -{{code language="none"}} 15 -<Engine name="Catalina" defaultHost="localhost"> 16 16 17 - <Valve className="org.apache.catalina.valves.RemoteIpValve" 18 - internalProxies="127\.0\.[0-1]\.1" 19 - remoteIpHeader="x-forwarded-for" 20 - requestAttributesEnabled="true" 21 - protocolHeader="x-forwarded-proto" 22 - protocolHeaderHttpsValue="https" /> 9 + <Valve className="org.apache.catalina.valves.RemoteIpValve" /> 23 23 24 24 </Engine> 25 25 {{/code}} 26 26 ))) 27 -1. Save the file. 28 -1. Restart Tomcat to apply the changes. 29 -1. Verify the configuration by accessing your wiki through the proxy URL: {{code language="none"}}https://yourdomain.com/xwiki{{/code}}. Verify that:((( 30 -* HTTPS URLs are generated correctly. 31 -* Redirects use HTTPS. 32 -* The client IP address is correctly forwarded. 33 -* Login sessions and WebSocket connections work properly. 34 -))) 35 - 14 +1. If the proxy runs on another machine, add an ##internalProxies## attribute that its address matches, for example {{code language="none"}}internalProxies="203\.0\.113\.7"{{/code}}. The value replaces the default, which covers the loopback and the private address ranges and is why the valve above needs nothing when the proxy sits on the same host, so the expression has to match every proxy the wiki is served through. Tomcat 10.1 reads the attribute as a regular expression; Tomcat 11 also accepts a list of CIDR blocks, for example {{code language="none"}}internalProxies="203.0.113.7/32"{{/code}}, and deprecates the regular expression form. 15 +1. Add ##requestAttributesEnabled="true"## to the ##AccessLogValve## element of the host, further down the same file, so that the access log uses what the valve found rather than the connection the request arrived on. This is the one place the attribute has to be written out: it defaults to ##false## there and to ##true## on the valve above. 16 +1. Restart Tomcat. 17 +1. Open a wiki page through the proxy. In the access log under ##TOMCAT_HOME/logs/##, for example ##localhost_access_log.2026-08-17.txt##, the first field of that request is now the reader's address instead of the proxy's, and the wiki keeps generating the links it already generated.
- DocApp.Code.DocumentationClass[0]
-
- FAQ
-
... ... @@ -1,0 +1,15 @@ 1 +== Do I need this for the wiki to generate HTTPS links? == 2 + 3 +No. XWiki reads the ##Forwarded##, ##X-Forwarded-Proto##, ##X-Forwarded-Host## and ##X-Forwarded-For## headers itself and builds its URLs from them, with no container-side configuration at all. If links are still plain ##HTTP##, the cause is elsewhere: the proxy is not sending ##X-Forwarded-Proto##, or ##xwiki.home## and ##xwiki.url.protocol## in the [[##xwiki.cfg## configuration file>>doc:documentation.xs.admin.configuration.WebHome]] name ##http##. Configure this valve so that Tomcat's own view of the request matches, not to fix the wiki's links. 4 + 5 +== Why is the logged client address still the proxy's? == 6 + 7 +Either the proxy's address does not match ##internalProxies##, so the valve leaves the header alone, or the access log is not using what the valve found: ##AccessLogValve## needs ##requestAttributesEnabled="true"## as well. 8 + 9 +== Which attributes does the valve need? == 10 + 11 +Only ##className##. Tomcat already reads ##x-forwarded-for## as ##remoteIpHeader##, ##X-Forwarded-Proto## as ##protocolHeader## and ##https## as ##protocolHeaderHttpsValue##, and ##requestAttributesEnabled## is already ##true## on the valve, so writing any of the four out changes nothing. ##hostHeader## and ##portHeader## are the attributes that default to nothing: set them to ##x-forwarded-host## and ##x-forwarded-port## if the host and port Tomcat reports must match the public ones too, and have the proxy send the port, which neither the NginX nor the Apache block does on its own. See the [[Remote IP Valve documentation>>https://tomcat.apache.org/tomcat-10.1-doc/config/valve.html#Remote_IP_Valve]]. 12 + 13 +== Is the same configuration needed on Jetty? == 14 + 15 +No. XWiki's Jetty distributions enable Jetty's ##forwarded## module, which processes the ##Forwarded## header and its ##X-Forwarded-*## predecessors, so nothing has to be added there. - Related
-
... ... @@ -1,0 +1,4 @@ 1 +* [[Configure Tomcat>>doc:documentation.xs.admin.installation.methods.install-xwiki-war.configure-servlet-container.configure-tomcat.WebHome]]. 2 +* [[HTTP Reverse Proxy for XWiki>>doc:documentation.xs.admin.installation.http-reverse-proxy.WebHome]]. 3 +* [[Configure HTTPS for the Apache HTTP Proxy Server>>doc:documentation.xs.admin.installation.http-reverse-proxy.apache-key-configurations.configurations.WebHome]]. 4 +* [[Tomcat Remote IP Valve>>https://tomcat.apache.org/tomcat-10.1-doc/config/valve.html#Remote_IP_Valve]].