App reference
Back to home
On this page
See all of the options for controlling your apps and how they’re built and deployed on Upsun.
Configuration is all done in a .upsun/config.yaml file,
located at the root of your Git repository.
See a comprehensive example of a configuration in a .upsun/config.yaml file.
Primary application properties
All application configuration takes place in a .upsun/config.yaml file, with each application configured under a unique key beneath the top-level applications key.
For example, it is possible to deploy two application containers - one JavaScript and the other Python - for the frontend and backend components of a deployed site.
In this case, the unified .upsun/config.yaml file would look like:
applications:
frontend:
type: 'nodejs:20'
# Additional frontend configuration
backend:
type: 'python:3.9'
# Additional backend configurationThe following table presents all properties available at the level just below the unique application name (frontend and backend above).
The column Set in instance? defines whether the given property can be overridden within a web or workers instance.
To override any part of a property, you have to provide the entire property.
| Name | Type | Required | Set in instance? | Description |
|---|---|---|---|---|
name |
string |
Yes | No | A unique name for the app. Must be lowercase alphanumeric characters. Changing the name destroys data associated with the app. |
type |
A type | Yes | No | The base image to use with a specific app language. Format: runtime:version. |
relationships |
A dictionary of relationships | Yes | Connections to other services and apps. | |
mounts |
A dictionary of mounts | Yes | Directories that are writable even after the app is built. Allocated disk for mounts is defined with a separate resource configuration call using upsun resources:set. |
|
web |
A web instance | N/A | How the web application is served. | |
workers |
A worker instance | N/A | Alternate copies of the application to run as background processes. | |
timezone |
string |
No | The timezone for crons to run. Format: a TZ database name. Defaults to UTC, which is the timezone used for all logs no matter the value here. See also app runtime timezones |
|
access |
An access dictionary | Yes | Access control for roles accessing app environments. | |
variables |
A variables dictionary | Yes | Variables to control the environment. | |
firewall |
A firewall dictionary | Yes | Outbound firewall rules for the application. | |
build |
A build dictionary | No | What happens when the app is built. | |
dependencies |
A dependencies dictionary | No | What global dependencies to install before the build hook is run. |
|
hooks |
A hooks dictionary | No | What commands run at different stages in the build and deploy process. | |
crons |
A cron dictionary | No | Scheduled tasks for the app. | |
source |
A source dictionary | No | Information on the app’s source code and operations that can be run on it. | |
runtime |
A runtime dictionary | No | Customizations to your PHP or Lisp runtime. | |
additional_hosts |
An additional hosts dictionary | Yes | Maps of hostnames to IP addresses. |
Root directory
Some of the properties you can define are relative to your app’s root directory. The root defaults to the root of the repository.
applications:
frontend:
type: 'nodejs:20'
# Default behavior of source.root
source:
root: "/"That is, if a custom value for source.root is not provided in your configuration, the default behavior is equivalent to the above.
To specify another directory, for example for a multi-app project,
use the source.root property.
Types
The type defines the base container image used to run the application.
The version is the major (X) and sometimes minor (X.Y) version numbers,
depending on the service, as in the following table.
Security and other patches are taken care of for you automatically.
Available languages and their supported versions:
| Language | runtime |
Supported version |
|---|---|---|
| C#/.Net Core | dotnet |
7.0, 6.0 |
| Elixir | elixir |
1.15, 1.14 |
| Go | golang |
1.21, 1.20 |
| Java | java |
21, 19, 18, 17, 11, 8 |
| Lisp | lisp |
2.1, 2.0, 1.5 |
| JavaScript/Node.js | nodejs |
20, 18, 16 |
| PHP | php |
8.3, 8.2, 8.1 |
| Python | python |
3.12, 3.11, 3.10, 3.9, 3.8 |
| Ruby | ruby |
3.3, 3.2, 3.1, 3.0 |
| Rust | rust |
1 |
Example configuration
These are used in the format runtime:version:
applications:
myapp:
type: 'php:8.3' Resources
Resources for application containers are not committed to YAML files, but instead managed over the API using either the Console or the upsun resources:set command.
For more information, see how to manage resources.
Relationships
To access another container within your project, you need to define a relationship to it.
You can give each relationship any name you want.
This name is used in the PLATFORM_RELATIONSHIPS environment variable,
which gives you credentials for accessing the service.
The relationship is specified in the form service_name:endpoint_name.
The service_name is the name of the service given in the services configuration
or the name of another application in the same project specified as the name in that app’s configration.
The endpoint_name is the exposed functionality of the service to use.
For most services, the endpoint is the same as the service type.
For some services (such as MariaDB and Solr),
you can define additional explicit endpoints for multiple databases and cores in the service’s configuration.
The following example shows a single MySQL service named mysqldb offering two databases,
a Redis cache service named rediscache, and an Elasticsearch service named searchserver.
applications:
myapp:
source:
root: "/"
type: 'nodejs:20'
relationships:
database: 'mysqldb:db1'
database2: 'mysqldb:db2'
cache: 'rediscache:redis'
search: 'searchserver:elasticsearch' Available disk space
Disk for application containers are not committed to YAML files, but instead managed over the API using either the Console or the upsun resources:set command.
For more information, see how to manage resources.
Downsize a disk
You can decrease the size of an existing disk for an app. If you do so, be aware that:
- Backups from before the downsize are incompatible and can no longer be used. You need to create new backups.
- The downsize fails if there’s more data on the disk than the desired size.
Mounts
Mounts define directories that are writable after the build is complete. They aren’t available during the build.
applications:
myapp:
source:
root: "/"
type: nodejs:20
mounts:
'DIRECTORY':
source: SOURCE_LOCATION
source_path: SOURCE_PATH_LOCATIONThe DIRECTORY is relative to the app’s root and represents the path in the app.
If you already have a directory with that name, you get a warning that it isn’t accessible after the build.
See how to troubleshoot the warning.
| Name | Type | Required | Description |
|---|---|---|---|
source |
storage, service, or tmp |
Yes | Specifies the mount type. Set to: - storage so your mount can be shared between instances of the same app. - service so your mount can be shared between several apps (using the Network Storage service). - tmp to mount a directory within the /tmp directory of your app.tmp mounts are local ephemeral mounts; their content may be removed during infrastructure maintenance operations. They allow you to store files that you’re not afraid to lose, such as your application cache that can be seamlessly rebuilt.Note that the /tmp directory has a maximum allocation of 8 GB. |
source_path |
string |
Yes | The subdirectory within the mounted disk (the source) where the mount should point. If an empty string is passed, points to the entire directory. |
service |
string |
The name of the network storage service. |
Example:
applications:
myapp:
source:
root: "/"
type: nodejs:20
mounts:
'web/uploads':
source: storage
source_path: uploads
'/.tmp_platformsh':
source: tmp
source_path: files/tmp_platformsh
'/build':
source: storage
source_path: files/build
'/.cache':
source: tmp
source_path: files/.cache
'/node_modules/.cache':
source: tmp
source_path: files/node_modules/.cacheFor examples of how to set up a service mount, see the dedicated Network Storage page.
The accessibility to the web of a mounted directory depends on the web.locations configuration.
Files can be all public, all private, or with different rules for different paths and file types.
Note that when you back up an environment, the mounts on that environment are backed up too.
Also, mounted directories aren’t deleted when they’re removed from .upsun/config.yaml.
The files still exist on disk until manually removed (or, for tmp mounts, until the app container is moved to another host during a maintenance operation).
Mounts, instances, and Network Storage
storage mounts can be shared between different instances of the same app,
which enables horizontal scaling.
In a multi-application context, if you want data in a mount to be shared between applications, you must explicitly define and use a Network Storage service. Note that workers share the Network Storage instance of their parent app container.
If you need a local mount (i.e. unique per container),
Upsun allows you to mount a directory within the /tmp directory of your app.
However, keep the following limitations in mind:
- Content from
tmpmounts is removed when your app container is moved to another host during an infrastructure maintenance operation - The
/tmpdirectory has a maximum allocation of 8 GB
Therefore, tmp mounts are ideal to store non-critical data, such as your application cache which can be seamlessly rebuilt,
but aren’t suitable for storing files that are necessary for your app to run smoothly.
Note that Upsun will provide new local mounts in the near future.
Web
Use the web key to configure the web server running in front of your app.
Defaults may vary with a different image type.
| Name | Type | Required | Description |
|---|---|---|---|
commands |
A web commands dictionary | See note | The command to launch your app. |
upstream |
An upstream dictionary | How the front server connects to your app. | |
locations |
A locations dictionary | How the app container responds to incoming requests. |
See some examples of how to configure what’s served.
Web commands
| Name | Type | Required | Description |
|---|---|---|---|
pre_start |
string |
Command run just prior to start, which can be useful when you need to run per-instance actions. See Mounts, instances, and Network Storage for an example. |
|
start |
string |
See note | The command to launch your app. If it terminates, it’s restarted immediately. |
Example:
applications:
myapp:
source:
root: "/"
type: 'python:3.9'
web:
commands:
start: 'uwsgi --ini conf/server.ini'This command runs every time your app is restarted, regardless of whether or not new code is deployed.
Note
Never “background” a start process using &.
That’s interpreted as the command terminating and the supervisor process starts a second copy,
creating an infinite loop until the container crashes.
Just run it as normal and allow the Upsun supervisor to manage it.
For an example and common use case of the pre_start command, see Mounts, instances, and Network Storage.
Required command
On all containers other than PHP, the value for start should be treated as required.
On PHP containers, it’s optional and defaults to starting PHP-FPM (/usr/bin/start-php-app).
It can also be set explicitly on a PHP container to run a dedicated process,
such as React PHP
or Amp.
See how to set up alternate start commands on PHP.
Upstream
| Name | Type | Required | Description |
|---|---|---|---|
socket_family |
tcp or unix |
Whether your app listens on a Unix or TCP socket. Defaults to tcp. |
|
protocol |
http or fastcgi |
Whether your app receives incoming requests over HTTP or FastCGI. Default varies based on image type. |
For PHP, the defaults are configured for PHP-FPM and shouldn’t need adjustment.
For all other containers, the default for protocol is http.
The following example is the default on non-PHP containers:
applications:
myapp:
source:
root: "/"
type: 'python:3.9'
web:
upstream:
socket_family: tcp
protocol: http Where to listen
Where to listen depends on your setting for web.upstream.socket_family (defaults to tcp).
socket_family |
Where to listen |
|---|---|
tcp |
The port specified by the PORT environment variable |
unix |
The Unix socket file specified by the SOCKET environment variable |
If your application isn’t listening at the same place that the runtime is sending requests,
you see 502 Bad Gateway errors when you try to connect to your website.
Locations
Each key in the locations dictionary is a path on your site with a leading /.
For example.com, a / matches example.com/ and /admin matches example.com/admin.
When multiple keys match an incoming request, the most-specific applies.
The following table presents possible properties for each location:
| Name | Type | Default | Description |
|---|---|---|---|
root |
string |
The directory to serve static assets for this location relative to the app’s root directory. Must be an actual directory inside the root directory. | |
passthru |
boolean or string |
false |
Whether to forward disallowed and missing resources from this location to the app. A string is a path with a leading / to the controller, such as /index.php. If your app is in PHP, when setting passthru to true, you might want to set scripts to false for enhanced security. This prevents PHP scripts from being executed from the specified location. You might also want to set allow to false so that not only PHP scripts can’t be executed, but their source code also can’t be delivered. |
index |
Array of strings or null |
Files to consider when serving a request for a directory. When set, requires access to the files through the allow or rules keys. |
|
expires |
string |
-1 |
How long static assets are cached. The default means no caching. Setting it to a value enables the Cache-Control and Expires headers. Times can be suffixed with ms = milliseconds, s = seconds, m = minutes, h = hours, d = days, w = weeks, M = months/30d, or y = years/365d. |
allow |
boolean |
true |
Whether to allow serving files which don’t match a rule. |
scripts |
boolean |
Whether to allow scripts to run. Doesn’t apply to paths specified in passthru. Meaningful only on PHP containers. |
|
headers |
A headers dictionary | Any additional headers to apply to static assets, mapping header names to values. Responses from the app aren’t affected. | |
request_buffering |
A request buffering dictionary | See below | Handling for chunked requests. |
rules |
A rules dictionary | Specific overrides for specific locations. |
Rules
The rules dictionary can override most other keys according to a regular expression.
The key of each item is a regular expression to match paths exactly.
If an incoming request matches the rule, it’s handled by the properties under the rule,
overriding any conflicting rules from the rest of the locations dictionary.
Under rules, you can set all of the other possible locations properties
except root, index and request_buffering.
In the following example, the allow key disallows requests for static files anywhere in the site.
This is overridden by a rule that explicitly allows common image file formats.
applications:
myapp:
source:
root: "/"
type: 'python:3.9'
web:
locations:
'/':
# Handle dynamic requests
root: 'public'
passthru: '/index.php'
# Disallow static files
allow: false
rules:
# Allow common image files only.
'\.(jpe?g|png|gif|svgz?|css|js|map|ico|bmp|eot|woff2?|otf|ttf)$':
allow: true Request buffering
Request buffering is enabled by default to handle chunked requests as most app servers don’t support them.
The following table shows the keys in the request_buffering dictionary:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
enabled |
boolean |
Yes | true |
Whether request buffering is enabled. |
max_request_size |
string |
250m |
The maximum size to allow in one request. |
The default configuration would look like this:
applications:
myapp:
source:
root: "/"
type: 'python:3.9'
web:
locations:
'/':
passthru: true
request_buffering:
enabled: true
max_request_size: 250m Workers
Workers are exact copies of the code and compilation output as a web instance after a build hook.
They use the same container image.
Workers can’t accept public requests and so are suitable only for background tasks. If they exit, they’re automatically restarted.
The keys of the workers definition are the names of the workers.
You can then define how each worker differs from the web instance using the top-level properties.
Each worker can differ from the web instance in all properties except for:
buildanddependenciesproperties, which must be the samecronsas cron jobs don’t run on workershooksas thebuildhook must be the same and thedeployandpost_deployhooks don’t run on workers.
A worker named queue that was small and had a different start command could look like this:
applications:
myapp:
source:
root: "/"
type: 'python:3.9'
workers:
queue:
commands:
start: |
./worker.sh Workers require resource definition using upsun resources:set, same as application containers.
For more information, see how to manage resources.
Access
The access dictionary has one allowed key:
| Name | Allowed values | Default | Description |
|---|---|---|---|
ssh |
admin, contributor, or viewer |
contributor |
Defines the minimum role required to access app environments via SSH. |
In the following example, only users with admin permissions for the given environment type
can access the deployed environment via SSH:
applications:
myapp:
source:
root: "/"
type: 'python:3.9'
access:
ssh: admin Variables
Upsun provides a number of ways to set variables. Variables set in your app configuration have the lowest precedence, meaning they’re overridden by any conflicting values provided elsewhere.
All variables set in your app configuration must have a prefix. Some prefixes have specific meanings.
Variables with the prefix env are available as a separate environment variable.
All other variables are available in the PLATFORM_VARIABLES environment variable.
The following example sets two variables:
- A variable named
env:AUTHORwith the valueJuanthat’s available in the environment asAUTHOR - A variable named
d8config:system.site:namewith the valueMy site rocksthat’s available in thePLATFORM_VARIABLESenvironment variable
applications:
myapp:
source:
root: "/"
type: 'python:3.9'
variables:
env:
AUTHOR: 'Juan'
d8config:
"system.site:name": 'My site rocks'You can also define and access more complex values.
Firewall
Set limits in outbound traffic from your app with no impact on inbound requests.
The outbound key is required and contains one or more rules.
The rules define what traffic is allowed; anything unspecified is blocked.
Each rule has the following properties where at least one is required and ips and domains can’t be specified together:
| Name | Type | Default | Description |
|---|---|---|---|
ips |
Array of strings |
["0.0.0.0/0"] |
IP addresses in CIDR notation. See a CIDR format converter. |
domains |
Array of strings |
Fully qualified domain names to specify specific destinations by hostname. | |
ports |
Array of integers |
Ports from 1 to 65535 that are allowed. If any ports are specified, all unspecified ports are blocked. If no ports are specified, all ports are allowed. Port 25, the SMTP port for sending email, is always blocked. |
The default settings would look like this:
applications:
myapp:
source:
root: "/"
type: 'python:3.9'
firewall:
outbound:
- ips: ["0.0.0.0/0"] Support for rules
Where outbound rules for firewalls are supported in all environments.
Multiple rules
Multiple firewall rules can be specified. In such cases, a given outbound request is allowed if it matches any of the defined rules.
So in the following example requests to any IP on port 80 are allowed and requests to 1.2.3.4 on either port 80 or 443 are allowed:
applications:
myapp:
source:
root: "/"
type: 'python:3.9'
firewall:
outbound:
- ips: ["1.2.3.4/32"]
ports: [443]
- ports: [80] Outbound traffic to CDNs
Be aware that many services are behind a content delivery network (CDN). For most CDNs, routing is done via domain name, not IP address, so thousands of domain names may share the same public IP addresses at the CDN. If you allow the IP address of a CDN, you are usually allowing many or all of the other customers hosted behind that CDN.
Outbound traffic by domain
You can filter outbound traffic by domain. Using domains in your rules rather than IP addresses is generally more specific and secure. For example, if you use an IP address for a service with a CDN, you have to allow the IP address for the CDN. This means that you allow potentially hundreds or thousands of other servers also using the CDN.
An example rule filtering by domain:
applications:
myapp:
source:
root: "/"
type: 'python:3.9'
firewall:
outbound:
- protocol: tcp
domains: ["api.stripe.com", "api.twilio.com"]
ports: [80, 443]
- protocol: tcp
ips: ["1.2.3.4/29","2.3.4.5"]
ports: [22] Determine which domains to allow
To determine which domains to include in your filtering rules,
find the domains your site has requested the DNS to resolve.
Run the following command to parse your server’s dns.log file
and display all Fully Qualified Domain Names that have been requested:
awk '/query\[[^P]\]/ { print $6 | "sort -u" }' /var/log/dns.logThe output includes all DNS requests that were made, including those blocked by your filtering rules. It doesn’t include any requests made using an IP address.
Example output:
facebook.com
fastly.com
platform.sh
www.google.com
www.platform.sh Build
The only property of the build dictionary is flavor, which specifies a default set of build tasks to run.
Flavors are language-specific.
See what the build flavor is for your language:
In all languages, you can also specify a flavor of none to take no action at all
(which is the default for any language other than PHP and Node.js).
applications:
myapp:
source:
root: "/"
type: 'nodejs:20'
build:
flavor: none Dependencies
Installs global dependencies as part of the build process.
They’re independent of your app’s dependencies
and are available in the PATH during the build process and in the runtime environment.
They’re installed before the build hook runs using a package manager for the language.
| Language | Key name | Package manager |
|---|---|---|
| PHP | php |
Composer |
| Python 2 | python or python2 |
Pip 2 |
| Python 3 | python3 |
Pip 3 |
| Ruby | ruby |
Bundler |
| Node.js | nodejs |
npm (see how to use yarn) |
| Java | java |
Apache Maven, Gradle, or Apache Ant |
The format for package names and version constraints are defined by the specific package manager.
An example of dependencies in multiple languages:
applications:
myapp:
source:
root: "/"
type: 'nodejs:20'
dependencies:
php: # Specify one Composer package per line.
drush/drush: '8.0.0'
composer/composer: '^2'
python2: # Specify one Python 2 package per line.
behave: '*'
requests: '*'
python3: # Specify one Python 3 package per line.
numpy: '*'
ruby: # Specify one Bundler package per line.
sass: '3.4.7'
nodejs: # Specify one NPM package per line.
pm2: '^4.5.0' Hooks
There are three different hooks that run as part of the process of building and deploying your app.
These are places where you can run custom scripts.
They are: the build hook, the deploy hook, and the post_deploy hook.
Only the build hook is run for worker instances, while web instances run all three.
The process is ordered as:
- Variables accessible at build time become available.
- Build flavor runs if applicable.
- Any dependencies are installed.
- The
buildhook is run. - The file system is changed to read only (except for any mounts).
- The app container starts. Variables accessible at runtime and services become available.
- The
deployhook is run. - The app container begins accepting requests.
- The
post_deployhook is run.
Note that if an environment changes by no code changes, only the last step is run. If you want the entire process to run, see how to manually trigger builds.
Writable directories during build
During the build hook, there are three writeable directories:
PLATFORM_APP_DIR: Where your code is checked out and the working directory when thebuildhook starts. Becomes the app that gets deployed.PLATFORM_CACHE_DIR: Persists between builds, but isn’t deployed. Shared by all builds on all branches./tmp: Isn’t deployed and is wiped between each build. Note thatPLATFORM_CACHE_DIRis mapped to/tmpand together they offer about 8GB of free space.
Hook failure
Each hook is executed as a single script, so they’re considered to have failed only if the final command in them fails.
To cause them to fail on the first failed command, add set -e to the beginning of the hook.
If a build hook fails for any reason, the build is aborted and the deploy doesn’t happen.
Note that this only works for build hooks –
if other hooks fail, the app is still deployed.
Automated testing
It’s preferable that you set up and run automated tests in a dedicated CI/CD tool. Relying on Upsun hooks for such tasks can prove difficult.
During the build hook, you can halt the deployment on a test failure but the following limitations apply:
- Access to services such as databases, Redis, Vault KMS, and even writable mounts is disabled. So any testing that relies on it is sure to fail.
- If you haven’t made changes to your app, an existing build image is reused and the build hook isn’t run.
- Test results are written into your app container, so they might get exposed to a third party.
During the deploy hook, you can access services but you can’t halt the deployment based on a test failure.
Note that there are other downsides:
- Your app container is read-only during the deploy hook, so if your tests need to write reports and other information, you need to create a file mount for them.
- Your app can only be deployed once the deploy hook has been completed. Therefore, running automated testing via the deploy hook generates slower deployments.
- Your environment isn’t available externally during the deploy hook. Unit and integration testing might work without the environment being available, but you can’t typically perform end-to-end testing until after the environment is up and available.
Crons
The keys of the crons definition are the names of the cron jobs.
The names must be unique.
If an application defines both a web instance and worker instances, cron jobs run only on the web instance.
See how to get cron logs.
The following table shows the properties for each job:
| Name | Type | Required | Description |
|---|---|---|---|
spec |
string |
Yes | The cron specification. To prevent competition for resources that might hurt performance, use H in definitions to indicate an unspecified but invariant time. For example, instead of using 0 * * * * to indicate the cron job runs at the start of every hour, you can use H * * * * to indicate it runs every hour, but not necessarily at the start. This prevents multiple cron jobs from trying to start at the same time. |
commands |
A cron commands dictionary | Yes | A definition of what commands to run when starting and stopping the cron job. |
shutdown_timeout |
integer |
No | When a cron is canceled, this represents the number of seconds after which a SIGKILL signal is sent to the process to force terminate it. The default is 10 seconds. |
timeout |
integer |
No | The maximum amount of time a cron can run before it’s terminated. Defaults to the maximum allowed value of 86400 seconds (24 hours). |
Note that you can cancel pending or running crons.
Cron commands
| Name | Type | Required | Description |
|---|---|---|---|
start |
string |
Yes | The command that’s run. It’s run in Dash. |
stop |
string |
No | The command that’s issued to give the cron command a chance to shutdown gracefully, such as to finish an active item in a list of tasks. Issued when a cron task is interrupted by a user through the CLI or Console. If not specified, a SIGTERM signal is sent to the process. |
applications:
myapp:
source:
root: "/"
type: 'nodejs:20'
crons:
mycommand:
spec: 'H * * * *'
commands:
start: sleep 60 && echo sleep-60-finished && date
stop: killall sleep
shutdown_timeout: 18In this example configuration, the cron specification uses the H syntax.
Example cron jobs
applications:
# The name of the app container. Must be unique within a project.
myapp:
# The location of the application's code.
source:
root: "/"
type: 'php:8.3'
crons:
# Run Drupal's cron tasks every 19 minutes.
drupal:
spec: '*/19 * * * *'
commands:
start: 'cd web ; drush core-cron'
# But also run pending queue tasks every 7 minutes.
# Use an odd number to avoid running at the same time as the `drupal` cron.
drush-queue:
spec: '*/7 * * * *'
commands:
start: 'cd web ; drush queue-run aggregator_feeds'applications:
# The name of the app container. Must be unique within a project.
myapp:
# The location of the application's code.
source:
root: "/"
type: 'ruby:3.3'
crons:
# Execute a rake script every 19 minutes.
ruby:
spec: '*/19 * * * *'
commands:
start: 'bundle exec rake some:task'applications:
# The name of the app container. Must be unique within a project.
myapp:
# The location of the application's code.
source:
root: "/"
type: 'php:8.3'
crons:
# Run Laravel's scheduler every 5 minutes.
scheduler:
spec: '*/5 * * * *'
cmd: 'php artisan schedule:run'applications:
# The name of the app container. Must be unique within a project.
myapp:
# The location of the application's code.
source:
root: "/"
type: 'php:8.3'
crons:
# Take a backup of the environment every day at 5:00 AM.
snapshot:
spec: 0 5 * * *
cmd: |
# Only run for the production environment, aka main branch
if [ "$PLATFORM_ENVIRONMENT_TYPE" = "production" ]; then
croncape symfony ...
fi Conditional crons
If you want to set up customized cron schedules depending on the environment type, define conditional crons. To do so, use a configuration similar to the following:
applications:
myapp:
source:
root: "/"
type: 'php:8.3'
crons:
update:
spec: '0 0 * * *'
commands:
start: |
if [ "$PLATFORM_ENVIRONMENT_TYPE" = production ]; then
upsun backup:create --yes --no-wait
upsun source-operation:run update --no-wait --yes
fi Cron job timing
The minimum time between cron jobs being triggered is 5 minutes.
For each app container, only one cron job can run at a time. If a new job is triggered while another is running, the new job is paused until the other completes.
To minimize conflicts, a random offset is applied to all triggers. The offset is a random number of seconds up to 20 minutes or the cron frequency, whichever is smaller.
Crons are also paused while activities such as backups are running. The crons are queued to run after the other activity finishes.
To run cron jobs in a timezone other than UTC, set the timezone property.
Paused crons
Preview environments are often used for a limited time and then abandoned. While it’s useful for environments under active development to have scheduled tasks, unused environments don’t need to run cron jobs. To minimize unnecessary resource use, crons on environments with no deployments are paused.
This affects all preview environments, and production environment that do not yet have a domain attached to them.
Such environments with deployments within 14 days have crons with the status running.
If there haven’t been any deployments within 14 days, the status is paused.
You can see the status in the Console
or using the CLI by running upsun environment:info and looking under deployment_state.
Restarting paused crons
If the crons on your preview environment are paused but you’re still using them, you can push changes to the environment or redeploy it.
To restart crons without changing anything:
- In the Console, navigate to your project.
- Open the environment where you’d like the crons to run.
- Click
Redeploynext to the cron status ofPaused.
Run the following command:
upsun redeploy Runtime
The following table presents the various possible modifications to your PHP or Lisp runtime:
| Name | Type | Language | Description |
|---|---|---|---|
extensions |
List of strings OR extensions definitions |
PHP | PHP extensions to enable. |
disabled_extensions |
List of strings |
PHP | PHP extensions to disable. |
request_terminate_timeout |
integer |
PHP | The timeout for serving a single request after which the PHP-FPM worker process is killed. |
sizing_hints |
A sizing hints definition | PHP | The assumptions for setting the number of workers in your PHP-FPM runtime. |
xdebug |
An Xdebug definition | PHP | The setting to turn on Xdebug. |
quicklisp |
Distribution definitions | Lisp | Distributions for QuickLisp to use. |
You can also set your app’s runtime timezone.
Extensions
You can enable PHP extensions just with a list of extensions:
applications:
myapp:
source:
root: "/"
type: 'php:8.3'
runtime:
extensions:
- geoip
- tidyAlternatively, if you need to include configuration options, use a dictionary for that extension:
applications:
myapp:
source:
root: "/"
type: 'php:8.3'
runtime:
extensions:
- geoip
- name: blackfire
configuration:
server_id: foo
server_token: barIn this case, the name property is required.
Sizing hints
The following table shows the properties that can be set in sizing_hints:
| Name | Type | Default | Minimum | Description |
|---|---|---|---|---|
request_memory |
integer |
45 | 10 | The average memory consumed per request in MB. |
reserved_memory |
integer |
70 | 70 | The amount of memory reserved in MB. |
See more about PHP-FPM workers and sizing.
Source
The following table shows the properties that can be set in source:
| Name | Type | Required | Description |
|---|---|---|---|
operations |
An operations dictionary | Operations that can be applied to the source code. See source operations | |
root |
string |
The path where the app code lives. Defaults to the root project directory. Useful for multi-app setups. |
Additional hosts
If you’re using a private network with specific IP addresses you need to connect to, you might want to map those addresses to hostnames to better remember and organize them. In such cases, you can add a map of those IP addresses to whatever hostnames you like. Then when your app tries to access the hostname, it’s sent to the proper IP address.
So in the following example, if your app tries to access api.example.com, it’s sent to 192.0.2.23.
applications:
myapp:
source:
root: "/"
type: 'php:8.3'
additional_hosts:
api.example.com: "192.0.2.23"
web.example.com: "203.0.113.42"This is equivalent to adding the mapping to the /etc/hosts file for the container.