Commit | Line | Data |
1d2376f3 |
1 | =head1 NAME |
2 | |
3 | Catalyst::Manual::Deployment::Apache::mod_perl - Deploying Catalyst with mod_perl |
4 | |
5 | =head2 mod_perl Deployment |
6 | |
7 | mod_perl is not the best solution for many applications, but we'll list some |
8 | pros and cons so you can decide for yourself. |
9 | |
10 | =head3 Pros |
11 | |
12 | =head4 Speed |
13 | |
14 | mod_perl is fast and your app will be loaded in memory |
15 | within each Apache process. |
16 | |
17 | =head4 Shared memory for multiple apps |
18 | |
19 | If you need to run several Catalyst apps on the same server, mod_perl will |
20 | share the memory for common modules. |
21 | |
22 | =head3 Cons |
23 | |
24 | =head4 Memory usage |
25 | |
26 | Since your application is fully loaded in memory, every Apache process will |
27 | be rather large. This means a large Apache process will be tied up while |
28 | serving static files, large files, or dealing with slow clients. For this |
29 | reason, it is best to run a two-tiered web architecture with a lightweight |
30 | frontend server passing dynamic requests to a large backend mod_perl |
31 | server. |
32 | |
33 | =head4 Reloading |
34 | |
35 | Any changes made to the core code of your app require a full Apache restart. |
36 | Catalyst does not support Apache::Reload or StatINC. This is another good |
37 | reason to run a frontend web server where you can set up an |
38 | C<ErrorDocument 502> page to report that your app is down for maintenance. |
39 | |
40 | =head4 Cannot run multiple versions of the same app |
41 | |
42 | It is not possible to run two different versions of the same application in |
43 | the same Apache instance because the namespaces will collide. |
44 | |
45 | =head4 Cannot run different versions of libraries. |
46 | |
47 | If you have two different applications which run on the same machine, |
48 | which need two different versions of a library then the only way to do |
49 | this is to have per-vhost perl interpreters (with different library paths). |
50 | This is entirely possible, but nullifies all the memory sharing benefits that |
51 | you get from having multiple applications sharing the same interpreter. |
52 | |
53 | =head4 Setup |
54 | |
55 | Now that we have that out of the way, let's talk about setting up mod_perl |
56 | to run a Catalyst app. |
57 | |
58 | =head4 1. Install Catalyst::Engine::Apache |
59 | |
60 | You should install the latest versions of both Catalyst and |
61 | Catalyst::Engine::Apache. The Apache engines were separated from the |
62 | Catalyst core in version 5.50 to allow for updates to the engine without |
63 | requiring a new Catalyst release. |
64 | |
65 | =head4 2. Install Apache with mod_perl |
66 | |
67 | Both Apache 1.3 and Apache 2 are supported, although Apache 2 is highly |
68 | recommended. With Apache 2, make sure you are using the prefork MPM and not |
69 | the worker MPM. The reason for this is that many Perl modules are not |
70 | thread-safe and may have problems running within the threaded worker |
71 | environment. Catalyst is thread-safe however, so if you know what you're |
72 | doing, you may be able to run using worker. |
73 | |
74 | In Debian, the following commands should get you going. |
75 | |
76 | apt-get install apache2-mpm-prefork |
77 | apt-get install libapache2-mod-perl2 |
78 | |
79 | =head4 3. Configure your application |
80 | |
81 | Every Catalyst application will automagically become a mod_perl handler |
82 | when run within mod_perl. This makes the configuration extremely easy. |
83 | Here is a basic Apache 2 configuration. |
84 | |
85 | PerlSwitches -I/var/www/MyApp/lib |
86 | PerlModule MyApp |
87 | |
88 | <Location /> |
89 | SetHandler modperl |
90 | PerlResponseHandler MyApp |
91 | </Location> |
92 | |
93 | The most important line here is C<PerlModule MyApp>. This causes mod_perl |
94 | to preload your entire application into shared memory, including all of your |
95 | controller, model, and view classes and configuration. If you have -Debug |
96 | mode enabled, you will see the startup output scroll by when you first |
97 | start Apache. |
98 | |
99 | For an example Apache 1.3 configuration, please see the documentation for |
100 | L<Catalyst::Engine::Apache::MP13>. |
101 | |
102 | =head3 Test It |
103 | |
104 | That's it, your app is now a full-fledged mod_perl application! Try it out |
105 | by going to http://your.server.com/. |
106 | |
107 | =head3 Other Options |
108 | |
109 | =head4 Non-root location |
110 | |
111 | You may not always want to run your app at the root of your server or virtual |
112 | host. In this case, it's a simple change to run at any non-root location |
113 | of your choice. |
114 | |
115 | <Location /myapp> |
116 | SetHandler modperl |
117 | PerlResponseHandler MyApp |
118 | </Location> |
119 | |
120 | When running this way, it is best to make use of the C<uri_for> method in |
121 | Catalyst for constructing correct links. |
122 | |
123 | =head4 Static file handling |
124 | |
125 | Static files can be served directly by Apache for a performance boost. |
126 | |
127 | DocumentRoot /var/www/MyApp/root |
128 | <Location /static> |
129 | SetHandler default-handler |
130 | </Location> |
131 | |
132 | This will let all files within root/static be handled directly by Apache. In |
133 | a two-tiered setup, the frontend server should handle static files. |
134 | The configuration to do this on the frontend will vary. |
135 | |
136 | The same is accomplished in lighttpd with the following snippet: |
137 | |
138 | $HTTP["url"] !~ "^/(?:img/|static/|css/|favicon.ico$)" { |
139 | fastcgi.server = ( |
140 | "" => ( |
141 | "MyApp" => ( |
142 | "socket" => "/tmp/myapp.socket", |
143 | "check-local" => "disable", |
144 | ) |
145 | ) |
146 | ) |
147 | } |
148 | |
149 | Which serves everything in the img, static, css directories |
150 | statically, as well as the favicon file. |
151 | |
152 | Note the path of the application needs to be stated explicitly in the |
153 | web server configuration for both these recipes. |
154 | |
155 | =head2 Catalyst on shared hosting |
156 | |
157 | So, you want to put your Catalyst app out there for the whole world to |
158 | see, but you don't want to break the bank. There is an answer - if you |
159 | can get shared hosting with FastCGI and a shell, you can install your |
160 | Catalyst app in a local directory on your shared host. First, run |
161 | |
162 | perl -MCPAN -e shell |
163 | |
164 | and go through the standard CPAN configuration process. Then exit out |
165 | without installing anything. Next, open your .bashrc and add |
166 | |
167 | export PATH=$HOME/local/bin:$HOME/local/script:$PATH |
168 | perlversion=`perl -v | grep 'built for' | awk '{print $4}' | sed -e 's/v//;'` |
169 | export PERL5LIB=$HOME/local/share/perl/$perlversion:$HOME/local/lib/perl/$perlversion:$HOME/local/lib:$PERL5LIB |
170 | |
171 | and log out, then back in again (or run C<". .bashrc"> if you |
172 | prefer). Finally, edit C<.cpan/CPAN/MyConfig.pm> and add |
173 | |
174 | 'make_install_arg' => qq[SITEPREFIX=$ENV{HOME}/local], |
175 | 'makepl_arg' => qq[INSTALLDIRS=site install_base=$ENV{HOME}/local], |
176 | |
177 | Now you can install the modules you need using CPAN as normal; they |
178 | will be installed into your local directory, and perl will pick them |
179 | up. Finally, change directory into the root of your virtual host and |
180 | symlink your application's script directory in: |
181 | |
182 | cd path/to/mydomain.com |
183 | ln -s ~/lib/MyApp/script script |
184 | |
185 | And add the following lines to your .htaccess file (assuming the server |
186 | is setup to handle .pl as fcgi - you may need to rename the script to |
187 | myapp_fastcgi.fcgi and/or use a SetHandler directive): |
188 | |
189 | RewriteEngine On |
190 | RewriteCond %{REQUEST_URI} !^/?script/myapp_fastcgi.pl |
191 | RewriteRule ^(.*)$ script/myapp_fastcgi.pl/$1 [PT,L] |
192 | |
193 | Now C<http://mydomain.com/> should now Just Work. Congratulations, now |
194 | you can tell your friends about your new website (or in our case, tell |
195 | the client it's time to pay the invoice :) ) |
196 | |
197 | =head2 FastCGI Deployment |
198 | |
199 | FastCGI is a high-performance extension to CGI. It is suitable |
200 | for production environments. |
201 | |
202 | =head3 Pros |
203 | |
204 | =head4 Speed |
205 | |
206 | FastCGI performs equally as well as mod_perl. Don't let the 'CGI' fool you; |
207 | your app runs as multiple persistent processes ready to receive connections |
208 | from the web server. |
209 | |
210 | =head4 App Server |
211 | |
212 | When using external FastCGI servers, your application runs as a standalone |
213 | application server. It may be restarted independently from the web server. |
214 | This allows for a more robust environment and faster reload times when |
215 | pushing new app changes. The frontend server can even be configured to |
216 | display a friendly "down for maintenance" page while the application is |
217 | restarting. |
218 | |
219 | =head4 Load-balancing |
220 | |
221 | You can launch your application on multiple backend servers and allow the |
222 | frontend web server to load-balance between all of them. And of course, if |
223 | one goes down, your app continues to run fine. |
224 | |
225 | =head4 Multiple versions of the same app |
226 | |
227 | Each FastCGI application is a separate process, so you can run different |
228 | versions of the same app on a single server. |
229 | |
230 | =head4 Can run with threaded Apache |
231 | |
232 | Since your app is not running inside of Apache, the faster mpm_worker module |
233 | can be used without worrying about the thread safety of your application. |
234 | |
235 | =head3 Cons |
236 | |
237 | You may have to disable mod_deflate. If you experience page hangs with |
238 | mod_fastcgi then remove deflate.load and deflate.conf from mods-enabled/ |
239 | |
240 | =head4 More complex environment |
241 | |
242 | With FastCGI, there are more things to monitor and more processes running |
243 | than when using mod_perl. |
244 | |
245 | =head3 Setup |
246 | |
247 | =head4 1. Install Apache with mod_fastcgi |
248 | |
249 | mod_fastcgi for Apache is a third party module, and can be found at |
250 | L<http://www.fastcgi.com/>. It is also packaged in many distributions, |
251 | for example, libapache2-mod-fastcgi in Debian. You will also need to install |
252 | the L<FCGI> module from cpan. |
253 | |
254 | Important Note! If you experience difficulty properly rendering pages, |
255 | try disabling Apache's mod_deflate (Deflate Module), e.g. 'a2dismod deflate'. |
256 | |
257 | =head4 2. Configure your application |
258 | |
259 | # Serve static content directly |
260 | DocumentRoot /var/www/MyApp/root |
261 | Alias /static /var/www/MyApp/root/static |
262 | |
263 | FastCgiServer /var/www/MyApp/script/myapp_fastcgi.pl -processes 3 |
264 | Alias /myapp/ /var/www/MyApp/script/myapp_fastcgi.pl/ |
265 | |
266 | # Or, run at the root |
267 | Alias / /var/www/MyApp/script/myapp_fastcgi.pl/ |
268 | |
269 | The above commands will launch 3 app processes and make the app available at |
270 | /myapp/ |
271 | |
272 | =head3 Standalone server mode |
273 | |
274 | While not as easy as the previous method, running your app as an external |
275 | server gives you much more flexibility. |
276 | |
277 | First, launch your app as a standalone server listening on a socket. |
278 | |
279 | script/myapp_fastcgi.pl -l /tmp/myapp.socket -n 5 -p /tmp/myapp.pid -d |
280 | |
281 | You can also listen on a TCP port if your web server is not on the same |
282 | machine. |
283 | |
284 | script/myapp_fastcgi.pl -l :8080 -n 5 -p /tmp/myapp.pid -d |
285 | |
286 | You will probably want to write an init script to handle starting/stopping |
287 | of the app using the pid file. |
288 | |
289 | Now, we simply configure Apache to connect to the running server. |
290 | |
291 | # 502 is a Bad Gateway error, and will occur if the backend server is down |
292 | # This allows us to display a friendly static page that says "down for |
293 | # maintenance" |
294 | Alias /_errors /var/www/MyApp/root/error-pages |
295 | ErrorDocument 502 /_errors/502.html |
296 | |
297 | FastCgiExternalServer /tmp/myapp.fcgi -socket /tmp/myapp.socket |
298 | Alias /myapp/ /tmp/myapp.fcgi/ |
299 | |
300 | # Or, run at the root |
301 | Alias / /tmp/myapp.fcgi/ |
302 | |
303 | =head3 More Info |
304 | |
305 | L<Catalyst::Engine::FastCGI>. |
306 | |
307 | =head2 Development server deployment |
308 | |
309 | The development server is a mini web server written in perl. If you |
310 | expect a low number of hits or you don't need mod_perl/FastCGI speed, |
311 | you could use the development server as the application server with a |
312 | lightweight proxy web server at the front. However, consider using |
313 | L<Catalyst::Engine::HTTP::Prefork> for this kind of deployment instead, since |
314 | it can better handle multiple concurrent requests without forking, or can |
315 | prefork a set number of servers for improved performance. |
316 | |
317 | =head3 Pros |
318 | |
319 | As this is an application server setup, the pros are the same as |
320 | FastCGI (with the exception of speed). |
321 | It is also: |
322 | |
323 | =head4 Simple |
324 | |
325 | The development server is what you create your code on, so if it works |
326 | here, it should work in production! |
327 | |
328 | =head3 Cons |
329 | |
330 | =head4 Speed |
331 | |
332 | Not as fast as mod_perl or FastCGI. Needs to fork for each request |
333 | that comes in - make sure static files are served by the web server to |
334 | save forking. |
335 | |
336 | =head3 Setup |
337 | |
338 | =head4 Start up the development server |
339 | |
340 | script/myapp_server.pl -p 8080 -k -f -pidfile=/tmp/myapp.pid |
341 | |
342 | You will probably want to write an init script to handle stop/starting |
343 | the app using the pid file. |
344 | |
345 | =head4 Configuring Apache |
346 | |
347 | Make sure mod_proxy is enabled and add: |
348 | |
349 | # Serve static content directly |
350 | DocumentRoot /var/www/MyApp/root |
351 | Alias /static /var/www/MyApp/root/static |
352 | |
353 | ProxyRequests Off |
354 | <Proxy *> |
355 | Order deny,allow |
356 | Allow from all |
357 | </Proxy> |
358 | |
359 | # Need to specifically stop these paths from being passed to proxy |
360 | ProxyPass /static ! |
361 | ProxyPass /favicon.ico ! |
362 | |
363 | ProxyPass / http://localhost:8080/ |
364 | ProxyPassReverse / http://localhost:8080/ |
365 | |
366 | # This is optional if you'd like to show a custom error page |
367 | # if the proxy is not available |
368 | ErrorDocument 502 /static/error_pages/http502.html |
369 | |
370 | You can wrap the above within a VirtualHost container if you want |
371 | different apps served on the same host. |
372 | |
c62b44f3 |
373 | # Set up your Catalyst app as a mod_perl 2.x application in httpd.conf |
374 | PerlSwitches -I/var/www/MyApp/lib |
375 | |
376 | # Preload your entire application |
377 | PerlModule MyApp |
378 | |
379 | <VirtualHost *> |
380 | ServerName myapp.hostname.com |
381 | DocumentRoot /var/www/MyApp/root |
382 | |
383 | <Location /> |
384 | SetHandler modperl |
385 | PerlResponseHandler MyApp |
386 | </Location> |
387 | |
388 | # you can also run your app in any non-root location |
389 | <Location /some/other/path> |
390 | SetHandler perl-script |
391 | PerlResponseHandler MyApp |
392 | </Location> |
393 | |
394 | # Make sure to let Apache handle your static files |
395 | # (It is not necessary to remove the Static::Simple plugin |
396 | # in production; Apache will bypass Static::Simple if |
397 | # configured in this way) |
398 | |
399 | <Location /static> |
400 | SetHandler default-handler |
401 | </Location> |
402 | |
403 | # If not running at a root location in a VirtualHost, |
404 | # you'll probably need to set an Alias to the location |
405 | # of your static files, and allow access to this location: |
406 | |
407 | Alias /myapp/static /filesystem/path/to/MyApp/root/static |
408 | <Directory /filesystem/path/to/MyApp/root/static> |
409 | allow from all |
410 | </Directory> |
411 | <Location /myapp/static> |
412 | SetHandler default-handler |
413 | </Location> |
414 | |
415 | </VirtualHost> |
416 | |
417 | =head1 DESCRIPTION |
418 | |
419 | This is the Catalyst engine specialized for Apache2 mod_perl version 2.x. |
420 | |
421 | =head1 ModPerl::Registry |
422 | |
423 | While this method is not recommended, you can also run your Catalyst |
424 | application via a ModPerl::Registry script. |
425 | |
426 | httpd.conf: |
427 | |
428 | PerlModule ModPerl::Registry |
429 | Alias / /var/www/MyApp/script/myapp_registry.pl/ |
430 | |
431 | <Directory /var/www/MyApp/script> |
432 | Options +ExecCGI |
433 | </Directory> |
434 | |
435 | <Location /> |
436 | SetHandler perl-script |
437 | PerlResponseHandler ModPerl::Registry |
438 | </Location> |
439 | |
440 | script/myapp_registry.pl (you will need to create this): |
441 | |
442 | #!/usr/bin/perl |
443 | |
444 | use strict; |
445 | use warnings; |
446 | use MyApp; |
447 | |
448 | MyApp->handle_request( Apache2::RequestUtil->request ); |
449 | |
450 | |
1d2376f3 |
451 | =head1 AUTHORS |
452 | |
453 | Catalyst Contributors, see Catalyst.pm |
454 | |
455 | =head1 COPYRIGHT |
456 | |
457 | This library is free software. You can redistribute it and/or modify it under |
458 | the same terms as Perl itself. |
459 | |
460 | =cut |
461 | |