Table of contents

Deploying apps

Deploying public apps

By default, all apps you deploy on Cloud Foundry are publicly accessible to everyone through the internet.

The cf push command can both create a new app and push a new version of an existing app.

  1. Put your app’s code and configuration files in a local directory.

  2. Target the appropriate organisation and space by running:

    cf target -o ORG_NAME -s SPACE_NAME
    

    where ORG_NAME is the name of the org, and SPACE_NAME is the name of the space.

  3. Create a manifest.yml file in the same local directory as your app’s code. The manifest file tells Cloud Foundry what to do with your app. An example manifest:

    ---
    applications:
    - name: APP_NAME
    

    where APP_NAME is the unique name for your app. You can run cf apps to see apps which already exist.

  4. Deploy your app by running the following in the directory which contains your app’s code, configuration files, and manifest:

    cf push
    

Your app should now be live at your app domain.

Refer to the Cloud Foundry documentation on Deploying with Application Manifests [external link] for more information on the options available when you deploy an app.

Refer to the production checklist if your app is a production app.

Set a target

To deploy an app, you need to set a target. A target is a combination of an org and a space.

Run the following to set the target:

cf target -o ORG_NAME -s SPACE_NAME

where ORG_NAME is the name of the org, and SPACE_NAME is the name of the space.

The Cloud Foundry client remembers the target until you change it.

You can change space without changing org by running:

cf target -s SPACE_NAME

You should target the sandbox space while you are testing your app. You can do this by running:

cf target -s sandbox

You will not normally need to target the sandbox space if you are a new user, as this space is the default for new users.

A possible exception to this is if your org is mature and has pre-existing spaces; you should check to ensure that you target the appropriate space for testing.

Caveats

  • Your app should not write to local storage. Cloud Foundry local storage is ephemeral and can be deleted at any time.
  • You may need to set environment variables for your app to work. All configuration information should be stored in environment variables, not in the code.
  • Instances will be restarted if they exceed memory limits.
  • Your application should write all its log messages to STDOUT/STDERR, rather than a log file.

Deploying private apps

You can deploy apps so they are not publicly accessible to everyone through the internet.

The simplest use case is that you have 2 apps to deploy:

  • a public app for your end users to interact with
  • a private app that the public app can securely connect to, but which is not accessible from the internet

To achieve this, you must:

  • specify the private route in the private app’s manifest
  • set the private app URL as an environment variable in the public app’s manifest
  • create a network policy to allow the apps to connect with each other

If you need to restrict access to a public app, you should refer to the documentation on route services.

Specify a private route in the private app’s manifest

Cloud Foundry uses routes [external link] to send requests to apps.

You must specify a private route in the private app’s manifest to tell Cloud Foundry that this app should not be accessible from the internet.

Create the private app’s manifest.yml with the following code:

---
applications:
- name: PRIVATE_APPNAME
  routes:
  - route: PRIVATE_APPNAME.apps.internal

If the private app was previously a public app, you must also run the following in the command line to remove the pre-existing public route:

cf unmap-route PRIVATE_APPNAME DOMAIN --hostname HOSTNAME

Set the private app URL in the public app’s manifest

The public app must read the private app URL from an environment variable in the public app’s manifest.


Warning Connections between public and private apps are not encrypted by default. If you need encrypted connections between your apps, it is your responsibility to implement this.

You must set:

  • the private app URL as a non-secure http URL
  • the domain as apps.internal
  • the URL as port 8080

To do this, create the public app’s manifest.yml with the following code:

---
applications:
- name: PUBLIC_APPNAME
  env:
    ENVIRONMENT_VARIABLE_NAME: http://PRIVATE_APPNAME.apps.internal:8080

where:

  • PUBLIC_APPNAME is the name of your public app
  • ENVIRONMENT_VARIABLE_NAME is the environment variable your public app reads (for example PRIVATE_APP_URL)
  • PRIVATE_APPNAME is the name of your private app

Create a network policy

By default, Cloud Foundry apps do not accept internal connections from other apps.

You must create a network policy [external link] to allow the public app to connect to the private app.

  1. Push both the public and private apps.
  2. Run the following in the command line to create the network policy:
cf add-network-policy PUBLIC_APPNAME --destination-app PRIVATE_APPNAME --protocol tcp --port 8080

Contact us at gov-uk-paas-support@digital.cabinet-office.gov.uk if you have any further questions.

Data security classification

You can store data classified up to ‘official’ on the GOV.UK PaaS.

You cannot store data classified ‘secret‘ or ‘top secret‘ on the GOV.UK PaaS.

Refer to the information assurance page for information on the assurance process.

Refer to the GOV.UK page on government security classifications for more information on these classifications.

Secure and non-secure requests

