Table of Contents
Before you do anything, you need to decide what version of Tomcat you want to run. Consider the following factorys.
This guide covers only major versions 5.0.x and 5.5.x. I have no desire to use 4.x versions-- they suck. I look forward to using 6.x, but have had no opportunity to yet.
If your OS distribution comes with a Tomcat distro of a
version that you're satisfied with (or if your organization
provides one), then
you could simplify your life by using that... or not.
Otherwise, go to http://jakarta.apache.org
and download the latest stable (non-alpha and non-beta)
core binary of desired major version.
Just get the one Core file in the file format that you want
(For UNIX users, I recommend using that tar.gz format intead of
the zip. Otherwise you will need to make the script files
executable).
For version 5.0.x, get just the core download, which contains
the Manager and Admin web apps, and documentation.
For version 5.5.x, get the core download, which contains the
Manager web app and docs; plus the Admin download if you want to
run the Admin web app; and the JDK 1.4 Compat download if you
plan to use Java version 1.4.
(If you don't run the Admin web app, you will need to edit the
server.xml
file manually for every
configuration change to the Tomcat server).
The Deployer download is not needed for a server install. This is not the Manager webapp, but a Java client for the Manager webapp. You install this on a workstation or server where you will run ant to deploy to the remote Tomcat server. (Not that you necessarily want to do that. It's overkill if you will only be deploying locally, and there are other ways to deploy remotely).
If you're using preconfigured packages, install them. Besides the base package, install packages for standalone docs, admin and manager webapps, samples webapp and docs webapp if you want them. It's a hard call whether to use OS-supplied Tomcat packages. The benefit is, upgrades are a snap, and can be automated, and, best of all, if your OS has packages for Apache HTTPD and a Tomcat plugin, 99% of the plugin setup is done for you.
You won't understand much of this document if you don't have a clear understanding of installation and instance.
A Tomcat installation is one set of all the stuff that you
extract from a Tomcat distribution (or packages, rpms, etc.).
You could very well have multiple installations on the same
server, for example, a Tomcat 5.5.9 installation and a Tomcat
5.0.28 installation.
There is no good reason to have multiple installations of the
exact same Tomcat distribution, since you can run as many
Tomcat instances as you want using one Tomcat installation.
The env variable CATALINA_HOME
identifies
the tomcat installation root directory for the current environment.
A tomcast instance is a single Tomcat JVM (and also the set of
files specific to this tomcat instance).
People often use the word server for the
same purpose.
I try to use the word instance to avoid
any ambiguity with the other uses of server.
The env variable CATALINA_BASE
identifies
the tomcat instance's root directory for the current environment.
The file conf/server.xml
for each
CATALINA_BASE
is where most of your
instance-based configurations are persisted, for example what
port to run on, where to write log files, etc.
The primary goal of the Admin webapp is to manage this file
(but most people edit it it manually instead).
Because of its importantce, you should take some time to study it.
The Tomcat documentation explains about half of it
well.
The XML tags and attributes are named pretty intuitively.
One question that most people have when they look at it is,
What are all of those ports for?.
There is the main http port that will server your webapps to
browsers, SOAP clients, etc.
There is the Coyote port that will service plugin clients.
The AJP protocol is used between plugins and Tomcat, so you
can't use it for any other purpose.
There's also the shutdown port.
You can telnet to this port on localhost,
type SHUTDOWN and hit ENTER to shut down the instance.
Then there are SSL versions of these three ports (all of which
care commented out by default).
I recommend that you install the distro as the super-user, and leave everything from the distributions writable only to the superuser. After that you copy the small set of read-write files and open up write privileges for this set. This directory branch of instance-specific, writable, files is called the CATALINA_BASE for the instance. This is useful for a single-user system because when Tomcat gets screwed up (as it eventually will), it is very easy to start a new instance up (with its own CATALINA_BASE), or just wipe out your hosed CATALINA_BASE with a new copy from the distro. If you plan to run multiple Tomcat instances (for yourself or to be shared), then you definitely should use CATALINA_BASEs.
If you have superuser privileges, I recommend that you run your Tomcat instance as a dedicated non-privileged user. Unless you already have a tomcat account, create a user and group with name "tomcat".
cd to the parent directory of where you want your Tomcat
installation to live (parent directory because the extraction
will create one subdirectory which will contain everything).
Extraction will create a new subdirectory with name like
jakarta-tomcat-5.0.28
.
If you are installing 5.5.x, extract the Admin distro file
from the same place (if you want the Admin web app).
After you extract everything,
you can shorten the installation root directory name if you
like (I get along just fine without the "jakarta-" part).
A common practice on UNIX is to make a peer sym-link to the
"current" version with no version number in it, like
mv jakarta-tomcat-5.0.28 tomcat-5.0.28 ln -s tomcat-5.0.28 tomcat
CATALINA_HOME
.
Just to make the examples below really work, I'll assume that
you set the environmental variable CATALINA_HOME
to the absolute path of this directory.
Your CATALINA_HOME contains the following subdirectories.
Users installing the 5.5.x JDK 1.4 Compatibility distro should be aware that (at least for the versions I have installed), they use a different root directory name for the Compat bunlde, so you can't just overlay it on top of your core installation (like you can with the Admin distro). You'll need to extract the JDK Compat distro to a temporary location then copy it like so.
mkdir /tmp/tctemp cd /tmp/tctemp tar -xzvf /path/to/jakarta-tomcat-5.5.28-admin.tar.gz ... cd jakarta-tomcat-5.5.28-admin cp -a * $CATALINA_HOME ... cd rm -rf /tmp/tctemp
I recommend that you edit the web.xml
for the bundled default ROOT web app.
to make your site home page editable.
If you will always install your own ROOT web app (i.e., a web
app with context root of "/"), or will otherwise never use
Tomcat's default ROOT web app, just skip this paragraph.
Tomcat comes with a great default web app, with a great home page
with links to the bundled web apps and documentation.
It just makes sense to add your own links to this home page--
at least to the web apps that you install, but also perhaps
to application log file or external documentation.
Unfortunately, recent versions of Tomcat precompile the home
page JSP so that you editing the home page will have no effect.
The easy work-around for this is to edit the file
CATALINA_HOME/webapps/ROOT/WEB-INF/web.xml
and just comment out the <servlet> and <servlet-mapping>
stanzas at the bottom.
This is a one-time customization.
Whenever you set up a CATALINA_BASE
from now on
(as described below), the home page for the instance will be
editable.
As described above, CATALINA_HOME
is where
you installed the Tomcat distribution to.
CATALINA_BASE
will be the root directory of
your new instance.
Now make the CATALINA_BASE for your first (or only) Tomcat
instance by making a new CATALINA_BASE directory anywhere.
If you anticipate running multiple Tomcat instances, you may
want to make a new directory to be the parent to all of the
instances, then make the CATALINA_BASE within that.
For example .../tomcat-intances/balder1
.
For the purposes of my examples, I'll assume that you set the
variable CATALINA_BASE
to the absolute path
of this directory.
Copy the five starred CATALINA_HOME subdirectories above to there.
Then set ownership to your instance owner and group.
Assuming that you've set variables
CATALINA_HOME
and
CATALINA_BASE
, you can do it like this on UNIX.
mkdir $CATALINA_BASE cd $CATALINA_HOME cp -a conf logs temp webapps work $CATALINA_BASE chown -R tomcat.tomcat $CATALINA_BASE
mkdir %CATALINA_BASE% cd %CATALINA_HOME% xcopy /e /i /q conf %CATALINA_BASE%\conf xcopy /e /i /q logs %CATALINA_BASE%\logs xcopy /e /i /q temp %CATALINA_BASE%\temp xcopy /e /i /q webapps %CATALINA_BASE%\webapps xcopy /e /i /q work %CATALINA_BASE%\work
One difficulty you will have to live with if you're using
Linux Tomcat packages is, the actual instance files are spread
out all over the place, with sym-links from the CATALINA_BASE.
It's not all that difficult if you leave the default
CATALINA_BASE alone to use as a model.
For example, on Suse, it sets up a CATALINA_BASE named
base
with CATALINA_BASE of
/srv/www/tomcat5/base
.
This CATALINA_BASE has sym-links to a config file under /etc,
log, temp, and work directories under /var, but a real webapps
directory.
Duplicate the same exact setup for your own instance, like
/srv/www/tomcat5/yourinstance
.
Make the webapps directory writable to whoever you want to permit to deploy by copying files into there.
chown -R deployer $CATALINA_BASE/webapps chmod gw+s $CATALINA_BASE/webapps
conf/server.xml
and or
conf/*user*
to people who can directly
edit the main instance configuration file and the password
file used by the bundled management webapps.
But, Tomcat rewrites these files sometimes, so don't be
surprised if the file attributes get changed on you.
If you followed my advice above, then you just repeat the CATALINA_BASE creation step above for each instance, then edit the server.xml file as described in the following subsection.
The Tomcat documentation says that you must edit the descriptors
for the bundled webapps.
That documentation is wrong, because the settings use filepaths
relative to CATALINA_BASE
, which works exactly
as needed.
Dear reader, please make a detour now and read the introductory and Initial Instance Configuration sections of the Configuring Tomcat chapter. You really need to understand that material before consuming the remainder of this chapter.
Generally, you want to bundle needed jar files in your web app. That will avoid most dependency conflicts with other web apps, and reduces dependencies on things outside of the war file. For example, it won't matter if Tomcat or other web apps have the right version of a lib, because you have it yourself. It also means that your war will be more likely to run as-is on some other application server. The trade off is inefficiency of disk space and memory, when multiple wars bundle equivalent jar files. The inefficiency problems are trivial compared to the alternative.
Exceptions to the general rule are for the mail api and JDBC
drivers.
In both cases, the exceptions are justified only so that you
can manage the mail and data source services as the app server
level as shared resources.
With Tomcat 5.5.x only, Tomcat doesn't bundle the email libraries
because of copyright laws.
(Ignore the rest of this paragraph if you're running a version an
earlier version, since it will include these two jar files).
Therefore, obtain the JavaMail and Activation Framework jars
and copy them into CATALINA_HOME/common/lib
.
These jar files are often named
mail.jar
or mailapi.jar
and activation.jar
or
jaf.jar
correspondingly
(or the same with version numbers).
CATALINA_HOME/shared/classes
and jars in
CATALINA_HOME/shared/lib
are not added to
the runtime classpath, at least with Tomcat 5.5.x.
I think something broke, because these folders serve no purpose
without this behavior.
I know it used to be there, but there is no longer an explanation
of the purpose of the different Tomcat directories in the 5.5.23
docs.
Always use the
CATALINA_HOME/common
branch for
shared resources, not
CATALINA_HOME/shared
The other exception is JDBC drivers.
In the J2EE world, application servers have the responsibility
of managing data sources which apps look up via JNDI.
Therefore, if you are going to get your data sources by the
traditional J2EE method, you need to put your JDBC driver
jar files for your target database servers into
CATALINA_HOME/common/lib
.
If you are not getting your datasources from
a JNDI lookup (regardless of whether there is an ORM, Spring, or
any other lay in between), then I recommend that you bundle your
JDBC libraries with your app (for the reasons given above) and
purposefully do not put them in any shared directory.
(If Tomcat is running when you change any files under
CATALINA_HOME/common/lib
, you will need
to restart Tomcat for it to see the changes).
At least with Tomcat 4.x, Tomcat does not recognize zip files
in the the global lib
directories, only
.jar files. This isn't much of an issue nowadays since Oracle,
the last holdout, has finally stopped using zip files when they
should be using jar files.
I assume you're using an Apache HTTPD server (including branded Apache HTTPD servers, such as those by IBM and Oracle). If you're using some other web server, like IIS, you're on your own. I'm only documenting use of jk. Setup of other plugins is similar, but jk has the widest user base (by far), and is actively supported. The Apache HTTPD server is often just called the Apache server, even though Apache also makes the Tomcat server. To try to avoid this ambiguity without being too verbose, when I say httpd server in this section, I mean the Apache HTTPD server.
You can use the httpd server's mod_proxy module instead of a plugin. This is do-able, but has its own set of quirks, which I don't have time to document. I recommend that you use the most common setup-- the JK plugin-- unless you just can't get it to work. (The only valid reason I've encountered is that you have to support a version of httpd server for which you can't build the JK plugin).
Use pre-packaged binary distributions if at all possible, due to dependency requirements, which are detailed below.
Tomcat calls a network listener which connects clients to the
Tomcat engine a Connector.
(They probably want to avoid possible confusion with
lifecycle listeners, which are defined with
<Listener> tags in the server.xml>
file).
To get a possible point of confusion out of the way, be aware that all of the modern Tomcat connectors are Coyote connectors. All of the connectors you use will be Coyote connectors. (The SHUTDOWN network listener is not a Connector, since it does not connect to any Tomcat engine). Most significantly, when I speak of an HTTP connector or an AJP connector, I mean the Coyote HTTP or Coyote AJP connector, not some other, deprecated implementation. I point this out because this was apparently not the case in the past, since Tomcat documentation and config file comments imply some significance to "Coyote".
The only setup for the Tomcat side is to enable the AJP 1.3,
Connector,
and that will already be enabled unless you deleted or commented
it out from your template server.xml
file.
However, read this section to make sure that it is running, and
to find out what network target to have your Apache plugin connect
to.
If something else is occupying the default AJP 1.3 listener port
(perhaps another Tomcat instance), you will need to change the
port number (see the
Configuring Tomcat chapter
for tips about finding available ports).
Take a look at CATALINA_BASE/conf/server.xml
.
Search for all uncommented <Connector> tags.
By default, there will only be two, one HTTP connector and one
AJP 1.3 connector: search for "AJP/1.3".
Both of the Tomcat-supplied server.xml
files
have misleading comments about this element, so just ignore them.
I will be calling this connector the AJP connector, since we are
only concerned with AJP version 1.3, and the connector just
serves AJP and doesn't mandate that the client be JK,
JK2, or anything else (you can write your own AJP 1.3 client).
Note the port number for the AJP connector.
I suggest that you remove the voluminous commented examples of
SSL connectors-- it clutters the file up with crap that you will
never use.
When I talk about Apache configuration directives, I will give
the Apache 2 module variant.
See your docs if you are running some other Apache variant.
In all cases, you can track down all Apache config files by
recursively following the includes from the main
httpd.conf
file
(which latter filepath has a compiled-in default which can be
overridden on the httpd command line
or use a compiled-in default).
httpd-server-side Plugin Configuration
This can be the most difficult step of all.
The .so binary must compatible with your version of Apache and
it must use the same version of AJP as your Tomcat distribution.
(If you are following these instructions, the second dependency
will be taken care of if you just stick to AJP version 1.3).
The shared library will be called something like
mod_jk.so
.
Hopefully, your can get a pre-built binary with your Apache
or OS distribution.
Otherwise, download the source and build it, according to the
very detailed instructions--- good luck.
Stick the .so file into the same directory
as all of your other native Apache module libraries.
Suse users can find mod_jk.so
in the
rpm apache2-jakarta-tomcat-connectors
or mod_jk-ap20
(in the latter name, the
20 means that it is for Apache version 2.0).
Building is not difficult on Linux if you have a the Apache 2 developer rpm (including apxs version 2) and gcc. It can be incredibly difficult on other UNIXes.
You must set the worker properties.
If you are running JK version 1.2.7 or later, you can set them
in your httpd server config file (exactly as described in the
following section) with JkWorkerProperty
directives.
All versions may make these settings in a
workers.properties
file, and
that is what I explain here
(only because most binary distributions which I encounter
are always pre-1.2.7; and for most distributions, you
can't even tell the JK version number).
If you have version 1.2.7 or later, I recommend you use
JkWorkerProperty
-- read this section, but
forget the workers.properties
and
make the corresponding
JkWorkerProperty
as explained in the next
section.
SuSE v. 9.3 and 10.0 both have version 4.1.30 of mod_jk-ap20, which contains a beta of JK version 1.2.6. Can you believe that shit? A year and a half old, and they can't even use a production cut.
This file defines the Tomcat server destinations that you can route to from your httpd server instance. You assign each Tomcat server destination a worker name, and you can then use that name to redirect specific request URLs from the httpd server to this Tomcat worker instance (as described in a following step).
Like I said, the workers.properties
file
just needs to define the Tomcat worker instances which you
want to make available to your httpd server instance.
If you have a sample file, just wipe it out, because in the
great majority of cases, you only need four lines.
(Most JK distributions come with a sample file filled with
inappropriate settings... you're better off without the
sample).
Example 2.1. workers.properties file
worker.list=tomcatWorker1 worker.tomcatWorker1.port=8009 worker.tomcatWorker1.host=localhost worker.tomcatWorker1.type=ajp13
server.xml
(which is explained above).
If you have a distributed, load-balancing setup, see the docs
about additional settings, and the Tomcat docs about the
server.xml
jvmRoute
setting..
Most documentation which I can find instructs to place the
workers.properties
under
CATALINA_BASE
.
That is a stupid place to put this file, since (a) the file
is read by httpd server, not Tomcat, and
(b) If you have a distributed setup, this file must
accompany your httpd server instances, not any Tomcat instance.
The Tomcat JK docs give the false impression that the
workers.properties
is part of the Tomcat
configuration (as definitely proven by the fact that with
recent versions, the functionality can be taken over entirely
by using httpd server directives).
These settings all need to go into httpd server config
file(s), either a main httpd.conf
,
or a file included directly or indirectly.
Which file(s) you put them into depends upon whether you
want the settings shared by all virtual servers or not,
and by the fact that some global settings must appear
before site-specific settings.
I recommend that put your global settings directly in
httpd.conf
, and all other settings
directly wherever your (virtual) site-specific settings
like DocumentRoot are.
To get JK working with other virtual hosts, just duplicate
the vhost-specific settings you made for your first vhost.
Attention name-based virtual host users.
This has nothing to do with Tomcat specifically, but it is
something that is very non-intuitive for standard httpd
name-based server setups.
The default httpd.conf
delivered with
many Apache 2 distributions includes a
default-server.conf
file which works
fine, but not if you use name based hosts.
The reason is, this file has useful settings for
documentRoot, etc, but, since they are not in a virtual
host block, they will always be overridden by your first
virtual host definition (which default host is determined
alphabetically with the default setup).
For security alone, you should not send users to a random
site accidentally.
What a sane person would want to happen is that requests
for URLs which match no defined virtual host name should
use the settings in the
default-server.conf
file.
You can accomplish this easily and elegantly by defining
a default VirtualHost before
including your virtual host files.
Just insert the following directives after the
Include /etc/apache2/default-server.conf
and before the
Include /etc/apache2/vhosts.d/*.conf
.
Example 2.2. Make the default-server config the default virtual host
NameVirtualHost *:80 <VirtualHost *:80> # Just inherit all the settings in /etc/apache2/default-server.conf </VirtualHost>
You need to load the JK module with a directive like
LoadModule jk_module /usr/lib/apache2/mod_jk.so
,
specifying the filepath to the native library file.
This is a global level setting, since you just load the
module one time, regardless of how many virtual sites or
Tomcat worker instances you have.
(Suse user be aware the Suse has an idiotic system where
they rebuild the LoadModule directives dynamically. You
set the variable APACHE_MODULES
, in the
file /etc/sysconfig/apache2
, to the
base names for all modules, with the assumption that the
native library files all reside in the normal directory,
and are named according to the supplied module name.
You need to specify the path to the
workers.properties
file, like
JkWorkersFile /etc/apache2/workers.properties
.
This is a global level setting, since you just need tone
workers file for an entire httpd server (because one
workers file can define any number of Tomcat worker target
instances).
If you are not using workers.properties
file (see previous step), then, instead of a
JkWorkersFile
directive, give a
JkWorkerProperty
directive for each
worker property you need (which are described in the
previous section--- for example,
JkWorkerProperty worker.tomcatWorker1.port=8009
.
You need to specify the path to the log file for the
httpd-server-side of JK, like
JkLogFile /var/log/tomcat5/base/mod_jk.log
.
You can specify a logging level of
trace
,
debug
,
warn
,
error
, if the default level of
info
doesn't suit you.
For example
JkLogLevel error
.
Tell httpd server to serve all static webapp content
directly.
The httpd server must have access to the exploded webapp
files to serve them directly
(i.e., they must reside on the physical httpd server in
exploded-- not war file-- state, and must be readable to
the httpd server process owner).
Most importantly, you must use Directory
directives to cover all of the webapp directories, so
that httpd can serve them.
You need the Directory directives regardless of how you
graft onto the URL tree.
If you have Tomcat and httpd server running on the same
server, then give a JkAutoAlias
directive to tell the httpd server to automatically graft
all webapp directories into the httpd URL namespace and
serve them directly.
The JkAutoAlias directive is just an alternative to giving
Location and DocumentRoot directives for the different
webapp directory branches.
If you only want Apache to serve static content from a
subset of the Tomcat webapps, then use normal Location and
DocumentRoot directives instead of JkAutoAlias.
If Tomcat is running on a different physical server, then
you will have to explode all of the wars on the httpd
server computer and then use one of the two methods above
to serve these directories.
(The JkAutoAlias just requires that the webapps all reside
in one parent directory).
You should understand that nothing in this paragraph will
cause any interaction with Tomcat, it just tells Apache
to serve some stuff in normal non-Tomcat fashion.
The next paragraph tells how to forward requests on to
Tomcat.
The JkAutoAlias does not know about the root context
web app.
Therefore, requests for
http://hosthame:port/file.txt
will
not map to WEBAPPDIR/ROOT/file.txt
,
which would be the desired thing to do.
JkAutoAlias is really useless for a default context
webapp.
You'll have to use other Apache directives to serve it.
JkAutoAlias is smart enough to never serve information from underneath WEB-INF of your webapps.
If you get an error upon UNIX startup about the command JkUnMount, then you probably have an ancient jk_mod binary. Either live without JkUnMount, or obtain or build a recent JK library.
Tell Apache which URLs to forward to Tomcat with the
JkMount
and JkUnMount
directives.
Both take a URL pattern and a Tomcat worker instance name.
JkUnMount commands take precedence over JkMount commands,
regardless of the sequence in which they appear.
Here's an example that shows both commands.
JkMount /servlet/* tomcatWorker1 JkUnMount /servlet/*.gif tomcatWorker1
http://hostname:port/servlet/
will not
be forwarded to Tomcat, due to the higher precedence of
JkUnMount commands.
Some JK distributions put samples of these settings into a
file named jk.conf
, or similar.
In most cases, this discourages effective directive sharing
among multiple virtual servers.
When running with multiple virtual servers, some directives
should be made just once for the entire server, other
settings should be duplicated for each virtual server, and
others require unique settings for each virtual server.
Since we are talking about a total of about four
sharable directives, in nearly all cases it's simpler and
more effective to just put each directive directly into
the desired virtual-site-specific or main
httpd.conf
file.
The actual URL-mapping directives, which comprise 90% of
the needed directives, are
virtual-server specific and can't be shared at all.
Example 2.3. Typical httpd.conf directives
# These toward the top in the main httpd.conf file LoadModule jk_module /usr/lib/apache2/mod_jk.so JkWorkersFile /etc/apache2/workers.properties # These in virtual-server specific files, or with other site-specific # settings like DocumentRoot and site-specific log file settings. JkLogFile /var/log/tomcat5/base/mod_jk.log JkLogLevel error JkAutoAlias /opt/tomcat/webapps # Then specify all URL patterns to pass to Tomcat JkMount /servlet/* tomcatWorker1 JkMount /*.jsp tomcatWorker1 JkUnMount /*/WEB-INF/* tomcatWorker1
Use of a Webapp Staging Directory avoids polling race condition
problems if you deploy webapps by manually copying or moving
files into the Tomcat webapps
directory.
The problem occurs because Tomcat monitors the
webapps
directory and the first time it sees
a new entry, it decides right then whether it will henceforth
consider this entry a war file, a web app directory, or ignore it.
If it looks at the directory or war file before it contains the
web.xml
file (because the copy has not reached that point yet),
then it won't attempt to deploy it at all and will ignore the
whole thing from this point forward.
If it sees the web.xml
, then it will attempt
to deploy. If your copy has not finished, it will deploy only
a portion of your webapp and will never finish it.
The solution to this problem is to not copy
anything into the webapps
directory, but to
move to there from the same filesystem
partition.
From Tomcat's perspective, the move is an atomic operation.
Before the move completes, it won't see the new item at all.
After the move completes, the entire webapp is available for
deployment.
The only real requirement for this to work is that you
move the webapps/war from another directory
in the same filesystem partition.
If you work with multiple servers, then I highly recommend that
you make a staging directory right under
webapps
specificaly for this purpose. For
purposes of this document, I'll assume it is
$CATALINA_BASE/webapps/stage
.
No matter what server you're on, you'll know that the staging
directory is in the same partition as webapps
,
and it's really convenient to be able to cd to
webapps
and deploy and undeploy web
applications with short commands like
cd $CATALINA_BASE/webapps mv appToUndeploy stage mv warToUndeploy stage mv stage/appToDeploy