§Deploying your application
We have seen how to run a Play application in development mode, however the run
command should not be used to run an application in production mode. When using run
, on each request, Play checks with sbt to see if any files have changed, and this may have significant performance impacts on your application.
There are several ways to deploy a Play application in production mode. Let’s start by using the recommended way, creating a distribution artifact.
§The application secret
Before you run your application in production mode, you need to generate an application secret. To read more about how to do this, see Configuring the application secret. In the examples below, you will see the use of -Dplay.http.secret.key=ad31779d4ee49d5ad5162bf1429c32e2e9933f3b
. You must generate your own secret to use when deploying to production.
§Deploying Play with JPA
If you are using JPA, you need to take a look at Deploying with JPA.
§Using the dist task
The dist
task builds a binary version of your application that you can deploy to a server without any dependency on SBT, the only thing the server needs is a Java installation.
In the Play console, simply type dist
:
[my-first-app] $ dist
And will see something like:
$ sbt
[info] Loading global plugins from /Users/play-developer/.sbt/0.13/plugins
[info] Loading project definition from /Users/play-developer/my-first-app/project
[info] Set current project to my-first-app (in build file:/Users/play-developer/my-first-app/)
[my-first-app] $ dist
[info] Packaging /Users/play-developer/my-first-app/target/scala-2.11/my-first-app_2.11-1.0-SNAPSHOT-sources.jar ...
[info] Done packaging.
[info] Wrote /Users/play-developer/my-first-app/target/scala-2.11/my-first-app_2.11-1.0-SNAPSHOT.pom
[info] Main Scala API documentation to /Users/play-developer/my-first-app/target/scala-2.11/api...
[info] Packaging /Users/play-developer/my-first-app/target/scala-2.11/my-first-app_2.11-1.0-SNAPSHOT-web-assets.jar ...
[info] Done packaging.
[info] Packaging /Users/play-developer/my-first-app/target/scala-2.11/my-first-app_2.11-1.0-SNAPSHOT.jar ...
[info] Done packaging.
model contains 21 documentable templates
[info] Main Scala API documentation successful.
[info] Packaging /Users/play-developer/my-first-app/target/scala-2.11/my-first-app_2.11-1.0-SNAPSHOT-javadoc.jar ...
[info] Done packaging.
[info] Packaging /Users/play-developer/my-first-app/target/scala-2.11/my-first-app_2.11-1.0-SNAPSHOT-sans-externalized.jar ...
[info] Done packaging.
[info]
[info] Your package is ready in /Users/play-developer/my-first-app/target/universal/my-first-app-1.0-SNAPSHOT.zip
[info]
[success] Total time: 5 s, completed Feb 6, 2017 2:08:44 PM
[my-first-app] $
This produces a ZIP file containing all JAR files needed to run your application in the target/universal
folder of your application.
To run the application, unzip the file on the target server, and then run the script in the bin
directory. The name of the script is your application name, and it comes in two versions, a bash shell script, and a windows .bat
script.
$ unzip my-first-app-1.0.zip
$ my-first-app-1.0/bin/my-first-app -Dplay.http.secret.key=ad31779d4ee49d5ad5162bf1429c32e2e9933f3b
You can also specify a different configuration file for a production environment, from the command line:
$ my-first-app-1.0/bin/my-first-app -Dconfig.file=/full/path/to/conf/application-prod.conf
For a full description of usage invoke the start script with a -h
option.
For Unix users, zip files do not retain Unix file permissions so when the file is expanded the start script will be required to be set as an executable:
$ chmod +x /path/to/bin/<project-name>
Alternatively a tar.gz file can be produced instead. Tar files retain permissions. Invoke the
universal:packageZipTarball
task instead of thedist
task:sbt universal:packageZipTarball
By default, the dist
task will include the API documentation in the generated package. If this is not necessary, add these lines in build.sbt
:
sources in (Compile, doc) := Seq.empty
publishArtifact in (Compile, packageDoc) := false
For builds with sub-projects, the statement above has to be applied to all sub-project definitions.
§The Native Packager
Play uses the SBT Native Packager plugin. The native packager plugin declares the dist
task to create a zip file. Invoking the dist
task is directly equivalent to invoking the following:
[my-first-app] $ universal:packageBin
Many other types of archive can be generated including:
- tar.gz
- OS X disk images
- Microsoft Installer (MSI)
- RPMs
- Debian packages
- System V / init.d and Upstart services in RPM/Debian packages
Please consult the documentation on the native packager plugin for more information.
§Build a server distribution
The sbt-native-packager plugins provides a number archetypes. The one that Play uses by default is called the Java server archetype, which enables the following features:
- System V or Upstart startup scripts
- Default folders
More information can be found in the Java Server Application Archetype documentation.
§Minimal Debian settings
Add the following settings to your build:
lazy val root = (project in file("."))
.enablePlugins(PlayScala, DebianPlugin)
maintainer in Linux := "First Lastname <[email protected]>"
packageSummary in Linux := "My custom package summary"
packageDescription := "My longer package description"
Then build your package with:
[my-first-app] $ debian:packageBin
§Minimal RPM settings
Add the following settings to your build:
lazy val root = (project in file("."))
.enablePlugins(PlayScala, RpmPlugin)
maintainer in Linux := "First Lastname <[email protected]>"
packageSummary in Linux := "My custom package summary"
packageDescription := "My longer package description"
rpmRelease := "1"
rpmVendor := "example.com"
rpmUrl := Some("http://github.com/example/server")
rpmLicense := Some("Apache v2")
Then build your package with:
[my-first-app] $ rpm:packageBin
There will be some error logging. This is because rpm logs to stderr instead of stdout.
§Including additional files in your distribution
Anything included in your project’s dist
directory will be included in the distribution built by the native packager. Note that in Play, the dist
directory is equivalent to the src/universal
directory mentioned in the native packager’s own documentation.
§Play PID Configuration
Play manages its own PID, which is described in the Production configuration.
Since Play uses a separate pidfile, we have to provide it with a proper path, which is packageName.value
here. The name of the pid file must be play.pid
. In order to tell the startup script where to place the PID file, put a file application.ini
inside the dist/conf
folder and add the following content:
s"-Dpidfile.path=/var/run/${packageName.value}/play.pid",
# Add all other startup settings here, too
Please see the sbt-native-packager page on Play for more details.
To prevent Play from creating a PID just set the property to /dev/null
:
-Dpidfile.path=/dev/null
For a full list of replacements take a closer look at the customize java server documentation and customize java app documentation.
§Publishing to a Maven (or Ivy) repository
You can also publish your application to a Maven repository. This publishes both the JAR file containing your application and the corresponding POM file.
You have to configure the repository you want to publish to, in your build.sbt
file:
publishTo := Some(
"My resolver" at "https://mycompany.com/repo"
)
credentials += Credentials(
"Repo", "https://mycompany.com/repo", "admin", "admin123"
)
Then in the Play console, use the publish
task:
[my-first-app] $ publish
Check the sbt documentation to get more information about the resolvers and credentials definition.
§Running a production server in place
In some circumstances, you may not want to create a full distribution, you may in fact want to run your application from your project’s source directory. This requires an SBT installation on the server, and can be done using the stage
task.
$ sbt clean stage
And you will see something like this:
$ sbt
[info] Loading global plugins from /Users/play-developer/.sbt/0.13/plugins
[info] Loading project definition from /Users/play-developer/my-first-app/project
[info] Set current project to my-first-app (in build file:/Users/play-developer/my-first-app/)
[my-first-app] $ stage
[info] Updating {file:/Users/play-developer/my-first-app/}root...
[info] Packaging /Users/play-developer/my-first-app/target/scala-2.11/my-first-app_2.11-1.0-SNAPSHOT-sources.jar ...
[info] Done packaging.
[info] Wrote /Users/play-developer/my-first-app/target/scala-2.11/my-first-app_2.11-1.0-SNAPSHOT.pom
[info] Resolving jline#jline;2.12.2 ...
[info] Done updating.
[info] Main Scala API documentation to /Users/play-developer/my-first-app/target/scala-2.11/api...
[info] Compiling 8 Scala sources and 1 Java source to /Users/play-developer/my-first-app/target/scala-2.11/classes...
[info] Packaging /Users/play-developer/my-first-app/target/scala-2.11/my-first-app_2.11-1.0-SNAPSHOT-web-assets.jar ...
[info] Done packaging.
model contains 21 documentable templates
[info] Main Scala API documentation successful.
[info] Packaging /Users/play-developer/my-first-app/target/scala-2.11/my-first-app_2.11-1.0-SNAPSHOT-javadoc.jar ...
[info] Done packaging.
[info] Packaging /Users/play-developer/my-first-app/target/scala-2.11/my-first-app_2.11-1.0-SNAPSHOT.jar ...
[info] Done packaging.
[info] Packaging /Users/play-developer/my-first-app/target/scala-2.11/my-first-app_2.11-1.0-SNAPSHOT-sans-externalized.jar ...
[info] Done packaging.
[success] Total time: 8 s, completed Feb 6, 2017 2:11:10 PM
[my-first-app] $
This cleans and compiles your application, retrieves the required dependencies and copies them to the target/universal/stage
directory. It also creates a bin/<start>
script where <start>
is the project’s name. The script runs the Play server on Unix style systems and there is also a corresponding bat
file for Windows.
For example to start an application of the project my-first-app
from the project folder you can:
$ target/universal/stage/bin/my-first-app -Dplay.http.secret.key=ad31779d4ee49d5ad5162bf1429c32e2e9933f3b
You can also specify a different configuration file for a production environment, from the command line:
$ target/universal/stage/bin/my-first-app -Dconfig.file=/full/path/to/conf/application-prod.conf
§Running a test instance
Play provides a convenient utility for running a test application in prod mode.
Note: This is not intended for production usage.
To run an application in prod mode, run runProd
:
[my-first-app] $ runProd
§Using the SBT assembly plugin
Though not officially supported, the SBT assembly plugin may be used to package and run Play applications. This will produce one jar as an output artifact, and allow you to execute it directly using the java
command.
To use this, add a dependency on the plugin to your project/plugins.sbt
file:
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.5")
Now add the following configuration to your build.sbt
:
mainClass in assembly := Some("play.core.server.ProdServerStart")
fullClasspath in assembly += Attributed.blank(PlayKeys.playPackageAssets.value)
assemblyMergeStrategy in assembly := {
case manifest if manifest.contains("MANIFEST.MF") =>
// We don't need manifest files since sbt-assembly will create
// one with the given settings
MergeStrategy.discard
case referenceOverrides if referenceOverrides.contains("reference-overrides.conf") =>
// Keep the content for all reference-overrides.conf files
MergeStrategy.concat
case x =>
// For all the other files, use the default sbt-assembly merge strategy
val oldStrategy = (assemblyMergeStrategy in assembly).value
oldStrategy(x)
}
Now you can build the artifact by running sbt assembly
, and run your application by running:
$ java -Dplay.http.secret.key=ad31779d4ee49d5ad5162bf1429c32e2e9933f3b -jar target/scala-2.XX/<yourprojectname>-assembly-<version>.jar
You’ll need to substitute in the right project name, version and scala version, of course.
Next: Production configuration