Requests could be made to an app’s public route over the non-secure http:// protocol due to:

  • misconfiguration of an app that allows non-encrypted traffic through
  • a service linking to the HTTP version of a page by mistake

Any requests made to a public app route over the http:// protocol will be automatically redirected to the base https:// version of that URL. The original query path and query parameters will be removed. This prevents a site from repeatedly redirecting back to the HTTP protocol without the user noticing.

Buildpacks

About buildpacks

Cloud Foundry uses buildpacks to provide runtime and framework support for applications in different languages (for example ensuring your app code has both the Ruby runtime and the Rails framework available to help it run). GOV.UK PaaS supports both standard and custom buildpacks:

  • standard buildpacks [external link] are buildpacks for common languages and frameworks that are supported by Cloud Foundry. You can check the installed buildpacks and their versions by running cf buildpacks.
  • custom buildpacks are developed by the wider community to enable hosting of applications in additional languages or frameworks
  • Docker images are a packaging format, and the requirements for the app and its runtime environment are the same as for apps deployed using buildpacks

Which buildpack should I use?

We recommend using the standard buildpacks to maximise the support you will receive from GOV.UK PaaS. Using a custom buildpack or Docker image will mean additional setup and maintenance costs.

Your responsibilities change depending on whether you use a standard buildpack, custom buildpack or a Docker image. Refer to the responsibility model guidance for further information.

Buildpack language version updates

You should tell Cloud Foundry which version of your app’s language to use in the buildpack. You can specify an exact, minor or major version of the language. For example, with Python:

 
Category Python Example
Exact 3.5.2
Minor 3.5.x
Major 3.x
 

If you specify an exact version, you must update this version when the GOV.UK PaaS team update the language’s buildpack. Your app will fail to start if the language version it relies on is not supported by the latest language buildpack.

If you specify a major or a minor version, your app will automatically upgrade to use a more recent version of its language when the GOV.UK PaaS team updates the buildpack. The major or minor version must still be live for this upgrade to work. However, if there is a breaking change between language versions, your app may not behave as expected or even fail.

You should always check the GOV.UK PaaS announcements email for information on which language versions are in the latest language buildpacks.

How to use custom buildpacks

There are many application attribute options available when you push an app. You can use the buildpack attribute to specify a custom buildpack for your app through:

  • specifying the buildpack in the manifest.yml file
  • using the command line

Specifying buildpacks in the manifest file

You can set application attribute options in a manifest.yml file in the directory from which you are running the push command. This is done in one of three ways:

  1. By name: MY-BUILDPACK.
  2. By GitHub URL: https://github.com/cloudfoundry/java-buildpack.git.
  3. By GitHub URL with a branch or tag: https://github.com/cloudfoundry/java-buildpack.git#v3.3.0 for the v3.3.0 tag.
---
  ...
  buildpack: buildpack_URL

Command line options override the manifest; the option that overrides the custom buildpack attribute is -b.

Using the command line to choose buildpacks

Once a custom buildpack has been created, it can be pushed to either a public or private git repository. The repository URL can then be included in the command line to push your app.

If the repository is private, the push command must include https and username/password authentication

  • Public: $ cf push my-new-app -b git://github.com/johndoe/my-buildpack.git
  • Private: $ cf push my-new-app -b https://username:password@github.com/johndoe/my-buildpack.git

The app will then be deployed to Cloud Foundry, and the buildpack will be cloned from the repository and applied to the app.

If a buildpack is specified using cf push -b the detect step will be skipped and as a result, no buildpack detect scripts will be run.

Excluding files

Cloud Foundry isn’t version-control-aware, so cf push will deploy the working state of whatever files you have in that directory. In most cases, you will want to exclude files [external link] ignored by Git. From within your project directory, run

ln -s .gitignore .cfignore

and commit the .cfignore to your repository. However, read on if you have a more advanced CF setup.

A couple of important points on the .cfignore:

  1. if you have a more advanced app setup and have apps with a path other than the project root (where you run cf push from), you will need an additional .cfignore file located in each app path;

  2. also note that more advanced .gitignore syntax, such as the ** recursive subdirectory wildcard, are not supported by .cfignore.

Environment variables

You must store all configuration information for your app as environment variables.

This could include:

  • credentials for external services that your app uses, for example a Twitter account
  • values that will vary with each deployment of the app, for example the canonical URL

To view an app’s current environment variables, run cf env APP_NAME.

To create or update a variable, run the following:

cf set-env APP_NAME ENV_VAR_NAME ENV_VAR_VALUE

If you’re deploying a pre-existing app, you should check the app’s documentation for any environment variables you need to set.

For example, if the app has these instructions for deploying to Heroku:

heroku config:set VARIABLE=value

then you should run the equivalent command using cf set-env:

cf set-env APP_NAME VARIABLE value

System-provided environment variables

