Wiki source code of Short XWiki URLs

Version 27.2 by Vincent Massol on 2013/08/02

Hide last authors
Manuel Smeria 19.4 1 {{box cssClass="floatinginfobox" title="**Contents**"}}
2 {{toc/}}
3 {{/box}}
Jerome 14.1 4
Manuel Smeria 19.4 5 This tutorial shows you how to tune your XWiki platform by replacing the default URL scheme with a shorter scheme.
Jerome 15.1 6
Jerome 14.1 7 {{info}}
8 A short URL is an URL without the ##xwiki/bin/view## parts.
9 {{/info}}
maalej 2.1 10
Dmitry Bakbardin 20.1 11 = I. Application name =
maalej 1.1 12
Jerome 14.1 13 The ##/xwiki/## part of the URL is the application name. It identifies the application that should process the request, and it allows a container to host more than one application. To change it you must refer to your container's documentation and find how to map the context path of a web application. For example on Tomcat it's enough to simply deploy the XWiki webapp in the ##webapps## directory, in a sub directory named after the application name you wish to use (e.g. ##webapps/myappname##).
maalej 1.1 14
Vincent Massol 26.1 15 A special case is when deploying XWiki as the ROOT application, which actually allows the application name part to be empty, so an URL can take the form ##server.com/bin/view/Space/Document##. Achieving this depends on the container, as there's no standard regarding the ROOT application. For example:
16 * in Tomcat, with the default configuration, all it takes is to deploy the XWiki web application in ##webapps##, in a sub directory named ##ROOT## (i.e. ##webapps/ROOT##).
17 * In Jetty, with the default configuration, all it takes is to deploy the XWiki web application in ##webapps##, in a sub directory named ##root##. Note that if you're using the Standalone distribution (which packages Jetty and HSQLDB) then you'll also need to:
18 ** Remove the existing ##webapps/root## directory which contains a redirect Servlet that automatically redirects root URLs to the ##xwiki## context. You won't need that anymore.
19 ** Rename the existing ##webapps/xwiki## directory into ##webapps/root##.
20 ** Remove the ##jetty/contexts/xwiki.xml## file and thus keep only the ##jetty/contexts/root.xml## file. Otherwise you'll get a warning in the console.
Vincent Massol 10.2 21
Vincent Massol 26.1 22 Refer to your container's documentation for more details.
23
Dmitry Bakbardin 20.1 24 = II. Servlet mapping name =
maalej 1.1 25
Manuel Smeria 19.4 26 The second part is the hardest part to remove. It identifies the servlet that should process the page, which, for ##/bin/##, is the Struts servlet. To get rid of ##/bin/##, for the moment ##web.xml## must be changed in a container-dependent way, so that the container's default servlet is configured to serve the existing directories, like skins, yui, tinymce and wikieditor.
maalej 1.1 27
Dmitry Bakbardin 20.1 28 == 2.1. Original Instructions ==
maalej 1.1 29
Dmitry Bakbardin 20.1 30 === 2.1.1. Container setup ===
31
Vincent Massol 27.1 32 In Jetty, the container shipped with the XWiki installer, you will have to write:
33 * For Jetty <= 7.x:(((
Jerome 14.1 34 {{code language="xml"}}
Vincent Massol 27.1 35 <servlet>
Sergiu Dumitriu 4.1 36 <servlet-name>defaultSkins</servlet-name>
PaulHarris 12.1 37 <servlet-class>org.mortbay.jetty.servlet.DefaultServlet</servlet-class>
Sergiu Dumitriu 4.1 38 <load-on-startup>1</load-on-startup>
39 </servlet>
40 <servlet-mapping>
41 <servlet-name>defaultSkins</servlet-name>
42 <url-pattern>/skins/*</url-pattern>
43 </servlet-mapping>
Jerome 18.1 44 <servlet-mapping>
45 <servlet-name>defaultSkins</servlet-name>
46 <url-pattern>/resources/*</url-pattern>
47 </servlet-mapping>
Jerome 14.1 48 {{/code}}
Vincent Massol 27.1 49 )))
50 * For Jetty >= 8.x:(((
Vincent Massol 27.2 51 {{code language="xml"}}
Vincent Massol 27.1 52 <servlet>
53 <servlet-name>defaultSkins</servlet-name>
54 <servlet-class>org.eclipse.jetty.servlet.DefaultServlet</servlet-class>
55 <load-on-startup>1</load-on-startup>
56 </servlet>
57 <servlet-mapping>
58 <servlet-name>defaultSkins</servlet-name>
59 <url-pattern>/skins/*</url-pattern>
60 </servlet-mapping>
61 <servlet-mapping>
62 <servlet-name>defaultSkins</servlet-name>
63 <url-pattern>/resources/*</url-pattern>
64 </servlet-mapping>
Vincent Massol 27.2 65 {{/code}}
Vincent Massol 27.1 66 )))
Sergiu Dumitriu 4.1 67
Jerome 16.1 68 {{warning}}
Manuel Smeria 19.4 69 If you are using Jetty 1.7 or higher, the correct servlet-class is ##org.eclipse.jetty.servlet.DefaultServlet##.
Jerome 16.1 70 {{/warning}}
71
Sergiu Dumitriu 7.1 72 In Tomcat, the default servlet does not accept a parameter for changing the resource base, so you will need to write another default servlet.
Sergiu Dumitriu 4.1 73
Dmitry Bakbardin 20.1 74 === 2.1.2. Container setup alternative: front-end by-pass ===
75
Manuel Smeria 19.4 76 Alternatively, you could by-pass the servlet container at the web front-end level. For example, if you are using Apache httpd as a front-end, and assuming a webapp deployed as a ROOT webapp and an AJP connection between httpd and the servlet container, the following configuration allows you to serve skin files and static resources directly from httpd:
Jerome 19.1 77
78 {{code}}
Manuel Smeria 19.4 79 Alias /skins /usr/local/xwiki/skins
80 Alias /resources /usr/local/xwiki/resources
81 ProxyPass /skins/ !
82 ProxyPass /resources/ !
Jerome 19.1 83 {{/code}}
84
Dmitry Bakbardin 22.1 85 == 2.2. Struts servlet mapping ==
Dmitry Bakbardin 20.1 86
Manuel Smeria 19.4 87 The second thing to do is to copy the mapping for the Struts servlet to also be activated for /, like:
Jerome 14.1 88
89 {{code language="xml"}}
90 <servlet-mapping>
Sergiu Dumitriu 4.1 91 <servlet-name>action</servlet-name>
92 <url-pattern>/*</url-pattern>
93 </servlet-mapping>
Jerome 14.1 94 {{/code}}
95
Manuel Smeria 19.4 96 Be sure to leave the other mappings in place, so that ##/bin/## works, too.
Sergiu Dumitriu 4.1 97
Vincent Massol 26.2 98 The last thing that must be changed is the default mapping used by the URL factory, by adding this piece of code in ##xwiki.cfg##: {{code language="none"}}xwiki.defaultservletpath={{/code}}.
Sergiu Dumitriu 4.1 99
Dmitry Bakbardin 20.1 100 == 2.3. Specific Lighttpd + Jetty Instructions ==
Sergiu Dumitriu 11.1 101
Manuel Smeria 19.4 102 The original instructions might work for you if you don't use the WYSIWYG editor. It did not work for me and this is what I had to do:
PaulHarris 12.1 103
Jerome 14.1 104 The problem is that you need to use Java Struts for the routing. They are not very powerful when it comes to the servlet-mapping configuration. We need to map:
PaulHarris 12.1 105
Jerome 14.1 106 * /resources/* ~-~-> static content
107 * /skins/* ~-~-> static content
108 * *.gwtrpc ~-~-> a servlet
109 * everything else ~-~-> other servlets
110
Manuel Smeria 19.4 111 The problem is that .gwtrpc files are in the ##/resources/## folder, and the ##/resources/*## mapping will always have a higher priority than *.gwtrpc due to the way structs works.
PaulHarris 12.1 112
Manuel Smeria 19.4 113 So, we have to cheat a bit, and offload the static content to the webserver, which does have a powerful route-map configuration.
PaulHarris 12.1 114
Manuel Smeria 19.4 115 I used lighttpd, but I assume it can be done with other webservers too. This is the configuration I used in the lighttpd config (note that my xwiki folder has been moved to ##/usr/share/jetty/webapps/root## (no 'xwiki' at all)):
PaulHarris 12.1 116
Jerome 14.1 117 {{code language="none"}}
PaulHarris 12.1 118 $HTTP["host"] =~ "^www\.domain\.com$" {
119 # ensure all requests for .gwtrpc files go through to java server
120 # we can put this rule first as a higher priority, which java couldn't do
121 $HTTP["url"] =~ "\.gwtrpc$" {
122 proxy.server = ( "" => (( "host" => "127.0.0.1", "port" => 8080 )))
123 }
124 # otherwise, we can handle the static resources
125 else $HTTP["url"] =~ "^/resources/" {
126 alias.url += ( "/resources" => "/usr/share/jetty/webapps/root/resources" )
127 }
128 # otherwise, we can handle the static resources
129 else $HTTP["url"] =~ "^/skins/" {
130 alias.url += ( "/skins" => "/usr/share/jetty/webapps/root/skins" )
131 }
132 # and here is the primary server
133 else $HTTP["host"] =~ "^www\.domain\.com$" {
134 proxy.server = ( "" => (( "host" => "127.0.0.1", "port" => 8080 )))
135 }
136 }
137 # redirect anything.domain.com to www.domain.com
138 else $HTTP["host"] =~ "\.domain\.com$" {
139 url.redirect = ( "^/(.*)" => "http://www.domain.com/$1" )
140 server.name = "www.domain.com"
141 }
142 # redirect domain.com to www.domain.com
143 else $HTTP["host"] =~ "domain\.com$" {
144 url.redirect = ( "^/(.*)" => "http://www.domain.com/$1" )
145 server.name = "www.domain.com"
146 }
Jerome 14.1 147 {{/code}}
PaulHarris 12.1 148
Manuel Smeria 19.4 149 So lighttpd will serve any static content unless it has .gwtrpc on the end of the URL.
PaulHarris 12.1 150
Dmitry Bakbardin 23.1 151 If you use Nginx as a web-server, just add three more locations and set "root" to them. By //try_files// Nginx checks static content presence and if doesn't exist, redirect it to the Tomcat (we expect dynamic content in this case, including all *.gwtrpc requests).
152
153 {{code}}
154 location /skins/ {
155 root /var/lib/tomcat7/webapps/ROOT;
156 }
157
158 location /resources/ {
159 try_files $uri $uri/ @fallback;
160 root /var/lib/tomcat7/webapps/ROOT;
161 }
162
163 location @fallback {
164 proxy_pass http://localhost:8080;
165 }
166
167 {{/code}}
168
Dmitry Bakbardin 25.1 169 In the example above XWiki installed as ROOT application in Tomcat. Change path to your XWiki application accordingly.
Dmitry Bakbardin 24.1 170
171
Manuel Smeria 19.4 172 Then in ##web.xml##, I changed the gwtrpc mapping to:
Jerome 14.1 173
174 {{code language="xml"}}
175 <servlet-mapping>
PaulHarris 12.1 176 <servlet-name>gwtrpc</servlet-name>
177
178 <url-pattern>/resources/*</url-pattern>
179 <url-pattern>/skins/*</url-pattern>
180 </servlet-mapping>
Jerome 14.1 181 {{/code}}
PaulHarris 12.1 182
Manuel Smeria 19.4 183 Since we are using a url-pattern of ##/path/##, it will be specific enough to be a higher priority than the / pattern we'll use next. And since the only thing that will come through via resources or skins will be gwtrpc, then we can be sure it's ok. Note that only ##resources## is required, but I did both anyway.
PaulHarris 12.1 184
Manuel Smeria 19.4 185 Now, as described above, add a rule to catch everything else and redirect it to your xwiki servlet:
Jerome 14.1 186
187 {{code language="xml"}}
188 <servlet-mapping>
PaulHarris 12.1 189 <servlet-name>action</servlet-name>
190 <url-pattern>/*</url-pattern>
191 </servlet-mapping>
Jerome 14.1 192 {{/code}}
PaulHarris 12.1 193
Manuel Smeria 19.4 194 The last thing that must be changed is the default mapping used by the URL factory, by adding this piece of code in ##xwiki.cfg##: {{code language="none"}}xwiki.defaultservletpath={{/code}}.
PaulHarris 12.1 195
Dmitry Bakbardin 20.1 196 == 2.4. Alternative: Changing the mapping name ==
PaulHarris 12.1 197
Manuel Smeria 19.4 198 If removing the ##/bin## part is not possible in your environment, you can still rename it to something less technical, and which would better fit your site, like ##/wiki##. To do this, you must first add a mapping for the new path, as in:
PaulHarris 12.1 199
Jerome 14.1 200 {{code language="xml"}}
201 <servlet-mapping>
Sergiu Dumitriu 11.3 202 <servlet-name>action</servlet-name>
203 <url-pattern>/wiki/*</url-pattern>
204 </servlet-mapping>
Jerome 14.1 205 {{/code}}
Sergiu Dumitriu 11.3 206
207 This means that the wiki now accepts requests through this mapping.
208
Jerome 14.1 209 {{info}}
210 This specific mapping (##/wiki##) should already be there, but you need to add a new one for other custom mappings.
211 {{/info}}
Sergiu Dumitriu 11.3 212
Jerome 14.1 213 {{warning}}
Manuel Smeria 19.4 214 The ##/wiki## mapping is reserved for multiwikis with path based wiki mapping setup, so use something else in this scenarion. It should work fine when multiwikis are disabled or when only hostname wiki mapping is used.
Jerome 14.1 215 {{/warning}}
Sergiu Dumitriu 11.4 216
Manuel Smeria 19.4 217 Then you must make sure that accessing the application without a servlet in the path (as in ##http:~/~/server.com/xwiki/## when XWiki is not set as the ROOT application, or ##http:~/~/server.com/## if XWiki is the ROOT application) redirects to the right servlet. This involves changing the configuration for the ##redirect## servlet in ##web.xml##; search for the declaration of the ##redirectHomeServlet##, uncomment the ##init-param## section, and adjust accordingly:
Sergiu Dumitriu 11.3 218
Jerome 14.1 219 {{code language="xml"}}
220 <servlet>
Sergiu Dumitriu 11.3 221 <servlet-name>redirectHomeServlet</servlet-name>
222 <servlet-class>com.xpn.xwiki.web.HomePageRedirectServlet</servlet-class>
223 <!-- Uncomment and edit this if you want to redirect to a different home page, or if you have different mappings.
224 Note: the URL should not start with /, because it allows the context name to be changed. If it starts with /,
225 then it should be an absolute URL, including the application context path. -->
226 <init-param>
227 <description>The address to redirect to when the client hits the root of the application.</description>
228 <param-name>homePage</param-name>
229 <param-value>wiki/</param-value>
230 </init-param>
231 </servlet>
Jerome 14.1 232 {{/code}}
Sergiu Dumitriu 11.3 233
Manuel Smeria 19.4 234 Also change the default mapping used by the URL factory, by adding this in ##xwiki.cfg##: {{code language="none"}}xwiki.defaultservletpath=wiki/{{/code}}.
Sergiu Dumitriu 11.3 235
Manuel Smeria 19.4 236 Optionally, you can make sure that accessing the hostname without a path (as in ##http:~/~/server.com/##) redirects to the right servlet. This depends on your environment. In a Tomcat + Apache HTTPD + mod_redirect, just update these settings:
Sergiu Dumitriu 11.3 237
Jerome 14.1 238 {{code language="none"}}
239 RedirectMatch ^/$ /xwiki/wiki/
Sergiu Dumitriu 11.3 240 RedirectMatch ^/xwiki/$ /xwiki/wiki/
Jerome 14.1 241 {{/code}}
Sergiu Dumitriu 11.3 242
Jerome 14.1 243 In the default standalone distribution (with Jetty), the ROOT application only redirects to the ##/xwiki## application, so configuring the XWiki redirect servlet is enough if you don't change the application name. If you do, just edit the ##web.xml## of the ##root## webapp, uncomment the ##init-param## of the ##XWikiDispatcherServlet## and change the application name.
Sergiu Dumitriu 11.3 244
Dmitry Bakbardin 20.1 245 = III. Struts action name =
Jerome 14.1 246
Manuel Smeria 19.4 247 The third part, ##/view/##, identifies the struts action that should process a request. So this tells what we want to do with the document, ##/view/## it, ##/edit/## it or ##/delete/## it, for example. The XWiki platform allows this part to be missing, considering that the default action is to just display the document, so an URL like ##server.com/bin/Space/Document## will work out of the box.
248
249 Even more, the URL factory, the component that generates URLs, can be configured to skip this part when the action is ##/view/##. To do this write this code in ##xwiki.cfg##: {{code language="none"}}xwiki.showviewaction=0{{/code}}.
250
Dmitry Bakbardin 20.1 251 = IV. Error Page =
Manuel Smeria 19.4 252
Jerome 14.1 253 At the ##WEB-INF/web.xml##, the ##location## of the 404 error code needs to be changed accordingly. For example:
254
255 {{code language="xml"}}
256 <error-page>
mingfai 9.1 257 <error-code>404</error-code>
258 <!--<location>/xwiki/bin/view/Main/DocumentDoesNotExist</location>-->
259 <location>/bin/Main/DocumentDoesNotExist</location>
260 </error-page>
Jerome 14.1 261 {{/code}}
mingfai 9.1 262
Dmitry Bakbardin 20.1 263 = V. Conclusion =
Sergiu Dumitriu 4.1 264
265 After performing all these changes, you should be able to access documents with URLs like:
Jerome 14.1 266
Sergiu Dumitriu 4.1 267 * server.com/Space/Document
268 * server.com/Space/ (pointing to Space.WebHome)
269 * server.com/Document (pointing to Main.Document)
270 * server.com/ will show Main.WebHome, without any redirect.
271
Vincent Massol 5.1 272 As a bonus, these changes are backwards compatible, meaning that any currently working URL will also work with these changes performed, so you won't have any broken bookmarks.

Get Connected