System-provided environment variables tell you about configuration details handled by the PaaS, for example:

  • the port on which the app is listening
  • the maximum memory each app instance can use
  • the external IP address of the app instance

Do not attempt to change the values of these system-provided variables using the command line or your app’s code.

VCAP_SERVICES and VCAP_APPLICATION are two important variables for initial setup:

  • VCAP_SERVICES contains details, including credentials, of any backing services bound to the app

  • VCAP_APPLICATION provides details of the currently running application, for example the language runtime version

To see the values of the system-provided variables, run cf env APP_NAME.

If your app connects to a backing service, you may need to have your app parse VCAP_SERVICES to get the credentials and other settings relating to that service and set the appropriate environment variables.

Some buildpacks will do this for you automatically. Refer to the deploy instructions for the language or framework you are using for more information.

Here is an example of the structure of the information contained in VCAP_SERVICES:

{
 "VCAP_SERVICES": {
  "postgres": [
   {
    "binding_name": null,
    "credentials": {
     "host": "rdsbroker-66ecd739-2e98-401a-9e45-15436165be06.c7uewwm9qebj.eu-west-1.rds.amazonaws.com",
     "jdbcuri": "jdbc:postgresql://rdsbroker-66ecd739-2e98-401a-9e45-17938165be06.c7uewwm9qebj.eu-west-1.rds.amazonaws.com:5432/DATABASE_NAME?password=PASSWORD\u0026ssl=true\u0026user=USERNAME",
     "name": "DATABASE_NAME",
     "password": "PASSWORD",
     "port": 5432,
     "uri": "postgres://USERNAME:PASSWORD@rdsbroker-66ecd739-2e98-401a-9e45-17938165be06.c7uewwm9qebj.eu-west-1.rds.amazonaws.com:5432/DATABASE_NAME",
     "username": "USERNAME"
    },
    "instance_name": "SERVICE_NAME",
    "label": "postgres",
    "name": "SERVICE_NAME",
    "plan": "PLAN",
    "provider": null,
    "syslog_drain_url": null,
    "tags": [
     "postgres",
     "relational"
    ],
    "volume_mounts": []
   }
  ]
 }
}

Refer to the Cloud Foundry Environment Variables documentation [external link] for a full list of environment variables.

Names, routes and domains

App names and domain hostname clash

When you push an app, you have to assign an app name, either in the manifest or using the command line. The app name is also used as the default hostname of the app domain where the app will be hosted.

For example, if you push an app called myappin the London region, the PaaS tries to host it at myapp.london.cloudapps.digital. This is done using Cloud Foundry’s route functions.

The app domain is shared across all PaaS tenants within a region. in this example, if another tenant is using myapp.cloudapps.digital in the Ireland region, and you try to push an app called myapp to the same region, you will receive an error like this:

Using route myapp.london.cloudapps.digital
Binding myapp.london.cloudapps.digital to myapp...
FAILED
The route myapp.london.cloudapps.digital is already in use.

This will also happen if there is an app with the same name within your own organisation, but in a different space.

There are a few possible solutions to this problem:

  1. Minimise the chance of name clash by the way you name your apps; incorporate the name of your team, department or service to produce names that are unlikely to clash with other PaaS tenants. For example, if you work for the Ministry of Peace, instead of myapp, you could use minipeace-myapp.

    If you run different versions of an app in different spaces, you will also need to name them differently: for example, you might have minipeace-myapp-dev, minipeace-myapp-test, minipeace-myapp-production and so on.

  2. Manually specify a hostname that is different from the app name. You can do this as a command line option when you push:

    cf push myapp -n HOSTNAME

    or with a line in the app’s manifest.yml file:

    ---
        ...
        host: HOSTNAME
    

    You will still need to pick a hostname that is not in use.

    This solution means you can change the hostname while keeping the app name the same. This is more flexible, but means you need to keep track of both a hostname and an app name for each app. It could potentially make it easier to deploy to the wrong target.

  3. Use the random-route option. This appends a couple of random words to the hostname, to avoid clashes. For example, if your app is hosted in the London region and you run:

    cf push myapp --random-route

    the app will be hosted at something like https://myapp-mummifying-giraffe.london.cloudapps.digital.

    You can also specify this in your app’s manifest.yml file:

    random-route: true

    This is a convenient way to avoid clashes automatically. The disadvantage is that if your end users can see the resulting URLs, they may find the random words strange.

Custom domains

In production, you will probably want your app to be available through your own url (for example, yourapp.service.gov.uk). Refer to managing custom domains using the cdn-route service to see how to set this up.

Deploy a static HTML page

Refer to the Deploy a test static HTML section of the documentation.

Deploy a Ruby on Rails app

This section explains minimal steps for deploying a basic Rails app. For full details of how to deploy Ruby on Rails apps, see the official Cloud Foundry guide Getting Started Deploying Ruby on Rails Apps [external link].

If your app requires a backing service, it must be able to work with one of the services supported by PaaS. Instructions for deploying both backing service and non-backing service apps are given in this section.

These steps assume you have already carried out the setup process explained in the Get started section.

When you deploy an app, you must select a combination of an organisation and a space. This is called the target.

We have provided a sandbox space for you to use for learning about the PaaS. You may want to target the sandbox while you are testing by running:

cf target -s sandbox

It’s also important to realise that if you deploy an app using the same name and target as an existing app, the original will be replaced. If you are not sure about where to deploy your app, consult the rest of your team.

Deploying an app

To deploy a Rails app that doesn’t require a backing service:

  1. Put the code for your Rails app into a local directory (for example, by checking it out of version control).

  2. Exclude files ignored by Git.

  3. If you’re using Rails 4, add the rails_12factor gem for better logging. Rails 5 has this functionality built in by default.

  4. Create a manifest.yml file in the folder where you checked out your app.

    ---
    applications:
    - name: my-rails-app
      memory: 256M
      buildpack: ruby_buildpack
    

    Replace my-rails-app with a unique name for your app. (You can use cf apps to see apps which already exist).

    The memory line tells the PaaS how much memory to allocate to the app.

    A buildpack provides any framework and runtime support required by an app. In this case, because the app is written in Ruby, you use the ruby_buildpack.

  5. Upload and start the application by running:

    cf push APPNAME
    

    from the directory which contains all the code and configuration files for your app.

    If you do not specify a name for the app after the cf push command, the name from the manifest file is used.

  6. Set any additional environment variables required by your app. For example:

    cf set-env APPNAME VARIABLE `value`
    

    where VARIABLE is a unique name for the variable, and value is the value to set.

Your app should now be available at your app domain.

For a production app, you should read the production checklist.

Deploying with a PostgreSQL database

These instructions are for deploying a Rails app with a PostgreSQL database, and can be applied to other backing services. If you require more guidance on deploying an app with other supported backing services, contact us at gov-uk-paas-support@digital.cabinet-office.gov.uk.

The Cloud Foundry buildpack for Ruby automatically gets the details of the first available PostgreSQL service from the VCAP_SERVICES environment variable and sets the Ruby DATABASE_URL environment variable accordingly. Ensure that your app is configured to use DATABASE_URL to set its database configuration when deployed to the PaaS.

  1. Put the code for your Rails app into a local directory (for example, by checking it out of version control).

  2. If you are using Git, you may wish to exclude files ignored by Git.

  3. If you’re using Rails 4, add the rails_12factor gem for better logging. Rails 5 has this functionality built in by default.

  4. Create a manifest.yml file in the directory where you checked out your app.

    ---
    applications:
    - name: my-rails-app
      memory: 256M
      buildpack: ruby_buildpack
    

    Replace my-rails-app with a unique name for your app. (You can use cf apps to see apps which already exist).

    The memory line tells the PaaS how much memory to allocate to the app.

    A buildpack provides any framework and runtime support required by an app. In this case, because the app is written in Ruby, you use the ruby_buildpack.

  5. Upload the app without starting it using this command:

    cf push --no-start APPNAME
    

    from the directory which contains all the code and configuration files for your app.

    If you do not specify a name for the app after the cf push command, the name from the manifest file is used.

  6. Set any additional environment variables required by your app. For example:

    cf set-env APPNAME VARIABLE `value`
    

    where VARIABLE is a unique name for the variable, and value is the value to set.

  7. Create a PostgreSQL backing service (if required) and bind it to your app.

    To enable Rails support for database migrations, you may wish to create a Procfile in the same directory as your manifest.yml and Gemfile. The Procfile is a way to specify commands to be run when deploying your app.

    This is a minimal example of the Procfile content for Rails 5.0:

    web: rake db:migrate && bin/rails server
    
  8. Start your app by running:

    cf start APPNAME
    

Your app should now be available at your app domain.

For a production app, you should read the production checklist.

Specify a Ruby version

You should tell Cloud Foundry which version of Ruby your app uses in the Ruby buildpack.

Refer to the documentation on buildpack language version updates for more information.

Refer to the Cloud Foundry documentation for more information on how to specify a Ruby version [external link].

Web servers

By default, the Cloud Foundry Ruby buildpack runs bin/rails server to spin up the application. In Rails 4 and below, this will use WEBrick as the web server. In Rails 5 and above, the default is puma.

You may want to use a different web server in production. See the Cloud Foundry docs for more information on configuring a production server [external link].

Troubleshooting asset precompilation

By default, the Rails buildpack performs asset precompilation during the staging phase. This is fine for most Rails apps, but it won’t work for those which need to connect to services (such as the database) during asset compilation. (For an example, see MyUSA issue #636)

There are multiple potential solutions for this. For more advice, see the Cloud Foundry document on the subject [external link].

Deploy a Node.js app

This section covers how to deploy a basic Node.js application to GOV.UK PaaS. See the Cloud Foundry Tips for Node.js Applications [external link] for more details.

If your app requires a backing service, it must be able to work with one of the services supported by PaaS. Instructions for deploying both backing service and non-backing service apps are given in this section.

These instructions assume you have already carried out the setup process explained in the Get started section.

This is the code for the example app we are going to use. It is a basic web server that responds with a ‘Hello World’ message.

const http = require('http');

const port = process.env.PORT || 3000;

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World\n');
});

server.listen(port, () => {
  console.log(`Server running on ${port}/`);
});
  1. Save the code to a new local directory as example.js.

  2. Add this manifest.yml file to the same directory:

    ---
    applications:
    - name: my-node-app
      command: node example.js
      memory: 256M
      buildpack: nodejs_buildpack
    

    Replace my-node-app with a unique name for your app. (You can use cf apps to see apps which already exist).

    The memory line tells the PaaS how much memory to allocate to the app.

    A buildpack provides any framework and runtime support required by an app. In this case, because the app is written in Node.js, you use the nodejs_buildpack.

  3. Include an npm package.json file to specify dependencies. The file should also specify a start command used to launch the app.

    This is a package.json file for our example app:

    {
      "name": "example",
      "version": "0.0.1",
      "author": "Demo",
      "engines": {
        "node": "6.11.x"
      }
    }
    

    The "engines" values specify the versions of Node.js and npm that the PaaS should use to run your app. Note that older versions may not be available: if your version is not supported, you will see an error message when you try to upload and start the app.

  4. You can optionally run npm install to preinstall dependencies rather than having them added during the PaaS staging process.

  5. Run cf push APPNAME from the top level of the directory which contains all the code and configuration files.

If you want to upload the app without starting it (for example, if you need to create a PostgreSQL service), run cf push --no-start APPNAME, then when you are ready to start the app, run cf start APPNAME.

See Tips for Node.js Applications [external link] in the Cloud Foundry documentation for more information.

PostgreSQL setup with Node.js

These instructions are for deploying a Node.js app with a PostgreSQL database, and can be applied to other backing services. If you require more guidance on deploying an app with other supported backing services, contact us at gov-uk-paas-support@digital.cabinet-office.gov.uk.

If your app depends on a backing service such as PostgreSQL, it will need to parse the VCAP_SERVICES environment variable to get required details, such as service URLs and credentials.

You must create the service and bind it to your Node.js app as described in the PostgreSQL section.

You can use the cfenv module to assist with parsing the environment variables.

In your package.json file, you would specify cfenv as a dependency:

    {
      // ...
      "dependencies": {
        "cfenv": "*",
        // ...
      }
    }

Then in your app, you can easily get configuration information for backing services. This is an example of how to connect to a PostgreSQL service.

    var cfenv = require("cfenv");
    var pg = require('pg');
    var appEnv = cfenv.getAppEnv();
    var connectionString = appEnv.getServiceURL("SERVICE NAME");
    var client = new pg.Client(connectionString);
    client.ssl = true;
    client.connect();

Replace “SERVICE NAME” in the above code with the exact name of the PostgreSQL service you created. The getServiceURL function returns a connection string which includes the username and password required to connect to the database.

Further information can be found in:

You should also remember to include dependencies for any service bindings in package.json.

{
  // ...
  "dependencies": {
    "pg": "*",
    // ...
  }
}

Specify a Node.js version

You should tell Cloud Foundry which version of Node.js your app uses in the Node.js buildpack.

Refer to the documentation on buildpack language version updates for more information.

Refer to the Cloud Foundry documentation for more information on how to specify a Node.js version [external link].

Deploy a Django app

This section explains how to deploy an app using the Django framework. You may also need to refer to the Cloud Foundry documentation about the Python buildpack [external link].

If your app requires a backing service, it must be able to work with one of the services supported by PaaS. Instructions for deploying both backing service and non-backing service apps are given in this section.

Before deploying a Django app, you must:

  1. Put the code for your Django app into a local directory (for example, by checking it out of version control).

  2. If you are using Git, add *.pyc and local_settings.py to your .gitignore file, then exclude files ignored by Git so Cloud Foundry will ignore them too.

  3. Run cf buildpacks in the command line to check the version of the Python buildpack.

  4. Go to the Python buildpack page on GitHub to check which versions of Python are currently included in the Python buildpack.

  5. Tell Cloud Foundry which version of Python to use by creating a runtime.txt file in the root of the local directory. This step is optional.

    Refer to the documentation on buildpack language version updates for more information.

    Refer to the Cloud Foundry documentation for more information on how to specify a Python version [external link].

  6. Make sure you have all the required modules for your project installed into your virtual environment (including Django).

  7. Generate a requirements.txt file if your project doesn’t already have one by running pip freeze > requirements.txt in the root of the local folder. Add the following lines to the requirements.txt file.

    whitenoise==1.0.6  #manages static assets
    waitress==0.8.9 #a pure python WSGI server that is a replacement for gunicorn
    
  8. Edit your wsgi.py file.

    When you create a Django project, a default wsgi.py file should be created for you in the project folder. Excluding the opening comments, the default wsgi.py looks like this:

    import os
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "PROJECTNAME.settings")
    
    from django.core.wsgi import get_wsgi_application
    application = get_wsgi_application()
    

    You’ll need to add a few lines to import the whitenoise package and wrap the middleware around the WSGI application so that all static files are served using whitenoise. Edit your wsgi.py to:

    import os
    from django.core.wsgi import get_wsgi_application
    
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "PROJECTNAME.settings")
    # important that the whitenoise import is after the line above
    from whitenoise.django import DjangoWhiteNoise
    
    application = get_wsgi_application()
    application = DjangoWhiteNoise(application)
    

    The order here is important. The DJANGO_SETTINGS_MODULE environment variable must be set before importing DjangoWhiteNoise.

  9. You should now tell Django where to look for static files. In settings.py within the project folder, add these lines below the import os statement.

    PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
    
    STATIC_ROOT = os.path.join(PROJECT_ROOT, 'static')
    STATIC_URL = '/static/'
    

    In this case, the STATIC_ROOT variable tells Django to look for static files in a directory called static inside the project folder, and the STATIC_URL variable sets the path where those files will be served.

    You may need to alter these values depending on how static files are handled in your app.

    If your static files are located across multiple folders, you may need to use the STATICFILES_DIRS variable. See the Django documentation for full details on managing static files.

  10. Create a file called Procfile in the root of your local folder, and put in it:

        web: python manage.py migrate && waitress-serve --port=$PORT PROJECTNAME.wsgi:application
    

    The Procfile is a way to specify commands to be run when deploying your app; in this case, for database migration.

    PROJECTNAME should be replaced with whatever the name of your WSGI module is. By default, this is the same as the name of your project module, but it may be changed using the DJANGO_SETTINGS_MODULE environment variable. Using this configuration will automatically apply any database migrations.

  11. Create a manifest.yml file in the root of your local folder.

    ---
    applications:
    - name: my-app
      memory: 512M
      buildpack: python_buildpack
    

    where my-django-app is the name that will be used for the app within GOV.UK PaaS.

    Replace my-django-app with a unique name for your app. (You can use cf apps to see apps which already exist).

    The memory line tells the PaaS how much memory to allocate to the app.

  12. If your app requires a database, create a PostgreSQL backing service and bind it to your app. Then see the section on PostgreSQL setup below.

  13. To push your app, do:

    cf push APPNAME

    from the directory which contains all the code and configuration files.

    If you want to upload the app without starting it (for example, if you need to create a PostgreSQL service), run cf push --no-start APPNAME, then when you are ready to start the app, run cf start APPNAME.

You can now view your app at your app domain.

PostgreSQL setup with Django

These instructions are for deploying a Django app with a PostgreSQL database, and can be applied to other backing services. If you require more guidance on deploying an app with other supported backing services, contact us at gov-uk-paas-support@digital.cabinet-office.gov.uk.

Add these lines to your requirements.txt:

psycopg2==2.6.2 #installs the postgres driver
dj-database-url==0.3.0 #grabs environment variables and dumps them into a Django settings file

In your settings.py file, make sure you import the dj_database_url package we added to the requirements.txt file above:

    import dj_database_url

This package will automatically parse the VCAP_SERVICES environment variable and set DATABASE_URL to the first database found.

Then you’ll need to add a DATABASES setting. It’s best to add this to the settings.py file.

    DATABASES = {}
    DATABASES['default'] =  dj_database_url.config()

Your local_settings.py file will override this when you’re working locally.

The Procfile configuration provided in the section above will automatically apply database migrations.

Deploy a Java app

This section covers how to deploy a Java application to GOV.UK PaaS using the Java buildpack [external link].

Deploying a JAR file

If your java application can be packaged as a self-executable JAR [external link] then deployment can be as simple as using cf push -p [your-app].jar [your-app-name].

This example will walk through creating a simple “Hello World” application that embeds the popular (Jetty) [external link] webserver. The instructions assume you have already carried out the setup process explained in the Get started section.

  1. Create a directory for your Java application:

    mkdir myapp
    cd myapp
    
  2. Download Jetty.

    curl -o ./jetty.jar http://central.maven.org/maven2/org/eclipse/jetty/aggregate/jetty-all/9.4.6.v20170531/jetty-all-9.4.6.v20170531-uber.jar
    

    This example uses version 9.4.6; check http://www.eclipse.org/jetty/download.html for the latest version of Jetty.

  3. Create a App.java file in your application directory. This class will serve as the entry point for your application:

    package app;
    
    import java.io.IOException;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import org.eclipse.jetty.server.Request;
    import org.eclipse.jetty.server.Server;
    import org.eclipse.jetty.server.handler.AbstractHandler;
    
    public class App extends AbstractHandler
    {
        @Override
        public void handle( String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response ) throws IOException, ServletException
        {
               response.setContentType("text/html; charset=utf-8");
               response.setStatus(HttpServletResponse.SC_OK);
               response.getWriter().println("<h1>Hello World</h1>");
               baseRequest.setHandled(true);
        }
    
        public static void main( String[] args ) throws Exception
        {
                int port = Integer.parseInt(System.getenv("PORT"));
                Server server = new Server(port);
                server.setHandler(new App());
    
                server.start();
                server.join();
        }
    }
    
  4. Compile your class:

    javac -d . -cp ./jetty.jar App.java
    
  5. Combine your class with Jetty to create an executable jar file:

    jar uvfe ./jetty.jar app.App app/App.class
    
  6. Push your jar file.

    cf push your-app-name -b java_buildpack -p ./jetty.jar
    

You have now deployed your Java application. Your application should now be accessible over HTTPS from the URL provided in the output.

If your application requires arguments in order to start, you can set the JBP_CONFIG_JAVA_MAIN environment variable. For example to add server and config.yml as arguments for your app, you could add the following to your application’s manifest.yml:

env:
  JBP_CONFIG_JAVA_MAIN: '{ arguments: "server config.yml" }

Deploying a WAR file

If your application can be packaged as a .war file you can deploy with the following:

cf push your-app-name -b java_buildpack -p your-app.war

If you need to use a specific version of Tomcat you can set the environment variable JBP_CONFIG_TOMCAT. For example to use Tomcat 8 you could add the following to your application’s manifest.yml:

env:
  JBP_CONFIG_TOMCAT: '{ tomcat: { version: 8.0.+ } }'

Note that you do not need to deploy Tomcat along with your application. The Java buildpack will run the servlet 2 and 3 web applications.

For more configuration options see Tomcat Container [external link].

Specify a Java version

You can specify the version of the Java Runtime Environment (JRE) by setting the environment variable JBP_CONFIG_OPEN_JDK_JRE in the application’s manifest.yml. For example, to use JRE 11:

  env:
    JBP_CONFIG_OPEN_JDK_JRE: '{ jre: { version: 11.+ } }'

The + in this example means it will use the latest point release available.

Deploying other JVM-based applications

The Java buildpack supports running any JVM-based applications (such as Scala, Clojure etc.) with little or zero additional configuration. For detailed examples of deploying applications using other frameworks and JVM-based languages:

Stopping and deleting apps

It’s important to know that when you perform a cf push command, there are three things that happen on the platform:

  1. your code is uploaded, after which a buildpack converts it to a single container, called a ‘droplet’, that can be run on PaaS as an app
  2. the droplet is used to start the requested number of instances of that app
  3. a route is created, connecting your app to the internet

When deleting apps you need to remember aspects 1 and 3.

Databases, CDNs and other services have a different lifecycle and need to be removed separately.

Stopping and starting apps

If you temporarily want to stop your app, freeing up memory from your quota, you can use the command

cf stop [appname]

This will stop the app running (although databases and other provisioned services will still be running and chargeable). Users visiting your app’s URL will get the error 404 Not Found: Requested route ('[appname].[app domain]') does not exist.

You can start a stopped app with

cf start [appname]

Deleting apps

BEFORE YOU START: This is irreversible. We strongly recommend running the cf target command before you start: check you are where you think you are, and working on what you think you are working on.

If you want to remove your app completely it’s tempting to jump in with the cf delete command, but there are a few things to beware of:

  • Services that are used by apps do not automatically get deleted, and would still be chargeable
  • Routes between the internet and your apps need to be explicitly removed.

If you have a simple app without any services the best way to delete it is

cf delete -r [APPNAME]

which will delete the app and its routes in one go. If your app does have services, please delete them first.

If you accidentally delete your app without the -r option, you can delete the route manually. First confirm the details of the orphaned route by typing the cf routes command, to get a list of all active routes in the current space. This will list the space, the hostname, the app domain, port, path, type and any bound apps or services. You will see your hostname listed but without an associated app. Use this information to populate the following command:

cf delete-route [domain name] --hostname [hostname]

Delete a service instance

You must unbind a service instance from any apps it is bound to before you can delete that service instance. Note:

  • you do not need to delete an app’s service instances before you can delete that app
  • a service instance can be bound to more than one app
  1. Run cf services to see all service instances in your targeted space. You will see the output as per this example:

    name      service    plan    bound apps    last operation
    mystuff   postgres   small   my-app        create succeeded
    mydb      mysql      large   not-my-app    create succeeded
    
  2. Run the following to unbind a service instance:

    cf unbind-service APPLICATION SERVICE_NAME
    

    where APPLICATION is the name of a deployed instance of your app (exactly as specified in your manifest or push command) and SERVICE_NAME is a unique descriptive name for this service instance, for example:

    cf unbind-service my-app mystuff
    
  3. Run cf delete-service SERVICE_NAME to delete that service instance.

Deploy a Docker image (experimental)

This section explains how to deploy an app from a Docker image. The role of the Docker image is to serve as a packaging format and the requirements for the app and its runtime environment are the same as for apps deployed using buildpacks. Configuration via manifest.yml also stays the same, albeit you should not specify buildpack. If you do, it will be ignored, which can create some confusion to anyone reading the manifest. Our platform currently supports deploying from the following:

Pushing local Docker images isn’t supported.

To deploy an app using a Docker image stored in Docker Hub via CF cli:

cf push myapp --docker-image dockerhuborg/app_image:tag

To deploy an app using a Docker image stored in Docker Trusted Registry (DTR) via CF cli:

cf push myapp --docker-image MY-PRIVATE-REGISTRY.DOMAIN:5000/image/name:tag

To deploy an app using a Docker image stored in a registry that requires authentication, follow the Cloud Foundry Docker image documentation instructions [external link].

You might notice that the staging process is simplified when deploying from a Docker image - this is because there is no need to build the app from the pushed code using a buildpack. Also, the buildpack for apps deployed from a Docker image will be reported as unknown in the app information (cf app <myapp>).

There are a few more specifics about Docker image support in Cloud Foundry:

  • Local storage in each container instance is ephemeral. Every container launch will start with unmodified image.
  • Traffic will be routed to the lowest exposed port (by EXPOSE command in Dockerfile). The PORT environment variable will be also set to this number.
  • Buildpack based apps use bash to execute the app start command (bash -c <command>), but Docker image based apps use sh (sh -c <command>) - as bash presence cannot be assumed in your Docker image.
  • Privileged container mode is not supported. Features depending on this will not work.
  • Only registries that use Docker Registry API V2 are supported.

Your responsibilities change if you use a Docker image instead of a buildpack. Refer to the responsibility model guidance for further information.

Docker Registry Availability Requirements

Deploying, scaling, restarting or restaging an app using a Docker image are all dependent on the Docker registry being available, because these actions require pulling the image from the registry.

Note that Cloud Foundry can restart your application due to circumstances outside of your direct control, such as platform scaling or deployments, or failure of the underlying hardware platform.

If Cloud Foundry attempts to pull the image from the registry when the registry is not available, your application instance will fail to start, and you will receive a Failed to create container message. Once the Docker registry is available again, you will be able to re-deploy, restart or restage your app as required.

Experimental feature

Please note that this is currently only an experimental feature, meaning you can potentially encounter some unexpected behaviour or glitches. It is also possible that we might turn the feature off in the future. It should not be used in live services at this stage.

Lastly, our support for this functionality has lower priority than usual requests, so it is possible that responses to your queries regarding this will take a bit longer. However we are turning on this feature in order get feedback from service teams, so please contact support with any comments or to talk about use in production systems.

Applying security updates

When your app is built with a standard buildpack, you are responsible only for the code of your app. The platform provides both the buildpacks and also a safe and secure root filesystem (cflinuxfs2). Buildpack based apps never have root access in their container, which adds another layer of security. We do periodically apply security and functionality updates to the buildpacks, container root FS and the platform itself.

When your app is deployed from Docker image, responsibility for the root filesystem and for the complete build of your app shifts to you. You need to ensure proper measures are applied to make your app and root image safe and with the latest security updates. We recommend you use one of the major and well supported linux distributions as your base container. This way you will be able to build an image with latest security patches easily.

Production checklist

Before deploying an app for production use, check the following:

  1. If your app uses a backing service, make sure that you have selected the high-availability plan for the service instance.
  2. You have a domain name for your service.
  3. You are running more than one instance of the app to ensure availability. Use cf scale APPNAME -i INSTANCES or amend the manifest file to add more running instances; see Scaling for more information.
  4. You are prepared to use a blue-green deployment process [external link] for when the app needs to be updated or restarted (this avoids problems due to a known issue with the PaaS that can generate transient 404 errors).
  5. You have configured a health check [external link] by setting health-check-type to http and setting health-check-http-endpoint to an appropriate endpoint for your app.