# Upsun > Upsun is a PaaS to host all of your web applications. Things to remember when deploying applications on Upsun: - *Ultimate developer flexibility*: Self-service. Usage-based pricing. Customize your resources, runtimes, users, frontends, backends, APIs. All the choices are yours. Welcome to the Upsun PaaS. - *Application development your way*, 4 options to get started sync your GitHub repo with Upsun, Deploy an existing local Git repository, Kickstart a new repository, Explore Upsun with our Demo app - *Agnostic freedom*: Tight integration with external systems, stacks, and tools you already use. Choice of IaaS platform(by geo or cloud provider) and services. Choose the road you want to travel. - *Self-service*: All the control and customization you want to experiment. Flexible resources. Sensible, transparent, usage-based pricing. Choose self-empowerment. - *Composable infrastructure*: Dozens of runtimes and backend services to mix and match, Managed routing, with built-in, multiregional edge-caching, automated TLS, and WAF, Full infrastructure preview environments, isolated, but identical to production, Full abstraction from underlying cloud provider; runs precisely the same way on every major cloud - *Collaboration-oriented*: The ability to collaborate on the infrastructure just like you collaborate on code, Git-driven infrastructure with support for multiple repositories, Bi-directional Git integrations, activity scripts, and webhooks to plug into any external service, Instantly created preview environments—per branch, per PR, per team, per developer, per anything - *Scalable on every dimension*: Vertical scaling of every component, horizontal scaling of applications and workers, Fully managed, multicloud edge-caching, From a single monolith to an automated service mesh, with microservices, workers' message queues, and multiple data backends, Built-in observability tools, with infrastructure metrics, built-in APM, profiling, and tracing - *Stability, security, responsibility*: Automated high availability and failover of every infrastructure component, with automated and transparent security-patching, Fine-grained team permissions, with MFA everywhere—even on SSH, Short-lived SSH certificates, with MFA and external identity provider support, PCI DSS, SOC 2, GDPR compliance, - *Polyglot? Hyperglot? We glot you*: Upsun supports an array of cool languages and frameworks. Monoliths. Microservices. Multistack. So you can keep your options open. Flexible. And future-proof. ## Get started ### Setup **Got code?**: In order to follow along with this guide, you need a local project. While the guide has been written to accommodate the following stacks, it is not limited to just those listed and are here only as examples. **JavaScript/Node.js** - [Express installation guide](https://expressjs.com/en/starter/installing.md) - [Next.js installation guide](https://nextjs.org/docs/getting-started/installation) - [Strapi installation guide](https://docs.strapi.io/dev-docs/installation) **PHP** - [Laravel installation guide](https://laravel.com/docs/10.x#creating-a-laravel-project) - [Symfony installation guide](https://docs.upsun.com/get-started/stacks/symfony.md) **Python** - [Flask installation guide](https://flask.palletsprojects.com/en/2.3.x/installation) - [Django installation guide](https://docs.djangoproject.com/en/5.0/intro/tutorial01/) ##### Before you begin You need: - [Git](https://git-scm.com/downloads). Git is the primary tool to manage everything your app needs to run. Push commits to deploy changes and control configuration through YAML files. These files describe your infrastructure, making it transparent and version-controlled. - A Upsun account. If you don't already have one, [register for a trial account](https://auth.upsun.com/register). You can sign up with an email address or an existing GitHub, Bitbucket, or Google account. If you choose one of these accounts, you can set a password for your Upsun account later. - The [Upsun CLI](https://docs.upsun.com/administration/cli.md). This lets you interact with your project from the command line. You can also do most things through the [Web Console](https://docs.upsun.com/administration/web.md). **Trials**: When you create your first organization on Upsun, you are also activating your trial for that organization. Get [more information on trials](https://docs.upsun.com/glossary.md#trial). ##### Initialize your Git repository A Git repository is required for Upsun projects. If you haven't already done so, initialize a Git repository for your codebase, and commit your files: ```bash {location="Terminal"} git init git add . git commit -m "Initial commit." ``` This guide assumes that your repository's default branch is `main`. Your Git configuration may result in different default branches (like `master`), so please run `git branch -M main` before proceeding. **Don’t commit dependencies**: Whether you’re migrating your own project, or testing Upsun with a starter project, **never commit your app’s dependencies**. Make sure you ignore directories containing dependencies by updating your ``.gitignore`` file. ```bash {} # JavaScript/Node.js echo "node_modules" >> .gitignore # PHP echo "vendor" >> .gitignore # Python echo "env" >> .gitignore git add .gitignore && git commit -m "Update .gitignore to ignore deps." ``` ### Create a project To create a new project on Upsun, you can take one of two paths: **Using the Console (recommended)** Open the [Upsun management console](https://console.upsun.com/-/create-project) to create your project. **Note**: If you haven’t done so already, you are prompted to create your first organization where your project will reside. ![Create project options](https://docs.upsun.com/images/console/create-project.png "0.4") From the Console, what you do next entirely depends on where the "source of truth" of your codebase is located. In this guide, you will push your local repository to Upsun. That is, the only copy of your codebase you'd like to deploy is on your local computer. Click **Start from scratch** from the **Deploy with Git** option. **Git integrations**: This guide does not specifically address integrating an Upsun project with a third party repository such as one on GitHub, even though the **Connect repository** option is available at this stage. For now, continue to work locally. Third party integrations will be addressed at the end of this guide. Add details about your project, such as: - The name of your project. - The default branch of your local repository. - Select the region where you want your project to be hosted. As suggested in the Console, connect the local copy of your repository to your project: ```bash upsun project:set-remote ``` Your local source code is automatically linked to your newly created Upsun project through the creation of a `.upsun/local/project.yaml` file. This file contains the corresponding `` and sets a Git remote to `upsun`. **Using the CLI** To create a new project with the Upsun CLI, use the following command and follow the prompts: ```bash {location="Terminal"} upsun project:create ``` **Default branches**: When creating a new project using the Upsun CLI command ``project:create``, the default production branch is set to ``main``. Change it if your default branch is different (e.g.: ``master``). Then, you are asked if you want to set the local remote to your new project. Enter **Yes (y)**. Your local source code is automatically linked to your newly created Upsun project through the creation of a `.upsun/local/project.yaml` file. This file contains the corresponding `` and sets a Git remote to `upsun`. In this guide, you will push your local repository to Upsun. That is, the only copy of your codebase you'd like to deploy is on your local computer. **Git integrations**: This guide does not specifically address integrating an Upsun project with a third party repository such as one on GitHub, even though you will notice the **Connect repository** option available at this stage. For now, continue to work locally. Third party integrations will be addressed at the end of this guide. So long as you chose `y` (yes) to the question `Set the new project as the remote for this repository?` during the `project:create` command, your local project is already integrated to the Upsun project. ### Configure your project ##### Required files To host your application on Upsun, a configuration file (YAML) is needed to manage the way your application behaves. This configuration file is located inside a `.upsun`folder at the root of your source code: ```bash my-app ├── .upsun │ └── config.yaml ├── [.environment] └── ``` To pre-generate these YAML files, run the following command from the root of your project. ```bash {location="Terminal"} upsun project:init ``` Follow the prompts. The `upsun project:init` command does the following: - If possible, automatically detects which framework you’re using. If not detected, you are asked which runtime language your codebase is in. - Asks if you want to add any services. - Generates the corresponding `.upsun/config.yaml` and `.environment` files. The generated configuration varies slightly based on your answers to these prompts and whether a framework is detected. However, the structure of the configuration file remains similar to the following: ```yaml {location=".upsun/config.yaml"} applications: # Configuration for all applications within an environment. myapp: # configuration for the application 'app' services: # Configuration for all services within an environment. db: # configuration for service 'db' routes: # Configuration for routing to applications 'https://{default}/': ``` **Note**: If you want more information on the structure of this configuration file, see the dedicated [YAML page](https://docs.upsun.com/learn/overview/yaml.md). **Committing variables**: An additional [.environment](https://docs.upsun.com/development/variables/set-variables.md#set-variables-via-script) may be located at the root of your source code. This file contains Upsun specific environment variables. Commit your new files: ```bash {location="Terminal"} git add . && git commit -m "Add configuration for Upsun." ``` Push up to your Upsun project: ```bash upsun push ``` Upsun now reads your configuration files, begins building your application image and allocates resources to your various containers. **Note**: By default, Upsun uses default resources for each of your services/apps. You can [adjust these resources](https://docs.upsun.com/get-started/here/set-resources.md). ##### Errors on first push If you try to push a source code that is not Upsun ready, the following error is usually triggered at this point: ![Create project options](https://docs.upsun.com/images/console/first-fail.png) This error is triggered because you have not yet added Upsun configuration to your project to setup deployments. ##### Errors The `project:init` CLI command uses your responses and some framework-detection logic to attempt to set some sane configuration for your project. Your project - like most projects - is unique, and this goal of a seamless first deployment may yet be incomplete at this stage. Have no fear! Upsun provides a highly customizable configuration schema that can be adjusted for your particular package manager, environment variables, builds, deploys, workers, crons, and other requirements to get you fully deployed. To start exploring what might still be needed, see the following language-specific configuration pages: - [JavaScript/Node.js](https://docs.upsun.com/get-started/here/configure/nodejs.md) - [PHP](https://docs.upsun.com/get-started/here/configure/php.md) - [Python](https://docs.upsun.com/get-started/here/configure/python.md) ##### Next steps With your deployment finished, you may have noticed that the resources allocated to the application and service containers of your project have been set automatically: ```bash Opening environment Environment configuration app (type: php:8.2, cpu: 0.5, memory: 224, disk: 512) db (type: mariadb:12.4, cpu: 0.5, memory: 1408, disk: 512) memcached (type: memcached:1.6, cpu: 0.5, memory: 1088) ``` **Note**: Each time you create a new branch, your new environment inherits its parent environment’s resource allocation. If you need more disk for uploaded files, or less memory for rarely used services, you can [adjust resources](https://docs.upsun.com/manage-resources/adjust-resources.md) at any time. #### JavaScript/Node.js When dealing with Javascript/Node.js stacks, the information below may help customize your configuration. These sections provide Javascript/Node.js-specific configuration details, but you can also refer to the common Upsun documentation: - [Configuring applications](https://docs.upsun.com/create-apps.md) - [Setting up managed services](https://docs.upsun.com/add-services.md) - [Handling requests](https://docs.upsun.com/define-routes.md) ###### Build flavors By default, Upsun makes assumptions about how you want to build your application. Namely, that you are managing your dependencies with npm, and that the very first thing you'd like to run is a particular and common production flavor of `npm install`. This is called a build `flavor`, but its assumption may prove inappropriate for your application and cause your builds to fail (such as if you'd like to use yarn or bun instead of npm). Therefore, you can [disable this feature](https://docs.upsun.com/languages/nodejs.md#dependencies). ###### Available package managers Certain package managers come pre-installed on all Upsun `nodejs` container types: * *npm*; example: ``npm install platformsh-config`` * *npx*; example: ``npx create-strapi-app `` * *bun*; example: ``bun install platformsh-config`` You can also use Yarn if you [install it explicitly](https://docs.upsun.com/languages/nodejs#use-yarn-as-a-package-manager), or [nvm](https://docs.upsun.com/languages/nodejs/node-version.md#use-nvm). ###### Sample configuration Below are some examples from common Node.js framework configuration: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: "nodejs:20" web: commands: start: "node index.js" build: flavor: none dependencies: nodejs: sharp: "*" #services: # db: # type: postgresql:14 routes: "https://{default}/": type: upstream upstream: "myapp:http" # A basic redirect definition # More information: https://docs.upsun.com/define-routes.html#basic-redirect-definition "https://www.{default}/": type: redirect to: "https://{default}/" ``` ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: "nodejs:20" relationships: postgresql: mounts: ... web: commands: start: "NODE_ENV=production yarn start" build: flavor: none dependencies: nodejs: yarn: "^1.22.0" hooks: build: | set -eux yarn yarn build services: postgresql: type: postgresql:15 routes: "https://{default}/": type: upstream upstream: "myapp:http" # A basic redirect definition # More information: https://docs.upsun.com/define-routes.html#basic-redirect-definition "https://www.{default}/": type: redirect to: "https://{default}/" ``` ###### Frameworks The Upsun documentation includes a wide array of community resources to help with framework-specific configuration: - [Express](https://docs.upsun.com/get-started/stacks/express.md) - [Next.js](https://docs.upsun.com/get-started/stacks/nextjs.md) - [Strapi](https://docs.upsun.com/get-started/stacks/strapi.md) ###### Get support While there are virtually no restrictions to you deploying any kind of application on Upsun, configuration may still be unclear at this point. Not to worry! The Upsun community is here to help. Come and say hello, share your work, ask for help, and peek in on what others are working on. Welcome to the Upsun community! Join us on Discord Ask a question on the forum #### PHP When dealing with PHP stacks, the information below may help customize your configuration. These sections provide PHP-specific configuration details, but you can also refer to the common Upsun documentation: - [Configuring applications](https://docs.upsun.com/create-apps.md) - [Setting up managed services](https://docs.upsun.com/add-services.md) - [Handling requests](https://docs.upsun.com/define-routes.md) ###### Build flavors By default, Upsun makes assumptions about how you want to build your application. Namely, that you are managing your dependencies with Composer, and that the very first thing you'd like to run is a particular and common production flavor of `composer install`. This is called a build `flavor`, but its assumption may prove inappropriate for your application and cause your builds to fail. Therefore, you can [disable this feature](https://docs.upsun.com/languages/php.md#dependencies). ###### Authenticated Composer Packagist is the primary Composer repository for public PHP packages. But you can also have Composer download PHP packages from a private, third-party Composer repository. To make sure Composer has the necessary credentials to do so, follow the instructions on the [Authenticated Composer documentation](https://docs.upsun.com/languages/php/composer-auth.md). ###### PHP settings Upsun provides additional configuration possibilities to control: - [PHP-FPM runtime configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#runtime) - [PHP settings](https://docs.upsun.com/languages/php.md#php-settings) ###### Enabling/disabling extensions PHP has a number of extensions developed by members of the community. Some of these extensions need to be enabled, while others are enabled by default and must be disabled if desirable. See which [PHP extensions](https://docs.upsun.com/languages/php/extensions.md) are available for your version of PHP. ###### Web servers While PHP-FPM is the default behavior, Upsun provides some support for different web servers by modifying the `web.commands.start` property: - [Alternate start commands](https://docs.upsun.com/languages/php.md#alternate-start-commands) - [Swoole](https://docs.upsun.com/languages/php/swoole.md) ###### Frameworks The Upsun documentation includes a wide array of community resources to help with framework-specific configuration: - [Laravel](https://docs.upsun.com/get-started/stacks/laravel.md) - [Symfony](https://docs.upsun.com/get-started/stacks/symfony.md) ###### Get support While there are virtually no restrictions to you deploying any kind of application on Upsun, configuration may still be unclear at this point. Not to worry! The Upsun community is here to help. Come and say hello, share your work, ask for help, and peek in on what others are working on. Welcome to the Upsun community! Join us on Discord Ask a question on the forum #### Python When dealing with Python stacks, the information below may help customize your configuration. These sections provide Python-specific configuration details, but you can also refer to the common Upsun documentation: - [Configuring applications](https://docs.upsun.com/create-apps.md) - [Setting up managed services](https://docs.upsun.com/add-services.md) - [Handling requests](https://docs.upsun.com/define-routes.md) ###### Managing dependencies Pip comes pre-installed in all `python` runtime containers. With it, you can add `pip install` to your build hook and be well on your way to building your apps. Alternatively, you can [use a different package manager](https://docs.upsun.com/languages/python/dependencies.md), such as Poetry or Pipvenv. ###### Configuring web servers Upsun doesn't enforce an assumption of what Python web server package you are using to serve your applications. You can use any server on Upsun by modifying the `web.commands.start` property of your application configuration. For more information, see how to [configure web servers](https://docs.upsun.com/languages/python/server.md). ###### Frameworks The Upsun documentation includes a wide array of community resources to help with framework-specific configuration: - [Django](https://docs.upsun.com/get-started/stacks/django.md) - [Flask](https://docs.upsun.com/get-started/stacks/flask.md) ###### Get support While there are virtually no restrictions to you deploying any kind of application on Upsun, configuration may still be unclear at this point. Not to worry! The Upsun community is here to help. Come and say hello, share your work, ask for help, and peek in on what others are working on. Welcome to the Upsun community! Join us on Discord Ask a question on the forum ### Set resources You can define how much CPU, memory, and disk you want to assign to each of your service and app containers. If you don't explicitly set resources, Upsun uses [default resources](https://docs.upsun.com/manage-resources/resource-init.md) instead. Upsun also offers several [resource initialization strategies](https://docs.upsun.com/manage-resources/resource-init.md) to help you allocate resources depending on your needs and use cases. However, for the sake of this guide, let's set resources manually. To do so, follow these steps: 1. Run the following command: ```bash {location="Terminal"} upsun resources:set ``` This launches an interactive prompt to walk you through setting up your application's resources: ```bash {location="Terminal"} upsun resources:set Resource configuration for the project app (123456azerty), environment main (type: production): +-----------------------+---------+---------+-------------+-----------+-----------+ | App or service | Size | CPU | Memory (MB) | Disk (MB) | Instances | +-----------------------+---------+---------+-------------+-----------+-----------+ | myapp | 1 | 1 | 384 | N/A | 1 | | []| 0.1 | 0.1 | 128 | N/A | 1 | +-----------------------+---------+---------+-------------+-----------+-----------+ ``` 2. Select the profile size you want applied to your application image. For instance, `0.1`: ```bash {location="Terminal"} App: myapp Choose a profile size: [0.1 ] CPU 0.1, memory 64 MB [0.25] CPU 0.25, memory 128 MB [0.5 ] CPU 0.5, memory 224 MB [1 ] CPU 1, memory 384 MB [2 ] CPU 2, memory 704 MB [4 ] CPU 4, memory 1216 MB [6 ] CPU 6, memory 1728 MB [8 ] CPU 8, memory 2240 MB [10 ] CPU 10, memory 2688 MB > 0.1 ``` 3. Define how many [instances](https://docs.upsun.com/manage-resources/adjust-resources.md#horizontal-scaling) of your application container you want to deploy. For instance, `1`: ```bash {location="Terminal"} Enter the number of instances (default: 1): 1 ``` 4. To confirm your choices, select `Y`. Upsun grabs the previous built images from earlier, applies your resource selections to them, and deploys your full application! **Note**: If the deployment fails, you may need to set the resources again. ### Make changes to your project Upsun allows you to make changes to your project and test them on a preview environment before introducing them to Production. In your project, the default branch (e.g. `main`, `master`, whichever chosen during project creation) always represents the production environment. Other branches are for developing new features, fixing bugs, or updating the infrastructure. To make changes to your project, follow these steps: ##### 1. Create a new environment Create a new environment (a Git branch) to make changes without impacting production: Run the following command: ```bash {location="Terminal"} upsun branch feat-a ``` This creates a new local `feat-a` Git branch based on the `main` Git branch and activates a related environment on Upsun. The new environment inherits the data (service data and assets) of its parent environment (the production environment here). ##### 2. Make changes to your project Depending on the stack you're using, change something within your source code. ##### 3. Commit your changes ```bash {location="Terminal"} git add index.js git commit -m "Update source code" ``` ##### 4. Deploy your changes Deploy your changes to the `feat-a` environment: ```bash {location="Terminal"} upsun push ``` Note that each environment has its own domain name. To open the URL of your new environment, run the following command: ```bash {location="Terminal"} upsun environment:url --primary ``` **Warnings**: If your environment is inactive, you need to [activate it](https://docs.upsun.com/environments/deactivate-environment.md#reactivate-an-environment) first, using the following command: ```bash {location="Terminal"} upsun environment:activate ``` ##### 5. Iterate Iterate by changing the code, committing, and deploying. When satisfied with your changes, merge them to the main branch, and remove the feature branch: ```bash {location="Terminal"} upsun merge Are you sure you want to merge feat-a into its parent, main? [Y/n] y upsun checkout main git pull upsun main upsun environment:delete feat-a git fetch --prune ``` **Note**: Deploying after a merge is fast because the image built for the feature environment is reused for the targeted environment. ##### 6. Keep your branch up to date For a long running development branch, to keep the code up-to-date with the `main` branch, use `git merge main` or `git rebase main`. You can also keep the data in sync with the parent environment by using [`upsun env:sync data`](https://docs.upsun.com/administration/cli/reference.md#environmentsynchronize). ### Local development A significant amount of work developing your app takes place locally rather than on an active Upsun environment. You want to ensure that the process of local development is as close as possible to a deployed environment. You can achieve this through the following approaches: - [Tethered local development](https://docs.upsun.com/get-started/here/local/tethered.md) - DDEV (coming soon!) Each of these approaches: - Creates a local development environment for your site. - Syncs data from the active Upsun environment where team review takes place. - Commits aspects of that local development method to the project so collaborators can replicate configuration to contribute. #### Tethered When you develop a project, a significant amount of work takes place locally rather than on an active Upsun environment. You want to ensure that the process of local development is as close as possible to a deployed environment. You can achieve this through various approaches. For example, you can use Symfony Server with tethered data. To do so, when testing changes locally, you can connect your locally running Symfony Server to service containers on an active Upsun environment. This methodology has several advantages: - It avoids installing anything on your local machine but your stack runtime. - It ensures that you are using the same versions of all services on your local machine and in production. **Warning**: Never use this method on the **main** environment as changes made on your local machine will impact production data. ###### 1. Start your local Server Use the official path to start your local server locally. ###### 2. Create the tethered connection 1. Create a new environment off of production: ```bash upsun branch new-feature main ``` 1. Open an SSH tunnel to the new environment's services: ```bash upsun tunnel:open ```` This command returns the addresses for SSH tunnels to all of your services that you can then use within your local source code: ```bash upsun tunnel:open SSH tunnel opened to rediscache at: redis://127.0.0.1:30000 SSH tunnel opened to database at: pgsql://main:main@127.0.0.1:30001/main Logs are written to: /Users/acmeUser/.upsun/tunnels.log List tunnels with: upsun tunnels View tunnel details with: upsun tunnel:info Close tunnels with: upsun tunnel:close Save encoded tunnel details to the PLATFORM_RELATIONSHIPS variable using: export PLATFORM_RELATIONSHIPS="$(upsun tunnel:info --encode)" ``` 1. When you've finished your work, close the tunnels to your services by running the following command: ```bash upsun tunnel:close --all -y ``` ### Third party integrations In this guide, you've configured and deployed a local copy of your codebase to Upsun. You can continue to work, but the primary remote your team would share would be Upsun itself. It's more likely that your codebase is on a third party Git service like GitHub, GitLab, or Bitbucket. Now that you've learned the basics of Upsun configuration and deployment, you can create new projects within the management console, by choosing the **Connect repository** option to set up a GitHub application. At this stage, if you want to make another remote (i.e. `origin`) the primary remote, and Upsun a deployment mirror, you can override your current configuration by setting up an integration: - [BitBucket](https://docs.upsun.com/integrations/source/bitbucket.md) - [GitHub](https://docs.upsun.com/integrations/source/github.md) - [GitLab](https://docs.upsun.com/integrations/source/gitlab.md) Once the integration is added, all commits on the service are mirrored, built, and deployed on Upsun. ### Get support There are virtually no restrictions to you deploying any kind of application on Upsun, and we're excited to hear about your experiments! Follow the links below to share your work, ask the community for help, and peek in on what others are working on. Welcome to the Upsun community! Join us on Discord Ask a question on the forum ### Deploy Express on Platform.sh **Note**: Before you start, check out the [Upsun demo app](https://console.upsun.com/projects/create-project) and the main [Getting started guide](https://docs.upsun.com/get-started/here.md). They provide all of the core concepts and common commands you need to know before using the materials below. ##### Before you begin You need: - [Git](https://git-scm.com/downloads). Git is the primary tool to manage everything your app needs to run. Push commits to deploy changes and control configuration through YAML files. These files describe your infrastructure, making it transparent and version-controlled. - A Upsun account. If you don't already have one, [register for a trial account](https://auth.upsun.com/register). You can sign up with an email address or an existing GitHub, Bitbucket, or Google account. If you choose one of these accounts, you can set a password for your Upsun account later. - The [Upsun CLI](https://docs.upsun.com/administration/cli.md). This lets you interact with your project from the command line. You can also do most things through the [Web Console](https://docs.upsun.com/administration/web.md). ##### 1. Create an Express app To create your Express app, follow these steps. 1. Follow the Express [installation guide](https://expressjs.com/en/starter/installing.md). To fast track the process, run the following commands: ```bash {location="Terminal"} mkdir my-express-app && cd my-express-app npx express-generator ``` 2. To initialize the local Git repository and commit local files, run the following commands: ```bash {location="Terminal"} git init echo "node_modules" >> .gitignore git add . git commit -m "Init Express application." ``` **Note**: You can view your running app locally by installing dependencies (``npm install``) and running ``npm run dev``. The local server is visible at ``localhost:3000``. ##### 2. Create a new project To create a project on Upsun, follow these steps. **Remember**: After creating your Upsun project, copy your new **project ID** for later use. **Note**: When creating a new project using the Upsun CLI command ``project:create``, you are asked if you want to set the local remote to your new project. Enter **Yes (y)**. Your local source code is automatically linked to your newly created Upsun project through the creation of a ``.upsun/local/project.yaml``. This file contains the corresponding ```` for the Upsun CLI to use, and sets a Git remote to ``upsun``. - Create an organization or select an existing one. - Click **Create from scratch**. - Fill in details like the project name and [region](https://docs.upsun.com/development/regions.md). **Note**: You can define resources for your project later on, after your first push. - To link your local source code to your new Upsun project, run the following command: ```bash {location="Terminal"} upsun project:set-remote ``` This command adds a new remote called ``upsun`` to your local Git repository, which is equivalent to the following commands: ```bash {location="Terminal"} git remote origin upsun ``` It also creates a new ``.upsun/local/project.yaml`` file that contains the ```` for the ``upsun`` CLI to use. **Tip**: If you forget your ````, run the following command and find your project in the list: ```bash {location="Terminal"} upsun project:list ``` ##### 3. Choose your Git workflow You can use Upsun projects as a classic Git repository, where you are able to push your source code in different ways, using either the Git CLI or the Upsun CLI. You can choose which way —or Git workflow— you want to use for your project from the following options: - Your project source code is **hosted on a Upsun Git repository** - Your project source code is **hosted on your own GitHub repository** Upsun provides a [Github integration](https://docs.upsun.com/integrations/source/github.md) that allows your Upsun project to be fully integrated with your Github repository. This enables you, as a developer, to use a normal Git workflow (``git add . && git commit -m "message" && git push``) to deploy your environment—with no need to connect to the Upsun Console. **Note**: Make sure you complete the following steps before adding a [Github integration](https://docs.upsun.com/integrations/source/github.md): - Create a Git repository in your own organization following the relevant [Github repository creation guide](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-new-repository). - Create a [Github integration](https://docs.upsun.com/integrations/source/github.md). - Add a Git remote to your local project, from the root of your Express directory. To do so, run the following commands: ```bash {location="Terminal"} git remote add origin git add . && git commit -m "init express" git push origin ``` ##### 4. Configure your project To host your Express application on Upsun, you need to have a few YAML configuration files at the root of your project. These files manage your app's behavior. They are located in a `.upsun/` folder at the root of your source code and structured in a similar way to this: ```txt my-express-app ├── .upsun │ └── config.yaml ├── [.environment] └── ``` To generate these files, run the following command at the root of your project: ``` {location="Terminal"} upsun project:init ``` Follow the prompts. To commit your new files, run the following commands: ```bash {location="Terminal"} git add . git commit -m "Add Upsun config files" ``` ##### 5. Deploy And just like that, it’s time to deploy! Depending on the Git workflow you chose at the beginning of this tutorial, there are two ways to deploy your source code changes. When you choose to use a third-party Git hosting service, the Upsun Git repository becomes a read-only mirror of the third-party repository. All your changes take place in the third-party repository. Add an integration to your existing third-party repository: - [BitBucket](https://docs.upsun.com/integrations/source/bitbucket.md) - [GitHub](https://docs.upsun.com/integrations/source/github.md) - [GitLab](https://docs.upsun.com/integrations/source/gitlab.md) If you are using an integration, on each code updates, use the normal Git workflow (``git add . && git commit -m "message" && git push``) to push your code to your external repository. To do so, run the following command: ```bash {location="Terminal"} git push origin ``` Your GitHub, GitLab, or Bibucket integration process then automatically deploys changes to your environment. If you’re pushing a new Git branch, a new environment is created. Upsun then reads your configuration files, and deploys your project using [default container resources](https://docs.upsun.com/manage-resources/resource-init.md). If you don't want to use those default resources, define your own [resource initialization strategy](https://docs.upsun.com/manage-resources/resource-init.md#specify-a-resource-initialization-strategy), or [amend those default container resources](https://docs.upsun.com/manage-resources/adjust-resources.md) after your project is deployed. Et voilà, your Express application is live! **Tip**: Each environment has its own domain name. To open the URL of your new environment, run the following command: ```bash {location="Terminal"} upsun environment:url --primary ``` ##### 6. Make changes to your project Now that your project is deployed, you can start making changes to it. For example, you might want to fix a bug or add a new feature. In your project, the `main` branch always represents the production environment. Other branches are for developing new features, fixing bugs, or updating the infrastructure. To make changes to your project, follow these steps: 1. Create a new environment (a Git branch) to make changes without impacting production: ```bash {location="Terminal"} upsun branch feat-a ``` This command creates a new local `feat-a` Git branch based on the main Git branch, and activates a related environment on Upsun. The new environment inherits the data (service data and assets) of its parent environment (the production environment here). 2. Make changes to your project. For example, edit the `views/index.jade` file and make the following changes: ```diff diff --git a/views/index.jade b/views/index.jade index 3d63b9a..77aee43 100644 --- a/views/index.jade +++ b/views/index.jade @@ -2,4 +2,4 @@ extends layout block content h1= title - p Welcome to #{title} + p Welcome to #{title} on Upsun `` 3. Commit your changes: ```bash {location="Terminal"} git add views/index.jade git commit -m "Update index page view." ``` 4. Deploy your changes to the `feat-a` environment: ```bash {location="Terminal"} upsun push ``` 5. Iterate by changing the code, committing, and deploying. When satisfied with your changes, merge them to the main branch, and remove the feature branch: ```bash {location="Terminal"} upsun merge Are you sure you want to merge feat-a into its parent, main? [Y/n] y upsun checkout main git pull upsun main upsun environment:delete feat-a git fetch --prune ``` Note that deploying to production is fast because the image built for the `feat-a` environment is reused. For a long running branch, to keep the code up-to-date with the main branch, use `git merge main` or `git rebase main`. You can also keep the data in sync with the production environment by using `upsun env:sync`. ##### Further resources ###### Documentation - [JavaScript/Node.js documentation](https://docs.upsun.com/languages/nodejs.md) - [Managing dependencies](https://docs.upsun.com/languages/nodejs.md#dependencies) - [Add a database to Express](https://docs.upsun.com/get-started/stacks/express/add-database.md) ###### Community content - [ExpressJS topics](https://support.platform.sh/hc/en-us/search?utf8=%E2%9C%93&query=express) - [Node.js topics](https://support.platform.sh/hc/en-us/search?utf8=%E2%9C%93&query=node) - [JavaScript topics](https://support.platform.sh/hc/en-us/search?utf8=%E2%9C%93&query=js) ###### Blogs - [A quick-start guide on hosting Express on Upsun](https://upsun.com/blog/setting-up-express-on-upsun/) #### Add a database to Express Once your Express app has been deployed on Upsun, you might want to add a service to it. Upsun projects already include a [variety of managed services](https://docs.upsun.com/add-services.md#available-services), so you don’t have to subscribe to an external cache or search-engine services. As these services are included in your project, you can manage them through Git. They’re backed up along with the rest of your project. You can add new services and manage existing service configurations from your `.upsun/config.yaml` file. For example, to add a [MariaDB database engine](https://docs.upsun.com/add-services/mysql.md) to your Express project, complete the following steps: ###### 1. Create a new branch for testing To create a new branch, run the following command: ```bash {location="Terminal"} upsun environment:branch add-mysql-database ``` ###### 2. Add a MariaDB service Configure the MariaDB service by adding a `database` service to your `.upsun/config.yaml` file: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: "nodejs:20" [...] services: database: type: mariadb:11.4 ``` To connect the service to your application (``myapp``), add the following relationship: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: "nodejs:20" [...] relationships: database: services: database: type: mariadb:11.4 ``` Commit your change: ```bash {location="Terminal"} git commit -am "adding MariaDb database service" upsun push ``` Upsun now reads your configuration files and deploys your project using [default container resources](https://docs.upsun.com/manage-resources/resource-init.md). If you don't want to use those default resources, define your own [resource initialization strategy](https://docs.upsun.com/manage-resources/resource-init.md#specify-a-resource-initialization-strategy), or [amend those default container resources](https://docs.upsun.com/manage-resources/adjust-resources.md) after your project is deployed. ###### 3. Connect to the service To configure your Express app so it uses your new database, you need a Node.s module named `mysql2`. To install it, run the following command: ```bash {location="Terminal"} npm install mysql2 ``` Wherever your application code attemps to connect to the database service, Upsun will automatically generate environment variables containing connection credentials as a function of the relationship name. In this example, the MariaDB service access is granted to the application container via the relationship `database`. Upsun will therefore generate the variable `DATABASE_HOST` (among many others), using this name. Here's an example of how this credential variable naming convention is used to connect to a MariaDB service: ```javascript {location="index.js"} const express = require('express') const app = express() const mysql = require("mysql2/promise"); const port = (process.env.PORT || '3000'); function openConnection() { return mysql.createConnection({ host: process.env.DATABASE_HOST, port: process.env.DATABASE_PORT, user: process.env.DATABASE_USERNAME, password: process.env.DATABASE_PASSWORD, database: process.env.DATABASE_DATABASE }); } function createTable(connection) { return connection.execute( `CREATE TABLE IF NOT EXISTS upsuninfo ( uid INT(10) NOT NULL AUTO_INCREMENT, username VARCHAR(64) NULL DEFAULT NULL, departname VARCHAR(128) NULL DEFAULT NULL, created DATE NULL DEFAULT NULL, PRIMARY KEY (uid) ) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;` ); } function insertData(connection) { return connection.execute( "INSERT INTO upsuninfo (username, departname, created) VALUES ('upsun', 'Deploy Friday', '2023-09-29')" ); } function readData(connection) { return connection.query("SELECT * FROM upsuninfo"); } function dropTable(connection) { return connection.execute("DROP TABLE upsuninfo"); } // Define the main route. app.get('/', async function(req, res){ // Connect to MariaDB. const connection = await openConnection(); await createTable(connection); await insertData(connection); const [rows] = await readData(connection); const droppedResult = await dropTable(connection); // Make the output. const outputString = `Hello, World! - A simple Express web framework template for Upsun MariaDB Tests: * Connect and add row: - Row ID (1): ${rows[0].uid} - Username (upsun): ${rows[0].username} - Department (Deploy Friday): ${rows[0].departname} - Created (2023-09-29): ${rows[0].created} * Delete row: - Status (0): ${droppedResult[0].warningStatus}`; res.set('Content-Type', 'text/plain'); res.send(outputString); }); // Get PORT and start the server app.listen(port, function() { console.log(`Listening on port ${port}`) }); ``` Commit and deploy your changes: ```bash {location="Terminal"} git add package.json package-lock.json index.js && git commit -m "adding MariaDb database service" upsun push upsun environment:url --primary ``` ###### 4. Merge to production When satisfied with your changes, merge them to the main branch: ```bash {location="Terminal"} upsun merge ``` **Note**: You can [adjust your project resources](https://docs.upsun.com/manage-resources/adjust-resources.md) at any time. ###### 5. Remove the feature branch Then, remove the feature branch: ```bash {location="Terminal"} upsun checkout main git pull upsun main upsun environment:delete add-mysql-database git fetch --prune ``` **Note**: When the ``environment:delete`` CLI command is run, the CLI suggests you deactivate and delete your ``add-mysql-database`` environment. Make sure you opt in. ###### Tips & Tricks You can get your project's relationship information using the following command: ```bash {location="Terminal"} upsun relationships ... database: - username: user scheme: mysql service: mariadb fragment: null ip: 198.12.123.45 hostname: abcdefghijklm1234567890123.mariadb.service._..platformsh.site public: false cluster: abcdefgh1234567-add-mysql-database-abcd123 host: mariadb.internal rel: mysql query: is_master: true path: main password: '' type: 'mariadb:10.6' port: 3306 host_mapped: false url: 'mysql://user:@mariadb.internal:3306/main' ``` ### Deploy Next.js on Platform.sh **Note**: Before you start, check out the [Upsun demo app](https://console.upsun.com/projects/create-project) and the main [Getting started guide](https://docs.upsun.com/get-started/here.md). They provide all of the core concepts and common commands you need to know before using the materials below. ##### Before you begin You need: - [Git](https://git-scm.com/downloads). Git is the primary tool to manage everything your app needs to run. Push commits to deploy changes and control configuration through YAML files. These files describe your infrastructure, making it transparent and version-controlled. - A Upsun account. If you don't already have one, [register for a trial account](https://auth.upsun.com/register). You can sign up with an email address or an existing GitHub, Bitbucket, or Google account. If you choose one of these accounts, you can set a password for your Upsun account later. - The [Upsun CLI](https://docs.upsun.com/administration/cli.md). This lets you interact with your project from the command line. You can also do most things through the [Web Console](https://docs.upsun.com/administration/web.md). ##### 1. Create a Next.js app To create your Next.js app, follow these steps. 1. Follow the Next.js [installation guide](https://nextjs.org/docs/getting-started/installation). To fast track the process, run the following commands: ```bash {location="Terminal"} npx create-next-app@latest myapp ``` 2. To initialize the local Git repository and commit local files, run the following commands: ```bash {location="Terminal"} cd myapp git init git add . git commit -m "Init Next.js application." ``` **Note**: You can view the running app locally by running ``npm run dev``. ##### 2. Create a new project To create a project on Upsun, follow these steps. **Remember**: After creating your Upsun project, copy your new **project ID** for later use. **Note**: When creating a new project using the Upsun CLI command ``project:create``, you are asked if you want to set the local remote to your new project. Enter **Yes (y)**. Your local source code is automatically linked to your newly created Upsun project through the creation of a ``.upsun/local/project.yaml``. This file contains the corresponding ```` for the Upsun CLI to use, and sets a Git remote to ``upsun``. - Create an organization or select an existing one. - Click **Create from scratch**. - Fill in details like the project name and [region](https://docs.upsun.com/development/regions.md). **Note**: You can define resources for your project later on, after your first push. - To link your local source code to your new Upsun project, run the following command: ```bash {location="Terminal"} upsun project:set-remote ``` This command adds a new remote called ``upsun`` to your local Git repository, which is equivalent to the following commands: ```bash {location="Terminal"} git remote origin upsun ``` It also creates a new ``.upsun/local/project.yaml`` file that contains the ```` for the ``upsun`` CLI to use. **Tip**: If you forget your ````, run the following command and find your project in the list: ```bash {location="Terminal"} upsun project:list ``` ##### 3. Choose your Git workflow You can use Upsun projects as a classic Git repository, where you are able to push your source code in different ways, using either the Git CLI or the Upsun CLI. You can choose which way —or Git workflow— you want to use for your project from the following options: - Your project source code is **hosted on a Upsun Git repository** - Your project source code is **hosted on your own GitHub repository** Upsun provides a [Github integration](https://docs.upsun.com/integrations/source/github.md) that allows your Upsun project to be fully integrated with your Github repository. This enables you, as a developer, to use a normal Git workflow (``git add . && git commit -m "message" && git push``) to deploy your environment—with no need to connect to the Upsun Console. **Note**: Make sure you complete the following steps before adding a [Github integration](https://docs.upsun.com/integrations/source/github.md): - Create a Git repository in your own organization following the relevant [Github repository creation guide](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-new-repository). - Create a [Github integration](https://docs.upsun.com/integrations/source/github.md). - Add a Git remote to your local project, from the root of your Next.js directory. To do so, run the following commands: ```bash {location="Terminal"} git remote add origin git add . && git commit -m "init next.js" git push origin ``` ##### 4. Configure your project To host your Next.js application on Upsun, you need to have a few YAML configuration files at the root of your project. These files manage your app's behavior. They are located in a `.upsun/` folder at the root of your source code and structured in a similar way to this: ```txt myapp ├── .upsun │ └── config.yaml ├── [.environment] └── ``` To generate these files, run the following command at the root of your project: ``` {location="Terminal"} upsun project:init ``` Follow the prompts, and you should result in such a config file. ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: "nodejs:22" mounts: "/.npm": source: "storage" source_path: "npm" hooks: build: | set -eux npm i npm run build web: commands: start: "npx next start -p $PORT" upstream: socket_family: tcp locations: "/": passthru: true routes: "https://{default}/": { type: upstream, upstream: "myapp:http" } "http://{default}/": { type: redirect, to: "https://{default}/" } ``` As an example, above is the minimum configuration needed to deploy a Next.js application on Upsun without any services. Depending on your answers to the prompts, you may also have `relationships` and `services` defined. To commit your new files, run the following commands: ```bash {location="Terminal"} git add . git commit -m "Add Upsun config files" ``` ##### 5. Deploy And just like that, it’s time to deploy! Depending on the Git workflow you chose at the beginning of this tutorial, there are two ways to deploy your source code changes. When you choose to use a third-party Git hosting service, the Upsun Git repository becomes a read-only mirror of the third-party repository. All your changes take place in the third-party repository. Add an integration to your existing third-party repository: - [BitBucket](https://docs.upsun.com/integrations/source/bitbucket.md) - [GitHub](https://docs.upsun.com/integrations/source/github.md) - [GitLab](https://docs.upsun.com/integrations/source/gitlab.md) If you are using an integration, on each code updates, use the normal Git workflow (``git add . && git commit -m "message" && git push``) to push your code to your external repository. To do so, run the following command: ```bash {location="Terminal"} git push origin ``` Your GitHub, GitLab, or Bibucket integration process then automatically deploys changes to your environment. If you’re pushing a new Git branch, a new environment is created. Upsun then reads your configuration files, and deploys your project using [default container resources](https://docs.upsun.com/manage-resources/resource-init.md). If you don't want to use those default resources, define your own [resource initialization strategy](https://docs.upsun.com/manage-resources/resource-init.md#specify-a-resource-initialization-strategy), or [amend those default container resources](https://docs.upsun.com/manage-resources/adjust-resources.md) after your project is deployed. Et voilà, your Next.js application is live! **Tip**: Each environment has its own domain name. To open the URL of your new environment, run the following command: ```bash {location="Terminal"} upsun environment:url --primary ``` ##### 6. Make changes to your project Now that your project is deployed, you can start making changes to it. For example, you might want to fix a bug or add a new feature. In your project, the `main` branch always represents the production environment. Other branches are for developing new features, fixing bugs, or updating the infrastructure. To make changes to your project, follow these steps: 1. Create a new environment (a Git branch) to make changes without impacting production: ```bash {location="Terminal"} upsun branch feat-a ``` This command creates a new local `feat-a` Git branch based on the main Git branch, and activates a related environment on Upsun. The new environment inherits the data (service data and assets) of its parent environment (the production environment here). 2. Make changes to your project. For example, edit the `views/index.jade` file and make the following changes: ```diff diff --git a/views/index.jade b/views/index.jade index 3d63b9a..77aee43 100644 --- a/views/index.jade +++ b/views/index.jade @@ -2,4 +2,4 @@ extends layout block content h1= title - p Welcome to #{title} + p Welcome to #{title} on Upsun `` 3. Commit your changes: ```bash {location="Terminal"} git add views/index.jade git commit -m "Update index page view." ``` 4. Deploy your changes to the `feat-a` environment: ```bash {location="Terminal"} upsun push ``` 5. Iterate by changing the code, committing, and deploying. When satisfied with your changes, merge them to the main branch, and remove the feature branch: ```bash {location="Terminal"} upsun merge Are you sure you want to merge feat-a into its parent, main? [Y/n] y upsun checkout main git pull upsun main upsun environment:delete feat-a git fetch --prune ``` Note that deploying to production is fast because the image built for the `feat-a` environment is reused. For a long running branch, to keep the code up-to-date with the main branch, use `git merge main` or `git rebase main`. You can also keep the data in sync with the production environment by using `upsun env:sync`. ##### Further resources ###### Documentation - [JavaScript/Node.js documentation](https://docs.upsun.com/languages/nodejs.md) - [Managing dependencies](https://docs.upsun.com/languages/nodejs.md#dependencies) ###### Community content - [Next.js topics](https://support.platform.sh/hc/en-us/search?utf8=%E2%9C%93&query=nextjs) - [Node.js topics](https://support.platform.sh/hc/en-us/search?utf8=%E2%9C%93&query=node) - [JavaScript topics](https://support.platform.sh/hc/en-us/search?utf8=%E2%9C%93&query=js) ###### Blogs - [A quick-start guide on hosting Next.js on Upsun](https://upsun.com/blog/setting-up-next-js-on-upsun/) ### Deploy Strapi on Platform.sh **Note**: Before you start, check out the [Upsun demo app](https://console.upsun.com/projects/create-project) and the main [Getting started guide](https://docs.upsun.com/get-started/here.md). They provide all of the core concepts and common commands you need to know before using the materials below. ##### Before you begin You need: - [Git](https://git-scm.com/downloads). Git is the primary tool to manage everything your app needs to run. Push commits to deploy changes and control configuration through YAML files. These files describe your infrastructure, making it transparent and version-controlled. - A Upsun account. If you don't already have one, [register for a trial account](https://auth.upsun.com/register). You can sign up with an email address or an existing GitHub, Bitbucket, or Google account. If you choose one of these accounts, you can set a password for your Upsun account later. - The [Upsun CLI](https://docs.upsun.com/administration/cli.md). This lets you interact with your project from the command line. You can also do most things through the [Web Console](https://docs.upsun.com/administration/web.md). ##### 1. Create a Strapi project To create your Strapi app, follow these steps. 1. Follow the Strapi [installation guide](https://docs.strapi.io/dev-docs/installation). To fast track the process, run the following commands: ```bash {location="Terminal"} npx create-strapi-app@latest my-strapi-project --quickstart --no-run ``` **Note**: If the ``create-strapi-app`` script fails, run ``export SHARP_IGNORE_GLOBAL_LIBVIPS=true``, remove the previous attempt (``rm -rf my-strapi-project``), and run the command again. 2. To initialize the local Git repository and commit local files, run the following commands: ```bash {location="Terminal"} cd my-strapi-project echo "\nhttp:" >> .gitignore git add . git commit -m "Init Strapi application." ``` **Note**: You can view the running app locally by running ``yarn develop``. The local server will be visible at ``localhost:1337``. You can create your first administrator user locally, but you will have to recreate that user once you’ve deployed to Upsun. ##### 2. Create a new project To create a project on Upsun, follow these steps. **Remember**: After creating your Upsun project, copy your new **project ID** for later use. **Note**: When creating a new project using the Upsun CLI command ``project:create``, you are asked if you want to set the local remote to your new project. Enter **Yes (y)**. Your local source code is automatically linked to your newly created Upsun project through the creation of a ``.upsun/local/project.yaml``. This file contains the corresponding ```` for the Upsun CLI to use, and sets a Git remote to ``upsun``. - Create an organization or select an existing one. - Click **Create from scratch**. - Fill in details like the project name and [region](https://docs.upsun.com/development/regions.md). **Note**: You can define resources for your project later on, after your first push. - To link your local source code to your new Upsun project, run the following command: ```bash {location="Terminal"} upsun project:set-remote ``` This command adds a new remote called ``upsun`` to your local Git repository, which is equivalent to the following commands: ```bash {location="Terminal"} git remote origin upsun ``` It also creates a new ``.upsun/local/project.yaml`` file that contains the ```` for the ``upsun`` CLI to use. **Tip**: If you forget your ````, run the following command and find your project in the list: ```bash {location="Terminal"} upsun project:list ``` ##### 3. Choose your Git workflow You can use Upsun projects as a classic Git repository, where you are able to push your source code in different ways, using either the Git CLI or the Upsun CLI. You can choose which way —or Git workflow— you want to use for your project from the following options: - Your project source code is **hosted on a Upsun Git repository** - Your project source code is **hosted on your own GitHub repository** Upsun provides a [Github integration](https://docs.upsun.com/integrations/source/github.md) that allows your Upsun project to be fully integrated with your Github repository. This enables you, as a developer, to use a normal Git workflow (``git add . && git commit -m "message" && git push``) to deploy your environment—with no need to connect to the Upsun Console. **Note**: Make sure you complete the following steps before adding a [Github integration](https://docs.upsun.com/integrations/source/github.md): - Create a Git repository in your own organization following the relevant [Github repository creation guide](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-new-repository). - Create a [Github integration](https://docs.upsun.com/integrations/source/github.md). - Add a Git remote to your local project, from the root of your Strapi directory. To do so, run the following commands: ```bash {location="Terminal"} git remote add origin git add . && git commit -m "init strapi" git push origin ``` ##### 4. Configure your project To host your Strapi application on Upsun, you need to have a few YAML configuration files at the root of your project. These files manage your app's behavior. They are located in a `.upsun/` folder at the root of your source code and structured in a similar way to this: ```txt my-strapi-project ├── .upsun │ └── config.yaml ├── [.environment] └── ``` To generate these files, run the following command at the root of your project: ``` {location="Terminal"} upsun project:init ``` Follow the prompts. To commit your new files, run the following commands: ```bash {location="Terminal"} git add . git commit -m "Add Upsun config files" ``` ##### 5. Deploy And just like that, it’s time to deploy! Depending on the Git workflow you chose at the beginning of this tutorial, there are two ways to deploy your source code changes. When you choose to use a third-party Git hosting service, the Upsun Git repository becomes a read-only mirror of the third-party repository. All your changes take place in the third-party repository. Add an integration to your existing third-party repository: - [BitBucket](https://docs.upsun.com/integrations/source/bitbucket.md) - [GitHub](https://docs.upsun.com/integrations/source/github.md) - [GitLab](https://docs.upsun.com/integrations/source/gitlab.md) If you are using an integration, on each code updates, use the normal Git workflow (``git add . && git commit -m "message" && git push``) to push your code to your external repository. To do so, run the following command: ```bash {location="Terminal"} git push origin ``` Your GitHub, GitLab, or Bibucket integration process then automatically deploys changes to your environment. If you’re pushing a new Git branch, a new environment is created. Upsun then reads your configuration files, and deploys your project using [default container resources](https://docs.upsun.com/manage-resources/resource-init.md). If you don't want to use those default resources, define your own [resource initialization strategy](https://docs.upsun.com/manage-resources/resource-init.md#specify-a-resource-initialization-strategy), or [amend those default container resources](https://docs.upsun.com/manage-resources/adjust-resources.md) after your project is deployed. Et voilà, your Strapi application is live! **Tip**: Each environment has its own domain name. To open the URL of your new environment, run the following command: ```bash {location="Terminal"} upsun environment:url --primary ``` ##### 6. Make changes to your project Now that your project is deployed, you can start making changes to it. For example, you might want to fix a bug or add a new feature. In your project, the `main` branch always represents the production environment. Other branches are for developing new features, fixing bugs, or updating the infrastructure. To make changes to your project, follow these steps: 1. Create a new environment (a Git branch) to make changes without impacting production: ```bash {location="Terminal"} upsun branch feat-a ``` This command creates a new local `feat-a` Git branch based on the main Git branch, and activates a related environment on Upsun. The new environment inherits the data (service data and assets) of its parent environment (the production environment here). 2. Make changes to your project. For example, you can create a new API and Collection (Content Type). To do so, run the following command: ```bash {location="Terminal"} npm run strapi -- generate content-type ``` Then follow the prompts to set up the `Blog` API containing an `Article` Content Type (Collection): ```bash {location="Suggested responses"} ? Content type display name Article ? Content type singular name article ? Content type plural name articles ? Please choose the model type Collection Type ? Use draft and publish? Yes ? Do you want to add attributes? Yes ? Name of attribute title ? What type of attribute string ? Do you want to add another attribute? Yes ? Name of attribute body ? What type of attribute richtext ? Do you want to add another attribute? Yes ? Name of attribute image ? What type of attribute media ? Choose media type Single ? Do you want to add another attribute? No ? Where do you want to add this model? Add model to new API ? Name of the new API? blog ? Bootstrap API related files? Yes ✔ ++ /api/blog/content-types/article/schema.json ✔ +- /api/blog/content-types/article/schema.json ✔ ++ /api/blog/controllers/article.js ✔ ++ /api/blog/services/article.js ✔ ++ /api/blog/routes/article.js ``` Verify that the new `Article` collection has been created. To do so, run the local server (`yarn develop`) again, and visit [http://localhost:1337/admin/content-manager](http://localhost:1337/admin/content-manager). This results in the following changes: ```bash $ git status On branch feat-a Changes not staged for commit: (use "git add ..." to update what will be committed) (use "git restore ..." to discard changes in working directory) modified: types/generated/contentTypes.d.ts Untracked files: (use "git add ..." to include in what will be committed) src/api/blog/ no changes added to commit (use "git add" and/or "git commit -a") ``` 3. Commit your changes: ```bash {location="Terminal"} git add . git commit -m "Add Article collection" ``` 4. Deploy your changes to the `feat-a` environment: ```bash {location="Terminal"} upsun push ``` **Tip**: Note that each environment has its own domain name. To open the URL of your new environment, run the following command: ```bash {location="Terminal"} upsun environment:url --primary ``` 5. Iterate by changing the code, committing, and deploying. When satisfied with your changes, merge them to the main branch, and remove the feature branch: ```bash {location="Terminal"} upsun merge Are you sure you want to merge feat-a into its parent, main? [Y/n] y upsun checkout main git pull upsun main upsun environment:delete feat-a git fetch --prune ``` Note that deploying to production is fast because the image built for the `feat-a` environment is reused. For a long running branch, to keep the code up-to-date with the main branch, use `git merge main` or `git rebase main`. You can also keep the data in sync with the production environment by using `upsun env:sync`. ##### Further resources ###### Documentation - [JavaScript/Node.js documentation](https://docs.upsun.com/languages/nodejs.md) - [Managing dependencies](https://docs.upsun.com/languages/nodejs.md#dependencies) - [Add a database to Strapi](https://docs.upsun.com/get-started/stacks/strapi/add-database.md) ###### Community content - [Strapi topics](https://support.platform.sh/hc/en-us/search?utf8=%E2%9C%93&query=strapi) - [Node.js topics](https://support.platform.sh/hc/en-us/search?utf8=%E2%9C%93&query=node) - [JavaScript topics](https://support.platform.sh/hc/en-us/search?utf8=%E2%9C%93&query=js) ###### Blogs - [Up(sun) and running with Strapi: a seamless journey to a powerful decoupled headless CMS](https://upsun.com/blog/strapi-deployment-on-upsun/) #### Add a database to Strapi Once Your Strapi application has been deployed on Upsun, you might want to add and configure a service to your application. This guide will show you how to provision and connect to two different databases on Upsun: - PostgreSQL - Oracle MySQL ###### 1. Branch Like all updates to your Upsun projects, first create a new dedicated environment to test this change. ```bash git checkout -b upgrade-db ``` ###### 2. Install the Node.js package ```bash {} yarn add mysql ``` ###### 3. Add a new service Add a new service to your `.upsun/config.yaml` file: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: "nodejs:20" [...] services: database: type: oracle-mysql:8.0 ``` ###### 4. Add a new relationship Add a new relationship to your `.upsun/config.yaml` file to allow access to the new service ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: "nodejs:20" [...] relationships: database: services: database: type: oracle-mysql:8.0 ``` ###### 5. Update `.environment` When you previously ran `upsun project:init`, the command generated some Strapi-specific environment variables: ```bash {location=".environment"} # Set Strapi-specific environment variables export DATABASE_HOST="$DB_HOST" export DATABASE_PORT="$DB_PORT" export DATABASE_NAME="$DB_PATH" export DATABASE_USERNAME="$DB_USERNAME" export DATABASE_PASSWORD="$DB_PASSWORD" export DATABASE_SCHEME="$DB_SCHEME" # Set secrets needed by Strapi, if they are not set # Prefer setting these as project secret variables with upsun variable:create env:SECRET_NAME --sensitive=true if [[ -z "$ADMIN_JWT_SECRET" ]]; then export ADMIN_JWT_SECRET="$PLATFORM_PROJECT_ENTROPY" fi if [[ -z "$JWT_SECRET" ]]; then export JWT_SECRET="$PLATFORM_PROJECT_ENTROPY" fi if [[ -z "$API_TOKEN_SALT" ]]; then export API_TOKEN_SALT="$PLATFORM_PROJECT_ENTROPY" fi if [[ -z "$APP_KEYS" ]]; then export APP_KEYS="$PLATFORM_PROJECT_ENTROPY" fi ``` Upsun will actually generate service credentials automatically for you in the runtime container, so we don't need the first half of this file anymore. Remove the first block (pertaining to `DATABASE` credentials). Then, add a single additional variable that will set the `DATABASE_CLIENT` variable at the appropriate time: ```bash {location=".environment"} # Set secrets needed by Strapi, if they are not set # Prefer setting these as project secret variables with upsun variable:create env:SECRET_NAME --sensitive=true if [[ -z "$ADMIN_JWT_SECRET" ]]; then export ADMIN_JWT_SECRET="$PLATFORM_PROJECT_ENTROPY" fi if [[ -z "$JWT_SECRET" ]]; then export JWT_SECRET="$PLATFORM_PROJECT_ENTROPY" fi if [[ -z "$API_TOKEN_SALT" ]]; then export API_TOKEN_SALT="$PLATFORM_PROJECT_ENTROPY" fi if [[ -z "$APP_KEYS" ]]; then export APP_KEYS="$PLATFORM_PROJECT_ENTROPY" fi # Switch to configure to the production database service _only_ at deploy time. if [[ -z "$PLATFORM_ENVIRONMENT" ]]; then export DATABASE_CLIENT="mysql" fi ``` ###### 6. Push to the environment Commit and push the changes to the Upsun environment: ```bash git commit -am "Add a new service" git push origin upgrade-db ``` **Note**: If you are using Upsun as your primary remote, you can use the ``upsun branch`` and ``upsun push`` commands directly. If instead you had already set up an integration to GitHub, GitLab or Bitbucket, make sure to open a pull/merge request to judge the revision. ### Deploy Django on Platform.sh **Note**: Before you start, check out the [Upsun demo app](https://console.upsun.com/projects/create-project) and the main [Getting started guide](https://docs.upsun.com/get-started/here.md). They provide all of the core concepts and common commands you need to know before using the materials below. For Django to successfully deploy and operate, **after completing the [Getting started guide](https://docs.upsun.com/get-started/here.md)**, you still need to make a few changes to your Upsun configuration. ##### Before you begin You need: - [Git](https://git-scm.com/downloads). Git is the primary tool to manage everything your app needs to run. Push commits to deploy changes and control configuration through YAML files. These files describe your infrastructure, making it transparent and version-controlled. - A Upsun account. If you don't already have one, [register for a trial account](https://auth.upsun.com/register). You can sign up with an email address or an existing GitHub, Bitbucket, or Google account. If you choose one of these accounts, you can set a password for your Upsun account later. - The [Upsun CLI](https://docs.upsun.com/administration/cli.md). This lets you interact with your project from the command line. You can also do most things through the [Web Console](https://docs.upsun.com/administration/web.md). ##### 1. Leverage environment variables Your `settings.py` file may allow for environment variables to be set for common pieces of configuration. In this case, add and commit a `.environment` file that includes those details. ```bash {location=".environment"} export DJANGO_SETTINGS_MODULE=config.settings.production export DJANGO_SECRET_KEY="$PLATFORM_PROJECT_ENTROPY" export DJANGO_ALLOWED_HOSTS=".platformsh.site" ``` **Warning**: Not all Django apps allow for configuration in this way. See the following sections to see how other common settings should be set on Upsun. ##### 2. Configure `ALLOWED_HOSTS` By default, other than `localhost`, Django only allows hosts listed in `settings.ALLOWED_HOSTS` to be accessed. However, Django does not allow for wildcard hosts that span multiple levels by default. This becomes relevant in order to support our dynamic preview environments you will want to dynamically add to the list. The simplest method is to add the following line to `.environment` : ```bash export DJANGO_ALLOWED_HOSTS=$(echo $PLATFORM_ROUTES | base64 --decode | jq -r 'to_entries[] | select(.value.primary == true) | .key' | sed 's:/*$::' | sed 's|https\?://||') ``` This will add the primary route of the current application to the `DJANGO_ALLOWED_HOSTS` environment variable. ##### 3. Upsun-specific settings Near the bottom of your `settings.py` file, define a block that: - Detects when Django is running on an Upsun environment - Override previous settings If your configuration is split into a `production.py` file for production settings, place it there instead. ```py {location="settings.py"} # Production/Upsun settings. if (os.getenv('PLATFORM_APPLICATION_NAME') is not None): DEBUG = False # Static dir. if (os.getenv('PLATFORM_APP_DIR') is not None): STATIC_ROOT = os.path.join(os.getenv('PLATFORM_APP_DIR'), 'static') # Secret Key. if (os.getenv('PLATFORM_PROJECT_ENTROPY') is not None): SECRET_KEY = os.getenv('PLATFORM_PROJECT_ENTROPY') # Production database configuration. if (os.getenv('PLATFORM_ENVIRONMENT') is not None): DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': os.getenv('DATABASE_PATH'), 'USER': os.getenv('DATABASE_USERNAME'), 'PASSWORD': os.getenv('DATABASE_PASSWORD'), 'HOST': os.getenv('DATABASE_HOST'), 'PORT': os.getenv('DATABASE_PORT'), }, 'sqlite': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } ``` This update includes a few important changes: 1. **Overwrites.** If the `PLATFORM_APPLICATION_NAME` Upsun built-in variable is found (that is, Django is running on an Upsun environment), override your previous settings. No matter what environment type we run on Upsun, this file uses production settings for Upsun (i.e. `DEBUG = False`). 1. **Static.** `STATIC_ROOT`, and the `static` files path is updated relative to the application root on Upsun. 1. **Secret key.** All Upsun projects come with a unique hash environment variable `PLATFORM_PROJECT_ENTROPY` that can be used to update your `SECRET_KEY`. 1. **Databases.** When Django is running on an Upsun enviroment _at runtime_, it has access to service containers like databases and caches. Every service container you configure in `.upsun/config.yaml` has a unique relationship name (`applications::relationships:`). Upsun automatically uses this relationship name to expose connection credentials through environment variables (for example, via `RELATIONSHIPNAME_HOST`). Update `settings.py` according to the example above (which configures a PostgreSQL service), where the relationship `database` results in environment variables that are leveraged to update the `DATABASES` setting for your application. You can use the exact same logic to configure `CACHES` from the `rediscache` relationship using the exposed `REDISCACHE_` environment variables to setup `django_redis.cache.RedisCache`. ##### 4. Start the app In your app configuration, locate the `web:commands:start` section and update it as follows: ```yaml {location=".upsun/config.yaml"} applications: myapp: ... web: commands: start: "gunicorn -b unix:$SOCKET config.wsgi" upstream: socket_family: unix ``` Note that if your Django instance requires a different web server, Upsun also supports [several other options](https://docs.upsun.com/languages/python/server.md). ##### 5. Configure static assets To access Django's static assets, you need to add a second location to the `web:locations` section of your app configuration. Locate the `web:locations` section and add a location for `/static`: ```yaml {location=".upsun/config.yaml"} applications: myapp: ... web: locations: "/": "passthru": true "/static": "allow": true "expires": "1h" "root": "static" ``` ##### 6. Install dependencies and builds Instruct Upsun to install your Python and Node (if needed) dependencies. Locate the `hooks:build` section and update it as follows: ```yaml {location=".upsun/config.yaml"} applications: myapp: ... build: | set -eux pip install --upgrade pip pip install -r requirements.txt npm install npm run build ``` Remove the `npm` steps if not required for your app's assets. Note that if your project uses a different package manager, Upsun also supports [several other options](https://docs.upsun.com/languages/python/dependencies.md). ##### 7. Configure the deploy phase In your app configuration, locate the `deploy` section and update it as follows: ```yaml {location=".upsun/config.yaml"} applications: myapp: ... deploy: | set -eux python manage.py collectstatic --noinput python manage.py migrate ``` ##### 8. Allow write access where needed Since Django can require a writable locations at runtime, you need to set up writable mounts. To do so, locate the `mounts` section (currently commented), and update it as follows: ```yaml {location=".upsun/config.yaml"} applications: myapp: ... mounts: "/staticfiles": source: "local" source_path: "static_assets" ``` You can now commit all of the above changes and push to Upsun. ```bash {location="Terminal"} git add . git commit -m "Add changes to complete my Upsun configuration" git push ``` ##### Further resources ###### Documentation - [Python documentation](https://docs.upsun.com/languages/python.md) - [Managing dependencies](https://docs.upsun.com/languages/python/dependencies.md) - [Configuring web servers](https://docs.upsun.com/languages/python/server.md) ###### Community content - [Django topics](https://support.platform.sh/hc/en-us/search?utf8=%E2%9C%93&query=django) - [Python topics](https://support.platform.sh/hc/en-us/search?utf8=%E2%9C%93&query=python) ###### Blogs - [_Up(sun) and running with Django_](https://upsun.com/blog/setting-up-django-on-upsun/) ### Deploy Flask on Platform.sh **Note**: Before you start, check out the [Upsun demo app](https://console.upsun.com/projects/create-project) and the main [Getting started guide](https://docs.upsun.com/get-started/here.md). They provide all of the core concepts and common commands you need to know before using the materials below. For Flask to successfully deploy and operate, **after completing the [Getting started guide](https://docs.upsun.com/get-started/here.md)**, you still need to make a few changes to your Upsun configuration. ##### Before you begin You need: - [Git](https://git-scm.com/downloads). Git is the primary tool to manage everything your app needs to run. Push commits to deploy changes and control configuration through YAML files. These files describe your infrastructure, making it transparent and version-controlled. - A Upsun account. If you don't already have one, [register for a trial account](https://auth.upsun.com/register). You can sign up with an email address or an existing GitHub, Bitbucket, or Google account. If you choose one of these accounts, you can set a password for your Upsun account later. - The [Upsun CLI](https://docs.upsun.com/administration/cli.md). This lets you interact with your project from the command line. You can also do most things through the [Web Console](https://docs.upsun.com/administration/web.md). ##### 1. Leverage environment variables The CLI generated a `.environment` file during the Getting started guide. Notice it has already created some environmental variables for you to connect to your database service. ```bash {location=".environment"} export RELATIONSHIPS_JSON="$(echo $PLATFORM_RELATIONSHIPS | base64 --decode)" # Set database environment variables export DB_HOST="$(echo $RELATIONSHIPS_JSON | jq -r '.postgresql[0].host')" export DB_PORT="$(echo $RELATIONSHIPS_JSON | jq -r '.postgresql[0].port')" export DB_DATABASE="$(echo $RELATIONSHIPS_JSON | jq -r '.postgresql[0].path')" export DB_USERNAME="$(echo $RELATIONSHIPS_JSON | jq -r '.postgresql[0].username')" export DB_PASSWORD="$(echo $RELATIONSHIPS_JSON | jq -r '.postgresql[0].password')" export DB_CONNECTION="$(echo $RELATIONSHIPS_JSON | jq -r '.postgresql[0].scheme')" export DATABASE_URL="postgresql://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_DATABASE}" ``` To configure all the environment variables Flask needs to run smoothly, follow these steps. 1. Set the `FLASK_APP` environment variable to specify how to load the app. ```bash {location=".environment"} export FLASK_APP="autoapp.py" ``` The above example uses the file `autoapp.py` as the main entry. Adjust according to your situation. 2. Set the `FLASK_ENV` environment variable to enable behaviors based on the environment type. Upsun provides information about what type of environment the app is running in via the `PLATFORM_ENVIRONMENT_TYPE` environment variable. Its values can be ``production``, ``development``, or ``staging``. Use this information to set the value for `FLASK_ENV`. ```bash {location=".environment"} export FLASK_ENV="${PLATFORM_ENVIRONMENT_TYPE}" ``` Several other environmental variables need to change based on the environment type. Leverage the information in `PLATFORM_ENVIRONMENT_TYPE` for these other variables too. 3. Set the `FLASK_DEBUG` environment variable to ``1`` (enabled) if you're not running in production. ```bash {location=".environment"} export FLASK_DEBUG=$( [ "${PLATFORM_ENVIRONMENT_TYPE}" = "production" ] && echo 0 || echo 1) ``` 4. Do the same for `LOG_LEVEL`. ```bash {location=".environment"} export LOG_LEVEL=$( [ "${PLATFORM_ENVIRONMENT_TYPE}" = "production" ] && echo "info" || echo "debug") ``` 5. Set the `SEND_FILE_MAX_AGE_DEFAULT` to ``0`` (disabled) if you're not in production, but a higher value if you are. ```bash {location=".environment"} export SEND_FILE_MAX_AGE_DEFAULT=$( [ "${PLATFORM_ENVIRONMENT_TYPE}" = "production" ] && echo 31556926 || echo 0) ``` 6. Optional: You may also need to set a `SECRET_KEY` environment variable. It's used for securely signing the session cookie and can be used for any other security-related needs by extensions or your app. It usually is a long random string. Set the `SECRET_KEY` environment variable to leverage the [`PLATFORM_PROJECT_ENTROPY` variable](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables) provided by Upsun: ```bash {location=".environment"} export SECRET_KEY="${PLATFORM_PROJECT_ENTROPY}" ``` Your `.environment` file should now look similar to the following: ```bash {location=".environment"} # Set database environment variables export DB_HOST="$POSTGRESQL_HOST" export DB_PORT="$POSTGRESQL_PORT" export DB_PATH="$POSTGRESQL_PATH" export DB_USERNAME="$POSTGRESQL_USERNAME" export DB_PASSWORD="$POSTGRESQL_PASSWORD" export DB_SCHEME="postgresql" export DATABASE_URL="${DB_SCHEME}://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_PATH}" export FLASK_ENV="${PLATFORM_ENVIRONMENT_TYPE}" export FLASK_DEBUG=$( [ "${PLATFORM_ENVIRONMENT_TYPE}" = "production" ] && echo 0 || echo 1) export LOG_LEVEL=$( [ "${PLATFORM_ENVIRONMENT_TYPE}" = "production" ] && echo "info" || echo "debug") export SEND_FILE_MAX_AGE_DEFAULT=$( [ "${PLATFORM_ENVIRONMENT_TYPE}" = "production" ] && echo 31556926 || echo 0) export SECRET_KEY="${PLATFORM_PROJECT_ENTROPY}" ``` ##### 2. Configure static assets You need to add some writable disk space to hold the static assets that `flask-static-digest` generates and `npm` builds. To do so, define the `.//static` directory as [a mount](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#mounts). In your app configuration, locate the section dedicated to mounts and update it as follows: ```yaml {location=".upsun/config.yaml"} applications: myapp: ... mounts: "/static": source: "storage" source_path: "static_assets" ``` Replace `` with the `app_name` you defined when creating your Flask project. ##### 3. Install dependencies and builds Instruct Upsun to automatically run `npm install` in addition to installing your Python dependencies when building the application container. To do so, customize your [build hook](https://docs.upsun.com/create-apps/hooks/hooks-comparison.md#build-hook). In your app configuration, locate the section dedicated to it and update it as follows: ```yaml {location=".upsun/config.yaml"} applications: myapp: ... # Hooks allow you to customize your code/environment as the project moves through the build and deploy stages # More information: https://docs.upsun.com/create-apps/app-reference.html#hooks hooks: # The build hook is run after any build flavor. # More information: https://docs.upsun.com/create-apps/hooks/hooks-comparison.html#build-hook build: | set -eux pip install -r requirements.txt ``` The Upsun CLI automatically added `pip install -r requirements.txt` to your build hook configuration when you [configured your Upsun project](https://docs.upsun.com/get-started/here/configure.md). If you want `pip` to be upgraded first to the latest version, add `pip install --upgrade pip` to the above line. Then, add `npm install`: ```yaml {location=".upsun/config.yaml"} applications: myapp: ... # Hooks allow you to customize your code/environment as the project moves through the build and deploy stages # More information: https://docs.upsun.com/create-apps/app-reference.html#hooks hooks: # The build hook is run after any build flavor. # More information: https://docs.upsun.com/create-apps/hooks/hooks-comparison.html#build-hook build: | set -eux pip install --upgrade pip pip install -r requirements.txt npm install ``` Note that if your project uses a different package manager, Upsun also supports [several other options](https://docs.upsun.com/languages/python/dependencies.md). ##### 4. Configure the deploy phase Instruct Upsun to automatically run `npm run build` when building the application container. To do so, customize your [deploy hook](https://docs.upsun.com/create-apps/hooks/hooks-comparison.md#deploy-hook). In your app configuration, locate the section dedicated to it: ```yaml {location=".upsun/config.yaml"} applications: myapp: ... # Hooks allow you to customize your code/environment as the project moves through the build and deploy stages # More information: https://docs.upsun.com/create-apps/app-reference.html#hooks hooks: ... # The deploy hook is run after the app container has been started, but before it has started accepting requests. # More information: https://docs.upsun.com/create-apps/hooks/hooks-comparison.html#deploy-hook deploy: | set -eux # echo 'Put your deploy command here' ``` Add `npm run build`: ```yaml {location=".upsun/config.yaml"} applications: myapp: ... # Hooks allow you to customize your code/environment as the project moves through the build and deploy stages # More information: https://docs.upsun.com/create-apps/app-reference.html#hooks hooks: ... # The deploy hook is run after the app container has been started, but before it has started accepting requests. # More information: https://docs.upsun.com/create-apps/hooks/hooks-comparison.html#deploy-hook deploy: | set -eux npm run build ``` ##### 5. Configure the web server [Configure the web server](https://docs.upsun.com/create-apps.md#configure-whats-served) running in front of your app to define how your app handles dynamic requests. To do so, in your app configuration, locate the section dedicated to the web server: ```yaml {location=".upsun/config.yaml"} applications: myapp: ... # The web key configures the web server running in front of your app. # More information: https://docs.upsun.com/create-apps/app-reference.html#web web: # Commands are run once after deployment to start the application process. # More information: https://docs.upsun.com/create-apps/app-reference.html#web-commands ``` To add a basic Flask server, replace the default information added by the Upsun CLI with `flask run -p $PORT`. Also, change the `socket_family` value from `unix` to `tcp`: ```yaml {location=".upsun/config.yaml"} applications: myapp: ... # The web key configures the web server running in front of your app. # More information: https://docs.upsun.com/create-apps/app-reference.html#web web: # Commands are run once after deployment to start the application process. # More information: https://docs.upsun.com/create-apps/app-reference.html#web-commands commands: start: "flask run -p $PORT" upstream: socket_family: tcp ``` You can now commit all of the above changes and push to Upsun. ```bash {location="Terminal"} git add . git commit -m "Add changes to complete my Upsun configuration" git push ``` Note that if your Flask project requires a different web server, Upsun also supports [several other options](https://docs.upsun.com/languages/python/server.md), including Gunicorn, Daphne, Uvicorn, and Hypercorn. If you use Pip, make sure you add your chosen web server to your `requirements.txt` file. ##### 6. Handle database migrations ###### Prepare database migrations If you have a new Flask project that uses [Flask-migrate](https://flask-migrate.readthedocs.io/en/latest/), or an existing app but need to set up the initial migrations, you can do so using the database service you created earlier. To do so, follow these steps. 1. Set up a virtual environment where your project can run: ```bash {location="Terminal"} python3 -m venv env && source venv/bin/activate ``` 2. Just like in your build hook, update pip and install the requirements: ```bash {location="Terminal"} pip install --upgrade pip && pip install -r requirements.txt ``` 3. Set up a way for your local instance of Flask to communicate with your database service: ```bash {location="Terminal"} upsun tunnel:open -y ``` This opens an SSH tunnel to all the services for the app. You can use this connection to allow your local instance to communicate with live services as if they too were local. To do so, you need to configure more environment variables. 4. Reopen your `.environment` file. Note the use of the `$PLATFORM_RELATIONSHIPS` environment variable to retrieve information about services and their credentials. The tunnel you created gives you access to that same data, allowing you to generate a local `PLATFORM_RELATIONSHIPS` environment variable containing the same information. Set the following environment variable: ```bash {location=".environment"} export PLATFORM_RELATIONSHIPS="$(upsun tunnel:info --encode)" ``` Since you now have this environmental variable set locally, you can reuse your `.environment` file for Upsun to recreate many of the other environmental variables you need to run locally. 5. Set the following environment variables as they aren't set via ``PLATFORM_RELATIONSHIPS``: ```bash {location=".environment"} export PLATFORM_ENVIRONMENT_TYPE=production export PORT=8888 export PLATFORM_PROJECT_ENTROPY=$(openssl rand -base64 32) ``` 6. Source your `.environment` file to finish setting up all the environmental variables in your current bash: ```bash {location="Terminal"} source ./.environment ``` You now have everything you need for Flask-Migrate to be able to connect to the database and generate your migration files. ###### Generate database migrations 1. Initiate the migrations directory and prepare for the ``migrate`` command: ```bash {location="Terminal"} flask db init ``` 2. Generate your migrations: ```bash {location="Terminal"} flask db migrate ``` 3. Commit your generated migrations: ```bash {location="Terminal"} git add migrations/* && git commit -m "Adds migrations" ``` 4. Instruct Upsun to run the Flask-migrate upgrade command when deploying so any migration changes are automatically applied. To do so, re-open your `.upsun/config.yaml` file. Locate the `deploy` hook where you added `npm run build` previously and update it as follows: ```yaml {location=".upsun/config.yaml"} applications: myapp: ... # Hooks allow you to customize your code/environment as the project moves through the build and deploy stages # More information: https://docs.upsun.com/create-apps/app-reference.html#hooks hooks: ... # The deploy hook is run after the app container has been started, but before it has started accepting requests. # More information: https://docs.upsun.com/create-apps/hooks/hooks-comparison.html#deploy-hook deploy: | set -eux npm run build flask db upgrade ``` 5. Commit all your changes and push to Upsun. ```bash {location="Terminal"} git add . git commit -m "Add changes to complete my Upsun configuration" git push ``` ##### Further resources ###### Documentation - [Python documentation](https://docs.upsun.com/languages/python.md) - [Managing dependencies](https://docs.upsun.com/languages/python/dependencies.md) - [Configuring web servers](https://docs.upsun.com/languages/python/server.md) ###### Community content - [Flask topics](https://support.platform.sh/hc/en-us/search?utf8=%E2%9C%93&query=flask) - [Python topics](https://support.platform.sh/hc/en-us/search?utf8=%E2%9C%93&query=python) ###### Blogs - [Up(sun) and running with Django](https://upsun.com/blog/setting-up-django-on-upsun/) ### Deploy Drupal on Platform.sh **Note**: Before you start, check out the [Upsun demo app](https://console.upsun.com/projects/create-project) and the main [Getting started guide](https://docs.upsun.com/get-started/here.md). They provide all of the core concepts and common commands you need to know before using the materials below. It should also be noted that this guide works for the following variations of Drupal: - [v10.x](https://www.drupal.org/project/drupal/releases/10.3.12) - [v11.x](https://www.drupal.org/project/drupal/releases/11.1.2) - [CMS](https://new.drupal.org/docs/drupal-cms/get-started/install-drupal-cms) For Drupal to successfully deploy and operate, **after completing the [Getting started guide](https://docs.upsun.com/get-started/here.md)**, you still need to make a few changes to your Upsun configuration. ##### Before you begin You need: - [Git](https://git-scm.com/downloads). Git is the primary tool to manage everything your app needs to run. Push commits to deploy changes and control configuration through YAML files. These files describe your infrastructure, making it transparent and version-controlled. - A Upsun account. If you don't already have one, [register for a trial account](https://auth.upsun.com/register). You can sign up with an email address or an existing GitHub, Bitbucket, or Google account. If you choose one of these accounts, you can set a password for your Upsun account later. - The [Upsun CLI](https://docs.upsun.com/administration/cli.md). This lets you interact with your project from the command line. You can also do most things through the [Web Console](https://docs.upsun.com/administration/web.md). In addition to the above, you should also have: - The Drupal files in a repository - A local copy of that repository where you have selected both `Redis` and `MariaDB` during the [Configure your project](https://docs.upsun.com/get-started/here/configure) portion of the [Getting Started](https://docs.upsun.com/get-started/here.md) guide ##### Configure Open the `.upsun/config.yaml` file that's been generated and replace with the following: ```yaml {filename=".upsun/config.yaml"} applications: drupal: type: "php:8.3" relationships: mariadb: 'db:mysql' redis: 'cache:redis' mounts: # The default Drupal files directory. '/web/sites/default/files': source: storage source_path: 'files' # Drupal gets its own dedicated tmp directory. The settings.platformsh.php # file will automatically configure Drupal to use this directory. '/tmp': source: storage source_path: 'tmp' # Private file uploads are stored outside the web root. The settings.platformsh.php # file will automatically configure Drupal to use this directory. '/private': source: storage source_path: 'private' # Drush needs a scratch space for its own caches. '/.drush': source: storage source_path: 'drush' # Drush will try to save backups to this directory, so it must be # writeable even though you will almost never need to use it. '/drush-backups': source: storage source_path: 'drush-backups' build: flavor: composer web: locations: '/': root: 'web' expires: 5m passthru: '/index.php' allow: false rules: '\.(avif|webp|jpe?g|png|gif|svgz?|css|js|map|ico|bmp|eot|woff2?|otf|ttf)$': allow: true '^/robots\.txt$': allow: true '^/sitemap\.xml$': allow: true '^/sites/sites\.php$': scripts: false '^/sites/[^/]+/settings.*?\.php$': scripts: false '/sites/default/files': allow: true expires: 5m passthru: '/index.php' root: 'web/sites/default/files' scripts: false rules: '^/sites/default/files/(css|js)': expires: 2w dependencies: php: composer/composer: "^2.7" hooks: build: | set -e # fast. deploy: | set -e php ./drush/upsun_generate_drush_yml.php cd web bash $PLATFORM_APP_DIR/drush/upsun_deploy_drupal.sh crons: # Run Drupal's cron tasks every 19 minutes. drupal: spec: '*/19 * * * *' commands: start: 'cd web ; drush core-cron' runtime: # Enable the redis extension so Drupal can communicate with the Redis cache. extensions: - redis - sodium - apcu - blackfire source: root: / services: db: type: mariadb:10.6 cache: type: redis:7.2 routes: "https://{default}/": type: upstream upstream: "drupal:http" cache: enabled: true # Base the cache on the session cookie and custom Drupal cookies. Ignore all other cookies. cookies: ['/^SS?ESS/', '/^Drupal.visitor/'] "https://www.{default}/": type: redirect to: "https://{default}/" ``` This configuration is similar to the deployment process for [Drupal on Platform.sh](https://docs.platform.sh/guides/drupal/deploy.md), however it is slightly updated for [Upsun's configuration](https://docs.upsun.com/learn/tutorials/migrating/from-psh.md). ##### Variables The `project:init` command created a `.environment` file containing environment variables for the two services (MariaDB and Redis). Now append the following Drush configuration to the bottom of that file: ```bash {location=".environment"} # Allow executable app dependencies from Composer to be run from the path. if [ -n "$PLATFORM_APP_DIR" -a -f "$PLATFORM_APP_DIR"/composer.json ] ; then bin=$(composer config bin-dir --working-dir="$PLATFORM_APP_DIR" --no-interaction 2>/dev/null) export PATH="${PLATFORM_APP_DIR}/${bin:-vendor/bin}:${PATH}" fi ``` ##### `settings.php` Open `web/sites/default/settings.php` and append the following to the bottom of that file. ```php {location="web/sites/default/settings.php"} // Upsun configuration if (getenv('PLATFORM_APPLICATION') && file_exists(__DIR__ . '/settings.upsun.php')) { include __DIR__ . '/settings.upsun.php'; } ``` ##### Upsun-specific settings Then create a new Upsun-specific settings file `web/sites/default/settings.upsun.php` that leverages the variables defined in `.environment`. This file should contain the following: ```php {location="web/sites/default/settings.upsun.php"} getenv('DB_SCHEME'), 'database' => getenv('DB_PATH'), 'username' => getenv('DB_USERNAME'), 'password' => getenv('DB_PASSWORD'), 'host' => getenv('DB_HOST'), 'port' => getenv('DB_PORT'), 'init_commands' => [ 'isolation_level' => 'SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED', ], ]; // Enable verbose error messages on development/staging branches, but not on the production branch. // You may add more debug-centric settings here if desired to have them automatically enable // on development but not production. if (getenv('PLATFORM_ENVIRONMENT_TYPE') == 'production') { // Production environment type. $config['system.logging']['error_level'] = 'hide'; } else { // Non-production environment types. $config['system.logging']['error_level'] = 'verbose'; } // Enable Redis caching. if (!InstallerKernel::installationAttempted() && extension_loaded('redis') && class_exists('Drupal\redis\ClientFactory')) { // Set Redis as the default backend for any cache bin not otherwise specified. $settings['cache']['default'] = 'cache.backend.redis'; $settings['redis.connection']['host'] = getenv('CACHE_HOST'); $settings['redis.connection']['port'] = getenv('CACHE_PORT'); // Apply changes to the container configuration to better leverage Redis. // This includes using Redis for the lock and flood control systems, as well // as the cache tag checksum. Alternatively, copy the contents of that file // to your project-specific services.yml file, modify as appropriate, and // remove this line. $settings['container_yamls'][] = 'modules/contrib/redis/example.services.yml'; // Allow the services to work before the Redis module itself is enabled. $settings['container_yamls'][] = 'modules/contrib/redis/redis.services.yml'; // Manually add the classloader path, this is required for the container cache bin definition below // and allows to use it without the redis module being enabled. $class_loader->addPsr4('Drupal\\redis\\', 'modules/contrib/redis/src'); // Use redis for container cache. // The container cache is used to load the container definition itself, and // thus any configuration stored in the container itself is not available // yet. These lines force the container cache to use Redis rather than the // default SQL cache. $settings['bootstrap_container_definition'] = [ 'parameters' => [], 'services' => [ 'redis.factory' => [ 'class' => 'Drupal\redis\ClientFactory', ], 'cache.backend.redis' => [ 'class' => 'Drupal\redis\Cache\CacheBackendFactory', 'arguments' => ['@redis.factory', '@cache_tags_provider.container', '@serialization.phpserialize'], ], 'cache.container' => [ 'class' => '\Drupal\redis\Cache\PhpRedis', 'factory' => ['@cache.backend.redis', 'get'], 'arguments' => ['container'], ], 'cache_tags_provider.container' => [ 'class' => 'Drupal\redis\Cache\RedisCacheTagsChecksum', 'arguments' => ['@redis.factory'], ], 'serialization.phpserialize' => [ 'class' => 'Drupal\Component\Serialization\PhpSerialize', ], ], ]; } if (getenv('PLATFORM_BRANCH')) { // Configure private and temporary file paths. if (!isset($settings['file_private_path'])) { $settings['file_private_path'] = getenv('PLATFORM_APP_DIR') . '/private'; } if (!isset($settings['file_temp_path'])) { $settings['file_temp_path'] = getenv('PLATFORM_APP_DIR') . '/tmp'; } // Configure the default PhpStorage and Twig template cache directories. if (!isset($settings['php_storage']['default'])) { $settings['php_storage']['default']['directory'] = $settings['file_private_path']; } if (!isset($settings['php_storage']['twig'])) { $settings['php_storage']['twig']['directory'] = $settings['file_private_path']; } // Set the project-specific entropy value, used for generating one-time // keys and such. $settings['hash_salt'] = empty($settings['hash_salt']) ? getenv('PLATFORM_PROJECT_ENTROPY') : $settings['hash_salt']; // Set the deployment identifier, which is used by some Drupal cache systems. $settings['deployment_identifier'] = $settings['deployment_identifier'] ?? getenv('PLATFORM_TREE_ID');; } // The 'trusted_hosts_pattern' setting allows an admin to restrict the Host header values // that are considered trusted. If an attacker sends a request with a custom-crafted Host // header then it can be an injection vector, depending on how the Host header is used. // However, Platform.sh already replaces the Host header with the route that was used to reach // Platform.sh, so it is guaranteed to be safe. The following line explicitly allows all // Host headers, as the only possible Host header is already guaranteed safe. $settings['trusted_host_patterns'] = ['.*']; ``` ##### `config/sync` Create the `config/sync` empty directory referenced in the settings file: ```bash {location="Terminal"} mkdir -p config/sync && touch config/sync/.gitkeep ``` ##### Configuration reader Install the required [Config Reader library](https://github.com/platformsh/config-reader-php). This will help us to pull routing details for each environment into our settings (highlighted in the snippet in the next step). ```bash composer require platformsh/config-reader ``` ##### Drush To configure Drush, use the following command to create the files that will be referenced in the configuration process. This process will allow Drush to be used within the Upsun container. ```bash {location="Terminal"} mkdir drush && touch drush/upsun_deploy_drupal.sh && touch drush/upsun_generate_drush_yml.php ``` Fill out the `drush/upsun_deploy_drupal.sh` with the following: ```bash {location="drush/upsun_deploy_drupal.sh"} #!/usr/bin/env bash # # Don't run drush commands if drupal isn't installed. # Don't run config-import if there aren't any config files to import if [ -n "$(drush status --field=bootstrap)" ]; then drush -y cache-rebuild drush -y updatedb if [ -n "$(ls $(drush php:eval "echo realpath(Drupal\Core\Site\Settings::get('config_sync_directory'));")/*.yml 2>/dev/null)" ]; then drush -y config-import else echo "No config to import. Skipping." fi else echo "Drupal not installed. Skipping standard Drupal deploy steps" fi ``` This file runs Drush commands (`cache-rebuild` and `updatedb`) only when Drupal is installed. It also will only run `config-import` if configuration YAMLs are present in the `config_sync_directory` -- `config/sync`. Change its permissions to run at deploy time: ```bash {location="Terminal"} chmod +x drush/upsun_deploy_drupal.sh ``` Then finally, fill out the Drush generator PHP file: ```php {location="drush/upsun_generate_drupal_yml.php"} inRuntime()) { return; } $routes = $platformsh->getUpstreamRoutes($platformsh->applicationName); // Sort URLs, with the primary route first, then by HTTPS before HTTP, then by length. usort($routes, function (array $a, array $b) { // false sorts before true, normally, so negate the comparison. return [!$a['primary'], strpos($a['url'], 'https://') !== 0, strlen($a['url'])] [!$b['primary'], strpos($b['url'], 'https://') !== 0, strlen($b['url'])]; }); // Return the url of the first one. return reset($routes)['url'] ?: NULL; } $appRoot = dirname(__DIR__); $filename = $appRoot . '/.drush/drush.yml'; $siteUrl = _platformsh_drush_site_url(); if (empty($siteUrl)) { echo "Failed to find a site URL\n"; if (file_exists($filename)) { echo "The file exists but may be invalid: $filename\n"; } exit(1); } $siteUrlYamlEscaped = json_encode($siteUrl, JSON_UNESCAPED_SLASHES); $scriptPath = __FILE__; $success = file_put_contents($filename, **Snippets**: You can also find all the snippets described in this post on GitHub - [Drupal 11](https://github.com/upsun/snippets/tree/main/examples/drupal11) ##### Further resources ###### Documentation - [PHP documentation](https://docs.upsun.com/languages/php.md) - [Authenticated Composer repositories](https://docs.upsun.com/languages/php/composer-auth.md) ###### Community content - [Drupal topics](https://support.platform.sh/hc/en-us/search?utf8=%E2%9C%93&query=drupal) - [PHP topics](https://support.platform.sh/hc/en-us/search?utf8=%E2%9C%93&query=php) ###### Blogs - [_Drupal and Upsun_](https://devcenter.upsun.com/posts/drupal-and-upsun/) ### Deploy Laravel on Platform.sh **Note**: Before you start, check out the [Upsun demo app](https://console.upsun.com/projects/create-project) and the main [Getting started guide](https://docs.upsun.com/get-started/here.md). They provide all of the core concepts and common commands you need to know before using the materials below. - [Get started](https://docs.upsun.com/get-started/stacks/laravel/get-started.md) - [Configure environment variables](https://docs.upsun.com/get-started/stacks/laravel/environment-variables.md) - [Set up Redis](https://docs.upsun.com/get-started/stacks/laravel/setup-redis.md) - [Handle queues with Horizon](https://docs.upsun.com/get-started/stacks/laravel/laravel-horizon.md) - [Set up cron jobs](https://docs.upsun.com/get-started/stacks/laravel/crons.md) - [Manage continous observability with Blackfire](https://docs.upsun.com/get-started/stacks/laravel/blackfire.md) - [Debug with Laravel Telescope](https://docs.upsun.com/get-started/stacks/laravel/laravel-telescope.md) - [FAQ](https://docs.upsun.com/get-started/stacks/laravel/faq.md) ##### Further resources ###### Documentation - [PHP documentation](https://docs.upsun.com/languages/php.md) - [Extensions](https://docs.upsun.com/languages/php/extensions.md) - [Performance tuning](https://docs.upsun.com/languages/php/tuning.md) - [PHP-FPM sizing](https://docs.upsun.com/languages/php/fpm.md) - [Swoole on Upsun](https://docs.upsun.com/languages/php/swoole.md) - [Authenticated Composer](https://docs.upsun.com/languages/php/composer-auth.md) ###### Community content - [Laravel topics](https://support.platform.sh/hc/en-us/search?utf8=%E2%9C%93&query=laravel) - [PHP topics](https://support.platform.sh/hc/en-us/search?utf8=%E2%9C%93&query=php) ###### Blogs - [_Upsun: the missing PaaS to scale Laravel applications_](https://upsun.com/blog/paas-to-scale-laravel-apps/) [Get started](https://docs.upsun.com/get-started/stacks/laravel/environment-variables.md) #### Get started This guide provides instructions for deploying and working with Laravel on Upsun. ###### Before you begin You need: - [Git](https://git-scm.com/downloads). Git is the primary tool to manage everything your app needs to run. Push commits to deploy changes and control configuration through YAML files. These files describe your infrastructure, making it transparent and version-controlled. - A Upsun account. If you don't already have one, [register for a trial account](https://auth.upsun.com/register). You can sign up with an email address or an existing GitHub, Bitbucket, or Google account. If you choose one of these accounts, you can set a password for your Upsun account later. - The [Upsun CLI](https://docs.upsun.com/administration/cli.md). This lets you interact with your project from the command line. You can also do most things through the [Web Console](https://docs.upsun.com/administration/web.md). ###### 1. Create your Laravel app 1. To create a new Laravel project, run the following commands: ```bash {location="Terminal"} composer create-project laravel/laravel:^11.0 cd git init . ``` Alternatively, you can deploy an **existing Laravel project**. To do so, `cd` into your Laravel repository root folder. 2. To generate a sensible default Upsun configuration, run the following command from within the project's directory: ```bash {location="Terminal"} upsun project:init ``` The Upsun CLI detects a PHP & Laravel stack. Follow the prompts to specify a name for your project and select the needed services. While optional, it is recommended to add [Redis](https://docs.upsun.com/add-services/redis.md) to your project to handle Laravel cache, queues & sessions. The `.upsun/config.yaml` and `.environment` configuration files are generated. 3. Enable the PHP extensions required by the services you selected. For example, `pdo_mysql` is enabled by default, but you may need to enable others like `redis` or `pdo_pgsql`: ```yaml {location=".upsun/config.yaml"} applications: myapp: [...] runtime: extensions: - redis - pdo_pgsql ``` See all the [available PHP extensions](https://docs.upsun.com/languages/php/extensions.md). 3. Laravel requires an [encryption key](https://laravel.com/docs/master/encryption#gracefully-rotating-encryption-keys). To generate the key locally, run `php artisan key:generate`. Copy the key from your local `.env` file into `.environment` as follows: ```bash {location=".environment"} export APP_KEY="base64:" ``` 4. Add and commit your changes: ```bash {location="Terminal"} git add .upsun/config.yaml .environment git commit -m "Add Upsun configuration" ``` ###### 2. Create your Upsun project To create a project on Upsun, run the following command from within the project's directory: ```bash {location="Terminal"} upsun project:create --title --set-remote ``` The `--set-remote` flag sets the new project as the remote for this repository. **Tip**: You can link any repository to an existing Upsun project using the following command: ```bash {location="Terminal"} upsun project:set-remote ``` ###### 3. Deploy your project To deploy your project, run the following command: ```bash {location="Terminal"} upsun push ``` During deployment, the logs from the Upsun API are displayed in your terminal so you can monitor progress. To stop the display of the logs **without interrupting the deployment**, use `CTRL+C` in your terminal. To go back to displaying the logs, run `upsun activity:log`. Congratulations, your first Laravel app has been deployed on Upsun! **Tip**: Now that your app is deployed in production mode, you can [set up a custom domain](https://docs.upsun.com/domains/steps.md). ###### 4. Configure write access The Upsun default configuration stipulates three writable folders in `.upsun/config.yaml`: - `"/.config"` - `"bootstrap/cache"` - `"storage"` If your application writes content outside of these default ones, you can [set up mounts](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#mounts). ###### 5. Make changes to your project Now that your project is deployed, you can start making changes to it. For example, you might want to fix a bug or add a new feature. In your project, the main branch always represents the production environment. Other branches are for developing new features, fixing bugs, or updating the infrastructure. To make changes to your project, follow these steps: 1. Create a new environment (a Git branch) to make changes without impacting production: ```bash {location="Terminal"} upsun branch feat-a ``` This command creates a new local `feat-a` Git branch based on the main Git branch, and activates a related environment on Upsun. The new environment inherits the data (service data and assets) of its parent environment (the production environment here). 2. Make changes to your project. For example, edit the `resources/views/welcome.blade.php` template and make the following visual changes: ```html {location="resources/views/welcome.blade.php"} - **Laravel** + **Laravel On Upsun** ``` 3. Add and commit your changes: ```bash {location="Terminal"} add . git commit -a -m "Update title" ``` 4. Deploy your changes to the `feat-a` environment: ```bash {location="Terminal"} upsun deploy ``` Note that each environment has its own domain name. To view the domain name of your new environment, run the following command: ```bash {location="Terminal"} upsun url --primary ``` 5. Iterate by changing the code, committing, and deploying. When satisfied with your changes, merge them to the main branch, deploy, and remove the feature branch: ```bash {location="Terminal"} git checkout main git merge feat-a upsun environment:delete feat-a git branch -d feat-a upsun deploy ``` Note that deploying to production is fast because the image built for the `feat-a` environment is reused. For a long running branch, keep the code up-to-date with the main branch by using `git merge main` or `git rebase main`. Also, keep the data in sync with the production environment by using `upsun env:sync`. ###### 6. Optional: Use a third-party Git provider When you choose to use a third-party Git hosting service, the Upsun Git repository becomes a read-only mirror of the third-party repository. All your changes take place in the third-party repository. Add an integration to your existing third-party repository: - [BitBucket](https://docs.upsun.com/integrations/source/bitbucket.md) - [GitHub](https://docs.upsun.com/integrations/source/github.md) - [GitLab](https://docs.upsun.com/integrations/source/gitlab.md) #### Configure environment variables By default, Upsun exposes some [environment variables](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). Laravel relies heavily on environment variables to configure application services (such as the database or the mailer). Therefore, the default configuration generated by `upsun project:init` includes the [environment variables for all the services](#service-environment-variables) connected to your app in the `.environment` file. **Tip**: You can tweak the ``.environment`` configuration to fit your needs and add specific project-level variables. You may need a variable to change per environment. If so, use the ``upsun variable`` command to add all the needed per-environment variables. ###### Default environment variables Upsun automatically exposes [environment variables](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables) about the app and its infrastructure. Assuming that MySQL, PostgreSQL, and Redis services have been added to your environment, and that the app has been granted access to those services via the following [relationships](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships): ```yaml {location=".upsun/config.yaml"} applications: myapp: [...] relationships: mysql: ... postgresql: ... redis: ... ``` You can transpose these variables to set up Laravel's default configuration in a `.environment` file: ```bash {location=".environment"} # Set MySQL database environment variables export DB_HOST="$MYSQL_HOST" export DB_PORT="$MYSQL_PORT" export DB_PATH="$MYSQL_PATH" export DB_USERNAME="$MYSQL_USERNAME" export DB_PASSWORD="$MYSQL_PASSWORD" export DB_SCHEME="$MYSQL_SCHEME" export DATABASE_URL="${DB_SCHEME}://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_PATH}" # Or for PostgreSQL export DB_HOST="$POSTGRESQL_HOST" export DB_PORT="$POSTGRESQL_PORT" export DB_PATH="$POSTGRESQL_PATH" export DB_USERNAME="$POSTGRESQL_USERNAME" export DB_PASSWORD="$POSTGRESQL_PASSWORD" export DB_SCHEME="$POSTGRESQL_SCHEME" export DATABASE_URL="${DB_SCHEME}://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_PATH}" # Set Laravel-specific environment variables export DB_CONNECTION="$DB_SCHEME" export DB_DATABASE="$DB_PATH" # Set Cache environment variables export CACHE_HOST="$REDIS_HOST" export CACHE_PORT="$REDIS_PORT" export CACHE_SCHEME="$REDIS_SCHEME" export CACHE_URL="${CACHE_SCHEME}://${CACHE_HOST}:${CACHE_PORT}" # Set Redis environment variables export REDIS_URL="$CACHE_URL" ``` ###### Service environment variables Each exposed environment variable is prefixed by the relationship name. For example, if you have the following relationships in your configuration: ```yaml {location=".upsun/config.yaml"} applications: myapp: relationships: database: service: "securitydb" endpoint: "postgresql" ``` The environment variables for the database service is prefixed by `DATABASE_`, which is the upper-cased version of the key defined in the relationship. For example, you could have a `DATABASE_URL` environment variable. **Note**: Environment variables aren’t exposed when the build hook script is running, as services aren’t available during the [build process](https://docs.upsun.com/learn/overview/build-deploy.md#the-build). To add specific variables available during the build, run ``upsun variable:create``. ####### Emails Upsun provides a SMTP service for sending emails. To configure email in Laravel, add the following mapping to your `.environment` file: ```bash {location=".environment"} # Email export MAIL_MAILER="smtp" export MAIL_HOST="${PLATFORM_SMTP_HOST}" export MAIL_PORT="25" ``` ####### HTTP If your project has multiple apps, the configuration is exposed via the following environment variables (where `SOME_SERVICE` is the upper-cased version of the key defined in the relationship): - `SOME_SERVICE_URL`: The full URL of the service - `SOME_SERVICE_IP`: The HTTP service IP - `SOME_SERVICE_PORT`: The HTTP service port - `SOME_SERVICE_SCHEME`: The HTTP service scheme - `SOME_SERVICE_HOST`: The HTTP service host ####### MySQL/MariaDB The [MySQL/MariaDB](https://docs.upsun.com/add-services/mysql.md) configuration is exposed via the following environment variables (where `DATABASE` is the upper-cased version of the key defined in the relationship above): - `DATABASE_URL`: The database URL (in PHP or Go format depending on your app) - `DATABASE_SERVER`: The database server - `DATABASE_DRIVER`: The database driver - `DATABASE_VERSION`: The database version - `DATABASE_HOST`: The database host - `DATABASE_PORT`: The database port - `DATABASE_NAME`: The database name - `DATABASE_DATABASE`: Alias for `DATABASE_NAME` - `DATABASE_USERNAME`: The database username - `DATABASE_PASSWORD`: The database password **Tip**: The database version and a default charset are included in the database URL. To override them, use the ``DATABASE_VERSION`` and ``DATABASE_CHARSET`` environment variables respectively. ####### PostgreSQL The [PostgreSQL](https://docs.upsun.com/add-services/postgresql.md) configuration is exposed via the following environment variables (where `DATABASE` is the upper-cased version of the key defined in the relationship): - `DATABASE_URL`: The database URL (in PHP or Go format depending on your app) - `DATABASE_SERVER`: The database server - `DATABASE_DRIVER`: The database driver - `DATABASE_VERSION`: The database version - `DATABASE_HOST`: The database host - `DATABASE_PORT`: The database port - `DATABASE_NAME`: The database name - `DATABASE_DATABASE`: Alias for `DATABASE_NAME` - `DATABASE_USERNAME`: The database username - `DATABASE_PASSWORD`: The database password **Tip**: The database version and a default charset are included in the database URL. To override them, use the ``DATABASE_VERSION`` and ``DATABASE_CHARSET`` environment variables respectively. ####### Redis The [Redis](https://docs.upsun.com/add-services/redis.md) configuration is exposed via the following environment variables (where `REDIS` is the upper-cased version of the key defined in the relationship): - `REDIS_URL`: The Redis URL - `REDIS_HOST`: The Redis host - `REDIS_PORT`: The Redis port - `REDIS_SCHEME`: The Redis scheme You can specify the Redis client in your `.environment` file: ```bash {location=".environment"} export REDIS_CLIENT="phpredis" ``` ####### Memcached The [Memcached](https://docs.upsun.com/add-services/memcached.md) configuration is exposed via the following environment variables (where `CACHE` is the upper-cased version of the key defined in the relationship): - `CACHE_HOST` - `CACHE_PORT` - `CACHE_IP` ####### Elasticsearch The [Elasticsearch](https://docs.upsun.com/add-services/elasticsearch.md) configuration is exposed via the following environment variables (where `ELASTICSEARCH` is the upper-cased version of the key defined in the relationship): - `ELASTICSEARCH_URL`: The full URL of the Elasticsearch service - `ELASTICSEARCH_HOST`: The Elasticsearch host - `ELASTICSEARCH_PORT`: The Elasticsearch port - `ELASTICSEARCH_SCHEME`: The Elasticsearch protocol scheme (`http` or `https`) ####### RabbitMQ The [RabbitMQ](https://docs.upsun.com/add-services/rabbitmq.md) configuration is exposed via the following environment variables (where `RABBITMQ` is the upper-cased version of the key defined in the relationship): - `RABBITMQ_URL`: The RabbitMQ standardized URL - `RABBITMQ_SERVER`: The RabbitMQ server - `RABBITMQ_HOST`: The RabbitMQ host - `RABBITMQ_PORT`: The RabbitMQ port - `RABBITMQ_SCHEME`: The RabbitMQ scheme - `RABBITMQ_USER`: The RabbitMQ username - `RABBITMQ_USERNAME`: The RabbitMQ username - `RABBITMQ_PASSWORD`: The RabbitMQ password ####### MongoDB The [MongoDB](https://docs.upsun.com/add-services/mongodb.md) configuration is exposed via the following environment variables (where `MONGODB` is the upper-cased version of the key defined in the relationship): - `MONGODB_SERVER` - `MONGODB_HOST` - `MONGODB_PORT` - `MONGODB_SCHEME` - `MONGODB_NAME` - `MONGODB_DATABASE` - `MONGODB_USER` - `MONGODB_USERNAME` - `MONGODB_PASSWORD` ####### InfluxDB The [InfluxDB](https://docs.upsun.com/add-services/influxdb.md) configuration is exposed via the following environment variables (where `TIMEDB` is the upper-cased version of the key defined in the relationship): - `TIMEDB_SCHEME` - `TIMEDB_HOST` - `TIMEDB_PORT` - `TIMEDB_IP` ####### Kafka The [Apache Kafka](https://docs.upsun.com/add-services/kafka.md) configuration is exposed via the following environment variables (where `KAFKA` is the upper-cased version of the key defined in the relationship): - `KAFKA_URL` - `KAFKA_SCHEME` - `KAFKA_HOST` - `KAFKA_PORT` - `KAFKA_IP` #### Set up Redis With Laravel, you can use Redis to handle session storage, cache storage, and queues. ###### 1. Add the Redis service 1. [Add the service](https://docs.upsun.com/add-services.md#add-a-service) to your app configuration using the `services` top-level key: ```yaml {location=".upsun/config.yaml"} services: [...] redis: type: redis:7.0 ``` 2. To connect the service to your app, add the following relationship: ```yaml {location=".upsun/config.yaml"} applications: myapp: [...] relationships: redis: services: [...] redis: type: redis:7.0 ``` ###### 2. Configure your Redis service The [Redis](https://docs.upsun.com/add-services/redis.md) configuration is exposed via the following environment variables (where `REDIS` is the upper-cased version of the key defined in the relationship): - `REDIS_URL`: The Redis URL - `REDIS_HOST`: The Redis host - `REDIS_PORT`: The Redis port - `REDIS_SCHEME`: The Redis scheme If the relationship is named `redis`, Laravel automatically detects these variables and configure its own Redis driver the right way. If not, you can map the variables in the `.environment` file. You can specify the Redis client in your `.environment` file: ```bash {location=".environment"} export REDIS_CLIENT="phpredis" ``` **Note**: If using ``phpredis``, make sure you add ``redis`` in the list of PHP ``runtime`` extensions in your ``.upsun/config.yaml``: ```yaml {location=".upsun/config.yaml"} applications: myapp: [...] runtime: extensions: - redis ``` ###### 3. Store the Laravel cache in Redis To enable cache storage in Redis, add the following environment variable to your `.environment` file: ```bash {location=".environment"} export CACHE_STORE="redis" ``` ###### 4. Store Laravel sessions in Redis Laravel relies on the `SESSION_DRIVER` variable to store sessions. Therefore, add the following environment variable to your `.environment` file: ```bash {location=".environment"} export SESSION_DRIVER="redis" ``` ###### 5. Use Redis for Laravel queues For a basic queueing system, configure the `QUEUE_CONNECTION` in your `.environment` file as follows: ```bash {location=".environment"} export QUEUE_CONNECTION="redis" ``` For more information, see the [Laravel Queues documentation](https://laravel.com/docs/master/queues) and Upsun's [Horizon configuration page](https://docs.upsun.com/get-started/stacks/laravel/laravel-horizon.md). #### Handle queues with Horizon [Laravel Horizon](https://laravel.com/docs/master/horizon#main-content) provides an appealing dashboard and code-driven configuration for your Laravel powered Redis queues. Horizon allows you to monitor key metrics of your queue system, such as job throughput, runtime, and job failures. ###### 1. Add Laravel Horizon **Note**: This procedure assumes you have followed the steps on [how to configure Redis and queues](https://docs.upsun.com/get-started/stacks/laravel/setup-redis.md#5-use-redis-for-laravel-queues). 1. To add Laravel Horizon, run the following command: ```bash {location="Terminal"} composer require laravel/horizon && php artisan horizon:install ``` 2. Add the `install` command to your `build` hook in your app configuration, so it's run on every deploy. ```yaml {location=".upsun/config.yaml"} applications: myapp: [...] hooks: build: | set -eux composer --no-ansi --no-interaction install --no-progress --prefer-dist --optimize-autoloader --no-dev php artisan horizon:install ``` ###### 2. Create a worker to run Horizon To run Horizon on your project, you need to add a separate [worker](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#workers). To do so, use the following configuration: ```yaml {location=".upsun/config.yaml"} applications: myapp: [...] workers: horizon: commands: start: | php artisan horizon ``` To enable the worker, push your changes to Upsun: ```bash {location="Terminal"} git add . git commit -m "Enable Laravel Horizon" upsun push ``` A new container is started automatically. It will spawn the Horizon process after the next deploy. ###### 3. Access your Horizon dashboard If you have restricted access to Horizon in your `HorizonServiceProvider.php`, log in to your app through the web. Then, go to `/horizon` to access your Horizon dashboard. ![Laravel Horizon Dashboard](https://docs.upsun.com/images/guides/laravel/horizon-dashboard.png "0.5") ###### 4. Optional: Customize Horizon Horizon handles jobs that are populated by the queue. If you need to customize how Horizon works (queues, processes, etc.), see the official [Laravel Horizon documentation](https://laravel.com/docs/master/horizon#main-content). **Warning**: Web and worker containers don’t share mount targets. You can’t share files between those containers using the filesystem. To share data between containers, use [services](https://docs.upsun.com/add-services.md). See more information on [workers](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#workers). Note that you can customize the resources of your Horizon worker container from the Upsun Console. ![Laravel Horizon Resources](https://docs.upsun.com/images/guides/laravel/horizon-resources.png "0.5") For more information, see how to [configure resources](https://docs.upsun.com/manage-resources/adjust-resources.md). #### Set up cron jobs Cron jobs allow you to run scheduled tasks at specified times or intervals. While you can run your own custom tasks, Laravel provides a scheduler to simplify the implementation. To implement it, see the Laravel [Task Scheduling documentation](https://laravel.com/docs/master/scheduling). ###### Set up a cron job To set up a cron job, update your Upsun configuration as follows: ```yaml {location=".upsun/config.yaml"} applications: myapp: [...] crons: snapshot: spec: * * * * * commands: start: | php artisan schedule:run >> /dev/null 2>&1 ``` ###### Run cron jobs based on environment type To run a command in a cron hook for specific environment types, use the `PLATFORM_ENVIRONMENT_TYPE` environment variable: ```yaml {location=".upsun/config.yaml"} applications: myapp: [...] crons: snapshot: spec: 0 5 * * * commands: start: | # only run for the production environment, aka main branch if [ "$PLATFORM_ENVIRONMENT_TYPE" = "production" ]; then php artisan schedule:run >> /dev/null 2>&1 fi ``` ###### Run the Laravel scheduler every minute Cron job execution on the default Upsun offering are limited to once every 5 minutes. For more information, see the [documentation on crons](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#crons). However, you can add a [worker](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#workers) and specify a start command that [runs the scheduler every minute](https://laravel.com/docs/11.x/scheduling#running-the-scheduler-locally). To do so, use the following configuration: ```yaml {location=".upsun/config.yaml"} applications: : [...] workers: scheduler: commands: start: | php artisan schedule:work ``` **Warning**: Web and worker containers don’t share mount targets. You can’t share files between those containers using the filesystem. To share data between containers, use [services](https://docs.upsun.com/add-services.md). #### Manage continous observability with Blackfire [Blackfire.io](https://docs.upsun.com/increase-observability/application-metrics/blackfire.md) is the recommended solution for monitoring and profiling web sites and apps. Blackfire works seamlessly with any app built with Laravel. Blackfire PHP SDK provides the following [integrations with Laravel](https://docs.blackfire.io/php/integrations/laravel/index): - [Laravel Artisan](https://docs.blackfire.io/php/integrations/laravel/artisan) - [Laravel Horizon and queue services](https://docs.blackfire.io/php/integrations/laravel/horizon) - [Laravel Tests](https://docs.blackfire.io/php/integrations/laravel/tests) - [Laravel Octane](https://docs.blackfire.io/php/integrations/laravel/octane) Please refer to the [Blackfire documentation](https://docs.blackfire.io/testing-cookbooks/tests#the-code-blackfire-yaml-code-file) to set up a `.blackfire.yml` configuration to enable custom [performance tests](https://docs.blackfire.io/testing-cookbooks/index) and automated [builds](https://docs.blackfire.io/builds-cookbooks/index). #### Debug with Laravel Telescope Laravel Telescope complements your local Laravel development environment. With Telescope, get insight into the requests coming into your app, exceptions, log entries, database queries, queued jobs, mail, notifications, cache operations, scheduled tasks, variable dumps, and more. To set up Laravel Telescope on your **non-production** environments, follow these steps. ###### 1. Create the APP_DEBUG variable To add the `APP_DEBUG` & `TELESCOPE_ENABLED` variables on your project, run the following commands: ```bash {location="Terminal"} upsun variable:create --level environment --name env:APP_DEBUG --value false upsun variable:create --level environment --name env:TELESCOPE_ENABLED --value false ``` Note that the default values for your main environment are set to `false`. To override them on other non-production environments, run the following commands: ```bash {location="Terminal"} upsun variable:update -e --value true env:APP_DEBUG upsun variable:update -e --value true env:TELESCOPE_ENABLED ``` ###### 2. Add Telescope to your project 1. Run the following Composer command: ```bash {location="Terminal"} composer require laravel/telescope && php artisan telescope:install ``` 2. Add the `install` command to your `build` hook in your app configuration, so it's run on every deploy. ```yaml {location=".upsun/config.yaml"} applications: myapp: [...] hooks: build: | set -eux composer --no-ansi --no-interaction install --no-progress --prefer-dist --optimize-autoloader --no-dev php artisan telescope:install ``` For more options and information on how to manage authentication for the dashboard, see the [Laravel Telecope documentation](https://laravel.com/docs/master/telescope#installation). ###### 3. Deploy the new release To enable Telescope, push your changes to Upsun: ```bash {location="Terminal"} git add . git commit -m "Enable Laravel Horizon" upsun push ``` You can now access the `/telescope` endpoint of your app. ![Laravel Horizon Dashboard](https://docs.upsun.com/images/guides/laravel/telescope-dashboard.png "0.5") **Note**: Telescope uses a gate defined in ``TelescopeServiceProvider.php`` to authorize access to the dashboard. Check that the logic here matches your needs. #### FAQ ###### How can I access my application logs? To display the application log file (`/var/log/app.log` file), run the following command: ```bash upsun log app --tail ``` All the log messages generated by your app are sent to this `/var/log/app.log` file. This includes language errors such as PHP errors, warnings, notices, as well as uncaught exceptions. The file also contains your application logs if you log on `stderr`. This log doesn't include the default `laravel.log` located in `/storage`. **Note**: Upsun manages the ``app.log`` file for you. This is to prevent disks from getting filled and using very fast local drives instead of slower network disks. Make sure your apps always output their logs to ``stderr``. With Laravel, you can change your logging configuration to use `memory` and stream `php://stderr`. In your `config/logging.php` file, add or update the following configuration: ```php {location="config/logging.php"} 'memory' => [ 'driver' => 'monolog', 'handler' => Monolog\Handler\StreamHandler::class, 'with' => [ 'stream' => 'php://stderr', ], 'processors' => [ // Simple syntax... Monolog\Processor\MemoryUsageProcessor::class, // With options... [ 'processor' => Monolog\Processor\PsrLogMessageProcessor::class, 'with' => ['removeUsedContextFields' => true], ], ], ], ``` **Warning**: If you log deprecations, make sure you **also** log them on ``stderr``. ###### What's this "`Oops! An Error Occurred`" message about? The `Oops! An Error Occurred` message comes from your app and is automatically generated based on the Laravel error template. ####### The server returned a "`500 Internal Server Error`" If your app's working as expected locally but you see the previous error message on Upsun, it usually means you have a configuration error or a missing dependency. To fix this issue, search your application logs. They likely contain an error message describing the root cause: ```bash upsun logs all [app] [14-Aug-2020 10:52:27 UTC] [critical] Uncaught PHP Exception Exception: [...] [app] [php.access] 2020-08-14T10:52:27Z GET 500 2.386 ms 2048 kB 419.11% / [access] 78.247.136.119 - - [14/Aug/2020:10:52:27 +0000] "GET / HTTP/1.1" 500 843 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36" ``` If the error occurs on a preview environment, or on the main environment of a non-production project, you can also enable Laravel's dev/debug mode to inspect the cause of the error via the `APP_DEBUG` [environment variable](https://docs.upsun.com/get-started/stacks/laravel/environment-variables.md) in your `.environment` file or via [upsun console](https://docs.upsun.com/development/variables.md): ```bash # Enable debug mode export APP_DEBUG=1 # Disable debug mode export APP_DEBUG=0 ``` ###### Other issues For other issues unrelated to Laravel, see [Troubleshoot development](https://docs.upsun.com/development/troubleshoot.md). [Back](https://docs.upsun.com/get-started/stacks/laravel/laravel-telescope.md) ### Deploy Magento on Platform.sh Before attempting to deploy Magento on Upsun, you **must complete the [Getting started guide](https://docs.upsun.com/get-started/here)**. You can also **check out the [Upsun demo app](https://console.upsun.com/projects/create-project)** and [Resource configuration guide](https://docs.upsun.com/manage-resources/adjust-resources.md). These provide all of the core concepts and common commands you need to easily follow this Magento guide. ##### Before you begin You need: - [Git](https://git-scm.com/downloads). Git is the primary tool to manage everything your app needs to run. Push commits to deploy changes and control configuration through YAML files. These files describe your infrastructure, making it transparent and version-controlled. - A Upsun account. If you don't already have one, [register for a trial account](https://auth.upsun.com/register). You can sign up with an email address or an existing GitHub, Bitbucket, or Google account. If you choose one of these accounts, you can set a password for your Upsun account later. - The [Upsun CLI](https://docs.upsun.com/administration/cli.md). This lets you interact with your project from the command line. You can also do most things through the [Web Console](https://docs.upsun.com/administration/web.md). **Authentication**: You will not need Adobe Commerce authentication keys for this process but if you would like to learn how to set them up if you want to adjust the Composer repository to [https://repo.magento.com/](https://repo.magento.com/), visit [Adobe Commerce Authentication](https://experienceleague.adobe.com/en/docs/commerce-on-cloud/user-guide/develop/authentication-keys). We will be using the [Upsun Magento example project](https://github.com/platformsh-templates/magentoCE24/blob/main/README.md) for this deployment process. The example specifically features: - PHP 8.3 - MariaDB 10.6 - Redis 7.2 - OpenSearch 2 - RabbitMQ 3.13 - Automatic TLS certificates - Composer-based build The example also features an [Upsun config.yaml](https://github.com/platformsh-templates/magentoCE24/blob/main/.upsun/config.yaml) file. Below is a **shortened example** of the config.yaml file: ```yaml {filename=".upsun/config.yaml"} applications: app: # The runtime the application uses. type: php:8.3 # Specify additional PHP extensions that should be loaded. runtime: extensions: - xsl - sodium - redis - blackfire variables: env: NVM_VERSION: master NODE_VERSION: 20 MAGENTO_DC_INDEXER__USE_APPLICATION_LOCK: true MAGENTO_INDEXER_BATCH_SIZE__CATALOGINVENTORY_STOCK__SIMPLE: 200 MAGENTO_INDEXER_BATCH_SIZE__CATALOG_CATEGORY_PRODUCT: 666 MAGENTO_INDEXER_BATCH_SIZE__CATALOGSEARCH_FULLTEXT__PARTIAL_REINDEX: 100 MAGENTO_INDEXER_BATCH_SIZE__CATALOGSEARCH_FULLTEXT__MYSQL_GET: 500 MAGENTO_INDEXER_BATCH_SIZE__CATALOGSEARCH_FULLTEXT__ELASTIC_SAVE: 500 MAGENTO_INDEXER_BATCH_SIZE__CATALOG_PRODUCT_PRICE__SIMPLE: 200 MAGENTO_INDEXER_BATCH_SIZE__CATALOG_PRODUCT_PRICE__DEFAULT: 500 MAGENTO_INDEXER_BATCH_SIZE__CATALOG_PRODUCT_PRICE__CONFIGURABLE: 666 MAGENTO_INDEXER_BATCH_SIZE__CATALOGPERMISSIONS_CATEGORY: 999 MAGENTO_INDEXER_BATCH_SIZE__INVENTORY__SIMPLE: 210 MAGENTO_INDEXER_BATCH_SIZE__INVENTORY__DEFAULT: 510 MAGENTO_INDEXER_BATCH_SIZE__INVENTORY__CONFIGURABLE: 616 php: memory_limit: "512M" ... ``` ##### Create project Copy and run the following command in command line: `upsun project:create --init-repo https://github.com/platformsh-templates/magentoCE24/` You will then have to make the following selections: - Select an organization to create the project under - Select a title for your project - Select a [region to deploy from](https://docs.upsun.com/development/regions.md#regions) - Select your default branch - Select whether you would like to set your new project as the remote for any existing repositories that have been detected under your organization Once you have made your selections, the Upsun bot will activate your project. When your project is created, you will be provided with the following details to access it: - `Region` - `Project ID` - `Project title` - `Project URL` - `Git URL` ##### Configure resources Copy the Project URL into your browser. You should see your newly created project in the Upsun console. For example, if you had named your Magento project `Mage`, you would see something similar to the screenshot below: ![Your magento project in the Upsun console](https://docs.upsun.com/images/guides/magento/mage-console-1.png) You will be prompted to configure your resources. At this stage you can select the CPU, RAM, instances and disk size for your Magento project. ![Configure the resources for your Magento project in the Upsun console](https://docs.upsun.com/images/guides/magento/configure-mage-resources.png) ###### Recommended configurations You will see that the `container_profile` for the app container is using the `BALANCED` profile by default. The standard CPU & RAM recommendation for your app container is a minimum of `0.5 CPU, 1088MB RAM`. Please see the table below for all **recommended minimum settings for your app container**: | CPU & RAM | Instances | Disk/storage | | ---------------------| ---------- | ------------ | | `0.5 CPU, 1088MB RAM`| No minimum | `256MB` | All other services will be using their [default container profiles](https://docs.upsun.com/manage-resources/adjust-resources.md#advanced-container-profiles) and therefore can be set to `0.1 CPU`, so the above values only apply as recommended minimums for your app container. Once your project is deployed, you may need to [adjust your resources](https://docs.upsun.com/manage-resources/adjust-resources.md) and [adjust the container profiles](https://docs.upsun.com/manage-resources/adjust-resources.md#adjust-a-container-profile) of your other services. **Note**: Please note that the deployment after configuring resources may take up to 25 minutes. ##### View your log Now that your resources have been configured, you can view a log of how Upsun creates your project. In the recents section, click the three dots to the right of the activity about your `updated resource allocation on Main`. ![Navigate to the log to see your Magento project being created](https://docs.upsun.com/images/guides/magento/log-console-1.png) Below is a **shortened example** of what your log would look like: ``` Configuring resources Setting 'app' resources to 0.5 CPU, 1088MB RAM. Setting 'app' disk to 256MB. Setting 'db' resources to 0.1 CPU, 448MB RAM. Setting 'db' disk to 256MB. Setting 'cache' resources to 0.1 CPU, 352MB RAM. Setting 'session' resources to 0.1 CPU, 352MB RAM. Setting 'session' disk to 256MB. Setting 'indexer' resources to 0.1 CPU, 448MB RAM. Setting 'indexer' disk to 256MB. Setting 'queue' resources to 0.1 CPU, 448MB RAM. Setting 'queue' disk to 256MB. Building application 'app' (runtime type: php:8.3, tree: 392d8f3) Generating runtime configuration. Installing build dependencies... ... Environment configuration app (type: php:8.3, cpu: 0.1, memory: 64, disk: 1024) db (type: mariadb:10.6, cpu: 0.1, memory: 448, disk: 256) cache (type: redis:7.2, cpu: 0.1, memory: 352) session (type: redis-persistent:7.2, cpu: 0.1, memory: 352, disk: 256) indexer (type: opensearch:2, cpu: 0.1, memory: 448, disk: 256) queue (type: rabbitmq:3.13, cpu: 0.1, memory: 448, disk: 256) Environment routes http://main-bvxea6i-g7baduaayq63y.eu-5.platformsh.site/ redirects to https://main-bvxea6i-g7baduaayq63y.eu-5.platformsh.site/ http://main-bvxea6i-g7baduaayq63y.eu-5.platformsh.site/static/ redirects to https://main-bvxea6i-g7baduaayq63y.eu-5.platformsh.site/static/ https://main-bvxea6i-g7baduaayq63y.eu-5.platformsh.site/ is served by application `app` https://main-bvxea6i-g7baduaayq63y.eu-5.platformsh.site/static/ is served by application `app` ``` ##### Preview your Magento project Now that your Magento project has been successfully created, you will see the standard Magento layout when you navigate to your preview link: ![Your magento project in preview mode](https://docs.upsun.com/images/guides/magento/preview-mage.png) ##### Fetch your Magento project locally First, get your project ID by clicking the three dots in the upper right hand of your console, next to the settings cog wheel. Your project ID will appear in a drop down menu. ![Your project ID in console](https://docs.upsun.com/images/guides/magento/project-id-mage-1.png) Copy the following command into your command line. ```upsun get ``` Make sure to replace `` with the Project ID you just copied from console. Once you run the command in command line, you will be asked if you want to set the remote project for any existing repositories to your project. You will also need to specify a directory for your project to be stored in when downloaded. Once your project has successfully downloaded, you will be able to access it locally by navigating to the directory you chose. ##### Further resources ###### Documentation - [PHP documentation](https://docs.upsun.com/languages/php/) - [Authenticated Composer repositories](https://docs.upsun.com/languages/php/composer-auth) - [Resource configuration guide](https://docs.upsun.com/manage-resources/adjust-resources.md) ###### Authentication - [Composer Authentication and Post Installation Setup](https://github.com/platformsh-templates/magentoCE24/blob/main/README.md#composer-authentication-and-post-installation-setup) - [Magento Repository authentication keys](https://devdocs.magento.com/guides/v2.4/install-gde/prereq/connect-auth.md) ###### Community content - [PHP topics](https://support.platform.sh/hc/en-us/search?utf8=%E2%9C%93&query=php) ### Deploy Symfony on Platform.sh **Note**: Before you start, check out the [Upsun demo app](https://console.upsun.com/projects/create-project) and the main [Getting started guide](https://docs.upsun.com/get-started/here.md). They provide all of the core concepts and common commands you need to know before using the materials below. - [Get started](https://docs.upsun.com/get-started/stacks/symfony/get-started.md) - [Symfony integration](https://docs.upsun.com/get-started/stacks/symfony/integration.md) - [Configure environment variables](https://docs.upsun.com/get-started/stacks/symfony/environment-variables.md) - [Configure workers](https://docs.upsun.com/get-started/stacks/symfony/workers.md) - [Set up cron jobs](https://docs.upsun.com/get-started/stacks/symfony/crons.md) - [Manage continous observability with Blackfire](https://docs.upsun.com/get-started/stacks/symfony/blackfire.md) - [Local development](https://docs.upsun.com/get-started/stacks/symfony/local.md) - [FAQ](https://docs.upsun.com/get-started/stacks/symfony/faq.md) - [Symfony CLI Tips](https://docs.upsun.com/get-started/stacks/symfony/symfony-cli-tips.md) ##### Further resources ###### Documentation - [PHP documentation](https://docs.upsun.com/languages/php.md) - [Extensions](https://docs.upsun.com/languages/php/extensions.md) - [Performance tuning](https://docs.upsun.com/languages/php/tuning.md) - [PHP-FPM sizing](https://docs.upsun.com/languages/php/fpm.md) - [Swoole on Upsun](https://docs.upsun.com/languages/php/swoole.md) - [Authenticated Composer](https://docs.upsun.com/languages/php/composer-auth.md) ###### Community content - [Symfony topics](https://support.platform.sh/hc/en-us/search?utf8=%E2%9C%93&query=symfony) - [PHP topics](https://support.platform.sh/hc/en-us/search?utf8=%E2%9C%93&query=php) ###### Videos - [Refactoring monolith to multi-app](https://youtu.be/5hApjWiTO1M?feature=shared) - [Upsun: From zero to scaling hero](https://youtu.be/FEFBUomV5aY?feature=shared) [Get started](https://docs.upsun.com/get-started/stacks/symfony/get-started.md) #### Get started Upsun is the official [Symfony](https://symfony.com/) PaaS. This guide provides instructions for deploying, and working with, Symfony on Upsun. ###### Before you begin You need: - [Git](https://git-scm.com/downloads). Git is the primary tool to manage everything your app needs to run. Push commits to deploy changes and control configuration through YAML files. These files describe your infrastructure, making it transparent and version-controlled. - A Upsun account. If you don't already have one, [register for a trial account](https://auth.upsun.com/register). You can sign up with an email address or an existing GitHub, Bitbucket, or Google account. If you choose one of these accounts, you can set a password for your Upsun account later. - The [Symfony CLI](https://symfony.com/download). This lets you interact with your project from the command line. You can also do most things through the [Web Console](https://docs.upsun.com/administration/web.md). **Note**: The Symfony CLI wraps the [Upsun CLI](https://docs.upsun.com/administration/cli.md) with added features related to Symfony. So when using Symfony, you can replace ``upsun `` by ``symfony upsun:`` in all of your commands. ###### 1. Create your Symfony app To get familiar with Upsun, create a new Symfony project from scratch. The present tutorial uses the [Symfony Demo](https://symfony.com/doc/current/setup.md#the-symfony-demo-application) app as an example : ```bash {location="Terminal"} symfony new --demo --upsun cd ``` The `--demo` flag pulls the [Symfony Demo skeleton](https://github.com/symfony/demo). The `--upsun` flag automatically generates the Upsun configuration file. **Note**: Alternatively, you can deploy an **existing Symfony project**. To do so, follow these steps: - To generate a sensible default Upsun configuration, run the following command from within the project’s directory: ```bash {location="Terminal"} symfony project:init --upsun ``` This generates the ``.upsun/config.yaml`` and ``php.ini`` configuration files. - Add and commit your changes: ```bash {location="Terminal"} git add .upsun/config.yaml php.ini git commit -m "Add Upsun configuration" ``` ###### 2. Create your Upsun project To create a project on Upsun, run the following command from within the project's directory: ```bash {location="Terminal"} symfony upsun:create --title PROJECT_TITLE --set-remote ``` The `--set-remote` flag sets the new project as the remote for this repository. **Tip**: You can link any repository to an existing Upsun project using the following command: ```bash {location="Terminal"} symfony upsun:set-remote ``` ###### 3. Deploy your project To deploy your project, run the following command: ```bash {location="Terminal"} symfony upsun:deploy ``` During deployment, the logs from the Upsun API are displayed in your terminal so you can monitor progress. To stop the display of the logs **without interrupting the deployment**, use `CTRL+C` in your terminal. To go back to displaying the logs, run `symfony upsun:activity:log`. Congratulations, your first Symfony app has been deployed on Upsun! **Tip**: Now that your app is deployed in production mode, you can define a custom domain for your live website. To do so, see how to [set up a custom domain on Upsun](https://docs.upsun.com/administration/web/configure-project.md#domains), or run the following command: ```bash {location="Terminal"} symfony upsun:domain:add ``` ###### 4. Make changes to your project Now that your project is deployed, you can start making changes to it. For example, you might want to fix a bug or add a new feature. In your project, the main branch always represents the production environment. Other branches are for developing new features, fixing bugs, or updating the infrastructure. To make changes to your project, follow these steps: 1. Create a new environment (a Git branch) to make changes without impacting production: ```bash {location="Terminal"} symfony upsun:branch feat-a ``` This command creates a new local `feat-a` Git branch based on the main Git branch, and activates a related environment on Upsun. The new environment inherits the data (service data and assets) of its parent environment (the production environment here). 2. Make changes to your project. For example, if you created a Symfony Demo app, edit the `templates/default/homepage.html.twig` template and make the following visual changes: ```html {location="templates/default/homepage.html.twig"} {% block body %} - {{ 'title.homepage'|trans|raw }} + Welcome to the Upsun Demo ``` 3. Add and commit your changes: ```bash {location="Terminal"} git commit -a -m "Update text" ``` 4. Deploy your changes to the `feat-a` environment: ```bash {location="Terminal"} symfony upsun:deploy ``` Note that each environment has its own domain name. To view the domain name of your new environment, run the following command: ```bash {location="Terminal"} symfony upsun:url --primary ``` 5. Iterate by changing the code, committing, and deploying. When satisfied with your changes, merge them to the main branch, deploy, and remove the feature branch: ```bash {location="Terminal"} git checkout main git merge feat-a symfony environment:delete feat-a git branch -d feat-a symfony upsun:deploy ``` Note that deploying to production is fast because the image built for the `feat-a` environment is reused. For a long running branch, keep the code up-to-date with the main branch by using `git merge main` or `git rebase main`. Also, keep the data in sync with the production environment by using `symfony upsun:env:sync`. ###### 5. Optional: Use a third-party Git provider When you choose to use a third-party Git hosting service, the Upsun Git repository becomes a read-only mirror of the third-party repository. All your changes take place in the third-party repository. Add an integration to your existing third-party repository: - [BitBucket](https://docs.upsun.com/integrations/source/bitbucket.md) - [GitHub](https://docs.upsun.com/integrations/source/github.md) - [GitLab](https://docs.upsun.com/integrations/source/gitlab.md) #### Symfony integration Symfony has a special integration with Upsun that makes it easier to use Upsun for Symfony projects. **When using the Symfony integration, you are contributing financially to the Symfony project.** The Symfony integration is automatically enabled when: - You run the `symfony new` command with the `--upsun` option - You run `symfony project:init --upsun` on an existing project to automatically generate the Upsun configuration If you already have a Upsun configuration without the Symfony integration, enable it by adding the following configuration: ```yaml {location=".upsun/config.yaml"} applications: app: hooks: build: | set -x -e curl -fs https://get.symfony.com/cloud/configurator | bash # ... ``` The **configurator** enables the following integration: - It installs some helper scripts that you can use as the [default build and deploy hook scripts](#hooks): - [`symfony-build`](#symfony-build) - [`symfony-deploy`](#symfony-deploy) - [`php-ext-install`](#php-ext-install) - It adds some [extra tools](#tools) - It defines [additional infrastructure environment variables](https://docs.upsun.com/get-started/stacks/symfony/environment-variables.md#symfony-environment-variables) and [environment variables for all services](https://docs.upsun.com/get-started/stacks/symfony/environment-variables.md#service-environment-variables) ###### Tools The **configurator** (`curl -fs https://get.symfony.com/cloud/configurator | bash`) is a script specially crafted for Upsun. It ensures that projects are always using the latest version of the following tools: - [croncape](https://docs.upsun.com/get-started/stacks/symfony/crons.md#use-croncape) for cron feedback - [Symfony CLI](https://symfony.com/download) - [Composer](https://getcomposer.org/download/) ###### Hooks The `hooks` section defines the scripts that Upsun runs at specific times of an application lifecycle: - The [build hook](https://docs.upsun.com/create-apps/hooks/hooks-comparison.md#build-hook) is run during the build process - The [deploy hook](https://docs.upsun.com/create-apps/hooks/hooks-comparison.md#deploy-hook) is run during the deployment process - The [post-deploy hook](https://docs.upsun.com/create-apps/hooks/hooks-comparison.md#post-deploy-hook) is run after the deploy hook, once the application container starts accepting connections Here's the default `hooks` section optimized for Symfony projects: ```yaml {location=".upsun/config.yaml"} applications: app: hooks: build: | set -x -e curl -s https://get.symfony.com/cloud/configurator | bash symfony-build deploy: | set -x -e symfony-deploy ``` **Warning**: As each hook is executed as a single script, a hook is considered as failed only if the final command fails. To have your hooks fail on the first failed command, start your scripts with ``set -e``. For more information, see [Hooks](https://docs.upsun.com/create-apps/hooks/hooks-comparison.md). To gain a better understanding of how hooks relate to each other when building and deploying an app, see the [Upsun philosophy](https://docs.upsun.com/learn/overview/philosophy.md). **Tip**: During the ``deploy`` or ``post_deploy`` hooks, you can execute actions for a specific environment type only. To do so, in your ``.upsun/config.yaml``file, use the ``PLATFORM_ENVIRONMENT_TYPE`` [environment variable](https://docs.upsun.com/development/variables.md)) in a condition: ```yaml {location=".upsun/config.yaml"} applications: myapp: hooks: deploy: | if [ "PLATFORM_ENVIRONMENT_TYPE" != "production" ]; then symfony console app:dev:anonymize fi ``` ####### symfony-build **symfony-build** is the script that builds a Symfony app in an optimized way for Upsun. Use it as the main build script in your `build` hook. **symfony-build** performs the following actions: - Removes the development frontend file (Symfony **Note**: The source code is cached between builds so compilation is skipped if it’s already been done. Changing the source of downloads or the version invalidates this cache. ####### Advanced Node configuration If you need to use the Node installation setup by [symfony-build](#symfony-build), use the following configuration: ```yaml {location=".upsun/config.yaml"} applications: myapp: hooks: build: | set -x -e curl -s https://get.symfony.com/cloud/configurator | bash symfony-build # Setup everything to use the Node installation unset NPM_CONFIG_PREFIX export NVM_DIR=${SPLATFORM_APP_DIR}/.nvm set +x && . "${NVM_DIR}/nvm.sh" use --lts && set -x # Starting from here, everything is setup to use the same Node yarn encore dev ``` If you want to use two different Node versions, use the following configuration instead: ```yaml {location=".upsun/config.yaml"} applications: myapp: hooks: build: | set -x -e curl -s https://get.symfony.com/cloud/configurator | bash symfony-build cd web/js_app unset NPM_CONFIG_PREFIX export NVM_DIR=${PLATFORM_APP_DIR}/.nvm NODE_VERSION=8 yarn-install # Setup everything to use the Node installation set +x && . "${NVM_DIR}/nvm.sh" use 8 && set -x # Starting from here, everything is setup to use Node 8 yarn build --environment=prod ``` #### Configure environment variables By default, Upsun exposes some [environment variables](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). If you're using the [Symfony integration](https://docs.upsun.com/get-started/stacks/symfony/integration.md), more [infrastructure environment variables](#symfony-environment-variables) related to Symfony are defined. As Symfony relies heavily on environment variables to configure application services (such as the database or the mailer DSN), the Symfony integration automatically defines [environment variables for all the services](#service-environment-variables) connected to your app. **Tip**: The code that defines these additional environment variables is part of the open-source [Symfony CLI tool](https://symfony.com/download). Check the code for [infrastructure](https://github.com/symfony-cli/symfony-cli/blob/main/envs/remote.go#L139) and [service](https://github.com/symfony-cli/symfony-cli/blob/main/envs/envs.go#L110) environment variables on GitHub. ###### Symfony environment variables Upsun exposes [environment variables](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables) about the app and its infrastructure. The Symfony integration exposes more environment variables: - `APP_ENV` is set to `prod` by default. You can manually override this value for a preview environment by setting the `SYMFONY_ENV` environment variable to `dev`, and remove it when done. - `APP_DEBUG` is set to `0` by default. You can manually override this value for a preview environment by setting the `SYMFONY_DEBUG` environment variable to `1`, and remove it when done. - `APP_SECRET` is set to the value of `PLATFORM_PROJECT_ENTROPY`, which is a random and unique value for all Upsun projects. It overrides the value configured in the `.env` file of your app. - `MAILFROM` is set to a random value. This value is used as a `From` header when using [croncape](https://docs.upsun.com/get-started/stacks/symfony/crons.md#use-croncape). - `SYMFONY_IS_WORKER` is set to `1` when the container is running in the context of a worker (instead of the main application container). - `SYMFONY_CACHE_DIR` (only available during the build hook execution): The absolute path to a subdirectory of your build cache directory. Note that the build cache directory is persisted between builds but **isn't** deployed. It’s a good place to store build artifacts, such as downloaded files that can be reused between builds. **Tip**: This directory is shared by **all** builds on **all** branches. Make sure your [build hook](https://docs.upsun.com/get-started/stacks/symfony/integration.md#hooks) accounts for that. If you need to clear the build cache directory, run the `symfony upsun:project:clear-build-cache` command. - `SYMFONY_PROJECT_DEFAULT_ROUTE_URL` (only defined at **runtime**): The default endpoint serving your project. Use this variable to avoid hard-coding domains that can be used to reach preview environments. Parts of the URL are also exposed as their own variables using the following syntax: `SYMFONY_PROJECT_DEFAULT_ROUTE_` followed by the name of the part (`SCHEME`, `DOMAIN`, `PORT`, and `PATH`). Guessing the default endpoint can prove difficult for multi-routes or multi-app projects. In such cases, the following preference order is used: 1. Project-wide route defined only by `{default}` or `{all}` (no path) 2. Project-wide route defined by `www.{default}` or `www.{all}` (no path) 3. Route for the **current application** including `{default}` or `{all}` (might include a path) 4. Route for the **current application** including `www.{default}` or `www.{all}` (might include a path) 5. First route for the current application 6. First route for the whole project When several routes match a rule, the first one wins, the user order is kept. There's no preference regarding protocols. **Tip**: If you have a multi-app project containing several publicly reachable apps, you might need to determine the current application endpoint (for webhooks for example) and the project endpoint (to send emails for example). In this case, you can use an additional ``SYMFONY_APPLICATION_DEFAULT_ROUTE_*`` set of environment variables. The same rules are applied to determine their value, but only routes matching the current application are evaluated. ###### Service environment variables When using the [Symfony integration](https://docs.upsun.com/get-started/stacks/symfony/integration.md), information about services are exposed via environment variables. To list all of the exposed environment variables, run the following command: ```bash symfony ssh -- symfony var:export --multiline ``` Each exposed environment variable is prefixed by the relationship name. For example, if you have the following [relationships](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) in your configuration: ```yaml {location=".upsun/config.yaml"} applications: myapp: relationships: database: service: securitydb endpoint: postgresql ``` The environment variables for the database service is prefixed by `DATABASE_` which is the upper-cased version of the key defined in the relationship. For example, you could have a `DATABASE_URL` environment variable. Most environment variable names are derived from the relationship and service names. But some are defined based on Symfony conventions, such as [`MAILER_DSN`](#emails). **Note**: Environment variables aren’t exposed when the build hook script is running as services aren’t available during the [build process](https://docs.upsun.com/learn/overview/build-deploy.md#the-build). ####### Emails The configuration is exposed via the following environment variables: - `MAILER_ENABLED`: 1 if outgoing emails are enabled, 0 otherwise - `MAILER_DSN`/`MAILER_URL`: The Symfony-compatible mailer URL - `MAILER_HOST`: The SMTP server host - `MAILER_PORT`: The SMTP server port - `MAILER_TRANSPORT`: The SMTP transport mode (`smtp`) - `MAILER_AUTH_MODE`: The SMTP auth mode (`plain`) - `MAILER_USER`: The SMTP server user - `MAILER_PASSWORD`: The SMTP server password Symfony Mailer automatically uses the value of `MAILER_DSN`. ####### HTTP If your project has multiple apps, the configuration is exposed via the following environment variables (where `SOME_SERVICE` is the upper-cased version of the key defined in the relationship): - `SOME_SERVICE_URL`: The full URL of the service - `SOME_SERVICE_IP`: The HTTP service IP - `SOME_SERVICE_PORT`: The HTTP service port - `SOME_SERVICE_SCHEME`: The HTTP service scheme - `SOME_SERVICE_HOST`: The HTTP service host ####### MySQL/MariaDB The [MySQL/MariaDB](https://docs.upsun.com/add-services/mysql.md) configuration is exposed via the following environment variables (where `DATABASE` is the upper-cased version of the key defined in the relationship above): - `DATABASE_URL`: The database URL (in PHP or Go format depending on your app) - `DATABASE_SERVER`: The database server - `DATABASE_DRIVER`: The database driver - `DATABASE_VERSION`: The database version - `DATABASE_HOST`: The database host - `DATABASE_PORT`: The database port - `DATABASE_NAME`: The database name - `DATABASE_DATABASE`: Alias for `DATABASE_NAME` - `DATABASE_USERNAME`: The database username - `DATABASE_PASSWORD`: The database password **Tip**: The database version and a default charset are included in the database URL. To override them, use the ``DATABASE_VERSION`` and ``DATABASE_CHARSET`` environment variables respectively. ####### PostgreSQL The [PostgreSQL](https://docs.upsun.com/add-services/postgresql.md) configuration is exposed via the following environment variables (where `DATABASE` is the upper-cased version of the key defined in the relationship): - `DATABASE_URL`: The database URL (in PHP or Go format depending on your app) - `DATABASE_SERVER`: The database server - `DATABASE_DRIVER`: The database driver - `DATABASE_VERSION`: The database version - `DATABASE_HOST`: The database host - `DATABASE_PORT`: The database port - `DATABASE_NAME`: The database name - `DATABASE_DATABASE`: Alias for `DATABASE_NAME` - `DATABASE_USERNAME`: The database username - `DATABASE_PASSWORD`: The database password **Tip**: The database version and a default charset are included in the database URL. To override them, use the ``DATABASE_VERSION`` and ``DATABASE_CHARSET`` environment variables respectively. ####### Redis The [Redis](https://docs.upsun.com/add-services/redis.md) configuration is exposed via the following environment variables (where `REDIS` is the upper-cased version of the key defined in the relationship): - `REDIS_URL`: The Redis URL - `REDIS_HOST`: The Redis host - `REDIS_PORT`: The Redis port - `REDIS_SCHEME`: The Redis scheme ####### Memcached The [Memcached](https://docs.upsun.com/add-services/memcached.md) configuration is exposed via the following environment variables (where `CACHE` is the upper-cased version of the key defined in the relationship): - `CACHE_HOST` - `CACHE_PORT` - `CACHE_IP` ####### Elasticsearch The [Elasticsearch](https://docs.upsun.com/add-services/elasticsearch.md) configuration is exposed via the following environment variables (where `ELASTICSEARCH` is the upper-cased version of the key defined in the relationship): - `ELASTICSEARCH_URL`: The full URL of the Elasticsearch service - `ELASTICSEARCH_HOST`: The Elasticsearch host - `ELASTICSEARCH_PORT`: The Elasticsearch port - `ELASTICSEARCH_SCHEME`: The Elasticsearch protocol scheme (`http` or `https`) ####### Solr The [Apache Solr](https://docs.upsun.com/add-services/solr.md) configuration is exposed via the following environment variables (where `SOLR` is the upper-cased version of the key defined in the relationship): - `SOLR_HOST`: The Solr host - `SOLR_PORT`: The Solr port - `SOLR_NAME`: The Solr name - `SOLR_DATABASE`: An alias for `SOLR_NAME` ####### RabbitMQ The [RabbitMQ](https://docs.upsun.com/add-services/rabbitmq.md) configuration is exposed via the following environment variables (where `RABBITMQ` is the upper-cased version of the key defined in the relationship): - `RABBITMQ_URL`: The RabbitMQ standardized URL - `RABBITMQ_SERVER`: The RabbitMQ server - `RABBITMQ_HOST`: The RabbitMQ host - `RABBITMQ_PORT`: The RabbitMQ port - `RABBITMQ_SCHEME`: The RabbitMQ scheme - `RABBITMQ_USER`: The RabbitMQ username - `RABBITMQ_USERNAME`: The RabbitMQ username - `RABBITMQ_PASSWORD`: The RabbitMQ password ####### MongoDB The [MongoDB](https://docs.upsun.com/add-services/mongodb.md) configuration is exposed via the following environment variables (where `MONGODB` is the upper-cased version of the key defined in the relationship): - `MONGODB_SERVER` - `MONGODB_HOST` - `MONGODB_PORT` - `MONGODB_SCHEME` - `MONGODB_NAME` - `MONGODB_DATABASE` - `MONGODB_USER` - `MONGODB_USERNAME` - `MONGODB_PASSWORD` ####### InfluxDB The [InfluxDB](https://docs.upsun.com/add-services/influxdb.md) configuration is exposed via the following environment variables (where `TIMEDB` is the upper-cased version of the key defined in the relationship): - `TIMEDB_SCHEME` - `TIMEDB_HOST` - `TIMEDB_PORT` - `TIMEDB_IP` ####### Kafka The [Apache Kafka](https://docs.upsun.com/add-services/kafka.md) configuration is exposed via the following environment variables (where `KAFKA` is the upper-cased version of the key defined in the relationship): - `KAFKA_URL` - `KAFKA_SCHEME` - `KAFKA_HOST` - `KAFKA_PORT` - `KAFKA_IP` #### Configure workers Workers (or consumers) are a great way to off-load processing in the background to make an app as fast as possible. You can implement workers in Symfony smoothly thanks to the [Messenger component](https://symfony.com/doc/current/components/messenger.md). To deploy a worker, add an entry under the `workers` section [in your app configuration](https://docs.upsun.com/create-apps/_index.md): ```yaml {location=".upsun/config.yaml"} applications: myapp: workers: mails: commands: start: symfony console messenger:consume --time-limit=60 --memory-limit=128M ``` Note that the `symfony` binary is available when you use the [Symfony integration](https://docs.upsun.com/get-started/stacks/symfony/integration.md) in your Upsun app configuration. On Upsun, worker containers run the exact same code as the web container. The container image is built only once and deployed multiple times in its own container alongside the web container. The *build* hook and dependencies might not vary but, as these containers are independent, they can be customized the same way using common properties. The values defined for the main container are used as default values. **Tip**: When the container is running in the context of a worker, the ``SYMFONY_IS_WORKER`` environment variable is defined and set to ``1``. The `commands.start` key is required. It specifies the command you can use to launch the application worker. If the command specified by the `start` key terminates, it's restarted automatically. For more information, see [Workers](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#workers). **Warning**: Web and worker containers don’t share mounts targets. So you can’t share files between those containers using the filesystem. To share data between containers, use [services](https://docs.upsun.com/add-services.md). #### Set up cron jobs Cron jobs allow you to run scheduled tasks at specified times or intervals. To set up a cron job, add a configuration similar to the following: ```yaml {location=".upsun/config.yaml"} applications: myapp: crons: snapshot: spec: 0 5 * * * commands: start: | croncape symfony ... ``` To run a command in a cron hook for specific environment types, use the `PLATFORM_ENVIRONMENT_TYPE` environment variable: ```yaml {location=".upsun/config.yaml"} applications: myapp: crons: snapshot: spec: 0 5 * * * commands: start: | # only run for the production environment, aka main branch if [ "$PLATFORM_ENVIRONMENT_TYPE" = "production" ]; then croncape symfony ... fi ``` ###### Use croncape When using the [Symfony integration](https://docs.upsun.com/get-started/stacks/symfony/integration.md), you can use `croncape` to get feedback through emails when something goes wrong. To specify which email address `croncape` must send the feedback emails to, add a `MAILTO` environment variable. To do so, run the following command: ```bash symfony var:create -y --level=project --name=env:MAILTO --value=sysadmin@example.com ``` To ensure better reliability, `croncape` sends the emails using: - `project-id@cron.noreply.platformsh.site` as the sender address (`project-id+branch@cron.noreply.platformsh.site` for non-main environments) - the provided [UpsunSMTP service](https://docs.upsun.com/get-started/stacks/symfony/environment-variables.md#emails), even if you define your own `MAILER_*` environment variables To use a custom SMTP and/or custom sender address, follow these steps: 1. To specify a sender address, define a [`MAILFROM` environment variable](https://docs.upsun.com/get-started/stacks/symfony/environment-variables.md#symfony-environment-variables). 2. Define the mandatory [environment variables to use your own email service](https://docs.upsun.com/get-started/stacks/symfony/environment-variables.md#emails). Note that only SMTP connections are supported. 3. To disable the provided SMTP service, run `symfony upsun:env:info enable_smtp false`. **Note**: To use ``croncape``, SMTP must be enabled on the environment, where the [PLATFORM_SMTP_HOST](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables) environment variable is accessible. This variable is available, and SMTP enabled, by default on all production environments. This is not the case for preview (non-production) environments, where it must be enabled with the command ``symfony cloud:env:info enable_smtp true``. #### Manage continous observability with Blackfire [Blackfire.io](https://docs.upsun.com/increase-observability/application-metrics/blackfire.md) is the recommended solution for monitoring and profiling web sites and apps. Blackfire works seamlessly with any app built with Symfony. Blackfire PHP SDK provides the following [integrations with Symfony](https://blackfire.io/docs/php/integrations/symfony/index): - [Symfony HTTPClient](https://blackfire.io/docs/php/integrations/symfony/http-client) - [Symfony Messenger](https://blackfire.io/docs/php/integrations/symfony/messenger) - [Symfony CLI Commands Monitoring](https://blackfire.io/docs/php/integrations/symfony/cli-commands-monitoring) - [Symfony Functional Tests Production](https://blackfire.io/docs/php/integrations/symfony/functional-tests) A `.blackfire.yaml` file is provided within the [Symfony Templates](https://github.com/symfonycorp/platformsh-symfony-template/blob/7.2/.blackfire.yaml) to help you bootstrap the writing of custom [performance tests](https://blackfire.io/docs/testing-cookbooks/index) and automated [builds](https://blackfire.io/docs/builds-cookbooks/index). #### Local development When you develop a Symfony project, a significant amount of work takes place locally rather than on an active Upsun environment. You want to ensure that the process of local development is as close as possible to a deployed environment. You can achieve this through various approaches. For example, you can use Symfony Server with tethered data. To do so, when testing changes locally, you can connect your locally running Symfony Server to service containers on an active Upsun environment. This methodology has several advantages: - It avoids installing anything on your local machine but PHP; - It ensures that you are using the same versions of all services on your local machine and in production. **Warning**: Never use this method on the **main** environment as changes made on your local machine will impact production data. ###### Before you begin You need: - A local copy of the repository for a project running on Upsun. You can clone an integrated source repository and set the remote branch. To do so, run ``symfony cloud:project:set-remote ``. - The [Symfony CLI](https://symfony.com/download) ###### 1. Start your Symfony Server To start your [Symfony Server](https://symfony.com/doc/current/setup/symfony_server.html) locally and display your Symfony app, run the following command: ```bash symfony server:start -d symfony open:local ``` This starts the Symfony Server and opens the app in your local browser. ###### 2. Create the tethered connection 1. Create a new environment off of production: ```bash symfony branch new-feature main ``` 2. Open an SSH tunnel to the new environment's services: ```bash symfony tunnel:open ```` This command returns the addresses for SSH tunnels to all of your services: ```bash symfony tunnel:open SSH tunnel opened to rediscache at: redis://127.0.0.1:30000 SSH tunnel opened to database at: pgsql://main:main@127.0.0.1:30001/main Logs are written to: /Users/acmeUser/.platformsh/tunnels.log List tunnels with: symfony tunnels View tunnel details with: symfony tunnel:info Close tunnels with: symfony tunnel:close Save encoded tunnel details to the PLATFORM_RELATIONSHIPS variable using: export PLATFORM_RELATIONSHIPS="$(symfony tunnel:info --encode)" ``` 3. To expose Upsun services to your Symfony app, run the following command: ```bash symfony var:expose-from-tunnel ``` This automatically configures your local Symfony app to use all your remote Upsun services (remote database, remote Redis component, etc.). To check that you're now using remote data and components from Upsun, reload your local app within your browser. 4. When you've finished your work, close the tunnels to your services by running the following command: ```bash symfony var:expose-from-tunnel --off symfony tunnel:close --all -y ``` #### FAQ ###### Why is `DATABASE_URL` not defined during the build hook? During the build hook, services are not available to avoid breaking the application that is still live. That is why the Symfony integration does not expose environment variables during the build hook. The `cache:clear` command does not need to connect to the database by default, except if you are using the Doctrine ORM and the database engine version is not set in your configuration. The version information can be set in your `.env` file or in the `doctrine.yaml` configuration file. The only important pieces of information there are the database engine and the version; everything else will be ignored. Note that the environment variables are available in the deploy hook. ###### How can I access my application logs? To display the application log file (`/var/log/app.log` file), run the following command: ```bash symfony log app --tail ``` All the log messages generated by your app are sent to this `/var/log/app.log` file. This includes language errors such as PHP errors, warnings, notices, as well as uncaught exceptions. The file also contains your application logs if you log on `stderr`. Note that Upsun manages the `/var/log/app.log` file for you. This is to prevent disks from getting filled and using very fast local drives instead of slower network disks. Make sure your apps always output their logs to `stderr`. If you use Monolog, add the following configuration to your `config/packages/prod/monolog.yaml` file: ```gitignore --- a/config/packages/prod/monolog.yaml +++ b/config/packages/prod/monolog.yaml @@ -11,7 +11,7 @@ monolog: members: [nested, buffer] nested: type: stream - path: "%kernel.logs_dir%/%kernel.environment%.log" + path: php://stderr level: debug buffer: type: buffer ``` **Warning**: If you log deprecations, make sure you **also** log them on ``stderr``. ###### What's this "Oops! An Error Occurred" message about? The *Oops! An Error Occurred* message comes from your app and is automatically generated based on the Symfony error template. ####### The server returned a "500 Internal Server Error" ![A 500 error page in production mode](https://docs.upsun.com/images/symfony/production-error-500.png "0.35") If your app's working as expected locally but you see the previous error message on Upsun, it usually means you have a configuration error or a missing dependency. To fix this issue, search your application logs. They likely contain an error message describing the root cause: ```bash symfony logs all [app] [14-Aug-2020 10:52:27 UTC] [critical] Uncaught PHP Exception Exception: [...] [app] [php.access] 2020-08-14T10:52:27Z GET 500 2.386 ms 2048 kB 419.11% / [access] 78.247.136.119 - - [14/Aug/2020:10:52:27 +0000] "GET / HTTP/1.1" 500 843 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36" ``` If the error occurs on a preview environment, or on the main environment of a non-production project, you can also enable Symfony's dev/debug mode to inspect the cause of the error: ```bash # Enable debug mode symfony env:debug # Disable debug mode symfony env:debug --off ``` ####### The server returned a "404 Not Found" By default, new Symfony apps come without controllers, which means there's no homepage to show. As a result, when you run your project locally, the following welcome page is displayed: ![The default Symfony welcome page in development mode](https://docs.upsun.com/images/symfony/new-symfony-welcome-page.png "0.45") But when you run your project on Upsun, the following error is displayed instead: ![A 404 error page in production mode](https://docs.upsun.com/images/symfony/production-error-404.png "0.35") This is because Upsun runs in production mode, leading Symfony to show a generic 404 error. To fix this issue, [create your first Symfony page](https://symfony.com/doc/current/page_creation.md). If you've already created a custom homepage, make sure you perform the following actions: 1. Commit all your files. 2. Run the `symfony deploy` command and check that the deployment is successful. ###### Other issues For other issues unrelated to Symfony, see [Troubleshoot development](https://docs.upsun.com/development/troubleshoot.md). #### Symfony CLI Tips The [Symfony CLI](https://symfony.com/download) allows you to interact with your project from the command line. It wraps the [Upsun CLI](https://docs.upsun.com/administration/cli.md) with added features related to Symfony. So when using Symfony, you can replace `upsun ` by `symfony upsun:` in all of your commands. ###### Useful Symfony CLI commands - Open the web administration console: ```bash symfony upsun:web ``` - Open the URL of the current environment: ```bash symfony upsun:url ``` - Open an SSH connection to your environment: ```bash symfony upsun:ssh ``` - Configure a project for Upsun: ```bash symfony project:init --upsun ``` - Get a list of all the domains: ```bash symfony upsun:domains ``` - Create a new environment: ```bash symfony upsun:branch new-branch ``` - Get a list of all the environments: ```bash symfony upsun:environments ``` - Push code to the current environment: ```bash symfony upsun:push ``` - Get a list of all the active projects: ```bash symfony upsun:projects ``` - Add a user to the project: ```bash symfony upsun:user:add ``` - List variables: ```bash symfony upsun:variables ``` ####### Useful commands when using Symfony with a database - Create a local dump of the remote database: ```bash symfony upsun:db:dump --relationship database ``` - Run an SQL query on the remote database: ```bash symfony upsun:sql 'SHOW TABLES' ``` - Import a local SQL file into a remote database: ```bash symfony upsun:sql < my_database_backup.sql ``` [Back](https://docs.upsun.com/get-started/stacks/symfony/faq.md) ### WordPress Upsun aims to provide sane defaults out-of-the-box, while exposing a high degree of flexibility when you are configuring your projects, environments, and applications. Because of this, you can deploy WordPress on Upsun in multiple ways, depending on your needs and requirements. **Note**: Before you start, check out the [Upsun demo app](https://console.upsun.com/projects/create-project) and the main [Getting started guide](https://docs.upsun.com/get-started/here.md). They provide all the core concepts and common commands you need to know before using the following materials. - [WordPress Composer](https://docs.upsun.com/get-started/stacks/wordpress/composer.md) - [WordPress Bedrock](https://docs.upsun.com/get-started/stacks/wordpress/bedrock.md) - [WordPress Vanilla](https://docs.upsun.com/get-started/stacks/wordpress/vanilla.md) #### Deploy Composer-based WordPress on Platform.sh **Note**: Before you start, check out the [Upsun demo app](https://console.upsun.com/projects/create-project) and the main [Getting started guide](https://docs.upsun.com/get-started/here.md). These resources provide all the core concepts and common commands you need to know before using the following materials. For WordPress to successfully deploy and operate, **after completing the [Getting started guide](https://docs.upsun.com/get-started/here.md)**, you still need to add some required files and make a few changes to your Upsun configuration. ###### Before you begin You need: - [Git](https://git-scm.com/downloads). Git is the primary tool to manage everything your app needs to run. Push commits to deploy changes and control configuration through YAML files. These files describe your infrastructure, making it transparent and version-controlled. - A Upsun account. If you don't already have one, [register for a trial account](https://auth.upsun.com/register). You can sign up with an email address or an existing GitHub, Bitbucket, or Google account. If you choose one of these accounts, you can set a password for your Upsun account later. - The [Upsun CLI](https://docs.upsun.com/administration/cli.md). This lets you interact with your project from the command line. You can also do most things through the [Web Console](https://docs.upsun.com/administration/web.md). **Assumptions**: There are many ways you can set up a WordPress site or Upsun project. The instructions on this page were designed based on the following assumptions: - You are building a composer-based WordPress site using John P Bloch’s [WordPress Composer Fork](https://github.com/johnpbloch/wordpress). - You do not have a ``composer.json`` file, or are comfortable making changes to your existing version. - You selected PHP as your runtime, and MariaDB as a service during the Getting Started guide. It’s also assumed that while using the Getting Started guide you named the project ``myapp``, which you will notice is the top-level key in all configuration below. ###### 1. Add required files To ensure you have all the required files and directories in your project, follow these steps: 1. Copy the following files from the [WordPress Composer template](https://github.com/platformsh-templates/wordpress-composer/) and add them to the root of your project: - The [composer.json](https://raw.githubusercontent.com/platformsh-templates/wordpress-composer/61da65da21039b280b588642cd329a2eb253e472/composer.json) file declares project dependencies and specifies project settings and metadata for [Composer](https://getcomposer.org/) to use - The [wp-cli.yml](https://github.com/platformsh-templates/wordpress-composer/blob/61da65da21039b280b588642cd329a2eb253e472/wp-cli.yml) file contains the configuration values, related to your site, for the [WordPress CLI](https://wp-cli.org/) to use - The [wp-config.php](https://github.com/platformsh-templates/wordpress-composer/blob/61da65da21039b280b588642cd329a2eb253e472/wp-config.php) file contains your site's base configuration details, such as database connection information 2. Optional: To support non-public plugins, add a `plugins` directory to your project. To ensure Git tracks empty folders, add a `plugins/.gitkeep` file as well. 3. Add and commit your changes. ```bash {location="Terminal"} git add . git commit -m "Add files and directory" git push ``` Now that you have pushed all the necessary files and directories to Upsun, make the following changes to your `./.upsun/config.yaml` file. ###### 2. Configure your root location Locate the `web:locations` section and update the root (`/`) location as follows: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: 'php:8.3' web: locations: "/": passthru: "/index.php" root: "wordpress" index: - "index.php" expires: 600 scripts: true allow: true rules: ^/license\.text$: allow: false ^/readme\.html$: allow: false ``` **Note**: If you’re migrating your site, you may already have a ``composer.json`` file. You may even have generated your own instead of starting from the Platform.sh template version. If so, you may also have added a [wordpress-install-dir](https://github.com/johnpbloch/wordpress-core-installer?tab=readme-ov-file#usage) for ``extras`` in your ``composer.json`` file. In this case, set ``root:`` to the name of the directory where you are installing WordPress. ###### 3. Set up a location for uploads WordPress needs a writable location to store uploaded media. To set one up, follow these steps: 1. Create the location. To do so, add a `/wp-content/uploads` location as follows: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: 'php:8.3' web: locations: "/": passthru: "/index.php" root: "wordpress" index: - "index.php" expires: 600 scripts: true allow: true rules: ^/license\.text$: allow: false ^/readme\.html$: allow: false "/wp-content/uploads": root: "wordpress/wp-content/uploads" scripts: false allow: false rules: '(?**Note**: If you have designated a different directory through the ``wordpress-install-dir`` property in your ``composer.json`` file, update the mount location accordingly. ###### 4. Install dependencies during the build hook To ensure your Composer dependencies are installed during the [build stage](https://docs.upsun.com/learn/overview/build-deploy.md#the-build), locate the `build:` section (below the `hooks:` section). Update the `build:` section as follows: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: 'php:8.3' ... hooks: build: | set -eux composer install --prefer-dist --optimize-autoloader --apcu-autoloader --no-progress --no-ansi --no-interaction rsync -a plugins/ wordpress/wp-content/plugins/ ``` You can adjust the `composer install` command to meet your specific requirements. If you aren't using the `plugins` directory to manage non-public plugins, remove the `rsync` command. ###### 5. Launch tasks during the deploy hook Some tasks need to be performed after the images for our application are built, but before the newly built application can receive requests. Therefore, the best time to launch them is during the [deploy hook](https://docs.upsun.com/learn/overview/build-deploy.md#deploy-steps). Such tasks include: - Flushing the object cache, which might have changed between current production and newly deployed changes - Running the WordPress database update procedure, in case core is being updated with the newly deployed changes - Running any due cron jobs To launch these tasks during the deploy hook, locate the `deploy:` section (below the `build:` section). Update the `deploy:` section as follows: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: 'php:8.3' ... hooks: deploy: | set -eux # Flushes the object cache wp cache flush # Runs the WordPress database update procedure wp core update-db # Runs all due cron events wp cron event run --due-now ``` ###### 6. Configure your default route Next, instruct the [router](learn/overview/structure.md#router) how to handle requests to your WordPress app. To do so, locate the `routes:` section, and beneath it, the `"https://{default}/":` route. Update the route as follows: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: 'php:8.3' ... routes: "https://{default}/": type: upstream upstream: "myapp:http" cache: enabled: true cookies: - '/^wordpress_*/' - '/^wp-*/' ``` Matching the application name `myapp` with the `upstream` definition `myapp:http` is the most important setting to ensure at this stage. If these strings aren't the same, the WordPress deployment will not succeed. ###### 7. Update your MariaDB service relationship You need to update the name used to represent the [relationship](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) between your app and your MariaDB service. To do so, locate the `relationships:` top-level property. Update the relationship for the database service as follows: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: 'php:8.3' # ... relationships: database: "mariadb:mysql" ``` You can now commit all the changes made to `.upsun/config.yaml` and push to Upsun. ```bash {location="Terminal"} git add . git commit -m "Add changes to complete my Upsun configuration" git push ``` ###### Further resources ####### Documentation - [PHP documentation](https://docs.upsun.com/languages/php.md) - [Extensions](https://docs.upsun.com/languages/php/extensions.md) - [Performance tuning](https://docs.upsun.com/languages/php/tuning.md) - [PHP-FPM sizing](https://docs.upsun.com/languages/php/fpm.md) - [Authenticated Composer](https://docs.upsun.com/languages/php/composer-auth.md) ####### Community content - [PHP topics](https://support.platform.sh/hc/en-us/search?utf8=%E2%9C%93&query=php) - [WordPress topics](https://support.platform.sh/hc/en-us/search?utf8=%E2%9C%93&query=wordpress) ####### Blogs - [To Upsun, a WordPress migration story](https://upsun.com/blog/to-upsun-a-wordpress-migration-story/) #### Deploy Bedrock-based WordPress on Platform.sh **Note**: Before you start, check out the [Upsun demo app](https://console.upsun.com/projects/create-project) and the main [Getting started guide](https://docs.upsun.com/get-started/here.md). They provide all the core concepts and common commands you need to know before using the following materials. For WordPress to successfully deploy and operate, **after completing the [Getting started guide](https://docs.upsun.com/get-started/here.md)**, you still need to add some required files and make a few changes to your Upsun configuration. ###### Before you begin You need: - [Git](https://git-scm.com/downloads). Git is the primary tool to manage everything your app needs to run. Push commits to deploy changes and control configuration through YAML files. These files describe your infrastructure, making it transparent and version-controlled. - A Upsun account. If you don't already have one, [register for a trial account](https://auth.upsun.com/register). You can sign up with an email address or an existing GitHub, Bitbucket, or Google account. If you choose one of these accounts, you can set a password for your Upsun account later. - The [Upsun CLI](https://docs.upsun.com/administration/cli.md). This lets you interact with your project from the command line. You can also do most things through the [Web Console](https://docs.upsun.com/administration/web.md). **Assumptions**: There are many ways you can set up a WordPress site or Upsun project. The instructions on this page were designed based on the following assumptions: - You are building a Bedrock-based WordPress site using Roots.io [Bedrock boilerplate](https://roots.io/bedrock/). - You have an existing Bedrock-based codebase or created a new Composer project using ``roots/bedrock`` during the Getting started guide. - You selected PHP as your runtime, and MariaDB as a service during the Getting Started guide. It’s also assumed that while using the Getting Started guide you named the project ``myapp``, which you will notice is the top-level key in all configuration below. ###### 1. Configure your root location Locate the `web:locations` section and update the root (`/`) location as follows: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: 'php:8.3' web: locations: "/": root: "web" # The front-controller script to send non-static requests to. passthru: "/index.php" # Wordpress has multiple roots (wp-admin) so the following is required index: - "index.php" # The number of seconds whitelisted (static) content should be cached. expires: 600 scripts: true allow: true rules: ^/composer\.json: allow: false ^/license\.txt$: allow: false ^/readme\.html$: allow: false "/wp/wp-content/cache": root: "web/wp/wp-content/cache" scripts: false allow: false "/wp/wp-content/uploads": root: "web/app/uploads" scripts: false allow: false rules: # Allow access to common static files. '(? mounts: "web/app/wp-content/cache": source: storage source_path: "cache" "web/app/uploads": source: storage source_path: "uploads" ``` ###### 3. Install dependencies during the build hook To ensure your Composer dependencies are installed during the [build stage](https://docs.upsun.com/learn/overview/build-deploy.md#the-build), locate the `build:` section (below the `hooks:` section). Update the `build:` section as follows: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: 'php:8.3' ... hooks: build: | set -eux composer install --prefer-dist --optimize-autoloader --apcu-autoloader --no-progress --no-ansi --no-interaction ``` You can adjust the `composer install` command to meet your specific requirements. ###### 4. Launch tasks during the deploy hook Once the images for our application have been built, there are a few key tasks that must be completed before our newly-built application can receive requests. These tasks include: application can receive requests. Such tasks include: - Flushing the object cache, which might have changed between current production and newly deployed changes - Running the WordPress database update procedure, in case core is being updated with the newly deployed changes - Running any due cron jobs To perform these tasks, we'll utilize the [deploy hook](https://docs.upsun.com/learn/overview/build-deploy.md#deploy-steps). Locate the `deploy:` section (below the `build:` section). Update the `deploy:` section as follows: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: 'php:8.3' ... hooks: deploy: | set -eux # Flushes the object cache wp cache flush # Runs the WordPress database update procedure wp core update-db # Runs all due cron events wp cron event run --due-now ``` ###### 5. Update App container depdencies Add the wp-cli tool and composer to your application build. Locate the `dependencies:` section that is commented out, and update it as follows: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: 'php:8.3' dependencies: php: composer/composer: '^2' wp-cli/wp-cli-bundle: "^2.4" ``` ###### 6. Configure your default route Locate the `routes:` section, and beneath it, the `"https://{default}/":` route. Update the route as follows: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: 'php:8.3' ... routes: "https://{default}/": type: upstream upstream: "myapp:http" cache: enabled: true cookies: - '/^wordpress_*/' - '/^wp-*/' ``` Matching the application name `myapp` with the `upstream` definition `myapp:http` is the most important setting to ensure at this stage. If these strings aren't the same, the WordPress deployment will not succeed. ###### 7. Update `.environment` The CLI generated a `.environment` file during the Getting started guide. Notice it has already created some environment variables for you to connect to your database service. ```bash {location=".environment"} # Set database environment variables export DB_HOST="$MARIADB_HOST" export DB_PORT="$MARIADB_PORT" export DB_PATH="$MARIADB_PATH" export DB_DATABASE="$DB_PATH" export DB_USERNAME="$MARIADB_USERNAME" export DB_PASSWORD="$MARIADB_PASSWORD" export DB_SCHEME="$MARIADB_SCHEME" export DATABASE_URL="${DB_SCHEME}://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_PATH}" ``` To configure the remaining environment variables that WordPress needs to run smoothly, follow these steps. 1. Open the `.environment` file for editing 2. Add the following at the end of the file: ```bash {location=".environment"} export WP_HOME=$(echo $PLATFORM_ROUTES | base64 --decode | jq -r 'to_entries[] | select(.value.primary == true) | .key') export WP_SITEURL="${WP_HOME}/wp" export WP_DEBUG_LOG=/var/log/app.log # Uncomment this line if you would like development versions of WordPress on non-production environments. # export WP_ENV="${PLATFORM_ENVIRONMENT_TYPE}" export AUTH_KEY="${PLATFORM_PROJECT_ENTROPY}AUTH_KEY" export SECURE_AUTH_KEY="${PLATFORM_PROJECT_ENTROPY}SECURE_AUTH_KEY" export LOGGED_IN_KEY="${PLATFORM_PROJECT_ENTROPY}LOGGED_IN_KEY" export NONCE_KEY="${PLATFORM_PROJECT_ENTROPY}NONCE_KEY" export AUTH_SALT="${PLATFORM_PROJECT_ENTROPY}AUTH_SALT" export SECURE_AUTH_SALT="${PLATFORM_PROJECT_ENTROPY}SECURE_AUTH_SALT" export LOGGED_IN_SALT="${PLATFORM_PROJECT_ENTROPY}LOGGED_IN_SALT" export NONCE_SALT="${PLATFORM_PROJECT_ENTROPY}NONCE_SALT" ``` ###### 8. Commit, Push, and Deploy! You can now commit all the changes made to `.upsun/config.yaml` and `.environment` and push to Upsun. ```bash {location="Terminal"} git add . git commit -m "Add changes to complete my Upsun configuration" upsun push -y ``` ###### Further resources - [All example files (`.environment`, `.upsun/config.yaml`)](https://github.com/upsun/snippets/tree/main/examples/wordpress-bedrock) ####### Documentation - [PHP documentation](https://docs.upsun.com/languages/php.md) - [Extensions](https://docs.upsun.com/languages/php/extensions.md) - [Performance tuning](https://docs.upsun.com/languages/php/tuning.md) - [PHP-FPM sizing](https://docs.upsun.com/languages/php/fpm.md) - [Authenticated Composer](https://docs.upsun.com/languages/php/composer-auth.md) ####### Community content - [PHP topics](https://support.platform.sh/hc/en-us/search?utf8=%E2%9C%93&query=php) - [WordPress topics](https://support.platform.sh/hc/en-us/search?utf8=%E2%9C%93&query=wordpress) ####### Blogs - [To Upsun, a WordPress migration story](https://upsun.com/blog/to-upsun-a-wordpress-migration-story/) #### Deploy Vanilla WordPress on Platform.sh **Note**: Before you start, check out the [Upsun demo app](https://console.upsun.com/projects/create-project) and the main [Getting started guide](https://docs.upsun.com/get-started/here.md). They provide all the core concepts and common commands you need to know before using the following materials. For WordPress to successfully deploy and operate, **after completing the [Getting started guide](https://docs.upsun.com/get-started/here.md)**, you still need to add some required files and make a few changes to your Upsun configuration. ###### Before you begin You need: - [Git](https://git-scm.com/downloads). Git is the primary tool to manage everything your app needs to run. Push commits to deploy changes and control configuration through YAML files. These files describe your infrastructure, making it transparent and version-controlled. - A Upsun account. If you don't already have one, [register for a trial account](https://auth.upsun.com/register). You can sign up with an email address or an existing GitHub, Bitbucket, or Google account. If you choose one of these accounts, you can set a password for your Upsun account later. - The [Upsun CLI](https://docs.upsun.com/administration/cli.md). This lets you interact with your project from the command line. You can also do most things through the [Web Console](https://docs.upsun.com/administration/web.md). **Assumptions**: There are many ways you can set up a WordPress site or Upsun project. The instructions on this page were designed based on the following assumptions: - You selected PHP as your runtime, and MariaDB as a service during the Getting Started guide. It’s also assumed that while using the Getting Started guide you named the project ``myapp``, which you will notice is the top-level key in all configuration below. - You are currently in the same directory where you created your project during the Getting Started guide. ###### 1. Add required files To ensure you have all the required files and directories in your project, follow these steps: 1. If you haven't already, you will need to retrieve the [WordPress](https://wordpress.org/) core files. You can either download a zip archive from WordPress.org, or use `curl` to download a tarball: ```shell curl https://wordpress.org/latest -o wordpress.tar.gz ``` 2. Extract the contents of the archive. If you used curl in step 1. you can extract the contents using `tar`: ```shell tar -xvf wordpress.tar.gz ``` 3. After extracting the files from the archive, delete the archive as it no longer needed (e.g. `rm wordpress.tar.gz`) 4. Whether you downloaded the zip, or the tarball, after extraction the extracted files should be contained in a directory named `wordpress`. This directory will become your public directory later. If you decide to rename this directory, make note of it for later steps. 5. Create a `wp-config.php` file inside the directory from step 4 and copy and paste the contents from [this example file](https://github.com/upsun/snippets/blob/main/examples/wordpress-vanilla/wordpress/wp-config.php). 6. Optional: if you plan on using [wp-cli](https://wp-cli.org/), add a `wp-cli.yml` file and add the following contents to it: ```yaml path: /app/wordpress/ color: true ``` **Note**: If you changed the name of the directory at step 4 you'll need to update the `path` property above to match. 7. Add all the files from the steps above to your repository 1. `git add .` 2. `git commit -m "adds wordpress core files"` ###### 2. Update configuration files 1. Open the `.upsun/config.yaml` file created during the [Getting started guide](https://docs.upsun.com/get-started/here.md) 2. Locate the `web:locations` section and update the root (`/`) location as follows: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: 'php:8.3' web: locations: "/": passthru: "/index.php" root: "wordpress" index: - "index.php" expires: 600 scripts: true allow: true rules: ^/license\.text$: allow: false ^/readme\.html$: allow: false "/wp-content/uploads": root: "wordpress/wp-content/uploads" scripts: false allow: false rules: '(?**Note**: If you changed the name of the directory at step 1.4 you’ll need to update the ``root`` property to match for both locations. 3. Application containers are read-only by default; WordPress needs a writable location to store uploaded media. To make the location writable, set up [a mount](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#mounts). To do so, locate the `mounts:` section that is commented out, and update it as follows: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: 'php:8.3' mounts: "wordpress/wp-content/uploads": source: storage source_path: "uploads" ``` 4. Once the images for our application have been built, there are a few key tasks that must be completed before our newly-built application can receive requests. These tasks include: - Flushing the object cache, which might have changed between current production and newly deployed changes - Running the WordPress database update procedure, in case core is being updated with the newly deployed changes - Running any due cron jobs To perform these tasks, we'll utilize the [deploy hook](https://docs.upsun.com/learn/overview/build-deploy.md#deploy-steps). Locate the `deploy:` section (below the `build:` section). Update the `deploy:` section as follows: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: 'php:8.3' hooks: deploy: | set -eux # Flushes the object cache wp cache flush # Runs the WordPress database update procedure wp core update-db # Runs all due cron events wp cron event run --due-now ``` 5. Locate the `routes:` section, and beneath it, the `"https://{default}/":` route. Update the route as follows: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: 'php:8.3' ... routes: "https://{default}/": type: upstream upstream: "myapp:http" cache: enabled: true cookies: - '/^wordpress_*/' - '/^wp-*/' ``` 6. Optional: Add the wp-cli tool to your application build. Locate the `dependencies:` section that is commented out, and update it as follows: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: 'php:8.3' dependencies: php: wp-cli/wp-cli-bundle: "^2.4" ``` 7. Add and commit your changes. ```bash {location="Terminal"} git add .upsun/config.yaml git commit -m "Updates configuration file" ``` ###### 3. Update `.environment` The CLI generated a `.environment` file during the Getting started guide. Notice it has already created some environment variables for you to connect to your database service. ```bash {location=".environment"} # Set database environment variables export DB_HOST="$MARIADB_HOST" export DB_PORT="$MARIADB_PORT" export DB_PATH="$MARIADB_PATH" export DB_DATABASE="$DB_PATH" export DB_USERNAME="$MARIADB_USERNAME" export DB_PASSWORD="$MARIADB_PASSWORD" export DB_SCHEME="$MARIADB_SCHEME" export DATABASE_URL="${DB_SCHEME}://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_PATH}" ``` To configure the remaining environment variables WordPress needs to run smoothly, follow these steps. 1. Open the `.environment` file for editing 2. Add the following at the end of the file: ```bash {location=".environment"} export WP_HOME=$(echo $PLATFORM_ROUTES | base64 --decode | jq -r 'to_entries[] | select(.value.primary == true) | .key') export WP_SITEURL="${WP_HOME}wordpress" export WP_DEBUG_LOG=/var/log/app.log if [ "$PLATFORM_ENVIRONMENT_TYPE" != "production" ] ; then export WP_ENV='development' else export WP_ENV='production' fi ``` 3. Add and commit your changes: 1. `git add .environment` 2. `git commit -m "adds remaining environment variables to .environment"` ###### 4. Push and deploy Now that we've added the required files, you're ready to push your changes and deploy your WordPress site: ```bash upsun push -y ``` ###### Further resources - [All files (Upsun configuration, `.environment`, `wp-cli.yml`, `wp-config.php`)](https://github.com/upsun/snippets/tree/main/examples/wordpress-vanilla) ####### Documentation - [PHP documentation](https://docs.upsun.com/languages/php.md) - [Extensions](https://docs.upsun.com/languages/php/extensions.md) - [Performance tuning](https://docs.upsun.com/languages/php/tuning.md) - [PHP-FPM sizing](https://docs.upsun.com/languages/php/fpm.md) ####### Community content - [PHP topics](https://support.platform.sh/hc/en-us/search?utf8=%E2%9C%93&query=php) - [WordPress topics](https://support.platform.sh/hc/en-us/search?utf8=%E2%9C%93&query=wordpress) ####### Blogs - [To Upsun, a WordPress migration story](https://upsun.com/blog/to-upsun-a-wordpress-migration-story/) ### Pimcore PaaS [Pimcore](https://pimcore.com/) is an open-source digital platform that aggregates, enriches, and manages enterprise data. It provides up-to-date, consistent, and personalized experiences to customers. In a seamlessly integrated platform, Pimcore offers a centralized solution for Product Information Management, Master Data Management, Digital Asset Management, Customer Data Platforms, Digital Experience Platforms/Content Management Systems, and digital commerce. Pimcore's PaaS solution is powered by Platform.sh, creators of Upsun. For more information, see [Pimcore's documentation](https://pimcore.com/docs/platform/next/Paas/).### Shopware PaaS [Shopware](https://www.shopware.com/) is an e-commerce platform to power your online business by offering top-of-the-line performance, agility, and security. Shopware's PaaS solution is powered by Platform.sh, creators of Upsun. For more information, see [Shopware's documentation](https://developer.shopware.com/docs/products/paas/). ## Learn ### Philosophy Upsun aims at reducing configuration and making developers more productive. It abstracts your project infrastructure and manages it for you, so you never have to configure services like a web server, a MySQL database, or a Redis cache from scratch again. Upsun is built on one main idea — your server infrastructure is part of your app, so it should be version controlled along with your app. Every branch you push to your Git repository can come with bug fixes, new features, **and** infrastructure changes. You can then test everything as an independent deployment, including your application code and all of your services with a copy of their data (database entries, search index, user files, etc.). This allows you to preview exactly what your site would look like if you merged your changes to production. ##### The basics On Upsun, a **project** is linked to a Git repository and is composed of one or more **apps**. An app is a directory in your Git repository with a specific Upsun configuration and dedicated HTTP endpoints (via the `.upsun/config.yaml` file). Projects are deployed in **environments**. An environment is a standalone copy of your live app which can be used for testing, Q&A, implementing new features, fixing bugs, and so on. Every project you deploy on Upsun is built as a *virtual cluster* containing a series of containers. The main branch of your Git repository is always deployed as a production cluster. Any other branch can be deployed as a staging or development cluster. There are three types of containers within your cluster, all usually configured from a single `.upsun/config.yaml` file stored alongside your code: - The [*router*](https://docs.upsun.com/define-routes.md) is a single Nginx process responsible for mapping incoming requests to an app container, and for optionally providing HTTP caching. - One or more [*apps*](https://docs.upsun.com/create-apps.md) holding the code of your project. - Some optional [*services*](https://docs.upsun.com/add-services.md) like MySQL/MariaDB, Elasticsearch, Redis, or RabbitMQ. They come as optimized pre-built images. ##### The workflow Every time you deploy a branch to Upsun, the code is *built* and then *deployed* on a new cluster. The [**build** process](https://docs.upsun.com/learn/overview/build-deploy.md#build-steps) looks through the configuration files in your repository and assembles the necessary containers. The [**deploy** process](https://docs.upsun.com/learn/overview/build-deploy.md#deploy-steps) makes those containers live, replacing the previous versions, with no service downtime. Depending on your needs, you can also [set up a **post-deploy** hook](#add-a-post-deploy-hook) to run after your app is deployed and your application container starts accepting traffic. Adding a [`post-deploy` hook](https://docs.upsun.com/create-apps/hooks/hooks-comparison.md#post-deploy-hook) can be useful to run updates that don't require exclusive database access. Note that if you're using Gatsby to pull from a backend container on the same environment, you need a `post-deploy` hook to successfully build and deploy your app. ###### How your app is built During the [build step](https://docs.upsun.com/learn/overview/build-deploy.md#build-steps), dependencies specified in `.upsun/config.yaml` are installed on application containers. You can also customize the build step by providing a [`build` hook](https://docs.upsun.com/create-apps/hooks/hooks-comparison.md#build-hook) composed of one or more shell commands that help create your production codebase. That could be compiling TypeScript files, running some scripts, rearranging files on disk, or whatever else you want. Note that at this point all you have access to is the filesystem; there are **no services or other databases available**. Your live website is unaffected. Once the build step is completed, the filesystem is frozen and a read-only container image is created. That filesystem is the final build artifact. ###### How your app is deployed Before starting the [deployment](https://docs.upsun.com/learn/overview/build-deploy.md#deploy-steps) of your app, Upsun pauses all incoming requests and holds them to avoid downtime. Then, the current containers are stopped and the new ones are started. Upsun then opens networking connections between the various containers, as specified in `.upsun/config.yaml`. The connection information for each service is available from the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables), or the [`PLATFORM_RELATIONSHIPS` environment variable](https://docs.upsun.com/development/variables/use-variables.md). Similar to the build step, you can define a [deploy hook](https://docs.upsun.com/create-apps/hooks/hooks-comparison.md#deploy-hook) to prepare your app. Your app has complete access to all services, but the filesystem where your code lives is now read-only. Finally, Upsun opens the floodgates and lets incoming requests through your newly deployed app. ###### Add a post-deploy hook You can add a [`post-deploy` hook](https://docs.upsun.com/create-apps/hooks/hooks-comparison.md#post-deploy-hook) to be run after the build and deploy steps. Similar to the [`deploy` hook](https://docs.upsun.com/create-apps/hooks/hooks-comparison.md#deploy-hook), the `post-deploy` hook only runs once your application container accepts requests. So you can use it to run updates such as content imports or cache warmups that can be executed simultaneously with normal traffic. During a redeploy, the `post-deploy` hook is the only hook that is run. ##### Get support If you're facing an issue with Upsun, open a [support ticket](https://docs.upsun.com/learn/overview/get-support.md). ##### What's next? To get a feeling of what working with Upsun entails, see the [Get Started](https://docs.upsun.com/get-started.md) framework guides. ### YAML [YAML](https://en.wikipedia.org/wiki/YAML) is a human-readable format for data serialization across languages. This means it's a good fit for human-edited configuration files, like those at Upsun. You can control nearly all aspects of your project's build and deploy pipeline with YAML files. Learn what YAML is or, if you're already familiar, what custom tags Upsun offers. #### What YAML is [YAML](https://en.wikipedia.org/wiki/YAML) is a human-readable format for data serialization. This means it can be used for structured data, like what you can find in configuration files. Some basic rules about YAML files: - YAML files end in `.yaml`. Some other systems use the alternative `.yml` extension. - YAML is case-sensitive. - YAML is whitespace-sensitive and indentation defines the structure, but it doesn't accept tabs for indentation. - Empty lines are ignored. - Comments are preceded by an octothorpe `#`. ###### Data types YAML represents data through three primitive data structures: - Scalars (strings/numbers/booleans) - Mappings (dictionaries/objects) - Sequences (arrays/lists) ####### Scalars (strings/numbers/booleans) The most straightforward data structure involves defining key–value pairs where the values are strings or integers. So you could have a basic configuration for an app: ```yaml {location=".upsun/config.yaml"} applications: myapp: type: "golang:1.18" source: root: /app hooks: build: ./build.sh ``` You can spot three key–value pairs: | Key | Value | | ------------------- |-------------------- | | `type` | "golang:1.18" | | `root` | root: /app | | `build ` | ./build.sh | You can define strings either with or without quotes, which can be single `'` or double `"`. Quotes let you escape characters (if double) and make sure the value is parsed as a string when you want it. For example, you might be representing version numbers and want to parse them as strings. If you use `version: 1.10`, it's parsed as an integer and so is treated the same as `1.1`. If you use `version: "1.10"`, it's parsed as a string and isn't treated as the same as `1.1`. ####### Mappings (dictionaries/objects) In addition to basic scalar values, each key can also represent a set of other key–value pairs. So you can define entire dictionaries of pairs. The structure of the mapping is determined by the indentation. So children are indented more than parents and siblings have the same amount of indentation. The exact number of spaces in the indentation isn't important, just the level relative to the rest of the map. In contrast, when you define mappings, the order doesn't matter. So you could expand the configuration from before to add another mapping: ```yaml {location=".upsun/config.yaml"} applications: myapp: type: "golang:1.18" web: commands: start: ./bin/app locations: '/': passthru: true allow: false ``` This creates a `web` dictionary that has two dictionaries within it: `commands` and `locations`, each with their own mappings: - `web` → `commands` → `start: ./bin/app` - `web` → `locations` → `'/'` → `passthru: true` and `allow: false` ####### Sequences (arrays/lists) In addition to maps defining further key–value pairs, you can also use sequences to include lists of information. ```yaml {location=".upsun/config.yaml"} applications: myapp: web: locations: '/': index: - index.html - index.htm passthru: true allow: false ``` You can also define sequences using a flow syntax: ```yaml {location=".upsun/config.yaml"} applications: myapp: web: locations: '/': index: [index.html, index.htm] passthru: true allow: false ``` In either case, you get a list of values within `index`: `web` → `locations` → `'/'` → `index` → `index.html` and `index.htm` ###### Define multi-line strings If you have a long string that spans multiple lines, use a pipe `|` to preserve line breaks. The new lines need to have at least the same indentation as the first (you can add more indentation that's then preserved). So you could add a multi-line string to a `build` key in the `hooks` map: ```yaml {location=".upsun/config.yaml"} applications: myapp: hooks: build: | set -x -e cp a.txt b.txt ``` And the resulting value preserves the line break. This lets you do things like enter small shell scripts within a YAML file. `hooks` → `build` → `set -x -e` and `cp a.txt b.txt` ###### Reuse content YAML supports internal named references, known as anchors, which can be referenced using an alias. This allows you to reuse YAML blocks in multiple places within a single file. Define an anchor by adding `&` to the start of a value, where `` is a unique identifier. The anchor represents this entire value. Then refer to the anchor using `*`. The following example shows 4 different workers: ```yaml {location=".upsun/config.yaml"} applications: myapp: # ... workers: queue1: &runner commands: start: python queue-worker.py queue2: *runner queue3: <<: *runner ``` All of the workers above are identical to each other. Note that you need to place an alias with `<<:` at the same level as the other keys within that value. ###### What's next - See what Upsun makes possible with [custom tags](https://docs.upsun.com/learn/overview/yaml/platform-yaml-tags.md). - Read everything that's possible with YAML in the [YAML specification](https://yaml.org/spec/1.2.2/). - See a [YAML file that explains YAML syntax](https://learnxinyminutes.com/docs/yaml/). #### Platform.sh YAML structure In addition to the [basic functions you should be familiar with](https://docs.upsun.com/learn/overview/yaml/what-is-yaml.md), YAML structure is important. Upsun accepts a specific structure for YAML configuration files. ###### YAML file location When you run the [`upsun project:init` command](https://docs.upsun.com/get-started/here/configure.md), a default ``config.yaml`` file is generated in the `.upsun` folder. It contains the minimum default configuration based on your detected local stack. This YAML file is located in your ``.upsun`` directory, at the root of your project source code, and is a good starting point before customization. ```bash . ├── .upsun | └── config.yaml └── ``` ###### Mandatory top-level keys In the ``config.yaml`` file, there are only three mandatory top-level YAML keys: - ``applications``: this section of the file contains all of your [app definitions](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md) - ``routes``: this section of the file contains all of your [route definitions](https://docs.upsun.com/define-routes.md) (for each of your apps) - ``services``: this section of the file contains all of your [service definitions](https://docs.upsun.com/add-services.md) (for each of your apps) This looks like: ```yaml {location="apps"} applications: myapp: ... services: mariadb: type: mariadb:10.6 # All available versions are: 10.6, 10.5, 10.4, 10.3 routes: "https://{default}/": type: upstream upstream: "myapp:http" ``` Below these three top-level key sections, you can use any of the [available YAML tags](https://docs.upsun.com/learn/overview/yaml/platform-yaml-tags.md) you need. **Note**: Any YAML files located at the first level of your ``.upsun`` folder, at the root of your project source code, are taken in account. See [Rules on YAML files](#rules-on-yaml-files). ###### Rules on YAML files The following rules apply to YAML files contained in the ``.upsun`` folder: - All the existing YAML files located at the first level of the ``.upsun`` folder are taken into account. - All the existing YAML files located at the first level of the ``.upsun`` folder must feature the [mandatory top-level keys](#mandatory-top-level-keys), and must contain a [valid YAML configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md). - All the YAML files in subdirectories of the ``.upsun`` folder need to be [manually imported](https://docs.upsun.com/learn/overview/yaml/platform-yaml-tags.md#include) and contain a [valid YAML configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md). **Warning**: When Upsun combines all the YAML files located at the first level of the ``.upsun`` folder, only the top-level keys (``applications``, ``services``, and ``routes``) are merged. So if you define an app named ``myapp`` in two different YAML files, Upsun only takes the second one into account. Example: ```yaml {location=".upsun/app.yaml"} applications: myapp: type: nodejs:16 source: root: folder1 ... ``` ```yaml {location=".upsun/app-bis.yaml"} applications: myapp: type: nodejs:20 build: flavor: none ... ``` Once Upsun has combined the two configuration files, the blended configuration will be the following: ```yaml {location="YAML config result"} applications: myapp: type: nodejs:20 build: flavor: none ... ``` Note that ``source.root`` (and any other ``.upsun/app.yaml`` parameters) will not be included in the final configuration. #### Platform.sh YAML tags In addition to the [basic functions you should be familiar with](https://docs.upsun.com/learn/overview/yaml/what-is-yaml.md), YAML allows for special tags. Upsun accepts certain custom tags to facilitate working with configuration files. These tags work with Upsun configuration files, but may not elsewhere. ###### Include Use the `!include` tag to embed external files within a given YAML file. The tag requires two properties: | Property | Type | Possible values | Description | | -------- | -------- | ----------------------------- | ----------- | | `type` | `string` | `string`, `binary`, or `yaml` | See the descriptions of [strings](#string), [binaries](#binary), and [YAML](#yaml). Defaults to `yaml`. | | `path` | `string` | | The path to the file to include, relative to the application directory or `source.root`. | **Note**: By default, ``path`` is relative to the current application’s directory (what you would define with ``source.root``). It is possible to include files from a directory parent to the folder however. For example, for the following project structure: ```bash {} . ├── .upsun |   └── .upsun/config.yaml ├── backend │   ├── main.py │   ├── requirements.txt │   └── scripts │   ├── ... │   └── common_build.sh └── frontend    ├── README.md    ├── package-lock.json    ├── package.json    ├── public    ├── scripts    │   └── clean.sh    └── src ``` This configuration is valid: ```yaml {location=".upsun/config.yaml"} applications: frontend: source: root: frontend # ... hooks: build: !include type: string path: ../backend/scripts/common_build.sh ``` ####### `string` Use `string` to include an external file inline in the YAML file as if entered as a multi-line string. For example, if you have a build hook like the following: ```yaml {location=".upsun/config.yaml"} applications: myapp: hooks: build: | set -e cp a.txt b.txt ``` You could create a file for the script: ```text {location="build.sh"} set -e cp a.txt b.txt ``` And replace the hook with an include tag for an identical result: ```yaml {location=".upsun/config.yaml"} applications: myapp: hooks: build: !include type: string path: build.sh ``` This helps you break longer configuration like build scripts out into a separate file for easier maintenance. Even if ``path`` is relative to the current application's directory, it is also possible to include a shell script from a directory parent to the folder however. For example, for the following project structure: ```bash . ├── .upsun |   └── config.yaml ├── backend │   ├── main.py │   ├── requirements.txt │   └── scripts │   ├── ... │   └── common_build.sh └── frontend    ├── README.md    ├── package-lock.json    ├── package.json    ├── public    ├── scripts    │   └── clean.sh    └── src ``` This configuration is valid: ```yaml {location=".upsun/config.yaml"} applications: frontend: source: root: frontend # ... hooks: build: !include type: string path: ../backend/scripts/common_build.sh ``` **Note**: Please note that Upsun will execute this ``../backend/scripts/common_build.sh`` script using [Dash](https://wiki.archlinux.org/title/Dash). ####### `binary` Use `binary` to include an external binary file inline in the YAML file. The file is base64 encoded. For example, you could include a `favicon.ico` file in the same folder as your app configuration. Then you can include it as follows: ```yaml {location=".upsun/config.yaml"} some-property: favicon: !include type: binary path: favicon.ico ``` ####### `yaml` Use `yaml` to include an external YAML file inline as if entered directly. Because `yaml` is the default, you can use it without specifying the type. For example, you could have your configuration for works defined in a `worker.yaml` file: ```yaml {location="worker.yaml"} commands: start: python queue-worker.py variables: env: type: worker ``` Then the following three configurations are exactly equivalent: ```yaml {location=".upsun/config.yaml"} workers: queue1: !include "worker.yaml" ``` ```yaml {location=".upsun/config.yaml"} workers: queue1: !include type: yaml path: 'worker.yaml' ``` ```yaml {location=".upsun/config.yaml"} workers: queue1: commands: start: python queue-worker.py variables: env: type: worker ``` This can help simplify more complex files. For [multiple application](https://docs.upsun.com/create-apps/multi-app.md) project, you can also include another ``.upsun/apps/my-app.yaml`` file in the main `.upsun/config.yaml`. ```yaml {location=".upsun/apps/my-app.yaml"} source: root: "/" type: "nodejs:18" web: commands: start: "node index.js" upstream: socket_family: tcp locations: "/": passthru: true ``` and including it: ```yaml {location=".upsun/config.yaml"} applications: myapp: !include ./apps/my-app.yaml ``` ###### Archive Use the `!archive` tag for a reference to an entire directory specified relative to where the YAML file is. For example, you might want to define a configuration directory for your [Solr service](https://docs.upsun.com/add-services/solr.md). You might do so as follows: ```yaml {location=".upsun/config.yaml"} mysearch: type: solr:8.0 configuration: conf_dir: !archive "solr/conf" ``` The `!archive` tag means that the value for `conf_dir` isn't the string `solr/conf` but the entire `solr/conf` directory. This directory is in the `.upsun` directory, since that's where the `.upsun/config.yaml` file is. The `solr/conf` directory is then copied into the Upsun management system to use with the service. ### Structure Each environment you deploy on Upsun is built as a set of containers. Each container is an isolated instance with specific resources. Each environment has 2 to 4 types of containers, all usually configured from your `.upsun/config.yaml` file. - One [*router*](#router) - One or more [*app* containers](#apps) - Zero or more [*service* containers](#services) - Zero or more [*worker* containers](#workers) If you have two app containers, two services (a database and a search engine), and a worker, requests to your environment might look something like this: ![A user request goes to the router, which sends it to either a Node.js app or a Python app. Each app communicates separately with the database and search services and sends responses to the user. The Node.js app triggers actions in a worker, which communicates separately with the database.](https://docs.upsun.com/images/config-diagrams/structure-diagram.png) If you have only one app container, your repository might look like this: ```text project ├── .git ├── .upsun │ └── config.yaml └── ``` ##### Router Each environment always has exactly one router. This router maps incoming requests to the appropriate app container and provides basic caching of responses, unless configured otherwise. The router is configured in a `.upsun/config.yaml` file. If you don't include configuration, a single [default route is deployed](https://docs.upsun.com/define-routes.md#default-route-definition). Read more about how to [define routes](https://docs.upsun.com/define-routes.md). ##### Apps You always need at least one app container, but you can have more. App containers run the code you provide via your Git repository. They handle requests from the outside world and can communicate with other containers within the environment. Each app container is built from a specific language image with a given version for the language. To configure your apps, you usually create a single `.upsun/config.yaml` file and place it in the repository root. Read more about how to [configure apps](https://docs.upsun.com/create-apps.md). ##### Services You don't need any service containers, but you can add them as you like. Service containers run predefined code for specific purposes, such as a database or search service. You don't need to add their code yourself, just set up how your apps communicate with them. Service containers are configured by the `.upsun/config.yaml` file. Read more about how to [add services](https://docs.upsun.com/add-services.md). ##### Workers You don't need any worker containers, but you can add them as you like. Worker containers are copies of an app containers that have no access to the outside world and can have a different start command. They're useful for continually running background processes. Read more about how to [work with workers](https://docs.upsun.com/create-apps/workers.md). ### Build and deploy Each time you push a change to your app through Git or activate an [environment](https://docs.upsun.com/environments.md), your app goes through a process to be built and deployed. If your app is redeployed with no changes to its codebase, the output of the previous build and deploy process is reused. The build process looks through the configuration files in your repository and assembles the necessary containers. The deploy process makes those containers live, replacing any previous versions, with minimal interruption in service. ![The steps in the build and deploy process](https://docs.upsun.com/images/workflow/build-pipeline.svg "0.50") Hooks are points in the build and deploy process where you can inject a custom script. ##### The build The outcome of the build process is designed to be repeatable and reusable. Each app in a project is built separately. Container configuration depends exclusively on your configuration files. So each container is tied to a specific Git commit. If there are no new changes for a given container, the existing container can be reused. This saves you the time the build step would take. This means the build is independent of the given environment and preview environments are perfect copies of production. If you use environment variables to set up different build configuration options for different environments, your build step isn't reused and your preview environments may differ from production. You can't connect to services (like databases) during the build step. Once the app has gone through all of the build steps, it can connect to services in the deploy process. ###### Build steps 1. **Validate configuration**: The configuration is checked by validating the `.upsun` directory and scanning the repository for any app configuration to validate. 2. **Pull container images**: Any container images that have been built before and that don't have any changes are pulled to be reused. 3. **Install dependencies**: If you have specified additional global dependencies, they're downloaded during this step. This is useful for commands you may need in the build hook. 4. **Run build flavor commands**: For some languages (NodeJS, PHP), a series of standard commands are run based on the build flavor. You can change the flavor or skip the commands by specifying it in your `.upsun/config.yaml` file. 5. **Run build hook**: The `build` hook comprises one or more shell commands that you write to finish creating your production code base. It could be compiling Sass files, running a bundler, rearranging files on disk, or compiling. The committed build hook runs in the build container. During this time, commands have write access to the file system, but there aren't connections to other containers (services and other apps). Note that you can [cancel deployments stuck on the build hook](https://docs.upsun.com/environments/cancel-activity.md). 6. **Freeze app container**: The file system is frozen and produces a read-only container image, which is the final build artifact. ##### The deploy The deploy process connects each container from the build process and any services. The connections are defined in your app and services configuration. So unlike the build process, you can now access other containers, but the file system is read-only. ###### Deploy steps 1. **Hold requests**: Incoming [idempotent requests](https://www.iana.org/assignments/http-methods/http-methods.xhtml) (like `GET`, `PUT`, `DELETE` but **not** `POST`, `PATCH` etc.) are held. 1. **Unmount current containers**: Any previous containers are disconnected from their file system mounts. 1. **Mount file systems**: The file system is connected to the new containers. New branches have file systems cloned from their parent. 1. **Expose services**: Networking connections are opened between any containers specified in your app and services configurations. 1. **Run (pre-) start commands**: The [commands](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#web-commands) necessary to start your app are run. Often this stage will only include a start command, which is restarted if ever terminated going forward. You may also, however, define a `pre_start` command, when you need to run _per-instance_ actions. In this case, as you might expect, the `pre_start` command is run, then the `start` command. 1. **Run deploy hook**: The `deploy` hook is any number of shell commands you can run to finish your deployment. This can include clearing caches, running database migrations, and setting configuration that requires relationship information. 1. **Serve requests**: Incoming requests to your newly deployed application are allowed. After the deploy process is over, any commands in your `post_deploy` hook are run. ##### Deployment philosophy Upsun values consistency over availability, acknowledging that it's nearly impossible to have both. During a deployment, the [deploy hook](https://docs.upsun.com/create-apps/hooks/hooks-comparison.md#deploy-hook) may make database changes that are incompatible with the previous code version. Having both old and new code running in parallel on different servers could therefore result in data loss. Upsun believes that a minute of planned downtime for authenticated users is preferable to a risk of race conditions resulting in data corruption, especially with a CDN continuing to serve anonymous traffic uninterrupted. That brief downtime applies only to the environment changes are being pushed to. Deployments to a staging or development branch have no impact on the production environment and cause no downtime. ##### What's next * See how to [configure your app](https://docs.upsun.com/create-apps.md) for the entire process. * Learn more about [using build and deploy hooks](https://docs.upsun.com/create-apps/hooks.md). ### Get support Find out how to get help if you’re experiencing issues with Upsun. ##### Create a support ticket If you're experiencing issues related to the proper functioning of the Upsun infrastructure, application container software, build processes, have found possible bugs, have general questions or wish to submit a feature request, open a support ticket: 1. [Open the Console](https://console.upsun.com/) 2. Click the **Help** dropdown in the upper right-hand corner. 3. Select **Support** from the options in the dropdown. 4. Click **+ New ticket**. 5. Fill in the ticket fields and click **Submit**. Or use these shortcuts to [access all support tickets](https://console.upsun.com/-/users/~/tickets) or [open a new ticket](https://console.upsun.com/-/users/~/tickets/open). Once you submit a ticket, you see it in a list of all tickets created, for all projects you have access to, within your organization. **Note**: Note that once you submit the ticket, you can’t modify or delete the submission. If you have any additional information, you can select the submitted ticket and write a message. ##### Community To talk about app development or framework-related questions, join other customers and engineers in the [Discord](https://discord.gg/PkMc2pVCDV). Also, the [Upsun Community forum](https://community.platform.sh/) has how-to guides with suggestions on how to get the most out of Upsun. Join us on Discord Ask a question on the forum ##### Contact Sales If you have questions about pricing or need help figuring out if Upsun is the right solution for your team, get in touch with [Sales](https://upsun.com/register/). ##### Delete your account To permanently delete your Upsun account, follow these steps: **Warning**: Deleting your Upsun account automatically deletes your linked Platform.sh account, as well as any linked Ibexa Cloud, Pimcore PaaS, or Shopware PaaS accounts you may hold. 1. [Open the Console](https://console.upsun.com/). 2. Open the user menu (your name or profile picture) and select **My Profile**. 3. Click **Delete account**. 4. Check that the pre-filled information is correct and click **Submit**. 5. Read the consequences of account deletion and click **Submit request** to confirm. Your request is now submitted and will be handled by Support shortly. ### Migrate your site to Platform.sh Learn how you can migrate your site from another hosting solution to Upsun. #### From Platform.sh If you already have an app running somewhere else, you want to migrate it to Upsun and deploy it. To do so, follow these steps. ###### Before you begin You need: - An app that works and is ready to be built - Code in Git - A Upsun account -- if you don't already have one, [register](https://upsun.com/register/). - The [Upsun CLI](https://docs.upsun.com/administration/cli.md) installed locally ###### 1. Export from previous system Start by exporting everything you might need from your current app. This includes data in databases, files on a file system, and for some apps, such as Drupal, configuration that you need to export from the system into files. ###### 2. Create a project Then run the following command to create a project: ```bash {} upsun project:create ``` When prompted, fill in details like the project name, [region](https://docs.upsun.com/development/regions.md), and the name of your organization. [Create a new project from scratch](https://console.upsun.com/org/create-project/info?_utm_campaign=cta_deploy_marketplace_template&utm_source=public_documentation&_utm_medium=organic). If you do not already have an organization created to put the project, you’ll first be instructed to create one. Once you have done so, select that organization from the dropdown, and select **Create from scratch**. In the form, fill in details like the project name and [region](https://docs.upsun.com/development/regions.md). You’ll be able to define resources for the project after your first push. ###### 3. Add configuration The exact configuration you want depends on your app. You likely want to configure three areas: - [The app itself](https://docs.upsun.com/create-apps.md) -- this is the only required configuration - [Services](https://docs.upsun.com/add-services.md) - [Routes](https://docs.upsun.com/define-routes.md) When you've added your configuration, make sure to commit it to Git. ###### 4. Optional: Define a resource initialization strategy By default, when you first deploy your project, Upsun allocates [default resources](https://docs.upsun.com/manage-resources/resource-init.md) to each of your containers. If you don't want to use those default resources, define your own [resource initialization strategy](https://docs.upsun.com/manage-resources/resource-init.md#specify-a-resource-initialization-strategy) before pushing your code. Alternatively, you can [amend those default container resources](https://docs.upsun.com/manage-resources/adjust-resources.md) after your project is deployed. ###### 5. Push your code The way to push your code to Upsun depends on whether you're hosting your code with a third-party service using a [source integration](https://docs.upsun.com/integrations/source.md). If you aren't, your repository is hosted in Upsun and you can use the CLI or just Git itself. - Add Upsun as a remote repository by running the following command: ```bash {} upsun project:set-remote ``` - Push to the Upsun repository by running the following command: ```bash {} upsun push ``` When you try to push, any detected errors in your configuration are reported and block the push. After any errors are fixed, a push creates a new environment. Set up the integration for your selected service: - [Bitbucket](https://docs.upsun.com/integrations/source/bitbucket.md) - [GitHub](https://docs.upsun.com/integrations/source/github.md) - [GitLab](https://docs.upsun.com/integrations/source/gitlab.md) Then push code to that service as you do normally. Pushing to a branch creates an environment from that branch. Note that the source integration doesn’t report any errors in configuration directly. You have to monitor those in your project activities. - Add an [SSH key](https://docs.upsun.com/development/ssh/ssh-keys.md). - In the Console, open your project and click **Code **. - Click **Git**. - From the displayed command, copy the location of your repository. It should have a format similar to the following: ```text {} abcdefgh1234567@git.eu.upsun.com:abcdefgh1234567.git ``` - Add Upsun as a remote repository by running the following command: ```bash {} git remote add upsun ``` - Push to the Upsun repository by running the following command: ```bash {} git push -u upsun ``` When you try to push, any detected errors in your configuration are reported and block the push. After any errors are fixed, a push creates a new environment. ###### 6. Import data Once you have an environment, you can import the data you backed up at step 1. The exact process may depend on the service you use. For SQL databases, for example, you can use a version of this command: ```bash upsun sql < ``` For any potential more details, see the [specific service](https://docs.upsun.com/add-services.md). ###### 7. Import files Your app may include content files, meaning files that aren't intended to be part of your codebase so aren't in Git. You can upload such files to [mounts you created](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#mounts). Upload to each mount separately. Suppose you have the following mounts defined: ```yaml {location=".upsun/config.yaml"} applications: myapp: mounts: 'web/uploads': source: local source_path: uploads 'private': source: local source_path: private ``` `instance` mounts on Upsun are the equivalent of `local` mounts on Platform.sh. To ensure continuity when migrating from Platform.sh to Upsun, the `local` mount type works as an alias for the `instance` mount type. However, it is recommended to change the type of your `local` mounts to `instance` or another [supported mount type](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#define-a-mount). For example: ```yaml {location=".upsun/config.yaml"} applications: myapp: mounts: 'web/uploads': source: instance source_path: uploads 'private': source: instance source_path: private ``` Then, to upload your files, run a command similar to the following: ```bash upsun mount:upload --mount web/uploads --source ./uploads upsun mount:upload --mount private --source ./private ``` Alternatively, you can upload to your mounts using a different [SSH method](https://docs.upsun.com/development/file-transfer.md#transfer-files-using-an-ssh-client). ###### Optional: Add variables If your app requires environment variables to build properly, [add them to your environment](https://docs.upsun.com/development/variables/set-variables.md). ###### What's next Now that your app is ready to be deployed, you can do more: - [Add a domain](https://docs.upsun.com/domains/steps.md). - Set up for [local development](https://docs.upsun.com/development/local.md). - Configure [health notifications](https://docs.upsun.com/integrations/notifications.md). - For monitoring and profiling, [integrate Blackfire](https://docs.upsun.com/increase-observability/application-metrics/blackfire.md). ### Automate your code updates Upsun allows you to update your dependencies through [source operations](https://docs.upsun.com/create-apps/source-operations.md). ##### Before you start You need: - The [Upsun CLI](https://docs.upsun.com/administration/cli.md) - An [API token](https://docs.upsun.com/administration/cli/api-tokens.md#2-create-an-api-token) ##### 1. Define a source operation to update your dependencies To facilitate updating your dependencies in your project, define a source operation in your `.upsun/config.yaml` file depending on your dependency manager: ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "myapp" source: operations: update: command: | set -e npm update git add package.json package-lock.json git add -A git diff-index --quiet HEAD || git commit --allow-empty -m "Update npm dependencies" ``` ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "myapp" source: operations: update: command: | set -e yarn upgrade git add yarn.lock git add -A git diff-index --quiet HEAD || git commit --allow-empty -m "Update yarn dependencies" ``` ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "myapp" source: operations: update: command: | set -e go get -u go mod tidy git add go.mod go.sum git add -A git diff-index --quiet HEAD || git commit --allow-empty -m "Update Go dependencies" ``` ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "myapp" source: operations: update: command: | set -e pipenv update git add Pipfile Pipfile.lock git add -A git diff-index --quiet HEAD || git commit --allow-empty -m "Update Python dependencies" ``` ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "myapp" source: operations: update: command: | set -e bundle update --all git add Gemfile Gemfile.lock git add -A git diff-index --quiet HEAD || git commit --allow-empty -m "Update Ruby dependencies" ``` ##### 2. Automate your dependency updates with a cron job After you've defined a source operation to [update your dependencies on your project](#1-define-a-source-operation-to-update-your-dependencies), you can automate it using a cron job. Note that it’s best not to run source operations on your production environment, but rather on a dedicated environment where you can test changes. Make sure you have the [Upsun CLI](https://docs.upsun.com/administration/cli.md) installed and [an API token](https://docs.upsun.com/administration/cli/api-tokens.md#2-create-an-api-token) so you can run a cron job in your app container. 1. Set your API token as a top-level environment variable: - Open the environment where you want to add the variable. - Click Settings **Settings**. - Click **Variables**. - Click **+ Add variable**. - In the **Variable name** field, enter ``env:UPSUN_CLI_TOKEN``. - In the **Value** field, enter your API token. - Make sure the **Available at runtime** and **Sensitive variable** options are selected. - Click **Add variable**. **Note**: Once you add the API token as an environment variable, anyone with [SSH access](https://docs.upsun.com/development/ssh.md) can read its value. Make sure you carefully check your [user access on this project](https://docs.upsun.com/administration/users.md#manage-project-users). 2. Add a build hook to your app configuration to install the CLI as part of the build process: ```yaml {location=".upsun/config.yaml"} applications: myapp: hooks: build: | set -e echo "Installing Upsun CLI" curl -fsSL https://raw.githubusercontent.com/platformsh/cli/main/installer.sh | bash echo "Testing Upsun CLI" upsun ``` 3. Then, to configure a cron job to automatically update your dependencies once a day, use a configuration similar to the following: ```yaml {location=".upsun/config.yaml"} applications: myapp: # ... crons: update: # Run the code below every day at midnight. spec: '0 0 * * *' commands: start: | set -e upsun sync -e development code data --no-wait --yes upsun source-operation:run update --no-wait --yes ``` The example above synchronizes the `development` environment with its parent and then runs the `update` source operation defined [previously](#1-define-a-source-operation-to-update-your-dependencies). ##### 3. Configure notifications about dependency updates To get notified every time a source operation is triggered and therefore every time a dependency is updated, you can configure activity scripts or webhooks. ###### Notifications through an activity script After you've defined a source operation to [update your dependencies on your project](#1-define-a-source-operation-to-update-your-dependencies), you can configure an activity script to receive notifications every time a dependency update is triggered. **Example**: You want to get notified of every dependency update through a message posted on a Slack channel. To do so, follow these steps: - In your Slack administrative interface, [create a new Slack webhook](https://api.slack.com/messaging/webhooks). You get a URL starting with ``https://hooks.slack.com/``. - Replace ``SLACK_URL`` in the following ``.js`` script with your webhook URL. - Add the following code to a ``.js`` file: ```javascript {} /** * Sends a color-coded formatted message to Slack. * * To control what events trigger it, use the --events switch in * the Upsun CLI. * * Replace SLACK_URL in the following script with your Slack webhook URL. * Get one here: https://api.slack.com/messaging/webhooks * You should get something like: const url = 'https://hooks.slack.com/...'; * * activity.text: a brief, one-line statement of what happened. * activity.log: the complete build and deploy log output, as it would be seen in the Console log screen. */ function sendSlackMessage(title, message) { const url = 'SLACK_URL'; const messageTitle = title; const color = activity.result === "success" ? "#66c000" : "#ff0000"; const body = { attachments: [ { title: messageTitle, text: message, color: color, }, ], }; const resp = fetch(url, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(body), }); if (!resp.ok) { console.log("Sending slack message failed: " + resp.body.text()); } } sendSlackMessage(activity.text, activity.log); ``` - Run the following [Upsun CLI](https://docs.upsun.com/administration/cli.md) command: ```bash {} upsun integration:add --type script --file ./my_script.js --events=environment.source-operation ``` Optional: to only get notifications about specific environments, add the following flag to the command: ``--environments=your_environment_name``. Anytime a dependency is updated via a source operation, the activity script now reports it to Slack. ###### Notifications through a webhook After you've defined a source operation to [update your dependencies on your project](#1-define-a-source-operation-to-update-your-dependencies), you can configure a webhook to receive notifications every time a dependency update is triggered. [Webhooks](https://docs.upsun.com/integrations/activity/webhooks.md) allow you to host a script yourself externally. This script receives the same payload as an activity script and responds to the same events, but can be hosted on your own server and in your own language. To configure the integration between your webhook and your source operation, run the following [Upsun CLI](https://docs.upsun.com/administration/cli.md) command: ```bash upsun integration:add --type=webhook --url=URL_TO_RECEIVE_JSON --events=environment.source-operation ``` Optional: to only get notifications about specific environments, add the following flag to the command: `--environments=your_environment_name`. To test the integration and the JSON response, you can generate a URL from a service such as [webhook.site](https://webhook.site) and use the generated URL as `URL_TO_RECEIVE_JSON`. This URL then receives the JSON response when a source operation is triggered. Anytime a dependency is updated via a source operation, the webhook now receives a POST message. This POST message contains complete information about the entire state of the project at that time. ### Restrict access to a service Upsun allows you to restrict access to a service. In this tutorial, learn how to grant your Data team `read-only` access to your production database. ##### Before you start You need: - A project with a database service - A `viewer` user on your project ##### 1. Add a read-only endpoint to your database service Edit your `.upsun/config.yaml` file and add the following [endpoints](https://docs.upsun.com/add-services/mysql/_index.md#define-permissions): - `website` with `admin` access to the `main` database - `reporting` with read-only `ro` access to the `main` database ```yaml {location=".upsun/config.yaml"} services: maindb: type: mariadb:10.5 configuration: schemas: - main endpoints: website: default_schema: main privileges: main: admin reporting: privileges: main: ro ``` ##### 2. Grant your app access to the new endpoints Edit your app configuration and add new relationships to your new endpoints: ```yaml {location=".upsun/config.yaml"} applications: myapp: # ... relationships: database: service: maindb endpoint: website reports: service: maindb endpoint: reporting ``` ##### 3. Create a worker with access to the read-only endpoint Edit your app configuration to add a new worker which: - Does nothing (`sleep infinity`) - Can access the read-only `reporting` endpoint - Allows SSH access to `viewer` ```yaml {location=".upsun/config.yaml"} applications: myapp: workers: data_access: mounts: {} commands: start: | sleep infinity relationships: reports: service: maindb endpoint: reporting access: ssh: viewer ``` You're done! From now on, your `viewer` users can SSH in to the worker application, and connect to your database with read-only permissions. ### Exporting data As a Upsun user, your code and data belong to you. At any time, you can download your site's data for local development, to back up your data, or to change provider. ##### Before you begin You need: - [Git](https://git-scm.com/downloads) - A Upsun account - Code in your project - Optional: the [Upsun CLI](https://docs.upsun.com/administration/cli.md) ##### 1. Download your app's code Your app's code is maintained through the Git version control system. To download your entire app's code history: - Retrieve the project you want to back up by running the following command: ```bash {} upsun get ``` - In the [Console](https://console.upsun.com/), open your project and click **Code **. - Click **Git**. - To copy the command, click ** Copy**. The command is similar to the following: ```text {} git clone abcdefgh1234567@git.eu.upsun.com:abcdefgh1234567.git project-name ``` ##### 2. Download your files Some files might not be stored in Git, such as data your app writes [in mounts](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#mounts). You can download your files [using the CLI](https://docs.upsun.com/development/file-transfer.md#transfer-files-using-the-cli) or [using SSH](https://docs.upsun.com/development/file-transfer.md#transfer-files-using-an-ssh-client). ##### 3. Download data from services The mechanism for downloading from each service (such as your database) varies. For services designed to hold non-persistent data, such as [Redis](https://docs.upsun.com/add-services/redis.md) or [Solr](https://docs.upsun.com/add-services/solr.md), it's generally not necessary to download data as it can be rebuilt from the primary data store. For services designed to hold persistent data, see each service's page for instructions: - [MySQL](https://docs.upsun.com/add-services/mysql.md#exporting-data) - [PostgreSQL](https://docs.upsun.com/add-services/postgresql.md#exporting-data) - [MongoDB](https://docs.upsun.com/add-services/mongodb.md#exporting-data) - [InfluxDB](https://docs.upsun.com/add-services/influxdb.md#export-data) ##### 4. Get environment variables Environment variables can contain critical information such as tokens or additional configuration options for your app. Environment variables can have different prefixes: - Variables beginning with `env:` are exposed [as Unix environment variables](https://docs.upsun.com/development/variables.md#top-level-environment-variables). - Variables beginning with `php:` are interpreted [as `php.ini` directives](https://docs.upsun.com/development/variables.md#php-specific-variables). All other variables are [part of `$PLATFORM_VARIABLES`](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). To back up your environment variables: Note that you can also get all the environment variable values by running the following command: ```bash {} upsun ssh -- env ``` - Store the data somewhere secure on your computer. - In the [Console](https://console.upsun.com/), open your project and click **Settings**. - Click **Project Settings **. - Click **Variables** and access your variable’s values and settings. - Store the data somewhere secure on your computer. Note that in the Console, you can’t access the value of variables that have been [marked as sensitive](https://docs.upsun.com/development/variables/set-variables.md#variable-options). Use the CLI to retrieve these values. ##### What's next - Migrate data from elsewhere [into Upsun](https://docs.upsun.com/learn/tutorials/migrating.md). - Migrate to [another region](https://docs.upsun.com/projects/region-migration.md). - To use data from an environment locally, export your data and set up your [local development environment](https://docs.upsun.com/development/local.md). ### HTTP caching You can configure HTTP caching for your site on Upsun in several ways. Which one you should use depends on your specific use case. You should use only one of these at a time and disable any others. Mixing them together most likely results in stale cache that can't be cleared. ##### The Upsun router cache Every project includes a router instance that includes [optional HTTP caching](https://docs.upsun.com/define-routes/cache.md). It's reasonably configurable and obeys HTTP cache directives, but doesn't support push-based clearing. If you're uncertain what caching tool to use, start with this one. It's enough for most uses. ##### A Content Delivery Network (CDN) Upsun is compatible with most commercial CDNs. CDNs generally offer the best performance as they're the only option that includes multiple geographic locations. But they do tend to be the most expensive option. See more on setting up [Fastly](https://docs.upsun.com/domains/cdn/fastly.md) and [Cloudflare](https://docs.upsun.com/domains/cdn/cloudflare.md). The methods for other CDNs are similar. ##### Varnish Upsun offers a [Varnish service](https://docs.upsun.com/add-services/varnish.md) that you can insert between the router and your app. It has roughly the same performance as the router cache. Varnish is more configurable, but it requires you to be comfortable with Varnish Configuration Language (VCL). Upsun doesn't help with VCL configuration and a misconfiguration may be difficult to debug. Varnish supports [clearing cache with a push](https://docs.upsun.com/add-services/varnish.md#clear-cache-with-a-push), but access control is complicated by the inability to have [circular relationships](https://docs.upsun.com/add-services/varnish.md#circular-relationships). Generally speaking, you should use Varnish only if your application requires push-based clearing or relies on Varnish-specific business logic. ##### App-specific caching Many web apps and frameworks include a built-in web cache layer that mimics what Varnish or the Router cache would do. Most of the time they're slower than a dedicated caching service as they still require invoking the app server and only serve as a fallback for users that don't have a dedicated caching service available. Generally speaking, use app-specific web cache only when it includes app-specific business logic you depend on, such as app-sensitive selective cache clearing or partial page caching. Note that this refers only to HTTP caching. Many apps have an internal app cache for data objects and similar information. That should remain active regardless of the HTTP cache in use. ##### Cookies and caching HTTP-based caching systems generally default to including cookie values in cache keys to avoid serving authenticated content to the wrong user. While this is a safe default, it means that *any* cookie effectively disables the cache, including mundane cookies like analytics. The solution is to set which cookies should impact the cache and limit them to session cookies. For the router cache, see [cookies in HTTP caching](https://docs.upsun.com/define-routes/cache.md#cookies). For other cache systems, consult their documentation. ### From monoliths through headless to microservices With Upsun, you can run multiple application containers in a single environment. This gives you access to a large variety of setups and allows you to seamlessly upgrade your app from a monolith with a single application server to a more elaborate and effective topology. You can set up multiple apps to achieve the following: - Keep your backend and frontend systems separate - Run workers alongside your main app - Or even go for a full microservices architecture Upsun makes implementing such setups and switching from one to the other pain-free. The same flexibility applies to any supported services, from relational databases to search engines and message queues. Depending on your specific use case, you can run a single database, multiple databases inside a single instance, or multiple databases in multiple versions... It's up to you! Whether you embrace a mono-repo approach with a single Git repository describing your entire setup, or divide your project into multiple repositories, Upsun allows you to build the best architecture for your needs. But while the possibilities are endless, making the right choice between creating one big project with multiple apps or keeping each app in its own project can be a tough formula to crack. So read on for guidance! ##### Separate projects If you have multiple apps sharing the same code but each of them has its own data, keep your apps in separate projects. Upsun provides the automation to deploy multiple projects from the same code base, which makes their maintenance effortless. **Note**: By design, Upsun doesn’t allow your app to access services in another project through HTTP. So separate projects are appropriate in the following cases: - Your apps are for different customers/clients - Your apps don't need to directly connect to the same database - Different teams are working on different apps - You want to develop true microservices, where each microservice is a fully standalone process with its own data When in doubt over your own needs, it's better to keep separate projects than build an architecture that may prove difficult for you to maintain. ##### Clustered applications A clustered application is one where your project requires multiple _app services_ that are all part of the same conceptual project. Clustered applications can range from a straightforward headless architecture, where frontend and backend systems are separated, to micro-services with dozens of apps in multiple runtimes and frameworks forming a consistent whole. Meaning, removing one of the app services would break the others. Upsun allows you to configure access from one service to another without having to worry about service discovery or complex _ingress controllers_. [Configuring incoming routes](https://docs.upsun.com/define-routes.md) is straightforward. You can have services that are only exposed to another service as well as services that are exposed to the internet. In a clustered application, you can have one of the following configurations: - Multiple [applications](https://docs.upsun.com/create-apps/multi-app.md), often in different directories or with separate code bases that deploy separately - A single app that spawns one or more [worker instances](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#workers) that run background processes With a clustered application, you often don't need multiple service instances. The [MySQL, MariaDB](https://docs.upsun.com/add-services/mysql.md), and [Solr](https://docs.upsun.com/add-services/solr.md) services support defining multiple databases on a single service, which is significantly more efficient than defining multiple services. [Redis](https://docs.upsun.com/add-services/redis.md), [Memcached](https://docs.upsun.com/add-services/memcached.md), [Elasticsearch](https://docs.upsun.com/add-services/elasticsearch.md), and [RabbitMQ](https://docs.upsun.com/add-services/rabbitmq.md) natively support multiple bins (also called _queues_ or _indexes_) defined by the client application as part of the request. Therefore, they don't need additional configuration on Upsun. Clustered applications are appropriate in the following cases: - You want one user-facing app and an entirely separate admin-facing app that are both operating on the same data - You want to have a user-facing app and a separate worker process (either the same code or separate) that handles background tasks - You want a single conceptual app written in multiple programming languages ##### A note on "multi-site" applications Some Content Management Systems or other applications support running multiple logical "sites" off of a single code base. This approach isn't recommended on Upsun. This multi-site logic is often dependent on the domain name of the incoming request, which on Upsun varies by branch. Running multiple databases, as is often recommended with this approach, is supported on Upsun but makes the setup process for each site more difficult. Leveraging the multi-site capabilities of an app are appropriate only in the following cases: - There is only a single team working on all of the "sites" involved - All "sites" should be updated simultaneously as a single unit - Each individual site is relatively low traffic, such that the aggregate traffic is appropriate for your plan size - All sites really do use the same codebase with no variation, just different data Otherwise, [separate projects](#separate-projects) are a better long-term plan. ### Keep your Git repository clean When a Git repository contains a high number of references and files, the performance of Git can decrease. This is why most Git providers have repository size limits in place (for more information, see the [GitHub](https://docs.github.com/en/repositories/working-with-files/managing-large-files/about-large-files-on-github), [GitLab](https://docs.gitlab.com/ee/user/gitlab_com/index.md#account-and-limit-settings) and [Bitbucket](https://support.atlassian.com/bitbucket-cloud/docs/reduce-repository-size/) documentation). The Upsun API and [Console](https://docs.upsun.com/administration/web.md) are closely tied to Git. When the performance of Git decreases, Upsun API servers also become slower. As a user, you can then experience significant latencies. If your repository becomes too large, your Console may even become unresponsive, leaving you unable to access your project. To avoid such issues, make sure you keep your Git repository clean by following the instructions on this page. If you're already facing performance issues and suspect they might be related to the size of your Git repository, see how you can [troubleshoot a sizeable Git repository](#troubleshoot-a-sizeable-git-repository). ##### Enable the automated pruning of old branches in your project To keep your repository size to a minimum, make sure that branches that don't exist anymore in your repository have also been deleted from Upsun. To automate this process, when setting up a [source integration](https://docs.upsun.com/integrations.md), enable the `prune-branches` option. If you already have a source integration set up and want to enable the `prune-branches` option, follow these steps: - Then, to enable the ``prune-branches`` option, run the following command: ```bash {} upsun integration:update --project --prune-branches true ``` - Navigate to your project. - Click Settings **Settings**. - Click **Project Settings**. - Click **Integrations** and select your source integration. - Click **Edit**. - Enter your access token and click **Continue**. - Select your repository and check the following boxes: - **Fetch branches from the remote repository to your project** (``fetch-branches`` option, mandatory to enable ``prune-branches``). - **Remove branches from your project that have disappeared remotely (requires the fetch branches option to be enabled)** (``prune-branches`` option). - Click **Save**. ##### Upload your files through mounts Keeping too many files, especially large binary files, in your Git repository can cause performance and stability issues. Therefore, Upsun recommends that you only commit your source code in Git. To upload any other files to your app, [create mounts](https://docs.platform.sh/create-apps/app-reference.md#mounts) and [transfer your files directly to them](https://docs.platform.sh/development/file-transfer.md#transfer-a-file-to-a-mount). **Note**: Upsun does not currently support [Git Large File Storage](https://git-lfs.com/). ##### Troubleshoot a sizeable Git repository If you're experiencing latencies or can't access your Console anymore, your Git repository may have become too large and may need to be cleaned up. To do so, follow these instructions: 1. Remove old, unwanted files from your repository (especially large files). You can do it manually, or use a tool such as [BFG Repo-Cleaner](https://rtyley.github.io/bfg-repo-cleaner/). 2. Remove stale branches from your repository and Upsun project. 3. Rebase and/or squash commits to clean up your history. 4. Make sure you [enable the automated pruning of old branches in your project](#enable-the-automated-pruning-of-old-branches-in-your-project) and [upload your files through mounts](#upload-your-files-through-mounts) to avoid facing the same situation in the future. ## Reference ### App reference To define your app, you can either use one of Upsun's [single-runtime image](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md) or its [composable image (BETA)](https://docs.upsun.com/create-apps/app-reference/composable-image.md). ##### Single-runtime image Upsun provides and maintains a list of single-runtime images you can use for each of your application containers. See [all of the options you can use](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md) to define your app using a single-runtime image. ##### Composable image (BETA) The Upsun composable image provides more flexibility than single-runtime images. When using a composable image, you can define a stack (or group of packages) for your application container to use. There are over 80,000 packages available from the [Nix Packages collection](https://search.nixos.org/) that you can add to your stack. You can add as many packages to your application container as you need. **Note**: Upsun guarantees optimal user experience with the specific [set of packages](https://docs.upsun.com/create-apps/app-reference/composable-image.md#supported-nix-packages) it supports. You can use any other package available from the [Nix Packages collection](https://search.nixos.org/), including unstable ones, but NixOs is responsible for their support. See [all of the options you can use](https://docs.upsun.com/create-apps/app-reference/composable-image.md) to define your app using the composable image. #### Single-runtime image 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](https://docs.upsun.com/create-apps.md#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: ```yaml {location=".upsun/config.yaml"} applications: frontend: type: 'nodejs:22' # Additional frontend configuration backend: type: 'python:3.9' # Additional backend configuration ``` The 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 | |--------------------|-----------------------------------------------------|----------|------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `type` | A [type](#types) | Yes | No | The base image to use with a specific app language. Format: `runtime:version`. | | `relationships` | A dictionary of [relationships](#relationships) | | Yes | Connections to other services and apps. | | `mounts` | A dictionary of [mounts](#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](#web) | | N/A | How the web application is served. | | `workers` | A [worker instance](#workers) | | 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](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). Defaults to `UTC`, which is the timezone used for all logs no matter the value here. See also [app runtime timezones](https://docs.upsun.com../timezone.md) | | `access` | An [access dictionary](#access) | | Yes | Access control for roles accessing app environments. | | `variables` | A [variables dictionary](#variables) | | Yes | Variables to control the environment. | | `firewall` | A [firewall dictionary](#firewall) | | Yes | Outbound firewall rules for the application. | | `build` | A [build dictionary](#build) | | No | What happens when the app is built. | | `dependencies` | A [dependencies dictionary](#dependencies) | | No | What global dependencies to install before the `build` hook is run. | | `hooks` | A [hooks dictionary](#hooks) | | No | What commands run at different stages in the build and deploy process. | | `crons` | A [cron dictionary](#crons) | | No | Scheduled tasks for the app. | | `source` | A [source dictionary](#source) | | No | Information on the app's source code and operations that can be run on it. | | `runtime` | A [runtime dictionary](#runtime) | | No | Customizations to your PHP or Lisp runtime. | | `additional_hosts` | An [additional hosts dictionary](#additional-hosts) | | 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. ```yaml {location=".upsun/config.yaml"} applications: frontend: type: 'nodejs:22' # 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](https://docs.upsun.com../multi-app.md), use the [`source.root` property](#source). ###### Types **Note**: You can now use the Upsun composable image (BETA) to install runtimes and tools in your application container. If you’ve reached this section from another page, you may be interested in supported ``stacks`` where ``type`` was referenced. See [supported Nix packages for the ](https://docs.upsun.com/create-apps/app-reference/composable-image.md#supported-nix-packages) for more information. 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](https://docs.upsun.com/languages/dotnet.md) | ``dotnet`` | 7.0, 6.0, 8.0 | | [Elixir](https://docs.upsun.com/languages/elixir.md) | ``elixir`` | 1.18, 1.15, 1.14 | | [Go](https://docs.upsun.com/languages/go.md) | ``golang`` | 1.23, 1.22, 1.21, 1.20 | | [Java](https://docs.upsun.com/languages/java.md) | ``java`` | 21, 19, 18, 17, 11, 8 | | [Lisp](https://docs.upsun.com/languages/lisp.md) | ``lisp`` | 2.1, 2.0, 1.5 | | [JavaScript/Node.js](https://docs.upsun.com/languages/nodejs.md) | ``nodejs`` | 22, 20, 18 | | [PHP](https://docs.upsun.com/languages/php.md) | ``php`` | 8.4, 8.3, 8.2, 8.1 | | [Python](https://docs.upsun.com/languages/python.md) | ``python`` | 3.12, 3.11, 3.10, 3.9, 3.8 | | [Ruby](https://docs.upsun.com/languages/ruby.md) | ``ruby`` | 3.3, 3.2, 3.1, 3.0 | | [Rust](https://docs.upsun.com/languages/rust.md) | ``rust`` | 1 | ####### Example configuration These are used in the format `runtime:version`: ```yaml {location=".upsun/config.yaml"} applications: myapp: type: 'php:8.4' ``` ####### Mix of images In a [multiple application context](https://docs.upsun.com/create-apps/multi-app.md), you can mix both [single-runtime image](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md) and [Composable Image (BETA)](https://docs.upsun.com/create-apps/app-reference/composable-image.md) per application. As an example configuration for a ``frontend`` and a ``backend`` application: ```yaml {location=".upsun/config.yaml"} applications: backend: type: 'nodejs:22 frontend: stack: - "php@8.4": extensions: - apcu - sodium - xsl - pdo_sqlite - "python@3.12" - "python312Packages.yq" # python package specific ``` ###### 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](https://docs.upsun.com/manage-resources.md). ###### Relationships To allow containers in your project to communicate with one another, you need to define relationships between them. You can define a relationship between an app and a service, or [between two apps](https://docs.upsun.com/create-apps/multi-app/relationships.md). The quickest way to define a relationship between your app and a service is to use the service's default endpoint. However, some services allow you to define multiple databases, cores, and/or permissions. In these cases, you can't rely on default endpoints. Instead, you can explicitly define multiple endpoints when setting up your relationships. **Note**: App containers don’t have a default endpoint like services. To connect your app to another app in your project, you need to explicitly define the ``http`` endpoint as the endpoint to connect both apps. For more information, see how to [define relationships between your apps](https://docs.upsun.com/create-apps/multi-app/relationships.md). **Availability**: New syntax (default and explicit endpoints) described below is supported by most, but not all, image types (``Relationship 'SERVICE_NAME' of application 'app' ... targets a service without a valid default endpoint configuration.``). This syntax is currently being rolled out for all images. If you encounter this error, use the “legacy” Upsun configuration noted at the bottom of this section. To define a relationship between your app and a service: The ``SERVICE_NAME`` is the name of the service as defined in its [configuration](https://docs.upsun.com/add-services.md). It is used as the relationship name, and associated with a ``null`` value. This instructs Upsun to use the service’s default endpoint to connect your app to the service. For example, if you define the following configuration: ```yaml {location=".upsun/config.yaml"} applications: : # ... relationships: mariadb: ``` Upsun looks for a service named ``mariadb`` in your ``.upsun/config.yaml`` file, and connects your app to it through the service’s default endpoint. For reference, the equivalent configuration using explicit endpoints would be the following: ```yaml {location=".upsun/config.yaml"} applications: : # ... relationships: mariadb: service: mariadb endpoint: mysql ``` You can define any number of relationships in this way: ```yaml {location=".upsun/config.yaml"} applications: : # ... relationships: mariadb: redis: elasticsearch: ``` **Tip**: An even quicker way to define many relationships is to use the following single-line configuration: ```yaml {location=".upsun/config.yaml"} applications: : # ... relationships: {, , } services: : type: mariadb:11.4 : type: redis:7.2 : type: elasticsearch:8.5 ``` Use the following configuration: ```yaml {location=".upsun/config.yaml"} applications: : # ... relationships: : service: endpoint: ``` - ``RELATIONSHIP_NAME`` is the name you want to give to the relationship. - ``SERVICE_NAME`` is the name of the service as defined in its [configuration](https://docs.upsun.com/add-services.md). - ``ENDPOINT_NAME`` is the endpoint your app will use to connect to the service (refer to the service reference to know which value to use). For example, to define a relationship named ``database`` that connects your app to a service called ``mariadb`` through the ``db1`` endpoint, use the following configuration: ```yaml {location=".upsun/config.yaml"} applications: : # ... relationships: database: # The name of the relationship. service: mariadb endpoint: db1 ``` For more information on how to handle multiple databases, multiple cores, and/or different permissions with services that support such features, see each service’s dedicated page: - [MariaDB/MySQL](https://docs.upsun.com/add-services/mysql.md#multiple-databases) (multiple databases and permissions) - [PostgreSQL](https://docs.upsun.com/add-services/postgresql.md#multiple-databases) (multiple databases and permissions) - [Redis](https://docs.upsun.com/add-services/redis.md#multiple-databases) (multiple databases) - [Solr](https://docs.upsun.com/add-services/solr.md#solr-6-and-later) (multiple cores) - [Vault KMS](https://docs.upsun.com/add-services/vault.md#multiple-endpoints-example) (multiple permissions) You can add as many relationships as you want to your app configuration, using both default and explicit endpoints according to your needs: ```yaml {location=".upsun/config.yaml"} applications: : # ... relationships: database1: service: mariadb endpoint: admin database2: service: mariadb endpoint: legacy cache: service: redis search: service: elasticsearch ``` **Legacy**: The following legacy syntax for specifying relationships is still supported by Upsun: ```yaml {location=".upsun/config.yaml"} applications: : # ... relationships: : ":" services: SERVICE_NAME_A: type: mariadb:11.4 ``` For example: ```yaml {} applications: : # ... relationships: database: "db:mysql" services: db: type: mariadb:11.4 ``` Feel free to use this until the default and explicit endpoint syntax is supported on all images. ###### 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](https://docs.upsun.com/manage-resources.md). ####### 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](https://docs.upsun.com/environments/backup.md). - The downsize fails if there’s more data on the disk than the desired size. ###### Mounts After your app is built, its file system is read-only. To make changes to your app's code, you need to use Git. For enhanced flexibility, Upsun allows you to define and use writable directories called "mounts". Mounts give you write access to files generated by your app (such as cache and log files) and uploaded files without going through Git. When you define a mount, you are mounting an external directory to your app container, much like you would plug a hard drive into your computer to transfer data. **Note**: - Mounts aren’t available during the build - When you [back up an environment](https://docs.upsun.com/environments/backup.md), the mounts on that environment are backed up too ####### Define a mount To define a mount, use the following configuration: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: nodejs:22 mounts: '': source: source_path: ``` is the path to your mount **within the app container** (relative to the app's root). 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](https://docs.upsun.com../troubleshoot-mounts.md#overlapping-folders). | Name | Type | Required | Description | | ------------- | -------------------- | -------- | ----------- | | `source` | `storage`, `instance`, `tmp` (also called `temporary`), or `service` | Yes | Specifies the type of the mount:- By design, `storage` mounts can be shared between instances of the same app. You can also configure them so they are [shared between different apps](#share-a-mount-between-several-apps).-`instance` mounts are local mounts. Unique to your app, they are useful to store files that remain local to the app instance, such as application logs.- `tmp` (or `temporary`) mounts are local ephemeral mounts, where an external directory is mounted to the `/tmp` directory of your app.The content of a `tmp` mount **may be removed during infrastructure maintenance operations**. Therefore, `tmp` mounts 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**.- `service` mounts can be useful if you want to explicitly define and use a [Network Storage](https://docs.upsun.com/add-services/network-storage.md) service to share data between different apps (instead of using a `storage` mount).| | `source_path` | `string` | No | Specifies where the mount points **inside the [external directory](#mounts)**. - If you explicitly set a `source_path`, your mount points to a specific subdirectory in the external directory. - If the `source_path` is an empty string (`""`), your mount points to the entire external directory. - If you don't define a `source_path`, Upsun uses the as default value, without leading or trailing slashes. For example, if your mount lives in the `/web/uploads/` directory in your app container, it will point to a directory named `web/uploads` in the external directory. **WARNING:** Changing the name of your mount affects the `source_path` when it's undefined. See [how to ensure continuity](#ensure-continuity-when-changing-the-name-of-your-mount) and maintain access to your files. | | `service` | `string` | | The purpose of the `service` key depends on your use case. In a multi-app context where a `storage` mount is shared between apps, `service` is required. Its value is the name of the app whose mount you want to share. See how to [share a mount between several apps](#share-a-mount-between-several-apps). In a multi-app context where a [Network Storage service](https://docs.upsun.com/add-services/network-storage.md) (`service` mount) is shared between apps, `service` is required and specifies the name of that Network Storage. | The accessibility to the web of a mounted directory depends on the [`web.locations` configuration](#web). Files can be all public, all private, or with different rules for different paths and file types. Note that when you remove a `tmp` mount from your `.upsun/config.yaml` file, the mounted directory isn't deleted. The files still exist on disk until manually removed, or until the app container is moved to another host during a maintenance operation. ####### Example configuration ```yaml {location=".upsun/config.yaml"} 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/.cache ``` ####### Ensure continuity when changing the name of your mount Changing the name of your mount affects the default `source_path`. Say you have a `/my/cache/` mount with an undefined `source_path`: ```yaml {location=".upsun/config.yaml"} applications: myapp: mounts: '/my/cache/': source: tmp ``` If you rename the mount to `/cache/files/`, it will point to a new, empty `/cache/files/` directory. To ensure continuity, you need to explicitly define the `source_path` as the previous name of the mount, without leading or trailing slashes: ```yaml {location=".upsun/config.yaml"} applications: myapp: mounts: '/cache/files/': source: tmp source_path: my/cache ``` The `/cache/files/` mount will point to the original `/my/cache/` directory, maintaining access to all your existing files in that directory. ####### Share a mount between several apps By design, [`storage` mounts](#mounts) are shared **between different instances of the same app**, which enables [horizontal scaling](https://docs.upsun.com/manage-resources.md). In a [multi-application context](https://docs.upsun.com/create-apps/multi-app.md), you can even share a `storage` mount **between different applications** in the same project. To do so, you need to define a `storage` mount in each of your app containers, and point each of those mounts to the same shared external network directory. Use the following configuration: ```yaml {location=".upsun/config.yaml"} applications: app1: mounts: '': source: storage source_path: app2: mounts: '': source: storage service: app1 source_path: ``` - and are the paths to each mount **within their respective app container** (relative to the app's root). - When configuring the first `storage` mount, you don't need to include the `service` key. The first mount implicitly points to an external network directory. The `service` key is required for subsequent mounts, to ensure they use the same external network directory as the first mount. - The `source_path` allows you to point each mount to the same subdirectory **within the shared external network directory**. **Example**: You have a ``backend`` app and a ``frontend`` app. You want both apps to share data from the same mount. Follow these steps: - In your ``backend`` app configuration, define a ``storage`` mount: ```yaml {location=".upsun/config.yaml"} applications: backend: mounts: var/uploads: #The path to your mount within the backend app container. source: storage source_path: backend/uploads #The path to the source of the mount within the external network directory. ``` This creates a ``storage`` mount named ``var/uploads`` in the ``backend`` app container. The mount points to the ``backend/uploads`` directory within an external network directory. - In your ``frontend`` app configuration, define another ``storage`` mount: ```yaml {location=".upsun/config.yaml"} applications: applications: backend: mounts: var/uploads: source: storage source_path: backend/uploads frontend: mounts: web/uploads: #The path to your mount within the frontend app container. source: storage service: backend #The name of the other app, so the mount can point to the same external network directory as that other app's mount. source_path: backend/uploads #The path to the source of the mount within the shared external network directory. ``` This creates another ``storage`` mount named ``web/uploads`` in the ``frontend`` app container. The ``service`` key allows you to specify that the ``web/uploads`` mount should use the same external network directory as the mount previously defined in the ``backend`` app container. The ``source_path`` key specifies which subdirectory within the external network directory both mounts should share ( here, the ``backend/uploads`` directory). Note that another way to share data between apps through a mount is by explicitly [defining a Network Storage service](https://docs.upsun.com/add-services/network-storage.md). ####### Overlapping mounts The locations of mounts as they are visible to application containers can overlap somewhat. For example: ```yaml {location=".upsun/config.yaml"} applications: myapp: # ... mounts: 'var/cache_a': source: storage source_path: cacheA 'var/cache_b': source: tmp source_path: cacheB 'var/cache_c': source: instance source_path: cacheC ``` In this case, it does not matter that each mount is of a different `source` type. Each mount is restricted to a subfolder within `var`, and all is well. The following, however, is not allowed and will result in a failure: ```yaml {location=".upsun/config.yaml"} applications: myapp: # ... mounts: 'var/': source: storage source_path: cacheA 'var/cache_b': source: tmp source_path: cacheB 'var/cache_c': source: instance source_path: cacheC ``` The `storage` mount type specifically exists to share data between instances of the same application, whereas `tmp` and `instance` are meant to restrict data to build time and runtime of a single application instance, respectively. These allowances are not compatible, and will result in an error if pushed. ###### Web Use the `web` key to configure the web server running in front of your app. Defaults may vary with a different [image `type`](#types). | Name | Type | Required | Description | |-------------|--------------------------------------------|-------------------------------|------------------------------------------------------| | `commands` | A [web commands dictionary](#web-commands) | See [note](#required-command) | The command to launch your app. | | `upstream` | An [upstream dictionary](#upstream) | | How the front server connects to your app. | | `locations` | A [locations dictionary](#locations) | | How the app container responds to incoming requests. | See some [examples of how to configure what's served](https://docs.upsun.com../web.md). ####### 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. | | `start` | `string` | See [note](#required-command) | The command to launch your app. If it terminates, it's restarted immediately. | Example: ```yaml {location=".upsun/config.yaml"} 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. ######## 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](https://github.com/platformsh-examples/platformsh-example-reactphp) or [Amp](https://github.com/platformsh-examples/platformsh-example-amphp). See how to set up [alternate start commands on PHP](https://docs.upsun.com/languages/php.md#alternate-start-commands). ####### Upstream | Name | Type | Required | Description | Default | |-----------------|---------------------|----------|-------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------| | `socket_family` | `tcp` or `unix` | | Whether your app listens on a Unix or TCP socket. | Defaults to `tcp` for all [image types](#types) except PHP; for PHP image types the default is `unix`. | | `protocol` | `http` or `fastcgi` | | Whether your app receives incoming requests over HTTP or FastCGI. | Default varies based on [image `type`](#types). | 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: ```yaml {location=".upsun/config.yaml"} 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](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables) | | `unix` | The Unix socket file specified by the [`SOCKET` environment variable](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables) | 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](#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 `string`s 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. If a `Cache-Control` appears on the `headers` configuration, `expires`, if set, will be ignored. Thus, make sure to set the `Cache-Control`'s `max-age` value when specifying a the header. | | `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 (see [Set custom headers on static content](https://docs.upsun.com/create-apps/web/custom-headers.md)). Responses from the app aren't affected. | | `request_buffering` | A [request buffering dictionary](#request-buffering) | See below | Handling for chunked requests. | | `rules` | A [rules dictionary](#rules) | | 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](#locations) 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. ```yaml {location=".upsun/config.yaml"} 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: ```yaml {location=".upsun/config.yaml"} 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](#hooks). 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](#primary-application-properties). Each worker can differ from the `web` instance in all properties _except_ for: - `build` and `dependencies` properties, which must be the same - `crons` as cron jobs don't run on workers - `hooks` as the `build` hook must be the same and the `deploy` and `post_deploy` hooks don't run on workers. A worker named `queue` that was small and had a different start command could look like this: ```yaml {location=".upsun/config.yaml"} 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](https://docs.upsun.com/manage-resources.md). ###### 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](https://docs.upsun.com/administration/users.md#environment-type-roles) can access the deployed environment via SSH: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: 'python:3.9' access: ssh: admin ``` ###### Variables Upsun provides a number of ways to set [variables](https://docs.upsun.com/development/variables.md). 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](https://docs.upsun.com/development/variables.md#variable-prefixes). Variables with the prefix `env` are available as a separate environment variable. All other variables are available in the [`PLATFORM_VARIABLES` environment variable](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). The following example sets two variables: - A variable named `env:AUTHOR` with the value `Juan` that's available in the environment as `AUTHOR` - A variable named `d8config:system.site:name` with the value `My site rocks` that's available in the `PLATFORM_VARIABLES` environment variable ```yaml {location=".upsun/config.yaml"} 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](https://docs.upsun.com/development/variables/use-variables.md#access-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 `string`s | `["0.0.0.0/0"]` | IP addresses in [CIDR notation](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing). See a [CIDR format converter](https://www.ipaddressguide.com/cidr). | | `domains` | Array of `string`s | | [Fully qualified domain names](https://en.wikipedia.org/wiki/Fully_qualified_domain_name) to specify specific destinations by hostname. | | `ports` | Array of `integer`s | | 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: ```yaml {location=".upsun/config.yaml"} 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: ```yaml {location=".upsun/config.yaml"} 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: ```yaml {location=".upsun/config.yaml"} 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: ```bash awk '/query\[[^P]\]/ { print $6 | "sort -u" }' /var/log/dns.log ``` The 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: ```bash facebook.com fastly.com upsun.com www.google.com www.upsun.com ``` ###### 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: - [Node.js](https://docs.upsun.com/languages/nodejs.md#dependencies) - [PHP](https://docs.upsun.com/languages/php.md#dependencies) 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). ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: 'nodejs:22' 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](https://getcomposer.org/) | | Python 2 | `python` or `python2` | [Pip 2](https://packaging.python.org/tutorials/installing-packages/) | | Python 3 | `python3` | [Pip 3](https://packaging.python.org/tutorials/installing-packages/) | | Ruby | `ruby` | [Bundler](https://bundler.io/) | | Node.js | `nodejs` | [npm](https://www.npmjs.com/) (see [how to use yarn](https://docs.upsun.com/languages/nodejs.md#use-yarn-as-a-package-manager)) | | Java | `java` | [Apache Maven](https://maven.apache.org/), [Gradle](https://gradle.org/), or [Apache Ant](https://ant.apache.org/) | The format for package names and version constraints are defined by the specific package manager. An example of dependencies in multiple languages: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: 'nodejs:22' 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](#workers), while [web instances](#web) run all three. The process is ordered as: 1. Variables accessible at build time become available. 1. [Build flavor](#build) runs if applicable. 1. Any [dependencies](#dependencies) are installed. 1. The `build` hook is run. 1. The file system is changed to read only (except for any [mounts](#mounts)). 1. The app container starts. Variables accessible at runtime and services become available. 1. The `deploy` hook is run. 1. The app container begins accepting requests. 1. The `post_deploy` hook 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](https://docs.upsun.com/development/troubleshoot.md#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 the `build` hook 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 that `PLATFORM_CACHE_DIR` is mapped to `/tmp` and 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](https://docs.upsun.com/increase-observability/logs/access-logs.md#container-logs). The following table shows the properties for each job: | Name | Type | Required | Description | |--------------------|----------------------------------------------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `spec` | `string` | Yes | The [cron specification](https://en.wikipedia.org/wiki/Cron#Cron_expression). 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](#cron-commands) | 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](https://docs.upsun.com/environments/cancel-activity.md). ####### Cron commands | Name | Type | Required | Description | |---------|----------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `start` | `string` | Yes | The command that's run. It's run in [Dash](https://en.wikipedia.org/wiki/Almquist_shell). | | `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. | ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: 'nodejs:22' crons: mycommand: spec: 'H * * * *' commands: start: sleep 60 && echo sleep-60-finished && date stop: killall sleep shutdown_timeout: 18 ``` In this example configuration, the [cron specification](#crons) uses the `H` syntax. ####### Example cron jobs ```yaml {location=".upsun/config.yaml"} 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' ``` ```yaml {location=".upsun/config.yaml"} 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.4' crons: # Run Laravel's scheduler every 5 minutes. scheduler: spec: '*/5 * * * *' commands: start: 'php artisan schedule:run' ``` ```yaml {location=".upsun/config.yaml"} 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.4' crons: # Take a backup of the environment every day at 5:00 AM. snapshot: spec: 0 5 * * * commands: start: | # 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: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: 'php:8.4' 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](https://docs.upsun.com/environments/backup.md) 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](#primary-application-properties). ####### Paused crons [Preview environments](https://docs.upsun.com/glossary.md#preview-environment) 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: Run the following command: ```bash {} upsun redeploy ``` ###### Runtime The following table presents the various possible modifications to your PHP or Lisp runtime: | Name | Type | Language | Description | |-----------------------------|------------------------------------------------------------|----------|--------------------------------------------------------------------------------------------| | `extensions` | List of `string`s OR [extensions definitions](#extensions) | PHP | [PHP extensions](https://docs.upsun.com/languages/php/extensions.md) to enable. | | `disabled_extensions` | List of `string`s | PHP | [PHP extensions](https://docs.upsun.com/languages/php/extensions.md) 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](#sizing-hints) | 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](https://docs.upsun.com/languages/php/xdebug.md). | | `quicklisp` | Distribution definitions | Lisp | [Distributions for QuickLisp](https://docs.upsun.com/languages/lisp.md#quicklisp-options) to use. | You can also set your [app's runtime timezone](https://docs.upsun.com/create-apps/timezone.md). ####### Extensions **Note**: You can now use the Upsun composable image (BETA) to install runtimes and tools in your application container. If you’ve reached this section from another page and are using the composable image, enabling/disabling extensions should be placed under the ``stack`` key instead of what is listed below. See [how to configure extensions with the composable image](https://docs.upsun.com/create-apps/app-reference/composable-image.md#primary-application-properties). You can enable [PHP extensions](https://docs.upsun.com/languages/php/extensions.md) just with a list of extensions: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: 'php:8.4' runtime: extensions: - geoip - tidy ``` Alternatively, if you need to include configuration options, use a dictionary for that extension: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: 'php:8.4' runtime: extensions: - geoip - name: blackfire configuration: server_id: foo server_token: bar ``` In 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](https://docs.upsun.com/languages/php/fpm.md). ###### 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](https://docs.upsun.com../source-operations.md) | | `root` | `string` | | The path where the app code lives. Defaults to the root project directory. Useful for [multi-app setups](https://docs.upsun.com../multi-app.md). | ###### Container profile By default, Upsun allocates a container profile to each app and service depending on the range of resources it’s expected to need. Each container profile gives you access to a specific list of CPU and RAM combinations. Using the Upsun CLI or Console, you can then pick a CPU and RAM combination for each of your apps and services. - [Container profile types and resources](https://docs.upsun.com/manage-resources/adjust-resources.md#advanced-container-profiles) - [Default container profiles](https://docs.upsun.com/manage-resources/adjust-resources.md#default-container-profiles) for runtime and service containers - [Customize resources using the `container_profile` key](https://docs.upsun.com/manage-resources/adjust-resources.md#adjust-a-container-profile) ###### 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`. ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: 'php:8.4' 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. #### Composable image The Upsun composable image provides enhanced flexibility when defining your app. It allows you to install several runtimes and tools in your application container, in a **"one image to rule them all"** approach. The composable image is built on [Nix](https://nix.dev), which offers the following benefits: - You can add as many packages to your application container as you need, choosing from over 80,000 packages from [the Nixpkgs collection](https://search.nixos.org/packages). - The packages you add are built in total isolation, so you can install different versions of the same package. - With [Nix](https://nix.dev/reference/glossary#term-Nix), there are no undeclared dependencies in your source code. What works on your local machine is guaranteed to work on any other machine. This page introduces all the settings available to configure your composable image from your `.upsun/config.yaml` file (usually located at the root of your Git repository). Note that multi-app projects can be [set in various ways](https://docs.upsun.com../multi-app.md). If you're pressed for time, jump to this comprehensive [configuration example](https://docs.upsun.com/create-apps.md#comprehensive-example). ###### 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. It is possible to use multiple runtimes in a single application container, for instance PHP, NodeJS and Python, while remaining in control of their versions. For example, the unified `.upsun/config.yaml` file may look like the following: ```yaml {location=".upsun/config.yaml"} applications: frontend: stack: - "php@8.4": extensions: - apcu - sodium - xsl - pdo_sqlite - "nodejs@22" - "python@3.12" # Additional frontend configuration ``` The following table presents all properties available at the level just below the unique application name (`frontend` 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 | |--------------------|-----------------------------------------------------|----------|------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `stack` | An array of [Nix packages](#stack) | Yes | No | A list of packages from the Upsun collection of [supported runtimes](#supported-nix-packages) and/or from [NixPkgs](https://search.nixos.org/packages). | | `relationships` | A dictionary of [relationships](#relationships) | | Yes | Connections to other services and apps. | | `mounts` | A dictionary of [mounts](#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](#web) | | N/A | How the web application is served. | | `workers` | A [worker instance](#workers) | | 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](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). Defaults to `UTC`, which is the timezone used for all logs no matter the value here. See also [app runtime timezones](https://docs.upsun.com../timezone.md) | | `access` | An [access dictionary](#access) | | Yes | Access control for roles accessing app environments. | | `variables` | A [variables dictionary](#variables) | | Yes | Variables to control the environment. | | `firewall` | A [firewall dictionary](#firewall) | | Yes | Outbound firewall rules for the application. | | `hooks` | A [hooks dictionary](#hooks) | | No | What commands run at different stages in the build and deploy process. | | `crons` | A [cron dictionary](#crons) | | No | Scheduled tasks for the app. | | `source` | A [source dictionary](#source) | | No | Information on the app's source code and operations that can be run on it. | | `additional_hosts` | An [additional hosts dictionary](#additional-hosts) | | Yes | Maps of hostnames to IP addresses. | **Note**: The ``type``, ``build``, ``dependencies``, and ``runtime`` keys are only supported when using a [single-runtime image](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md). They are **not** supported when using the composable image. They are replaced by the ``stack`` key. ###### Stack Use the ``stack`` key to define which runtimes and binaries you want to install in your application container. Define them as a YAML array as follows: ```yaml {location=".upsun/config.yaml"} applications: myapp: stack: [ "@" ] # OR stack: - "@" ``` To add a language to your stack, use the `@` format. To add a tool to your stack, use the `` format, as no version is needed. **Warning**: While technically available during the build phase, ``nix`` commands aren’t supported at runtime as the image becomes read-only. When using the Upsun composable image, you don’t need ``nix`` commands. Everything you install using the ``stack`` key is readily available to you as the binaries are linked and included in ``$PATH``. For instance, to [start a secondary runtime](#primary-runtime), just issue the command (e.g. in the [start](https://docs.upsun.com/create-apps/app-reference/composable-image.md#web-commands)) instead of the ``nix run`` command. ######## Primary runtime If you add multiple runtimes to your application container, the first declared runtime becomes the primary runtime. The primary runtime is the one that is automatically started. To start other declared runtimes, you need to start them manually, using [web commands](#web-commands). To find out which start command to use, go to the [Languages](https://docs.upsun.com/languages.md) section, and visit the documentation page dedicated to your runtime. **Note**: If you use PHP, note that PHP-FPM is only started automatically if PHP is defined as the primary runtime. ####### Supported Nix packages **Note**: The Nix packages listed in the following table are officially supported by Upsun to provide optimal user experience. However, you can add any other packages from [the Nixpkgs collection](https://search.nixos.org/) to your ``stack``. This includes packages from the ``unstable`` channel, like [FrankenPHP](https://search.nixos.org/packages?channel=unstable&show=frankenphp&from=0&size=50&sort=relevance&type=packages&query=frankenphp). While available for you to install, packages that aren’t listed in the following table are supported by Nix itself, not Upsun. Depending on the Nix package, you can select only the major runtime version, or the major and minor runtime versions as shown in the table. Security and other patches are applied automatically. | **Language** | **Nix package** | **Supported version(s)** | |----------------------------------------------|---------------|----------------------------------------| | [Clojure](https://clojure.org/) | `clojure` | 1 | | [Common Lisp (SBCL)](https://docs.upsun.com/languages/lisp.md) | `sbcl` | 2 | | [Elixir](https://docs.upsun.com/languages/elixir.md) | `elixir` | 1.151.14 | | [Go](https://docs.upsun.com/languages/go.md) | `golang` | 1.221.21 | | [Java](https://docs.upsun.com/languages/java.md) | `java` | 21 | | [Javascript/Bun](https://bun.sh/) | `bun` | 1 | | [JavaScript/Node.js](https://docs.upsun.com/languages/nodejs.md) | `nodejs` | 222018 | | [Perl](https://www.perl.org/) | `perl` | 5 | | [PHP](https://docs.upsun.com/languages/php.md) | `php` | 8.38.28.1 | | [Python](https://docs.upsun.com/languages/python.md) | `python` | 3.123.113.103.92.7 | | [Ruby](https://docs.upsun.com/languages/ruby.md) | `ruby` | 3.33.23.1 | **Example:** You want to add PHP version 8.4 and ``facedetect`` to your application container. To do so, use the following configuration: ```yaml {location=".upsun/config.yaml"} applications: myapp: stack: [ "php@8.4", "facedetect" ] # OR stack: - "php@8.4" - "facedetect" ``` ####### PHP extensions and Python packages When you add PHP or Python to your application container, you can define which extensions (for PHP) or packages (for Python) you also want to add to your stack. To find out which extensions you can install with your runtime, follow these steps: 1. Go to the [NixOS search](https://search.nixos.org/). 2. Enter a runtime and click **Search**. 3. In the **Package sets** side bar, select the right set of extensions/packages for your runtime version. You can choose the desired extensions/packages from the filtered results. ![Screenshot of the Nix package sets selection for PHP@8.3](https://docs.upsun.com/images/nixos/nixos-packages.png "0.5") ######## Install PHP extensions To enable [PHP extensions](https://docs.upsun.com/languages/php/extensions.md), specify a list of `extensions` below the language definition. To disable [PHP extensions](https://docs.upsun.com/languages/php/extensions.md), specify a list of `disabled_extensions` below the language definition. For instance: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" stack: - "php@8.4": extensions: - apcu - sodium - xsl - pdo_sqlite disabled_extensions: - gd ``` **Note**: To help you find out the name of the PHP package you want to use, some maintainers provide a ``PHP upstream extension`` value in the [NixOS search engine](https://search.nixos.org/packages?channel=unstable&show=php82Extensions.gd). ![Screenshot of an upstream extension value shown in the NixOS search](https://docs.upsun.com/images/nixos/nixossearch-upstream-value.png) If this information is not provided, note that PHP package names on NixOS always respect the ``Extensions.`` format. Therefore, you can copy the ```` as shown in the NixOS search results, and use it in your configuration. Note that you can use environment variables or your ``php.ini`` file to [include further configuration options](https://docs.upsun.com/languages/php.md#customize-php-settings) for your PHP extensions. ######## Install Python packages To install Python packages, add them to your stack as new packages. To do so, use the full name of the package. For instance, to install [``python312Packages.yq``](https://search.nixos.org/packages?channel=unstable&show=python312Packages.yq), use the following configuration: ```yaml {location=".upsun/config.yaml"} applications: myapp: stack: - "python@3.12" - "python312Packages.yq" # python package specific ``` Alternatively, if you need to include configuration options for your extensions, use either your ``php.ini`` file or [environment variables](https://docs.upsun.com/development/variables/set-variables.md). ####### Example configuration Here is a full composable image configuration example. Note the use of the `@` format. ```yaml {location=".upsun/config.yaml"} applications: myapp: stack: - "php@8.4": extensions: - apcu - sodium - xsl - pdo_sqlite - "python@3.12" - "python312Packages.yq" # python package specific - "yq" # tool ``` ####### Combine single-runtime and composable images In a [multiple application context](https://docs.upsun.com/create-apps/multi-app.md), you can use a mix of [single-runtime images](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md) and [composable images](https://docs.upsun.com/create-apps/app-reference/composable-image.md). Here is an example configuration including a ``frontend`` app and a ``backend`` app: ```yaml {location=".upsun/config.yaml"} applications: frontend: stack: - "php@8.4": extensions: - apcu - sodium - xsl - pdo_sqlite - "python@3.12" - "python312Packages.yq" # python package specific backend: type: 'nodejs:22 ``` **Note**: If you add multiple runtimes to your application container, the first declared runtime becomes the primary runtime. The primary runtime is the one that is automatically started. To start other declared runtimes, you need to start them manually, using [web commands](#web-commands). To find out which start command to use, go to the [Languages](https://docs.upsun.com/languages.md) section, and visit the documentation page dedicated to your language. If you use PHP, note that PHP-FPM is only started automatically if PHP is defined as the primary runtime. ###### 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](https://docs.upsun.com/manage-resources.md). **Note**: Composable image container profile defaults to ``HIGH_CPU``.
If multiple runtimes are added to your stack, you would need to change the [default container_profile](https://docs.upsun.com/manage-resources/adjust-resources.md#advanced-container-profiles) or change [default CPU and RAM ratio](https://docs.upsun.com/manage-resources/resource-init.md) on first deployment using the following commands: ```bash {} upsun push --resources-init=manual ``` ###### Relationships To allow containers in your project to communicate with one another, you need to define relationships between them. You can define a relationship between an app and a service, or [between two apps](https://docs.upsun.com/create-apps/multi-app/relationships.md). The quickest way to define a relationship between your app and a service is to use the service's default endpoint. However, some services allow you to define multiple databases, cores, and/or permissions. In these cases, you can't rely on default endpoints. Instead, you can explicitly define multiple endpoints when setting up your relationships. **Note**: App containers don’t have a default endpoint like services. To connect your app to another app in your project, you need to explicitly define the ``http`` endpoint as the endpoint to connect both apps. For more information, see how to [define relationships between your apps](https://docs.upsun.com/create-apps/multi-app/relationships.md). **Availability**: New syntax (default and explicit endpoints) described below is supported by most, but not all, image types (``Relationship 'SERVICE_NAME' of application 'myapp' ... targets a service without a valid default endpoint configuration.``). This syntax is currently being rolled out for all images. If you encounter this error, use the “legacy” Upsun configuration noted at the bottom of this section. To define a relationship between your app and a service: The ``SERVICE_NAME`` is the name of the service as defined in its [configuration](https://docs.upsun.com/add-services.md). It is used as the relationship name, and associated with a ``null`` value. This instructs Upsun to use the service’s default endpoint to connect your app to the service. For example, if you define the following configuration: ```yaml {location=".upsun/config.yaml"} applications: : # ... relationships: mariadb: ``` Upsun looks for a service named ``mariadb`` in your ``.upsun/config.yaml`` file, and connects your app to it through the service’s default endpoint. For reference, the equivalent configuration using explicit endpoints would be the following: ```yaml {location=".upsun/config.yaml"} applications: : # ... relationships: mariadb: service: mariadb endpoint: mysql ``` You can define any number of relationships in this way: ```yaml {location=".upsun/config.yaml"} applications: : # ... relationships: mariadb: redis: elasticsearch: ``` **Tip**: An even quicker way to define many relationships is to use the following single-line configuration: ```yaml {location=".upsun/config.yaml"} applications: : # ... relationships: {, , } services: : type: mariadb:11.4 : type: redis:7.2 : type: elasticsearch:8.5 ``` Use the following configuration: ```yaml {location=".upsun/config.yaml"} applications: : # ... relationships: : service: endpoint: ``` - ``RELATIONSHIP_NAME`` is the name you want to give to the relationship. - ``SERVICE_NAME`` is the name of the service as defined in its [configuration](https://docs.upsun.com/add-services.md). - ``ENDPOINT_NAME`` is the endpoint your app will use to connect to the service (refer to the service reference to know which value to use). For example, to define a relationship named ``database`` that connects your app to a service called ``mariadb`` through the ``db1`` endpoint, use the following configuration: ```yaml {location=".upsun/config.yaml"} applications: : # ... relationships: database: # The name of the relationship. service: mariadb endpoint: db1 ``` For more information on how to handle multiple databases, multiple cores, and/or different permissions with services that support such features, see each service’s dedicated page: - [MariaDB/MySQL](https://docs.upsun.com/add-services/mysql.md#multiple-databases) (multiple databases and permissions) - [PostgreSQL](https://docs.upsun.com/add-services/postgresql.md#multiple-databases) (multiple databases and permissions) - [Redis](https://docs.upsun.com/add-services/redis.md#multiple-databases) (multiple databases) - [Solr](https://docs.upsun.com/add-services/solr.md#solr-6-and-later) (multiple cores) - [Vault KMS](https://docs.upsun.com/add-services/vault.md#multiple-endpoints-example) (multiple permissions) You can add as many relationships as you want to your app configuration, using both default and explicit endpoints according to your needs: ```yaml {location=".upsun/config.yaml"} applications: : # ... relationships: database1: service: mariadb endpoint: admin database2: service: mariadb endpoint: legacy cache: service: redis search: service: elasticsearch ``` **Legacy**: The following legacy syntax for specifying relationships is still supported by Upsun: ```yaml {location=".upsun/config.yaml"} applications: : # ... relationships: : ":" services: SERVICE_NAME_A: type: mariadb:11.4 ``` For example: ```yaml {location=".upsun/config.yaml"} applications: : # ... relationships: database: "db:mysql" services: db: type: mariadb:11.4 ``` Feel free to use this until the default and explicit endpoint syntax is supported on all images. ###### 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](https://docs.upsun.com/manage-resources.md). ####### 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](https://docs.upsun.com/environments/backup.md). - The downsize fails if there’s more data on the disk than the desired size. ###### Mounts After your app is built, its file system is read-only. To make changes to your app's code, you need to use Git. For enhanced flexibility, Upsun allows you to define and use writable directories called "mounts". Mounts give you write access to files generated by your app (such as cache and log files) and uploaded files without going through Git. When you define a mount, you are mounting an external directory to your app container, much like you would plug a hard drive into your computer to transfer data. **Note**: - Mounts aren’t available during the build - When you [back up an environment](https://docs.upsun.com/environments/backup.md), the mounts on that environment are backed up too ####### Define a mount To define a mount, use the following configuration: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" stack: [ "nodejs@22" ] mounts: '': source: source_path: ``` is the path to your mount **within the app container** (relative to the app's root). 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](https://docs.upsun.com../troubleshoot-mounts.md#overlapping-folders). | Name | Type | Required | Description | |---------------|--------------------------------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `source` | `storage`, `tmp`, or `service` | Yes | Specifies the type of the mount:- By design, `storage` mounts can be shared between instances of the same app. You can also configure them so they are [shared between different apps](#share-a-mount-between-several-apps).-`instance` mounts are local mounts. Unique to your app, they are useful to store files that remain local to the app instance, such as application logs.- `tmp` mounts are local ephemeral mounts, where an external directory is mounted to the `/tmp` directory of your app.The content of a `tmp` mount **may be removed during infrastructure maintenance operations**. Therefore, `tmp` mounts 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**.- `service` mounts can be useful if you want to explicitly define and use a [Network Storage](https://docs.upsun.com/add-services/network-storage.md) service to share data between different apps (instead of using a `storage` mount). | | `source_path` | `string` | No | Specifies where the mount points **inside the [external directory](#mounts)**. - If you explicitly set a `source_path`, your mount points to a specific subdirectory in the external directory. - If the `source_path` is an empty string (`""`), your mount points to the entire external directory. - If you don't define a `source_path`, Upsun uses the as default value, without leading or trailing slashes. For example, if your mount lives in the `/web/uploads/` directory in your app container, it will point to a directory named `web/uploads` in the external directory. **WARNING:** Changing the name of your mount affects the `source_path` when it's undefined. See [how to ensure continuity](#ensure-continuity-when-changing-the-name-of-your-mount) and maintain access to your files. | | `service` | `string` | | The purpose of the `service` key depends on your use case. In a multi-app context where a `storage` mount is shared between apps, `service` is required. Its value is the name of the app whose mount you want to share. See how to [share a mount between several apps](#share-a-mount-between-several-apps). In a multi-app context where a [Network Storage service](https://docs.upsun.com/add-services/network-storage.md) (`service` mount) is shared between apps, `service` is required and specifies the name of that Network Storage. | The accessibility to the web of a mounted directory depends on the [`web.locations` configuration](#web). Files can be all public, all private, or with different rules for different paths and file types. Note that when you remove a `tmp` mount from your `.upsun/config.yaml` file, the mounted directory isn't deleted. The files still exist on disk until manually removed, or until the app container is moved to another host during a maintenance operation. ####### Example configuration ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" stack: [ "nodejs@22" ] 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/.cache ``` ####### Ensure continuity when changing the name of your mount Changing the name of your mount affects the default `source_path`. Say you have a `/my/cache/` mount with an undefined `source_path`: ```yaml {location=".upsun/config.yaml"} mounts: '/my/cache/': source: tmp ``` If you rename the mount to `/cache/files/`, it will point to a new, empty `/cache/files/` directory. To ensure continuity, you need to explicitly define the `source_path` as the previous name of the mount, without leading or trailing slashes: ```yaml {location=".upsun/config.yaml"} mounts: '/cache/files/': source: tmp source_path: my/cache ``` The `/cache/files/` mount will point to the original `/my/cache/` directory, maintaining access to all your existing files in that directory. ####### Share a mount between several apps By design, [`storage` mounts](#mounts) are shared **between different instances of the same app**, which enables [horizontal scaling](https://docs.upsun.com/manage-resources.md). In a [multi-application context](https://docs.upsun.com/create-apps/multi-app.md), you can even share a `storage` mount **between different applications** in the same project. To do so, you need to define a `storage` mount in each of your app containers, and point each of those mounts to the same shared external network directory. Use the following configuration: ```yaml {location=".upsun/config.yaml"} applications: app1: mounts: '': source: storage source_path: app2: mounts: '': source: storage service: app1 source_path: ``` - and are the paths to each mount **within their respective app container** (relative to the app's root). - When configuring the first `storage` mount, you don't need to include the `service` key. The first mount implicitly points to an external network directory. The `service` key is required for subsequent mounts, to ensure they use the same external network directory as the first mount. - The `source_path` allows you to point each mount to the same subdirectory **within the shared external network directory**. **Example**: You have a ``backend`` app and a ``frontend`` app. You want both apps to share data from the same mount. Follow these steps: - In your ``backend`` app configuration, define a ``storage`` mount: ```yaml {location=".upsun/config.yaml"} applications: backend: mounts: var/uploads: #The path to your mount within the backend app container. source: storage source_path: backend/uploads #The path to the source of the mount within the external network directory. ``` This creates a ``storage`` mount named ``var/uploads`` in the ``backend`` app container. The mount points to the ``backend/uploads`` directory within an external network directory. - In your ``frontend`` app configuration, define another ``storage`` mount: ```yaml {location=".upsun/config.yaml"} applications: backend: mounts: var/uploads: source: storage source_path: backend/uploads frontend: mounts: web/uploads: #The path to your mount within the frontend app container. source: storage service: backend #The name of the other app, so the mount can point to the same external network directory as that other app's mount. source_path: backend/uploads #The path to the source of the mount within the shared external network directory. ``` This creates another ``storage`` mount named ``web/uploads`` in the ``frontend`` app container. The ``service`` key allows you to specify that the ``web/uploads`` mount should use the same external network directory as the mount previously defined in the ``backend`` app container. The ``source_path`` key specifies which subdirectory within the external network directory both mounts should share ( here, the ``backend/uploads`` directory). Note that another way to share data between apps through a mount is by explicitly [defining a Network Storage service](https://docs.upsun.com/add-services/network-storage.md). ####### Local mounts 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, the following limitations apply: - Content from `tmp` mounts is removed when your app container is moved to another host during an infrastructure maintenance operation - The `/tmp` directory has a [maximum allocation of 8 GB](https://docs.upsun.com/create-apps/troubleshoot-disks.md#no-space-left-on-device) 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. ####### Overlapping mounts The locations of mounts as they are visible to application containers can overlap somewhat. For example: ```yaml {location=".upsun/config.yaml"} applications: myapp: # ... mounts: 'var/cache_a': source: storage source_path: cacheA 'var/cache_b': source: tmp source_path: cacheB 'var/cache_c': source: instance source_path: cacheC ``` In this case, it does not matter that each mount is of a different `source` type. Each mount is restricted to a subfolder within `var`, and all is well. The following, however, is not allowed and will result in a failure: ```yaml {location=".upsun/config.yaml"} applications: myapp: # ... mounts: 'var/': source: storage source_path: cacheA 'var/cache_b': source: tmp source_path: cacheB 'var/cache_c': source: instance source_path: cacheC ``` The `storage` mount type specifically exists to share data between instances of the same application, whereas `tmp` and `instance` are meant to restrict data to build time and runtime of a single application instance, respectively. These allowances are not compatible, and will result in an error if pushed. ###### Web Use the `web` key to configure the web server running in front of your app. | Name | Type | Required | Description | |-------------|--------------------------------------------|-------------------------------|------------------------------------------------------| | `commands` | A [web commands dictionary](#web-commands) | See [note](#required-command) | The command to launch your app. | | `upstream` | An [upstream dictionary](#upstream) | | How the front server connects to your app. | | `locations` | A [locations dictionary](#locations) | | How the app container responds to incoming requests. | See some [examples of how to configure what's served](https://docs.upsun.com../web.md). ####### 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. | | `start` | `string` | See [note](#required-command) | The command to launch your app. If it terminates, it's restarted immediately. | Example: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" stack: [ "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. ######## 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](https://github.com/platformsh-examples/platformsh-example-reactphp) or [Amp](https://github.com/platformsh-examples/platformsh-example-amphp). See how to set up [alternate start commands on PHP](https://docs.upsun.com/languages/php.md#alternate-start-commands). ####### Upstream | Name | Type | Required | Description | Default | |-----------------|---------------------|----------|-------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------| | `socket_family` | `tcp` or `unix` | | Whether your app listens on a Unix or TCP socket. | Defaults to `tcp` for all [primary runtimes](#primary-runtime) except PHP; for PHP the default is `unix`. | | `protocol` | `http` or `fastcgi` | | Whether your app receives incoming requests over HTTP or FastCGI. | Default varies based on the [primary runtimes](#primary-runtime). | 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: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" stack: [ "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](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables) | | `unix` | The Unix socket file specified by the [`SOCKET` environment variable](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables) | 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 ([see `source.root`](#source)). 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 `string`s 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 (see [Set custom headers on static content](https://docs.upsun.com/create-apps/web/custom-headers.md)). Responses from the app aren't affected. | | `request_buffering` | A [request buffering dictionary](#request-buffering) | See below | Handling for chunked requests. | | `rules` | A [rules dictionary](#rules) | | 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](#locations) 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. ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" stack: [ "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: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" stack: [ "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](#hooks). 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](#primary-application-properties). Each worker can differ from the `web` instance in all properties _except_ for: - `crons` as cron jobs don't run on workers - `hooks` as the `build` hook must be the same and the `deploy` and `post_deploy` hooks don't run on workers. A worker named `queue` that was small and had a different start command could look like this: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" stack: [ "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](https://docs.upsun.com/manage-resources.md). ###### 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](https://docs.upsun.com/administration/users.md#environment-type-roles) can access the deployed environment via SSH: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" stack: [ "python@3.9" ] access: ssh: admin ``` ###### Variables Upsun provides a number of ways to set [variables](https://docs.upsun.com/development/variables.md). 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](https://docs.upsun.com/development/variables.md#variable-prefixes). Variables with the prefix `env` are available as a separate environment variable. All other variables are available in the [`PLATFORM_VARIABLES` environment variable](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). The following example sets two variables: - A variable named `env:AUTHOR` with the value `Juan` that's available in the environment as `AUTHOR` - A variable named `d8config:system.site:name` with the value `My site rocks` that's available in the `PLATFORM_VARIABLES` environment variable ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" stack: [ "python@3.9" ] variables: env: AUTHOR: 'Juan' d8config: "system.site:name": 'My site rocks' ``` You can also define and access more [complex values](https://docs.upsun.com/development/variables/use-variables.md#access-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 `string`s | `["0.0.0.0/0"]` | IP addresses in [CIDR notation](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing). See a [CIDR format converter](https://www.ipaddressguide.com/cidr). | | `domains` | Array of `string`s | | [Fully qualified domain names](https://en.wikipedia.org/wiki/Fully_qualified_domain_name) to specify specific destinations by hostname. | | `ports` | Array of `integer`s | | 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: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" stack: [ "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: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" stack: [ "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: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" stack: [ "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: ```bash awk '/query\[[^P]\]/ { print $6 | "sort -u" }' /var/log/dns.log ``` The 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: ```bash facebook.com fastly.com upsun.com www.google.com www.upsun.com ``` ###### 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](#workers), while [web instances](#web) run all three. The process is ordered as: 1. Variables accessible at build time become available. 1. The `build` hook is run. 1. The file system is changed to read only (except for any [mounts](#mounts)). 1. The app container starts. Variables accessible at runtime and services become available. 1. The `deploy` hook is run. 1. The app container begins accepting requests. 1. The `post_deploy` hook 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](https://docs.upsun.com/development/troubleshoot.md#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 the `build` hook 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 that `PLATFORM_CACHE_DIR` is mapped to `/tmp` and 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](https://docs.upsun.com/increase-observability/logs/access-logs.md#container-logs). The following table shows the properties for each job: | Name | Type | Required | Description | |--------------------|----------------------------------------------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `spec` | `string` | Yes | The [cron specification](https://en.wikipedia.org/wiki/Cron#Cron_expression). 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](#cron-commands) | 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](https://docs.upsun.com/environments/cancel-activity.md). ####### Cron commands | Name | Type | Required | Description | |---------|----------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `start` | `string` | Yes | The command that's run. It's run in [Dash](https://en.wikipedia.org/wiki/Almquist_shell). | | `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. | ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" stack: [ "nodejs@22" ] crons: mycommand: spec: 'H * * * *' commands: start: sleep 60 && echo sleep-60-finished && date stop: killall sleep shutdown_timeout: 18 ``` In this example configuration, the [cron specification](#crons) uses the `H` syntax. ####### Example cron jobs ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" stack: [ "ruby@3.3" ] crons: # Execute a rake script every 19 minutes. ruby: spec: '*/19 * * * *' commands: start: 'bundle exec rake some:task' ``` ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" stack: [ "php@8.4" ] crons: # Run Laravel's scheduler every 5 minutes. scheduler: spec: '*/5 * * * *' commands: start: 'php artisan schedule:run' ``` ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" stack: [ "php@8.4" ] crons: # Take a backup of the environment every day at 5:00 AM. snapshot: spec: 0 5 * * * commands: start: | # 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: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" stack: [ "php@8.4" ] 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](https://docs.upsun.com/environments/backup.md) 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](#primary-application-properties). ####### Paused crons [Preview environments](https://docs.upsun.com/glossary.md#preview-environment) 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: Run the following command: ```bash {} upsun redeploy ``` ####### 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](https://docs.upsun.com/languages/php/fpm.md). ###### 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](https://docs.upsun.com../source-operations.md) | | `root` | `string` | | The path where the app code lives. Defaults to the root project directory. Useful for [multi-app setups](https://docs.upsun.com../multi-app.md). | ###### Container profile By default, Upsun allocates a container profile to each app and service depending on the range of resources it’s expected to need. Each container profile gives you access to a specific list of CPU and RAM combinations. Using the Upsun CLI or Console, you can then pick a CPU and RAM combination for each of your apps and services. - [Container profile types and resources](https://docs.upsun.com/manage-resources/adjust-resources.md#advanced-container-profiles) - [Default container profiles](https://docs.upsun.com/manage-resources/adjust-resources.md#default-container-profiles) for runtime and service containers - [Customize resources using the `container_profile` key](https://docs.upsun.com/manage-resources/adjust-resources.md#adjust-a-container-profile) ###### 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`. ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" stack: [ "php@8.4" ] 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. ### Source operations On Upsun, you can run automated code updates through a feature called **source operations**. Defined in your [app configuration](https://docs.upsun.com/create-apps.md), source operations let you specify commands that can commit changes to your project's repository when called. For example, you can set up a source operation to [automatically update your application dependencies](https://docs.upsun.com/learn/tutorials/dependency-updates.md), [update a site from an upstream repository](#update-a-site-from-an-upstream-repository-or-template), or [revert to the last commit](#revert-to-the-last-commit) pushed to your Git repository. To run your source operations, you can use the [Upsun CLI](https://docs.upsun.com../administration/cli.md) or the [Console](https://console.platform.sh). If you want to run your source operations and update your code automatically, you can also define [cron jobs](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#crons). ##### How source operations work When you trigger a source operation, the following happens in order: 1. The current environment HEAD commit is checked out in Git. It doesn't have any remotes or tags defined in the project. It only has the current environment branch. 2. Sequentially, for each app that has an operation bearing [the name](#define-a-source-operation) of the triggered source operation in its configuration, the operation command is run in the app container. The container isn't part of the environment's runtime cluster and doesn't require that the environment is running. The environment has all of the variables normally available during the build phase. These may be optionally overridden by the variables specified when the operation is run. 3. If any new commits were created, they're pushed to the repository and the normal build process is triggered. If multiple apps in a single project both result in a new commit, there are two distinct commits in the Git history but only a single new build process. ##### Define a source operation A source operation requires two things: - A name that must be unique within the application. The name is the key of the block defined under `source.operations` in your [app configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#source). - A `command` that defines what's run when the operation is triggered. The syntax is similar to the following: ```yaml {location=".upsun/config.yaml"} applications: myapp: type: nodejs:22 source: root: "/" operations: : command: ``` For example, to update a file from a remote location, you could define an operation like this: ```yaml {location=".upsun/config.yaml"} applications: myapp: type: nodejs:22 source: root: "/" operations: update-file: command: | set -e curl -O https://example.com/myfile.txt git add myfile.txt git commit -m "Update remote file" ``` The name of the source operation in this case is `update-file`. For more possibilities, see other [source operation examples](#source-operation-examples). ##### Run a source operation Run the following command: ```bash {} upsun source-operation:run ``` Replace with the name of your operation, such as ``update-file`` in the [example above](#define-a-source-operation). After running a source operation, to apply the changes to your local development environment run the `git pull` command. Note that you can [cancel pending or running source operations](https://docs.upsun.com../environments/cancel-activity.md). ##### Use variables in your source operations You can add [variables](https://docs.upsun.com../development/variables.md) to the environment of the source operation. Use the `env:` prefix to expose each of those variables as a Unix environment variable. In this way, they're referenced by the source operation and interpreted the same way as any other variable set in your project. For example, you might want to have a `FILE` variable available with the value `example.txt` to pass to a source operation similar to the following: ```yaml {location=".upsun/config.yaml"} applications: myapp: type: nodejs:22 source: root: "/" operations: update-file: command: | set -e curl -O https://example.com/$FILE git add $FILE git commit -m "Update remote file" ``` Follow these steps to run the source operation: ```bash {} upsun source-operation:run update-file --variable env:FILE="example.txt" ``` ##### Source integrations If your project is using a [source integration](https://docs.upsun.com../integrations/source.md), any new commits resulting from a source operation are first pushed to your external Git repository. Then the source integration pushes those commits to Upsun and redeploys the environment. When using a source integration, you can't run source operations on environments created from pull or merge requests created on the external repository. If you try running a source operation on a non-supported environment, you see the following error: ```text [ApiFeatureMissingException] This project doesn't support source operations. ``` ##### Automated source operations using a cron job You can use a cron to automatically run your source operations. Note that it’s best not to run source operations on your production environment, but rather on a dedicated environment where you can test changes. Make sure you have the [Upsun CLI](https://docs.upsun.com../administration/cli.md) installed and [an API token](https://docs.upsun.com../administration/cli/api-tokens.md#2-create-an-api-token) so you can run a cron job in your app container. 1. Set your API token as a top-level environment variable: - Open the environment where you want to add the variable. - Click Settings **Settings**. - Click **Variables**. - Click **+ Add variable**. - In the **Variable name** field, enter ``env:UPSUN_CLI_TOKEN``. - In the **Value** field, enter your API token. - Make sure the **Available at runtime** and **Sensitive variable** options are selected. - Click **Add variable**. **Note**: Once you add the API token as an environment variable, anyone with [SSH access](https://docs.upsun.com/development/ssh.md) can read its value. Make sure you carefully check your [user access on this project](https://docs.upsun.com/administration/users.md#manage-project-users). 2. Add a build hook to your app configuration to install the CLI as part of the build process: ```yaml {location=".upsun/config.yaml"} applications: myapp: hooks: build: | set -e echo "Installing Upsun CLI" curl -fsSL https://raw.githubusercontent.com/platformsh/cli/main/installer.sh | bash echo "Testing Upsun CLI" upsun ``` 3. Then, to configure a cron job to automatically run a source operation once a day, use a configuration similar to the following: ```yaml {location=".upsun/config.yaml"} applications: myapp: type: nodejs:22 source: root: "/" operations: update-file: command: | set -e curl -O https://example.com/$FILE git add $FILE git commit -m "Update remote file" crons: update: # Run the code below every day at midnight. spec: '0 0 * * *' commands: start: | set -e upsun sync -e development code data --no-wait --yes upsun source-operation:run update-file --no-wait --yes ``` The example above synchronizes the `development` environment with its parent and then runs the `update-file` source operation defined [previously](#define-a-source-operation). ##### Source operation examples ###### Update your application dependencies You can set up a source operation and a cron job to [automate your dependency updates](https://docs.upsun.com/learn/tutorials/dependency-updates.md). ###### Update a site from an upstream repository or template The following source operation syncronizes your branch with an upstream Git repository. 1. [Add a project-level variable](https://docs.upsun.com../development/variables/set-variables.md#create-project-variables) named `env:UPSTREAM_REMOTE` with the Git URL of the upstream repository. That makes that repository available as a Unix environment variable in all environments, including in the source operation's environment. - Variable name: `env:UPSTREAM_REMOTE` - Variable example value: `https://github.com/platformsh/platformsh-docs` 2. In your app configuration, define a source operation to fetch from that upstream repository: ```yaml {location=".upsun/config.yaml"} applications: myapp: type: nodejs:22 source: root: "/" operations: upstream-update: command: | set -e git remote add upstream $UPSTREAM_REMOTE git fetch --all git merge upstream/main ``` 3. Now every time you run the `upstream-update` operation on a given branch, the branch fetches all changes from the upstream git repository and then merges the latest changes from the default branch in the upstream repository. If there’s a conflict merging from the upstream repository, the source operation fails and doesn't update from the upstream repository. Run the `upstream-update` operation on a preview environment rather than directly on Production. ###### Revert to the last commit The following source operation reverts the last commit pushed to the Git repository. This can be useful if you didn't properly test the changes of another operation and you need to quickly revert to the previous state. ```yaml {location=".upsun/config.yaml"} applications: myapp: type: nodejs:22 source: root: "/" operations: revert: command: | git reset --hard HEAD~ ``` Now every time you run the `revert` operation on a given branch, the operation reverts to the last commit pushed to that branch. ###### Update Drupal Core The following source operation uses Composer to update Drupal Core: ```yaml {location=".upsun/config.yaml"} applications: myapp: type: php:8.4 source: root: "/" operations: update-drupal-core: command: | set -e composer update drupal/core --with-dependencies git add composer.lock git commit -m "Automated Drupal Core update." ``` `--with-dependencies` is used to also update Drupal Core dependencies. Read more on how to [update Drupal Core via Composer on Drupal.org](https://www.drupal.org/docs/updating-drupal/updating-drupal-core-via-composer). Now every time you run the `update-drupal-core` operation, it updates Drupal Core. ###### Download a Drupal extension The following source operation downloads a Drupal extension. You can define the Drupal extension by setting an `EXTENSION` variable or [overriding it](#use-variables-in-your-source-operations) when running the source operation. ```yaml {location=".upsun/config.yaml"} applications: myapp: type: php:8.4 source: root: "/" operations: download-drupal-extension: command: | set -e composer require $EXTENSION git add composer.json git commit -am "Automated install of: $EXTENSION via Composer." ``` Now every time you run the `download-drupal-extension` operation, it downloads the defined extension. If it's a new extension, after the source operation finishes, you need to enable the new extension via the Drupal management interface or using Drush. ###### Update Git submodules The following source operation updates all Git submodules recursively: ```yaml {location=".upsun/config.yaml"} applications: myapp: type: php:8.4 source: root: "/" operations: rebuild: command: | set -e git submodule update --init --recursive git submodule update --remote --checkout SHA=$(git submodule | awk -F' ' '{print $1}' | sed -s 's/+//g') echo -n "$SHA" > .sha git add uppler .sha git commit -m "Updating submodule to commit '$SHA'" ``` Now every time you run the `rebuild` operation, it updates the Git submodules. ### Runtime operations Runtime operations allow you to trigger one-off commands or scripts on your project. Similar to [crons](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#crons), they run in the app container but not on a specific schedule. You can [define runtime operations](#define-a-runtime-operation) in your [app configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md) and [trigger them](#run-a-runtime-operation) at any time through the Upsun CLI. For example, if you have a static website, you may want to set up a runtime operation to occasionally fetch content from a backend system without having to rebuild your whole app. ##### Define a runtime operation To define a runtime operation, add a configuration similar to the following: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" operations: : role: commands: start: ``` When you define a runtime operation, you can specify which users can trigger it according to their user `role`: - `viewer` - `contributor` - `admin` If you don't set the `role` option when configuring your runtime operation, by default all users with the `contributor` role can trigger it. For example, to allow admin users to clear the cache of a Drupal site, you could define an operation like the following: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" operations: clear-rebuild: role: admin commands: start: drush cache:rebuild ``` The name of the runtime operation in this case is `clear-rebuild`. For more possibilities, see other [runtime operation examples](#runtime-operation-examples). ##### Run a runtime operation A runtime operation can be triggered through the Upsun CLI once it has been [defined](#define-a-runtime-operation). Run the following command: ```bash {} upsun operation:run --project --environment ``` You can only trigger a runtime operation if you have permission to do so. Permissions are granted through the ``role`` option specified in the [runtime operation configuration](#define-a-runtime-operation). This can only be done if a [runtime operation has been defined](#define-a-runtime-operation). For example, to trigger the runtime operation [defined previously](#define-a-runtime-operation), you could run the following command: ```bash {} upsun operation:run clear-rebuild --project --environment ``` ##### List your runtime operations To list all the runtime operations available on an environment, run the following command: ```bash upsun operation:list --project --environment ``` ##### Runtime operation examples ###### Build your app when using a static site generator During every Upsun deployment, a standard [`build` step](https://docs.upsun.com/learn/overview/build-deploy.md#the-build) is run. When you use a static site generator like Gatsby or Next.js with a headless backend you need to run a second `build` step to get your app ready for production. This is because, as its framework is being built, your frontend needs to pull content-related data from your backend’s API (to generate all the static HTML pages your site is to serve). To accomplish this on Upsun, where each app goes through a build-deploy pipeline in parallel, your frontend’s build must be delayed _until after_ your backend has fully deployed. It's often delayed up until the [`post_deploy` hook](https://docs.upsun.com../create-apps/hooks/hooks-comparison.md#post-deploy-hook) stage, when the filesystem is read-only. You can use a runtime operation to trigger the second `build` step after the initial deployment of your app or after a redeployment. You can also trigger it when you need to fetch content from your backend but want to avoid going through the whole Upsun [build and deploy processes](https://docs.upsun.com/learn/overview/build-deploy.md) again. **Note**: The following examples assume that the frontend and backend containers are included in the same environment. This isn’t necessary for the commands to run successfully.
What is necessary is that the build destination for your frontend **is writable at runtime** (meaning, you must [define a mount](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#mounts) for it). If you don’t want to include a build within a mount (especially if your data source **isn’t** on Upsun), you can use [source operations](https://docs.upsun.com/create-apps/source-operations.md) to achieve a similar effect, but through generating a new commit. To trigger your runtime operation, run a command similar to the following: ```bash {} upsun operation:run gatsby-build --project --environment ``` To run the [Next.js build](https://nextjs.org/docs/deployment#nextjs-build-api) step, define a runtime operation similar to the following: ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "myapp" operations: next-build: role: admin commands: # All below are valid, depending on your setup start: next build # start: npx next build # start: npm run build ``` To trigger your runtime operation, run a command similar to the following: ```bash {} upsun operation:run next-build --project --environment ``` ###### Execute actions on your Node.js app You can define runtime operations for common [pm2](https://pm2.io/docs/runtime/overview/) process manager tasks. To trigger your runtime operation, run a command similar to the following: ```bash {} upsun operation:run pm2-ping --project --environment ``` To reload your Node.js app, define a runtime operation similar to the following: ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "myapp" operations: pm2-reload: role: admin commands: start: | # Assuming pm2 start npm --no-daemon --watch --name $APP -- start -- -p $PORT APP=$(cat package.json | jq -r '.name') pm2 reload $APP ``` To trigger your runtime operation, run a command similar to the following: ```bash {} upsun operation:run pm2-reload --project --environment ``` To restart your Node.js app, define a runtime operation similar to the following: ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "myapp" operations: pm2-restart: role: admin commands: start: | # Assuming pm2 start npm --no-daemon --watch --name $APP -- start -- -p $PORT APP=$(cat package.json | jq -r '.name') pm2 restart $APP ``` To trigger your runtime operation, run a command similar to the following: ```bash {} upsun operation:run pm2-restart --project --environment ``` ###### Define management commands on your Django project On a Django project, you can [define custom `django-admin` commands](https://docs.djangoproject.com/en/4.2/howto/custom-management-commands/), for example to run a one-off management command (`manual migration` in the example above) outside of the Django ORM migration framework. To do so, define a runtime operation similar to the following: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: python:3.9 operations: manual-migration: role: admin commands: start: python manage.py manual_migration ``` To trigger your runtime operation, run a command similar to the following: ```bash upsun operation:run manual-migration --project --environment ``` ### Configure what's served How you should configure your web server depends a lot on what you want to serve. The following examples show how in specific scenarios you might define [your web server](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#web). #### Create a basic PHP app with a front controller To handle dynamic requests to your PHP app, you might want to use a [front controller](https://en.wikipedia.org/wiki/Front_controller). The following example shows how for such an app you might start defining [your web server](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#web). ###### Define a document root Start by defining your document root (where all your publicly visible pages are). ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" web: locations: '/': root: 'public' ``` ###### Define a front controller Define where all requests that don't match a file in the document root are sent. ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" web: locations: '/': root: 'public' passthru: '/index.php' index: - index.php ``` In this case, `/index.php` acts as a front controller and handles dynamic requests. Because it handles dynamic requests, you want to ensure that scripts are enabled and responses aren't cached. ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" web: locations: '/': ... scripts: true # No caching for static files. # (Dynamic pages use whatever cache headers are generated by the program.) expires: -1 ``` ###### Define rules You might want to define specific rules for the location. For example, you might want to allow all kinds of files except mp4 files. ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" web: locations: '/': ... # Allow all file types generally allow: true rules: # Disallow .mp4 files specifically. \.mp4$: allow: false ``` ###### Set different rules for specific locations You might want to set specific rules for specific locations. For example, you might have files in your `/public/images` directory that are served at `/images`. You could define a specific cache time for them and limit them to only static image files. ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" web: locations: '/': ... # Set a 5 min expiration time for static files in this location. # Missing files are sent to front controller # through the '/' location above. '/images': expires: 300 passthru: true # Do not execute PHP scripts from this location and do not # deliver their source code (for enhanced security). scripts: false allow: false rules: # Only allow static image files in this location '\.(jpe?g|png|gif|svgz?|ico|bmp)$': allow: true ``` ###### Complete example ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" web: locations: '/': root: 'public' passthru: '/index.php' index: - index.php scripts: true # No caching for static files. # (Dynamic pages use whatever cache headers are generated by the program.) expires: -1 # Allow all file types generally allow: true rules: # Disallow .mp4 files specifically. \.mp4$: allow: false # Set a 5 min expiration time for static files in this location. # Missing files are sent to front controller # through the '/' location above. '/images': expires: 300 passthru: true # Do not execute PHP scripts from this location and do not # deliver their source code (for enhanced security). scripts: false allow: false rules: # Only allow static image files in this location '\.(jpe?g|png|gif|svgz?|ico|bmp)$': allow: true ``` #### Rewrite requests without redirects You might want to rewrite requests so they're served by specific sections of your app without having to redirect users. For example, you might want to make URLs seem semantic to users without having to rewrite your app architecture. In such a case, you might want requests to `/shoes/great-shoe/` to be served as if they were requests to `/?category=shoes&product=great-shoe`. If so, add a [rule](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#rules) similar to the following: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" web: locations: '/': ... rules: '^/(?[^/]+)/(?[^/]+)/$': passthru: '/?category=$category&product=$product' ``` Or you might organize your images by file type, but don't want to expose the organization externally. You could rewrite requests to do that behind the scenes: ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" web: locations: '/': ... rules: '^/img/(?.*)\.(?.*)$': passthru: '/$type/$name.$type' ``` Now a request to `/img/image.png` returns the file found at `/png/image.png`. ###### Query parameters Query parameters in the request are unaffected and are passed in the request to the app. So if you have the category and product rule from previously, a request to `/shoes/great-shoe/?product=terrible-shoe` is rewritten to `?category=shoes&product=great-shoe&product=terrible-shoe`. In that case, the `product` query parameter returns as `terrible-shoe`. #### Serve directories at different paths In some cases you might want to depart from the common practice of serving directories directly. You might want to create a URL structure different than the structure on your disk. For example, in Git you might have a folder for your app and another folder that builds your documentation. Your entire Git repository might look like the following: ```text .upsun config.yaml application/ [app-code-files] docs-src/ [docs-code-files] ``` And your build process might build the documentation with an output folder such as `docs-public`. If so, you can serve all requests by your app code except for those that start with `/docs`, which you serve with your generated docs. Use a [`web` configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#web) similar to the following: ```yaml {location=".upsun/config.yaml"} applications: docs: source: root: "/" web: locations: '/': passthru: true '/docs': root: 'docs-public' index: - "index.html" expires: 24h scripts: false allow: true ``` This way, your app can safely coexist with static files as if it were a single site hierarchy. And you can keep the static pages separate from your app code. #### Serve static sites Static site generators are a popular way to create fast sites. Because there's no need to wait for responses from servers, the sites may load faster. To learn how to serve your static site using Upsun, you can start with the required [minimal app configuration](#minimal-app-configuration) and build on it, or jump straight to an [example of a complete configuration](#complete-example-configuration). ###### Minimal app configuration To successfully serve a static site using Upsun, you need to set up a minimal app configuration similar to the following: ```yaml {location=".upsun/config.yaml"} applications: myapp: # The type of the application to build. type: "nodejs:22" source: root: "/" # The web key configures the web server running in front of your app. web: locations: /: # Static site generators usually output built static files to a specific directory. # Define this directory (must be an actual directory inside the root directory of your app) # as the root for your static site. root: "public" # Files to consider when serving a request for a directory. index: - index.html ``` See more information on the required minimal settings: - [Top-level properties](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#primary-application-properties). - [`web` property](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#web). - [`locations` properties](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#locations). ###### Add more features ####### Allow static files but not dynamic files on PHP containers If you have a PHP container, you might want to enable client-side scripts but disable server-side scripts. To enable static files that don't match any rule while disabling server-side scripts on a PHP container, use the following configuration: ```yaml {location=".upsun/config.yaml"} applications: myapp: # The type of the application to build. type: "nodejs:22" source: root: "/" web: locations: '/': ... scripts: false allow: true ``` See more information on [`locations` properties](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#locations). ####### Create cache rules You can create sensible cache rules to improve performance. For example, if you publish new content regularly without updating images or site files much, you might want to cache text files for a day but all image files for longer. To do so, use a configuration similar to the following: ```yaml {location=".upsun/config.yaml"} applications: myapp: # The type of the application to build. type: "nodejs:22" source: root: "/" web: locations: '/': ... expires: 24h rules: \.(css|js|gif|jpe?g|png|svg)$: expires: 4w ``` You can also set a `Cache-Control` header in your rules. ```yaml {location=".upsun/config.yaml"} applications: myapp: web: locations: '/': ... expires: 24h rules: \.(css|js|gif|jpe?g|png|svg)$: headers: Cache-Control: "public, max-age=2419200, immutable" ``` If `expires` and a `Cache-Control` header are set, the rule ignores the `expires` and sets only the `Cache-Control` header. For this reason, make sure to add a `max-age` value, in seconds, for the `Cache-Control` header. ####### Conserve the server Because your site is completely static, it doesn't need the server to be running. To set a background process that blocks the server and conserves resources, use the following configuration: ```yaml {location=".upsun/config.yaml"} applications: myapp: # The type of the application to build. type: "nodejs:22" source: root: "/" web: commands: start: sleep infinity ``` You can also use this place to start small programs, such as a [script to handle 404 errors](https://support.platform.sh/hc/en-us/community/posts/16439636723474). ###### Complete example configuration ```yaml {location=".upsun/config.yaml"} applications: myapp: # The type of the application to build. type: "python:3.9" source: root: "/" web: locations: '/': # The public directory of the application relative to its root root: 'public' # The files to look for when serving a directory index: - 'index.html' # Disable server-side scripts scripts: false allow: true # Set caching policy expires: 24h rules: \.(css|js|gif|jpe?g|png|svg)$: expires: 4w commands: # Run a no-op process that uses no CPU resources since this is a static site start: sleep infinity ``` #### Set custom headers on static content When your app responds to dynamic requests, it can generate headers on the fly. To set headers for static content, add them in [your `web` configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#web). You might want to do so to add custom content-type headers, limit what other sites can embed your content, or allow cross origin requests. Say you want to limit most files to be embedded only on your site, but you want an exception for Markdown files. And you want to serve both Markdown and [AAC](https://en.wikipedia.org/wiki/Advanced_Audio_Coding) files with the correct content types to avoid [MIME sniffing](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#mime_sniffing). Start by defining a header for files in general: ```yaml {location=".upsun/config.yaml"} applications: myapp: # The type of the application to build. type: "nodejs:22" source: root: "/" web: locations: "/": ... # Apply rules to all static files (dynamic files get rules from your app) headers: X-Frame-Options: SAMEORIGIN ``` This sets the `X-Frame-Options` header to `SAMEORIGIN` for all static files. Now your files can only be embedded within your site. Now set up an exception for Markdown (`*.md`) using a [rule](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#rules): ```yaml {location=".upsun/config.yaml"} applications: myapp: # The type of the application to build. type: "nodejs:22" source: root: "/" web: locations: "/": #... rules: \.md$: headers: Content-Type: "text/markdown; charset=UTF-8" ``` This rule sets an explicit content type for files that end in `.md`. Because specific rules override the general heading configuration, Markdown files don't get the `X-Frame-Options` header set before. **Setting charset**: By default, [HTTP charset parameters](https://www.w3.org/International/articles/http-charset/index.en) are not sent to the response. If not set, modern browsers will detect ``ISO-8859-1`` and likely default to ``windows-1252`` as this has 32 more international characters. To set the HTTP charset parameters to your desired charset, you can add ``; charset=UTF-8`` in the ``Content-Type`` parameters. Now set a rule for AAC files. ```yaml {location=".upsun/config.yaml"} applications: myapp: # The type of the application to build. type: "nodejs:22" source: root: "/" web: locations: "/": ... rules: \.aac$: headers: X-Frame-Options: SAMEORIGIN Content-Type: audio/aac ``` This rule sets an explicit content type for files that end in `.aac`. It repeats the rule for `X-Frame-Options` because the `headers` block here overrides the more general configuration. So now you have three header configurations: * `X-Frame-Options: SAMEORIGIN` **and** `Content-Type: audio/aac` for AAC files * Only `Content-Type: text/markdown` for Markdown files * Only `X-Frame-Options: SAMEORIGIN` for everything else ###### Cross origin requests To allow cross origin requests, add a `Access-Control-Allow-Origin` header to responses. You can do so for specific origins or for all origins with a wildcard. ```yaml {location=".upsun/config.yaml"} applications: myapp: # The type of the application to build. type: "nodejs:22" source: root: "/" web: locations: "/": ... # Apply rules to all static files (dynamic files get rules from your app) headers: Access-Control-Allow-Origin: "*" ``` If you use the wildcard value, the headers are modified for each request in the following ways: * The value of the `Access-Control-Allow-Origin` header is set to the value of the `Origin` request header. * The `Vary` header is included with a value of `Origin`. See why in the [MDN web docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#access-control-allow-origin). This is done so that credentialed requests can be supported. They would otherwise fail CORS checks if the wildcard value is used. ###### `Strict_Transport_Security` header The `Strict_Transport_Security` header returns a value of `max-age=0` unless you enable [HTTP Strict Transport Security (HSTS)](https://docs.platform.sh/define-routes/https.md#enable-http-strict-transport-security-hsts) in your [routes configuration](https://docs.upsun.com../../define-routes.md). Note that once HSTS is enabled, configuration capabilities depend on the [HSTS properties](https://docs.platform.sh/define-routes/https.md#enable-http-strict-transport-security-hsts) set in your routes configuration. For example, the `max-age` value is set to `31536000` by Upsun and can't be customized. ### Set up multiple apps in a single project You can create multiple apps within a single project so they can share data. This can be useful if you have several apps that are closely related, such as a backend-only CMS and a frontend system for content delivery and display. No matter how many apps you have in one project, they're all served by a single [router for the project](https://docs.upsun.com/create-apps/multi-app/routes.md). To allow your apps to communicate with each other, [create relationships](https://docs.upsun.com/create-apps/multi-app/relationships.md). Each app separately defines its relationships to [services](https://docs.upsun.com/add-services.md), so apps can share services or have their own. #### Choose a project structure How you structure a project with multiple apps depends on how your code is organized and what you want to accomplish. For example, there are various ways you could set up the following multiple apps: Here are some example use cases and potential ways to organize the project: | Use case | Structure | |-----------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------| | Separate basic apps that are worked on together. | [Unified app configuration](#unified-app-configuration) | | One app depends on code from another app. | [Nested directories](#nested-directories) | | You want to keep configuration separate from code, such as through Git submodules. | [Configuration separate from code](#split-your-code-source-into-multiple-git-submodule-repositories) | | You want multiple apps from the same source code. | [Unified app configuration](#unified-app-configuration) | | You want to control all apps in a single location. | [Unified app configuration](#unified-app-configuration) | ###### Unified app configuration You can configure all your apps from a single file. To do so, create a `.upsun/config.yaml` and define each app as a key. For example, if you have an API Platform backend with a Symfony API, a Mercure Rocks server, and a Gatsby frontend, you can organize your repository like this: ```txt ├── .upsun │ ├── config.yaml **Note**: The ``.upsun`` directory is located at the root, separate from your apps. It contains all the needed configuration files to set up the routing, services and behavior of each app. Since the code bases of your apps live in a different directory, you need to [change the source root of each app](#change-the-source-root-of-your-app). To build multiple apps from the repository root, set ``source.root`` to ``/``. This allows you to control all your apps in one place and even build multiple apps from the same source code. To allow your apps to communicate with each other, define [relationships](https://docs.upsun.com/create-apps/multi-app/relationships.md). Note that with this setup, when you amend the code of one of your apps, the build image for your other apps can still be reused. Once your repository is organized, you can use a configuration similar to the following: ```yaml {location=".upsun/config.yaml"} applications: api: type: php:8.2 relationships: database: service: "database" endpoint: "postgresql" mounts: "/var/cache": "shared:files/cache" "/var/log": "shared:files/log" "/var/sessions": "shared:files/sessions" web: locations: "/": root: "public" passthru: '/index.php' index: - index.php headers: Access-Control-Allow-Origin: "*" hooks: build: | set -x -e curl -s https://get.symfony.com/cloud/configurator | bash symfony-build deploy: | set -x -e symfony-deploy source: root: api-app admin: type: nodejs:16 mounts: '/.tmp_platformsh': 'shared:files/tmp_platformsh' '/build': 'shared:files/build' '/.cache': 'shared:files/.cache' '/node_modules/.cache': 'shared:files/node_modules/.cache' web: locations: "/admin": root: "build" passthru: "/admin/index.html" index: - "index.html" headers: Access-Control-Allow-Origin: "*" hooks: build: | set -eu corepack yarn install --immutable --force post_deploy: | corepack yarn run build source: root: admin gatsby: type: 'nodejs:18' mounts: '/.cache': { source: tmp, source_path: cache } '/.config': { source: storage, source_path: config } '/public': { source: storage, source_path: public } web: locations: '/site': root: 'public' index: [ 'index.html' ] scripts: false allow: true hooks: build: | set -e yarn --frozen-lockfile post_deploy: | yarn build --prefix-paths source: root: gatsby mercure: type: golang:1.18 mounts: 'database': { source: storage, source_path: 'database' } '/.local': { source: storage, source_path: '.local' } '/.config': { source: storage, source_path: '.config' } web: commands: start: ./mercure run --config Caddyfile.platform_sh locations: /: passthru: true scripts: false request_buffering: enabled: false headers: Access-Control-Allow-Origin: "*" hooks: build: | # Install Mercure using cache FILE="mercure_${MERCUREVERSION}_Linux_x86_64.tar.gz" if [ ! -f "$PLATFORM_CACHE_DIR/$FILE" ]; then URL="https://github.com/dunglas/mercure/releases/download/v${MERCUREVERSION}/$FILE" wget -O "$PLATFORM_CACHE_DIR/$FILE" $URL else echo "Found $FILE in cache, using cache" fi file $PLATFORM_CACHE_DIR/$FILE tar xvzf $PLATFORM_CACHE_DIR/$FILE source: root: mercure/.config ``` ###### Nested directories When code bases are separate, changes to one app don't necessarily mean that the other apps in the project get rebuilt. You might have a situation where app `main` depends on app `languagetool`, but `languagetool` doesn't depend on `main`. In such cases, you can nest the dependency so the parent (`main`) gets rebuilt on changes to it or its children, but the child (`languagetool`) is only rebuilt on changes to itself. For example, you might have a Python app (`main`) that runs a script that requires Java code to be up to date. But the Java app (`languagetool`) doesn't require updating when the Python app (`main`) is updated. In that case, you can nest the Java app within the Python app: ```txt ├── .upsun │ ├── .upsun/config.yaml ├── languagetool │ └── main.java **Note**: The ``.upsun`` directory is located at the root, separate from your apps. It contains all the needed configuration files to set up the routing, services and behavior of each app. Since the code base of the ``languagetool`` app lives in a different directory (``languagetool/``), you need to [change the source root](#change-the-source-root-of-your-app) of the ``languagetool`` app. Once your repository is organized, you can use a configuration similar to the following: ```yaml {location=".upsun/config.yaml"} applications: main: type: 'python:3.11' source: root: '/' ... languagetool: type: 'java:17' source: root: 'languagetool' ... ``` ###### Split your code source into multiple Git submodule repositories If you have different teams working on different code with different processes, you might want each app to have its own repository. Then you can build them together in another repository using [Git submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules). With this setup, your apps are kept separate from the top application. Each app has its own [Git submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules) containing its code base. All your apps are configured in a single `.upsun/config.yaml` file. So you could organize your [project repository](https://github.com/platformsh-templates/bigfoot-multiapp/tree/submodules-root-app-yaml) like this: ```text ├── .upsun │ ├── config.yaml ├── @admin **Note**: In this case, and any other case where your app configuration files are kept outside of the app directory, make sure you [change the source root](#change-the-source-root-of-your-app) for each of your apps. ###### Change the source root of your app When your app's code base and configuration file aren't located at the same directory level in your project repository, you need to [define a root directory](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#root-directory) for your app. To do so, add a new `source.root` property in your app configuration. For example, to change the source root of the `admin` app from the [unified app configuration](#unified-app-configuration) example project, you could add the following configuration: ```yaml {location=".upsun/config.yaml"} applications: admin: source: root: admin ``` The `source.root` path is relative to the repository root. In this example, the `admin` app now treats the `admin` directory as its root when building. If `source.root` isn't specified, it defaults to the project root directory, that is `"/"`. #### Define routes for your multiple apps When you set up a project containing multiple applications, all of your apps are served by a single [router for the project](https://docs.upsun.com/define-routes.md). Each of your apps must have a `name` that's unique within the project. To define specific routes for one of your apps, use this `name`. There are various ways you can define routes for multiple app projects. In this project, you have a CMS app, two frontend apps (one using Symfony and another using Gatsby), and a Mercure Rocks server app, defined as follows: ```yaml {location=".upsun/config.yaml"} applications: admin: source: root: admin type: nodejs:22 api: source: root: api type: php:8.4 gatsby: source: root: gatsby type: nodejs:22 mercure: source: root: mercure/.config type: golang:1.23 ``` **Note**: You don’t need to define a route for each app in the repository. If an app isn’t specified, then it isn’t accessible to the web. One good example of defining an app with no route is when you [use Git submodules](https://docs.upsun.com/create-apps/multi-app/project-structure.md#split-your-code-source-into-multiple-git-submodule-repositories) and want to [use a source operation to update your submodules](https://docs.upsun.com/development/submodules.md#update-submodules). You can also achieve the same thing by defining the app as a [worker](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#workers). Depending on your needs, you could configure the router container [using subdomains](#define-routes-using-subdomains) or using [subdirectories](#define-routes-using-subdirectories). ####### Define routes using subdomains You could define routes for your apps as follows: ```yaml {location=".upsun/config.yaml"} routes: "https://mercure.{default}/": type: upstream upstream: "mercure:http" "https://{default}/": type: upstream upstream: "api:http" ``` So if your default domain is `example.com`, that means: - `https://mercure.example.com/` is served by your Mercure Rocks app (`mercure`). - `https://example.com/` is served by your Symfony frontend app (`api`). **Note**: Using a subdomain might [double your network traffic](https://nickolinger.com/blog/2021-08-04-you-dont-need-that-cors-request/), so consider using a path like ``https://{default}/api`` instead. ####### Define routes using subdirectories Alternatively, you could define your routes as follows: ```yaml {location=".upsun/config.yaml"} routes: "https://{default}/": type: upstream upstream: "api:http" "https://{default}/admin": type: upstream upstream: "admin:http" ``` Then you would need to configure each app's `web.locations` property to match these paths: ```yaml {location=".upsun/config.yaml"} applications: admin: source: root: admin type: nodejs:22 ... web: locations: '/admin': passthru: '/admin/index.html' root: 'build' index: - 'index.html' api: source: root: api type: php:8.4 ... web: locations: "/": passthru: "/index.php" root: "public" index: - index.php routes: "https://{default}/": type: upstream upstream: "api:http" "https://{default}/admin": type: upstream upstream: "admin:http" ``` So if your default domain is `example.com`, that means: - `https://example.com/` is served by your Symfony frontend app (`api`). - `https://example.com/admin` is served by your Admin app (`admin`). Note that in this example, for the configuration of your `admin` app, you need to add the URL suffix `/admin` as both an index in the `web.locations` and a value for the `passhtru` setting. For a complete example, [go to this project on GitHub](https://github.com/platformsh-templates/bigfoot-multiapp/tree/submodules-root-subfolders-applications). #### Define relationships between your multiple apps When you set up a project containing multiple applications, by default your apps can't communicate with each other. To enable connections, define relationships between apps using the `http` endpoint. You can't define circular relationships. If `app1` has a relationship to `app2`, then `app2` can't have a relationship to `app1`. If you need data to go both ways, consider coordinating through a shared data store, like a database or [RabbitMQ server](https://docs.upsun.com/add-services/rabbitmq.md). Relationships between apps use HTTP, not HTTPS. This is still secure because they're internal and not exposed to the outside world. ###### Relationships example You have two apps, `app1` and `app2`, and `app1` needs data from `app2`. In your app configuration for `app1`, define a relationship to `app2`: ```yaml {location=".upsun/config.yaml"} applications: app1: relationships: api: service: "app2" endpoint: "http" ``` Once they're both built, `app1` can access `app2` at the following URL: `http://api.internal`. The specific URL is always available through the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables), or through the [`PLATFORM_RELATIONSHIPS` variable](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables): It uses the ``jq`` library, which is included in all app containers for this purpose. ```bash {location="Terminal on app1 container"} $ echo $PLATFORM_RELATIONSHIPS | base64 --decode | jq '.api[0].host' api.internal ``` ### Timezones On Upsun, there are several timezones you might want to keep in mind. All timezones default to UTC time. You can customize some of them, but in most cases, it's best if you leave them in UTC and store user data with an associated timezone instead. The different timezones on Upsun are the following: | Timezone | Description |Customizable | |----------------------|----------------------------------------------|--------------| | Container timezone | The timezone for all Upsun containers (UTC). |No | | App runtime timezone | [Set an app runtime timezone](#set-an-app-runtime-timezone) if you want your app runtime to use a specific timezone instead of the container timezone.
The app runtime timezone only affects your app itself. | Yes | | Cron timezone | [Set a cron timezone](#set-a-cron-timezone) if you want your crons to run in a specific timezone instead of the app runtime timezone (or instead of the container timezone if no app runtime timezone is set on your project).
The cron timezone only affects your cron jobs. | Yes | | Log timezone | The timezone for all Upsun logs (UTC). | No | **Note**: Each Upsun project also has a **project timezone** that only affects [automated backups](https://docs.upsun.com/environments/backup.md#automated-backups). By default, the project timezone is based on the [region](https://docs.upsun.com/development/regions.md) where your project is hosted. You can [change it from the Console](https://docs.upsun.com/projects/change-project-timezone.md) at any time. ##### Set an app runtime timezone How you can set an app runtime timezone depends on your actual app runtime: Start the server with ``env TZ=’’ node server.js``.Start the server with ``env TZ=’’ python server.py``. - Start the server with ``env TZ=’’ java -jar …`` OR. - Set the Java virtual machine argument ``user.timezone``. This Java virtual machine argument takes precedence over the environment variable TZ. For example, you can use the flag ``-D`` when running the application: ``java -jar -D user.timezone=GMT`` or ``java -jar -D user.timezone="Asia/Kolkata"`` ##### Set a cron timezone You can set a specific timezone for your crons so they don't run in your app runtime timezone (or container timezone if no app runtime timezone is set on your project). To do so, [set the `timezone` top-level property](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#primary-application-properties) in your app configuration. ### Troubleshoot disks For more general information, see how to [troubleshoot development](https://docs.upsun.com/development/troubleshoot.md). ##### Low disk space If you have set up [health notifications](https://docs.upsun.com../integrations/notifications.md), you may receive a notification of low disk space. To solve this issue: * [Check mount usage](https://docs.upsun.com/create-apps/troubleshoot-mounts.md#disk-space-issues) * [Check your database disk space](#check-your-database-disk-space) (if applicable) * [Increase the available disk space](#increase-available-disk-space) (if necessary) ###### Check your database disk space To get approximate disk usage for a database, run the command `upsun db:size`. This returns an estimate such as the following: ```text +----------------+-----------------+--------+ | Allocated disk | Estimated usage | % used | +----------------+-----------------+--------+ | 1.0 GiB | 520.3 MiB | ~ 51% | +----------------+-----------------+--------+ ``` Keep in mind that this estimate doesn't represent the exact real size on disk. But if you notice that the usage percentage is high, you may need to increase the available space. ###### Increase available disk space If you find that your application or service is running out of disk space, you can increase the available storage. To increase the space available for applications and services, use the `upsun resources:set` command. For more information, see how to [manage resources](https://docs.upsun.com/manage-resources.md). ##### No space left on device During the `build` hook, you may see the following error: ```text W: [Errno 28] No space left on device: ... ``` This is caused by the amount of disk provided to the build container before deployment. Application images are restricted to 8 GB during build, no matter how much writable disk has been set aside for the deployed application. Some build tools (yarn/npm) store cache for different versions of their modules. This can cause the build cache to grow over time beyond the maximum. Try [clearing the build cache](https://docs.upsun.com../development/troubleshoot.md#clear-the-build-cache) and [triggering a redeploy](https://docs.upsun.com../development/troubleshoot.md#force-a-redeploy). If for some reason your application absolutely requires more than 8 GB during build, you can open a [support ticket](https://docs.upsun.com/learn/overview/get-support.md) to have this limit increased. ### Troubleshoot mounts For more general information, see how to [troubleshoot development](https://docs.upsun.com/development/troubleshoot.md). ##### Overlapping folders If you have a mount with the same name as a directory you've committed to Git or you create such a directory during the build, you get a message like the following: ```bash W: The mount '/example' has a path that overlaps with a non-empty folder. The content of the non-empty folder either comes from: - your git repository (you may have accidentally committed files). - or from the build hook. Please be aware that this content isn't accessible at runtime. ``` This shows that the files in Git or from your build aren't available after the build. The only files that are available are those in your mount. To make the files available in the mount, move them away and then copy them into the mount: 1. In the `build` hook, use `mv` to move the files to another location. ```bash mv example tmp/example ``` 2. In the `deploy` hook, use `cp` to copy the files into the mount. ```bash cp -r tmp/example example ``` To see the files without copying them, temporarily remove the mount from your app configuration. Then SSH into your app and view the files. You can then put the mount back in place. ##### Mounted files not publicly accessible If you've set up mounts to handle files like user uploads, you want to make sure the files are accessible. Do so by managing their [location](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#locations). This example defines two mounts, one named `private` and one `upload`: ```yaml {location=".upsun/config.yaml"} applications: myapp: mounts: 'private': source: storage source_path: private 'uploads': source: storage source_path: uploads ``` With only this definition, their behavior is the same. To make `uploads` accessible, define a location with different rules as in the following example: ```yaml {location=".upsun/config.yaml"} applications: myapp: web: locations: '/': # Handle dynamic requests root: 'public' passthru: '/app.php' # Allow uploaded files to be served, but don't run scripts. '/uploads': root: 'uploads' expires: 300s scripts: false allow: true ``` ##### Mounts starting with a dot ignored Upsun ignores YAML keys that start with a dot. This causes a mount like `.myhiddenfolder` to be ignored. To mount a directory starting with a dot, put a `/` at the start of its definition: ```yaml {location=".upsun/config.yaml"} applications: myapp: web: mounts: '/.myhiddenfolder': source: storage source_path: 'myhiddenfolder' ``` ##### Disk space issues If you are worried about how much disk your mounts are using, check the size with the following command: ```bash upsun resources:get ``` ### Use build and deploy hooks As your app goes through the [build and deploy process](https://docs.upsun.com/learn/overview/build-deploy.md), you might want to run custom commands. These might include compiling the app, setting the configuration for services based on variables, and rebuilding search indexes. Do these tasks using one of [three hooks](https://docs.upsun.com/create-apps/hooks/hooks-comparison.md). The following example goes through each of these hooks for a multi-app project - Next.js acts as the frontend container, `client` - Drupal serves data as the backend container, `api` Configuration for [both applications](https://docs.upsun.com../multi-app.md) resides in a single [`.upsun/config.yaml` configuration file](https://docs.upsun.com...md). Be sure to notice the `source.root` property for each. ##### Build dependencies The Next.js app uses Yarn for dependencies, which need to be installed. Installing dependencies requires writing to disk and doesn't need any relationships with other services. This makes it perfect for a `build` hook. In this case, the app has two sets of dependencies: * For the main app * For a script to test connections between the apps Create your `build` hook to install them all: 1. Create a `build` hook in your [app configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md): ```yaml {location=".upsun/config.yaml"} applications: client: source: root: client hooks: build: | set -e ``` The hook has two parts so far: * The `|` means the lines that follow can contain a series of commands. They aren't interpreted as new YAML properties. * Adding `set -e` means that the hook fails if _any_ of the commands in it fails. Without this setting, the hook fails only if its _final_ command fails. 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 deploy still happens. 2. Install your top-level dependencies inside this `build` hook: ```yaml {location=".upsun/config.yaml"} applications: client: source: root: client hooks: build: | set -e yarn --frozen-lockfile ``` This installs all the dependencies for the main app. ##### Configure Drush and Drupal The example uses [Drush](https://www.drush.org/latest/) to handle routine tasks. For its configuration, Drush needs the URL of the site. That means the configuration can't be done in the `build` hook. During the `build` hook, the site isn't yet deployed and so there is no URL to use in the configuration. (The [`PLATFORM_ROUTES` variable](https://docs.upsun.com../../development/variables/use-variables.md#use-provided-variables) isn't available.) Add the configuration during the `deploy` hook. This way you can access the URL before the site accepts requests (unlike in the `post_deploy` hook). The script also prepares your environment to handle requests, such as by [rebuilding the cache](https://www.drush.org/latest/commands/cache_rebuild/) and [updating the database](https://www.drush.org/latest/commands/updatedb/). Because these steps should be done before the site accepts request, they should be in the `deploy` hook. All of this configuration and preparation can be handled in a bash script. 1. Copy the [preparation script from the Platform.sh template](https://github.com/platformsh-templates/nextjs-drupal/blob/master/api/platformsh-scripts/hooks.deploy.sh) into a file called `hooks.deploy.sh` in a `api/platformsh-scripts` directory. Note that hooks are executed using the dash shell, not the bash shell used by SSH logins. 2. Copy the [Drush configuration script from the template](https://github.com/platformsh-templates/nextjs-drupal/blob/master/api/drush/platformsh_generate_drush_yml.php) into a `drush/platformsh_generate_drush_yml.php` file. 3. Set a [mount](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#mounts). Unlike in the `build` hook, in the `deploy` hook the system is generally read-only. So create a mount where you can write the Drush configuration: ```yaml {location=".upsun/config.yaml"} applications: api: source: root: api mounts: /.drush: source: storage source_path: 'drush' ``` 4. Add a `deploy` hook that runs the preparation script: ```yaml {location=".upsun/config.yaml"} applications: api: source: root: api mounts: /.drush: source: storage source_path: 'drush' hooks: deploy: !include type: string path: platformsh-scripts/hooks.deploy.sh ``` This `!include` syntax tells the hook to process the script as if it were included in the YAML file directly. This helps with longer and more complicated scripts. ##### Get data from Drupal to Next.js This Next.js app generates a static site. Often, you would generate the site for Next.js in a `build` hook. In this case, you first need to get data from Drupal to Next.js. This means you need to wait until Drupal is accepting requests and there is a relationship between the two apps. So the `post_deploy` hook is the perfect place to build your Next.js site. You can also redeploy the site every time content changes in Drupal. On redeploys, only the `post_deploy` hook runs, meaning the Drupal build is reused and Next.js is built again. So you don't have to rebuild Drupal but you still get fresh content. 1. Set a relationship for Next.js with Drupal. This allows the Next.js app to make requests and receive data from the Drupal app. ```yaml {location=".upsun/config.yaml"} applications: client: source: root: client relationships: api: service: 'api' endpoint: 'http' ``` 2. Set [mounts](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#mounts). Like the [`deploy` hook](#configure-drush-and-drupal), the `post_deploy` hook has a read-only file system. Create mounts for your Next.js files: ```yaml {location=".upsun/config.yaml"} applications: client: source: root: client mounts: /.cache: source: tmp source_path: 'cache' /.next: source: storage source_path: 'next' /.pm2: source: storage source_path: 'pm2' deploy: source: storage service: files source_path: deploy ``` 3. Add a `post_deploy` hook that first tests the connection between the apps: ```yaml {location=".upsun/config.yaml"} applications: client: source: root: client hooks: post_deploy: | . deploy/platformsh.environment cd platformsh-scripts/test && yarn debug ``` Note that you could add `set -e` here, but even if the job fails, the build/deployment itself can still be counted as successful. 4. Then build the Next.js site: ```yaml {location=".upsun/config.yaml"} applications: client: source: root: client hooks: post_deploy: | . deploy/platformsh.environment cd platformsh-scripts/test && yarn debug cd $PLATFORM_APP_DIR && yarn build ``` The `$PLATFORM_APP_DIR` variable represents the app root and can always get you back there. ##### Final hooks ```yaml {location=".upsun/config.yaml"} applications: api: # The runtime the app uses. type: 'php:8.4' dependencies: php: composer/composer: '^2' # The relationships of the app with services or other apps. relationships: database: service: 'db' endpoint: 'mysql' redis: service: 'cache' endpoint: 'redis' # The hooks executed at various points in the lifecycle of the app. hooks: deploy: !include type: string path: platformsh-scripts/hooks.deploy.sh # The 'mounts' describe writable, persistent filesystem mounts in the app. mounts: /.drush: source: storage source_path: 'drush' /drush-backups: source: storage source_path: 'drush-backups' deploy: source: service service: files source_path: deploy client: # The type key specifies the language and version for your app. type: 'nodejs:22' dependencies: nodejs: yarn: "1.22.17" pm2: "5.2.0" build: flavor: none relationships: api: service: 'api' endpoint: 'http' # The hooks that are triggered when the package is deployed. hooks: build: | set -e yarn --frozen-lockfile # Install dependencies for the main app cd platformsh-scripts/test yarn --frozen-lockfile # Install dependencies for the testing script # Next.js's build is delayed to the post_deploy hook, when Drupal is available for requests. post_deploy: | . deploy/platformsh.environment cd platformsh-scripts/test && yarn debug cd $PLATFORM_APP_DIR && yarn build mounts: /.cache: source: tmp source_path: 'cache' /.next: source: storage source_path: 'next' /.pm2: source: storage source_path: 'pm2' deploy: source: storage service: files source_path: deploy ``` #### Change hooks in different environments You might have certain commands you want to run only in certain environments. For example enabling detailed logging in preview environments or purging your CDN cache for production environments. The `deploy` and `post_deploy` hooks can access all [runtime environment variables](https://docs.upsun.com../../development/variables/use-variables.md#use-provided-variables). Use this to vary those hooks based on the environment. Check the `PLATFORM_ENVIRONMENT_TYPE` variable to see if it's in a production environment: ```yaml {location=".upsun/config.yaml"} applications: myapp: hooks: deploy: | if [ "$PLATFORM_ENVIRONMENT_TYPE" = production ]; then # Run commands only when deploying to production else # Run commands only when deploying to development or staging environments fi # Commands to run regardless of the environment ``` #### Comparison of hooks The following table presents the main differences among the three available hooks: | Hook name | Failures stop build | Variables available | Services available | Timeout | Run on `worker` instances | Writable directories | Blocks requests | Runs on all redeploys\* | | ------------- | ------------------- |-------------------- | ------------------ | ------- | ------------------------- | -------------------- | --------------- | --------------- | | `build` | Yes | Build variables | No | 1 hour | Yes | `$PLATFORM_APP_DIR`, `$PLATFORM_CACHE_DIR`, and `/tmp` | No | No | | `deploy` | No | Runtime variables | Yes | None | No | [Mounts](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#mounts) | Yes | No | | `post_deploy` | No | Runtime variables | Yes | None | No | [Mounts](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#mounts) | No | Yes | \* All of the hooks run with changes to the code or environment. This column indicates which hooks run on a redeploy without any code changes. ###### Build hook The `build` hook is run after any [build flavor](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#build). During this hook, no services (such as a database) or any persistent file mounts are available as the application hasn't yet been deployed. The `build` hook can only use [environment variables](https://docs.upsun.com../../development/variables/use-variables.md#use-provided-variables) that are available at build time. During the `build` hook, there are three writeable directories: - `$PLATFORM_APP_DIR`: This is where your code is checked out and is the working directory when the `build` hook starts. The contents of this directory after the build hook is the application that gets deployed. - `$PLATFORM_CACHE_DIR`: This directory persists between builds, but isn't deployed as part of your application. It's a good place for temporary build artifacts that can be reused between builds. It's shared by all builds on all branches. - `/tmp`: The temp directory is also useful for writing files that aren't needed in the final application, but it's wiped between each build. Note that `$PLATFORM_CACHE_DIR` is mapped to `/tmp` and together they offer about 8GB of free space. The only constraint on what can be downloaded during a `build` hook is the disk space available for builds. This is _not_ the disk specified by your [resources configuration](https://docs.upsun.com/manage-resources.md). If you exceed this limit, you receive a `No space left on device` error. See how to [troubleshoot this error](https://docs.upsun.com../troubleshoot-disks.md#no-space-left-on-device). The `build` hook runs only when the app or its runtime (variables and such) have changed. Redeploys with no changes trigger only the `post_deploy` hook. If you need the `build` hook to run, [manually trigger a build](https://docs.upsun.com../../development/troubleshoot.md#manually-trigger-builds). 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 deploy still happens. ####### Timeout Build hooks automatically time out if they run for 1 hour. So if you accidentally add an unbroken loop, it gets cut off and you can continue with other activities. ###### Deploy hook The `deploy` hook is run after the app container has been started but before it has started accepting requests. Note that the deploy hook only runs on [`web` instances](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#web), not [`worker` instances](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#workers). You can access other services at this stage (such as MySQL, Solr, Redis). The disk where the application lives is read-only at this point. This hook should be used when something needs to run once when new code is deployed. It isn't run when a host is restarted (such as during region maintenance), so anything that needs to run each time an instance of an app starts (regardless of whether there's new code) should go in the `pre_start` key in [your `web` configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#web-commands). For example, clearing the cache. Be aware: The deploy hook blocks the site accepting new requests. If your `deploy` hook is only a few seconds, incoming requests in that time are paused and continue when the hook is finished. So it effectively appears as if the site just took a few extra seconds to respond. If the hook takes too long, requests can't be held and appear as dropped connections. Only run tasks in your deploy hook that have to be run exclusively, such as database schema updates or some types of cache clear (those where the code must match what's on the disk). A task that can safely run concurrently with new incoming requests should be run as a `post_deploy` hook instead. After a Git push, in addition to the log shown in the activity log, the execution of the `deploy` hook is logged in the [deploy log](https://docs.upsun.com../../increase-observability/logs/access-logs.md#container-logs). For example: ```bash [2022-03-01 08:27:25.495579] Launching command 'bash export-config.sh'. 🔥 Successfully cleared configuration 🚀 Added new configuration details ``` Your `deploy` hook is tied to commits in the same way as your builds. Once a commit has been pushed and a new build image has been created, the result of both the `build` and `deploy` hooks are reused until there is a new git commit. Redeploys with no changes trigger only the `post_deploy` hook. If you need the `deploy` hook to run, [manually trigger a build](https://docs.upsun.com../../development/troubleshoot.md#manually-trigger-builds). ###### Post-deploy hook The `post_deploy` hook functions exactly the same as the `deploy` hook, but after the container is accepting connections. It runs concurrently with normal incoming traffic. That makes it well suited to any updates that don't require exclusive database access. What's "safe" to run in a `post_deploy` hook vs. in a `deploy` hook varies by the application. Often times content imports, some types of cache warmups, and other such tasks are good candidates for a `post_deploy` hook. In addition to the activity log, the `post_deploy` hook logs to the [post-deploy log](https://docs.upsun.com../../increase-observability/logs/access-logs.md#container-logs). The `post_deploy` hook is the only hook that runs during a redeploy. #### Use hooks with dependencies If you use a specific package in a hook, you may want to manage dependencies for it. For example, you may want to compile Sass files as part of your build process. You can set dependencies along with hooks in your [app configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#dependencies). The following example assumes you have some Sass source files, such as a `index.scss` file. You also need a script to compile the files, such as the following: ```json {location="package.json"} { "scripts": { "build-css": "sass index.scss css/index.css" }, } ``` Set your app configuration to have Sass available globally and use it: ```yaml {location=".upsun/config.yaml"} applications: myapp: # Ensure sass is available globally dependencies: nodejs: sass: "^1.47.0" hooks: # Run the script defined in package.json build: | npm run build-css ``` ### Work with workers Workers are instances of your code that aren't open to connections from other apps or services or the outside world. They're good for handling background tasks. See how to [configure a worker](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#workers) for your app. ##### Access the worker container Like with any other application container, Upsun allows you to connect to the worker instance through SSH to inspect logs and interact with it. Use the `--worker` switch in the Upsun CLI, like so: ```bash upsun ssh --worker=queue ``` ##### Stopping a worker If a worker instance needs to be updated during a new deployment, a `SIGTERM` signal is first sent to the worker process to allow it to shut down gracefully. If your worker process can't be interrupted mid-task, make sure it reacts to `SIGTERM` to pause its work gracefully. If the process is still running after 15 seconds, a `SIGKILL` message is sent that force-terminates the worker process, allowing the container to be shut down and restarted. To restart a worker manually, [access the container](#access-the-worker-container) and run the following commands: ```bash sv stop app sv start app ``` ##### Workers vs cron jobs Worker instances don't run cron jobs. Instead, both worker instances and cron tasks address similar use cases. They both address out-of-band work that an application needs to do but that shouldn't or can't be done as part of a normal web request. They do so in different ways and so are fit for different use cases. A cron job is well suited for tasks when: * They need to happen on a fixed schedule, not continually. * The task itself isn't especially long, as a running cron job blocks a new deployment. * It's long but can be divided into many small queued tasks. * A delay between when a task is registered and when it actually happens is acceptable. A dedicated worker instance is a better fit if: * Tasks should happen "now", but not block a web request. * Tasks are large enough that they risk blocking a deploy, even if they're subdivided. * The task in question is a continually running process rather than a stream of discrete units of work. The appropriateness of one approach over the other also varies by language; single-threaded languages would benefit more from either cron or workers than a language with native multi-threading, for instance. If a given task seems like it would run equally well as a worker or as a cron, cron is generally more efficient as it doesn't require its own container. ##### Commands The `commands` key defines the command to launch the worker application. For now there is only a single command, `start`, but more will be added in the future. The `commands.start` property is required. The `start` key specifies the command to use to launch your worker application. It may be any valid shell command, although most often it runs a command in your application in the language of your application. If the command specified by the `start` key terminates, it's restarted automatically. Note that [`deploy` and `post_deploy` hooks](https://docs.upsun.com/create-apps/hooks.md) as well as [`cron` commands](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#crons) run only on the [`web`](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#web) container, not on workers. ##### Inheritance Any top-level definitions for [`relationships`](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships), [`access`](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#access), [`mount`](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#mounts), and [`variables`](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#variables) are inherited by every worker, unless overridden explicitly. Likewise [resources defined for the application container](https://docs.upsun.com/manage-resources.md) are inherited by every worker, unless overridden explicitly. That means, for example, that the following two `.upsun/config.yaml` definitions produce identical workers. ```yaml {location=".upsun/config.yaml"} applications: myapp: #The name of the app, which must be unique within the project. type: python:3.9 mounts: test: source: storage source_path: test relationships: mysql: workers: queue: commands: start: | python queue-worker.py mail: commands: start: | python mail-worker.py services: mysql: type: mariadb:11.4 ``` ```yaml {location=".upsun/config.yaml"} applications: myapp: #The name of the app, which must be unique within the project. type: python:3.9 workers: queue: commands: start: | python queue-worker.py mounts: test: source: storage source_path: test mysql: mail: commands: start: | python mail-worker.py mounts: test: source: storage source_path: test mysql: services: mysql: type: mariadb:11.4 ``` In both cases, there are two worker instances named `queue` and `mail`. Both have access to a MySQL/MariaDB service defined in `.upsun/config.yaml`, through a [relationship](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) that is identical to the _name_ of that service (`mysql`). Both also have their own separate [`storage` mount](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#mounts). ##### Customizing a worker The most common properties to set in a worker to override the top-level settings are `variables` and its resources. `variables` lets you instruct the application to run differently as a worker than as a web site, whereas you can allocate [fewer worker-specific resources](https://docs.upsun.com/manage-resources.md) for a container that is running only a single background process (unlike the web site which is handling many requests at once). For example, consider the following configuration: ```yaml {location=".upsun/config.yaml"} applications: myapp: #The name of the app, which must be unique within the project. type: "python:3.9" hooks: build: | pip install -r requirements.txt pip install -e . pip install gunicorn relationships: mysql: rabbitmq: variables: env: type: 'none' web: commands: start: "gunicorn -b $PORT project.wsgi:application" variables: env: type: 'web' mounts: uploads: source: storage source_path: uploads locations: "/": root: "" passthru: true allow: false "/static": root: "static/" allow: true workers: queue: commands: start: | python queue-worker.py variables: env: type: 'worker' mounts: scratch: source: storage source_path: scratch mail: commands: start: | python mail-worker.py variables: env: type: 'worker' mounts: {} relationships: rabbitmq: services: mysql: type: 'mariadb:11.4' rabbitmq: type: 'rabbitmq:4.0' ``` There's a lot going on here, but it's all reasonably straightforward. The configuration in `.upsun/config.yaml` takes a single Python 3.9 code base from your repository, downloads all dependencies in `requirements.txt`, and then installs Gunicorn. That artifact (your code plus the downloaded dependencies) is deployed as three separate container instances, all running Python 3.9. The `web` instance starts a Gunicorn process to serve a web application. - It runs the Gunicorn process to serve web requests, defined by the `project/wsgi.py` file which contains an `application` definition. - It has an environment variable named `TYPE` with value `web`. - It has a writable mount at `/app/uploads`. - It has access to both a MySQL database and a RabbitMQ server, both of which are defined in `.upsun/config.yaml`. The `queue` instance is a worker that isn't web-accessible. - It runs the `queue-worker.py` script, and restart it automatically if it ever terminates. - It has an environment variable named `TYPE` with value `worker`. - It has a writable mount at `/app/scratch`. - It has access to both a MySQL database and a RabbitMQ server, both of which are defined in `.upsun/config.yaml` (because it doesn't specify otherwise). The `mail` instance is a worker that isn't web-accessible. - It runs the `mail-worker.py` script, and restart it automatically if it ever terminates. - It has an environment variable named `TYPE` with value `worker`. - It has no writable file mounts at all. - It has access only to the RabbitMQ server, through a different relationship name than on the `web` instance. It has no access to MySQL. **Note**: Upsun automatically allocates [default resources](https://docs.upsun.com/manage-resources/resource-init.md) to each instance, unless you [define a different resource initialization strategy](https://docs.upsun.com/manage-resources/resource-init.md#specify-a-resource-initialization-strategy). You can also [adjust resources](https://docs.upsun.com/manage-resources/adjust-resources.md) after your project has been deployed. For example, if you want the `web` instance to have a large upload space and the `queue` instance to have a small amount of scratch space for temporary files, you can allocate more CPU and RAM to the `web` instance than to the `queue` instance. The `mail` instance has no persistent writable disk space at all, as it doesn't need it. The `mail` instance also doesn't need any access to the SQL database, so for security reasons it has none. Each instance can also check the `TYPE` environment variable to detect how it's running and, if appropriate, adjust its behavior accordingly. ##### Mounts When defining a [worker](https://docs.upsun.com../create-apps/app-reference/single-runtime-image.md#workers) instance, keep in mind what mount behavior you want. `tmp` and `instance` local mounts are a separate storage area for each instance, while `storage` mounts can be shared between instances. For example, you can define a `storage` mount (called `shared_dir`) to be used by a `web` instance, and a `tmp` mount (called `local_dir`) to be used by a `queue` worker instance: ```yaml {location=".upsun/config.yaml"} applications: myapp: #The name of the app, which must be unique within the project. type: "nodejs:22" # Define a web instance web: locations: "/": root: "public" passthru: true index: ['index.html'] mounts: # Define a storage mount that's available to both instances together 'shared_dir': source: storage service: files source_path: our_stuff # Define a local mount that's available to each instance separately 'local_dir': source: tmp source_path: my_stuff # Define a worker instance from the same code but with a different start workers: queue: commands: start: ./start.sh ``` Both the `web` instance and `queue` worker have their own, dedicated `local_dir` mount. Note that: - Each `local_dir` mount is a [`tmp` mount](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#mounts) with a **maximum allocation of 8 GB**. - `tmp` mounts **may be removed** during infrastructure maintenance operations. Both the `web` instance and `queue` worker also have a `shared_dir` mount pointing to the same network storage space. They can both read and write to it simultaneously. ### ClickHouse ClickHouse is a high-performance column-oriented, distributed, OLAP (Online Analytical Processing) database. It allows you to generate real-time analytical data reports using SQL queries. For more information, see the [ClickHouse documentation](https://ClickHouse.com/docs). **Note**: Upsun supports ClickHouse with the following limitations: - High availability of service isn’t supported. - You can only configure single-node ClickHouse clusters. ##### Supported versions - 24.3 - 23.8 Upsun plans on supporting long-term support ClickHouse versions in priority. ##### Relationship reference For each service [defined via a relationship](#usage-example) to your application, Upsun automatically generates corresponding environment variables within your application container, in the ``$_`` format. Here is example information available through the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) themselves, or through the [``PLATFORM_RELATIONSHIPS`` environment variable](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). For some advanced use cases, you can use the [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). The structure of the ``PLATFORM_RELATIONSHIPS`` environment variable can be obtained by running ``upsun relationships`` in your terminal: ```json {} { "username": "main", "fragment": null, "ip": "123.456.78.90", "cluster": "azertyuiop-main-afdwftq", "host": "clickhouse.internal", "path": "main", "query": { "is_master": true }, "password": "ChangeMe", "port": 9000, "host_mapped": false, "service": "clickhouse", "hostname": "azertyuiopqsdfghjklm.clickhouse.service._.eu-1.platformsh.site", "epoch": 0, "rel": "clickhouse", "scheme": "https", "type": "clickhouse:24.3", "public": false } ``` Here is an example of how to gather [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables) information in a [.environment](https://docs.upsun.com/development/variables/set-variables.md#use-env-files): ```bash {location=".environment"} # Decode the built-in credentials object variable. export RELATIONSHIPS_JSON=$(echo $PLATFORM_RELATIONSHIPS | base64 --decode) # Set environment variables for individual credentials. export APP_CLICKHOUSE_HOST=="$(echo $RELATIONSHIPS_JSON | jq -r '.clickhouse[0].host')" ``` ##### Usage example ###### 1. Configure the service To define the service, use the `clickhouse` type: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. : type: clickhouse: ``` Note that changing the name of the service replaces it with a brand new service and all existing data is lost. Back up your data before changing the service. ###### 2. Define the relationship To define the relationship, use one of the following endpoints. ####### `clickhouse` endpoint The `clickhouse` endpoint allows you to use the Native Protocol port (also known as ClickHouse TCP protocol). This protocol is used by ClickHouse apps and processes such as `clickhouse-server`, `clickhouse-client`, and native ClickHouse tools. It is also used for inter-server communication for distributed queries. Use the following configuration: You can define ```` as you like. ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. : # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: : service: endpoint: clickhouse ``` You can define ```` and ```` as you like, but it’s best if they’re distinct. With this definition, the application container (````) now has access to the service via the corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). ####### `clickhouse-http` endpoint The `clickhouse-http` endpoint allows you to use the HTTP API Port for HTTP requests. This protocol is used by [JDBC](https://docs.oracle.com/javase/8/docs/technotes/guides/jdbc/), [ODBC](https://learn.microsoft.com/en-us/sql/odbc/microsoft-open-database-connectivity-odbc?view=sql-server-ver16), and web interfaces. Use the following configuration: ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. : # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: : service: endpoint: clickhouse-http services: # The name of the service container. Must be unique within a project. : type: clickhouse: ``` You can define ```` and ```` as you like, so long as it's unique between all defined services and relationships and matches in both the application and services configuration. With this definition, the application container (````) now has access to the service via the corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). ###### Example configuration ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: clickhouse: service: clickhouse endpoint: clickhouse services: # The name of the service container. Must be unique within a project. clickhouse: type: clickhouse:24.3 ``` ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: clickhouse: service: clickhouse endpoint: clickhouse-http services: # The name of the service container. Must be unique within a project. clickhouse: type: clickhouse:24.3 ``` If you want to change the ``clickhouse`` endpoint to ``clickhouse-http``, you need to use explicit endpoint definition as it defaults to ``clickhouse`` endpoint when using default endpoint (aka. as relationship definition). ##### Multiple databases You can configure multiple databases, much like [with PostgreSQL](https://docs.upsun.com/add-services/postgresql.md#multiple-databases). To do so, you can use a configuration similar to the following: ```yaml {location=".upsun/config.yaml"} # Complete list of all available properties: https://docs.upsun.com/create-apps/app-reference.html applications: myapp: # Relationships enable access from this app to a given service. # The example below shows configuration with explicitly set service names and endpoints. # See the Application reference for all options for defining relationships and endpoints. relationships: clickhouse-admin: service: clickhouse endpoint: admin clickhouse-reporter: service: clickhouse endpoint: reporter clickhouse-importer: service: clickhouse endpoint: importer services: clickhouse: type: clickhouse:24.3 configuration: databases: - main - legacy endpoints: admin: port: 9000 # binary port privileges: main: admin legacy: admin reporter: default_database: main port: 8123 # http port privileges: main: ro importer: default_database: legacy port: 9000 # binary port privileges: legacy: rw ``` ### Elasticsearch (Search service) Elasticsearch is a distributed RESTful search engine built for the cloud. See the [Elasticsearch documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current/index.md) for more information. ##### Supported versions You can select the major and minor version. Patch versions are applied periodically for bug fixes and the like. When you deploy your app, you always get the latest available patches. - 8.5 - 7.17 ##### Deprecated versions The following versions are still available in your projects for free, but they're at their end of life and are no longer receiving security updates from upstream. - 7.10 - 7.9 - 7.7 - 7.5 - 7.2 - 6.8 - 6.5 - 5.4 - 5.2 - 2.4 - 1.7 - 1.4 To ensure your project remains stable in the future, switch to [a premium version](#supported-versions). Alternatively, you can switch to one of the latest, free versions of [OpenSearch](https://docs.upsun.com/add-services/opensearch.md). To do so, follow the same procedure as for [upgrading](#upgrading). ##### Relationship reference For each service [defined via a relationship](#usage-example) to your application, Upsun automatically generates corresponding environment variables within your application container, in the ``$_`` format. Here is example information available through the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) themselves, or through the [``PLATFORM_RELATIONSHIPS`` environment variable](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). For some advanced use cases, you can use the [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). The structure of the ``PLATFORM_RELATIONSHIPS`` environment variable can be obtained by running ``upsun relationships`` in your terminal: ```json {} { "username": null, "scheme": "http", "service": "elasticsearch", "fragment": null, "ip": "123.456.78.90", "hostname": "azertyuiopqsdfghjklm.elasticsearch.service._.eu-1.platformsh.site", "port": 9200, "cluster": "azertyuiopqsdf-main-7rqtwti", "host": "elasticsearch.internal", "rel": "elasticsearch", "path": null, "query": [], "password": "ChangeMe", "type": "elasticsearch:8.5", "public": false, "host_mapped": false } ``` Here is an example of how to gather [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables) information in a [.environment](https://docs.upsun.com/development/variables/set-variables.md#use-env-files): ```bash {location=".environment"} # Decode the built-in credentials object variable. export RELATIONSHIPS_JSON=$(echo $PLATFORM_RELATIONSHIPS | base64 --decode) # Set environment variables for individual credentials. export APP_ELASTICSEARCH_HOST=="$(echo $RELATIONSHIPS_JSON | jq -r '.elasticsearch[0].host')" ``` For [premium versions](#supported-versions), the service type is `elasticsearch-enterprise`. ##### Usage example ###### 1. Configure the service To define the service, use the `elasticsearch` type: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. : type: elasticsearch: ``` If you’re using a [premium version](https://docs.upsun.com/add-services/elasticsearch.md#supported-versions), use the ``elasticsearch-enterprise`` type instead. Note that changing the name of the service replaces it with a brand new service and all existing data is lost. Back up your data before changing the service. ###### 2. Define the relationship To define the relationship, use the following configuration: You can define ```` as you like, so long as it’s unique between all defined services and matches in both the application and services configuration. The example above leverages [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships. That is, it uses default endpoints behind-the-scenes, providing a [relationship](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) (the network address a service is accessible from) that is identical to the name of that service. Depending on your needs, instead of default endpoint configuration, you can use [explicit endpoint configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships). With the above definition, the application container now has [access to the service](#use-in-app) via the relationship ```` and its corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. : # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: : service: endpoint: elasticsearch ``` You can define ```` and ```` as you like, so long as it’s unique between all defined services and relationships and matches in both the application and services configuration. The example above leverages [explicit endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships. Depending on your needs, instead of explicit endpoint configuration, you can use [default endpoint configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships). With the above definition, the application container now has [access to the service](#use-in-app) via the relationship ```` and its corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). ###### Example configuration If you’re using a [premium version](https://docs.upsun.com/add-services/elasticsearch.md#supported-versions), use the ``elasticsearch-enterprise`` type instead. ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: elasticsearch: service: elasticsearch endpoint: elasticsearch services: # The name of the service container. Must be unique within a project. elasticsearch: type: elasticsearch:8.5 ``` If you’re using a [premium version](https://docs.upsun.com/add-services/elasticsearch.md#supported-versions), use the ``elasticsearch-enterprise`` type instead. ###### Use in app To use the configured service in your app, add a configuration file similar to the following to your project. Note that configuration for [premium versions](#supported-versions) may differ slightly. ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/myapp" # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: elasticsearch: service: elasticsearch endpoint: elasticsearch services: elasticsearch: type: elasticsearch:8.5 ``` This configuration defines a single application (`myapp`), whose source code exists in the `/myapp` directory. `myapp` has access to the `elasticsearch` service, via the corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) (as per [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships). From this, `myapp` can retrieve access credentials to the service through the [relationship environment variable](https://docs.upsun.com/add-services/elasticsearch.md#relationship-reference). ```bash {location="myapp/.environment"} # Set environment variables for individual credentials, # For more information, please visit https://docs.upsun.com/development/variables.html#service-environment-variables. export ELASTIC_SCHEME=${ELASTICSEARCH_SCHEME} export ELASTIC_HOST=${ELASTICSEARCH_HOST} export ELASTIC_PORT=${ELASTICSEARCH_PORT} # Surface more common Elasticsearch connection string variables for use in app. export ELASTIC_USERNAME=${ELASTICSEARCH_USERNAME} export ELASTIC_PASSWORD=${ELASTICSEARCH_PASSWORD} export ELASTIC_HOSTS=["$ELASTIC_SCHEME://$ELASTIC_HOST:$ELASTIC_PORT"] ``` The above file — ``.environment`` in the ``myapp`` directory — is automatically sourced by Upsun into the runtime environment, so that the variable ``ELASTIC_HOSTS`` can be used within the application to connect to the service. Note that ``ELASTIC_HOSTS``, and all [Upsun-service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) like ``ELASTICSEARCH_HOST``, are environment-dependent. Unlike the build produced for a given commit, they can’t be reused across environments and only allow your app to connect to a single service instance on a single environment. A file very similar to this is generated automatically for your when using the ``upsun ify`` command to [migrate a codebase to Upsun](https://docs.upsun.com/get-started.md). **Note**: When you create an index on Elasticsearch, don’t specify the ``number_of_shards`` or ``number_of_replicas`` settings in your Elasticsearch API call. These values are set automatically based on available resources. ##### Authentication By default, Elasticsearch has no authentication. No username or password is required to connect to it. Starting with Elasticsearch 7.2 you may optionally enable HTTP Basic authentication. To do so, include the following in your `.upsun/config.yaml` configuration: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. elasticsearch: type: elasticsearch:8.5 configuration: authentication: enabled: true ``` If you're using a [premium version](#supported-versions), use the `elasticsearch-enterprise` type. That enables mandatory HTTP Basic auth on all requests. The credentials are available in any relationships that point at that service, in the `username` and `password` properties. You can obtain the complete list of available service environment variables in your app container by running ``upsun ssh env``. Note that the information about the relationship can change when an app is redeployed or restarted or the relationship is changed. So your apps should only rely on the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) directly rather than hard coding any values. This functionality is generally not required if Elasticsearch isn't exposed on its own public HTTP route. However, certain applications may require it, or it allows you to safely expose Elasticsearch directly to the web. To do so, add a route to `.upsun/config.yaml` that has `elasticsearch:elasticsearch` as its upstream (where `elasticsearch` is whatever you named the service). For example: ```yaml {location=".upsun/config.yaml"} routes: "https://es.{default}/": type: upstream upstream: "elasticsearch:elasticsearch" services: # The name of the service container. Must be unique within a project. elasticsearch: type: elasticsearch:8.5 configuration: authentication: enabled: true ``` ##### Plugins Elasticsearch offers a number of plugins. To enable them, list them under the `configuration.plugins` key in your `.upsun/config.yaml` file, like so: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. elasticsearch: type: elasticsearch:8.5 configuration: plugins: - analysis-icu ``` If you're using a [premium version](#supported-versions), use the `elasticsearch-enterprise` type. In this example you'd have the ICU analysis plugin and Python script support plugin. If there is a publicly available plugin you need that isn't listed here, [contact support](https://docs.upsun.com/learn/overview/get-support.md). ###### Available plugins This is the complete list of official Elasticsearch plugins that can be enabled: | Plugin | Description | 2.4 | 5.x | 6.x | 7.x | 8.x | |-------------------------|-------------------------------------------------------------------------------------------|-----|-----|-----|-----|-----| | `analysis-icu` | Support ICU Unicode text analysis | * | * | * | * | * | | `analysis-nori` | Integrates Lucene Nori analysis module into Elasticsearch | | | * | * | * | | `analysis-kuromoji` | Japanese language support | * | * | * | * | * | | `analysis-smartcn` | Smart Chinese Analysis Plugins | * | * | * | * | * | | `analysis-stempel` | Stempel Polish Analysis Plugin | * | * | * | * | * | | `analysis-phonetic` | Phonetic analysis | * | * | * | * | * | | `analysis-ukrainian` | Ukrainian language support | | * | * | * | * | | `cloud-aws` | AWS Cloud plugin, allows storing indices on AWS S3 | * | | | | | | `delete-by-query` | Support for deleting documents matching a given query | * | | | | | | `discovery-multicast` | Ability to form a cluster using TCP/IP multicast messages | * | | | | | | `ingest-attachment` | Extract file attachments in common formats (such as PPT, XLS, and PDF) | | * | * | * | * | | `ingest-user-agent` | Extracts details from the user agent string a browser sends with its web requests | | * | * | | | | `lang-javascript` | JavaScript language plugin, allows the use of JavaScript in Elasticsearch scripts | | * | | | | | `lang-python` | Python language plugin, allows the use of Python in Elasticsearch scripts | * | * | | | | | `mapper-annotated-text` | Adds support for text fields with markup used to inject annotation tokens into the index | | | * | * | * | | `mapper-attachments` | Mapper attachments plugin for indexing common file types | * | * | | | | | `mapper-murmur3` | Murmur3 mapper plugin for computing hashes at index-time | * | * | * | * | * | | `mapper-size` | Size mapper plugin, enables the `_size` meta field | * | * | * | * | * | | `repository-s3` | Support for using S3 as a repository for Snapshot/Restore | | * | * | * | * | | `transport-nio` | Support for NIO transport | | | | * | * | ###### Plugin removal Removing plugins previously added in your `.upsun/config.yaml` file doesn't automatically uninstall them from your Elasticsearch instances. This is deliberate, as removing a plugin may result in data loss or corruption of existing data that relied on that plugin. Removing a plugin usually requires reindexing. To permanently remove a previously enabled plugin, [upgrade the service](#upgrading) to create a new instance of Elasticsearch and migrate to it. In most cases it isn't necessary as an unused plugin has no appreciable impact on the server. ##### Upgrading The Elasticsearch data format sometimes changes between versions in incompatible ways. Elasticsearch doesn't include a data upgrade mechanism as it's expected that all indexes can be regenerated from stable data if needed. To upgrade (or downgrade) Elasticsearch, use a new service from scratch. There are two ways to do so. ###### Destructive In your `.upsun/config.yaml` file, change the version *and* name of your Elasticsearch service. Be sure to also update the reference to the now changed service name in its corresponding application's `relationship` block. When you push that to Upsun, the old service is deleted and a new one with the new name is created with no data. You can then have your application reindex data as appropriate. This approach has the downsides of temporarily having an empty Elasticsearch instance, which your application may or may not handle gracefully, and needing to rebuild your index afterward. Depending on the size of your data that could take a while. ###### Transitional With a transitional approach, you temporarily have two Elasticsearch services. Add a second Elasticsearch service with the new version, a new name, and give it a new relationship in `.upsun/config.yaml`. You can optionally run in that configuration for a while to allow your application to populate indexes in the new service as well. Once you're ready to switch over, remove the old Elasticsearch service and relationship. You may optionally have the new Elasticsearch service use the old relationship name if that's easier for your app to handle. Your application is now using the new Elasticsearch service. This approach has the benefit of never being without a working Elasticsearch instance. On the downside, it requires two running Elasticsearch servers temporarily, each of which consumes resources and needs adequate disk space. Depending on the size of your data, that may be a lot of disk space. ### Gotenberg Gotenberg is a stateless API for converting various document formats into PDF files. For more information, see the [Gotenberg documentation](https://gotenberg.dev/docs/getting-started/introduction). ##### Supported versions - 8 You can select the major version. But the latest compatible minor version is applied automatically and can’t be overridden. Patch versions are applied periodically for bug fixes and the like. When you deploy your app, you always get the latest available patches. ##### Relationship reference For each service [defined via a relationship](#usage-example) to your application, Upsun automatically generates corresponding environment variables within your application container, in the ``$_`` format. Here is example information available through the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) themselves, or through the [``PLATFORM_RELATIONSHIPS`` environment variable](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). For some advanced use cases, you can use the [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). The structure of the ``PLATFORM_RELATIONSHIPS`` environment variable can be obtained by running ``upsun relationships`` in your terminal: ```json {} { "host": "gotenberg.internal", "hostname": "rssjaxyeoorjje6axcq35xu5gq.gotenberg.service._.eu-5.platformsh.site", "cluster": "p2f2xrzyq7a6k-main-bvxea6i", "service": "gotenberg", "rel": "http", "scheme": "http", "port": "3000", "type": "gotenberg:8", "instance_ips": [ "249.45.240.83" ], "ip": "169.254.137.3", "url": "http://gotenberg.internal:3000" } ``` Here is an example of how to gather [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables) information in a [.environment](https://docs.upsun.com/development/variables/set-variables.md#use-env-files): ```bash {location=".environment"} # Decode the built-in credentials object variable. export RELATIONSHIPS_JSON=$(echo $PLATFORM_RELATIONSHIPS | base64 --decode) # Set environment variables for individual credentials. export APP_GOTENBERG_HOST=="$(echo $RELATIONSHIPS_JSON | jq -r '.gotenberg[0].host')" ``` ##### Usage example ###### 1. Configure the service To define the service, use the `gotenberg` type: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. : type: gotenberg: ``` Note that changing the name of the service replaces it with a brand new service and all existing data is lost. Back up your data before changing the service. ###### 2. Define the relationship To define the relationship, use the ``http`` endpoint: You can define ```` as you like, so long as it’s unique between all defined services and matches in both the application and services configuration. ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. : # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: : service: endpoint: http ``` You can define ```` and ```` as you like, so long as it’s unique between all defined services and relationships and matches in both the application and services configuration. With the above definition, Upsun uses the `http` endpoint, providing a [relationship](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) (the network address a service is accessible from) that is identical to the _name_ of that service. The `http` endpoint uses port `3000` by default. ###### Example configuration ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: gotenberg: service: gotenberg endpoint: http services: # The name of the service container. Must be unique within a project. gotenberg: type: gotenberg:8 ``` ##### Generate a PDF using Gotenberg As an example, to generate a PDF file of the Upsun website, run the following cURL command: ```bash {location="Terminal"} curl \ --request POST http://yduimhaby523ase4lju3qhimre.gotenberg8.service._.eu-3.platformsh.site/forms/chromium/convert/url \ --form url=https://upsun.com \ --form landscape=true \ --form marginTop=1 \ --form marginBottom=1 \ -o my.pdf ``` ### Headless Chrome Headless Chrome is a headless browser that can be configured on projects like any other service on Upsun. You can interact with the `chrome-headless` service container using Puppeteer, a Node.js library that provides an API to control Chrome over the DevTools Protocol. Puppeteer can be used to generate PDFs and screenshots of web pages, automate form submission, and test your project's UI. You can find out more information about using Puppeteer on [GitHub](https://github.com/GoogleChrome/puppeteer) or in their [documentation](https://pptr.dev/). ##### Supported versions You can select the major version. But the latest compatible minor version is applied automatically and can’t be overridden. Patch versions are applied periodically for bug fixes and the like. When you deploy your app, you always get the latest available patches. - 120 - 113 - 95 - 91 - 86 - 84 - 83 - 81 - 80 - 73 ##### Relationship reference For each service [defined via a relationship](#usage-example) to your application, Upsun automatically generates corresponding environment variables within your application container, in the ``$_`` format. Here is example information available through the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) themselves, or through the [``PLATFORM_RELATIONSHIPS`` environment variable](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). For some advanced use cases, you can use the [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). The structure of the ``PLATFORM_RELATIONSHIPS`` environment variable can be obtained by running ``upsun relationships`` in your terminal: ```json {} { "service": "chrome-headless", "ip": "123.456.78.90", "hostname": "azertyuiopqsdfghjklm.chrome-headless.service._.eu-1.platformsh.site", "cluster": "azertyuiop-main-7rqtwti", "host": "chrome-headless.internal", "rel": "http", "scheme": "http", "type": "chrome-headless:120", "port": 9222 } ``` Here is an example of how to gather [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables) information in a [.environment](https://docs.upsun.com/development/variables/set-variables.md#use-env-files): ```bash {location=".environment"} # Decode the built-in credentials object variable. export RELATIONSHIPS_JSON=$(echo $PLATFORM_RELATIONSHIPS | base64 --decode) # Set environment variables for individual credentials. export APP_HEADLESSCHROME_HOST=="$(echo $RELATIONSHIPS_JSON | jq -r '.chrome-headless[0].host')" ``` ##### Requirements Puppeteer requires at least Node.js version 6.4.0, while using the async and await examples below requires Node 7.6.0 or greater. If your app container uses a language other than Node.js, upgrade the Node.js version before using Puppeteer. See how to [manage your Node.js version](https://docs.upsun.com../languages/nodejs/node-version.md). ##### Usage example ###### 1. Configure the service To define the service, use the `chrome-headless` type: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. : type: chrome-headless: ``` Note that changing the name of the service replaces it with a brand new service and all existing data is lost. Back up your data before changing the service. ###### 2. Define the relationship To define the relationship, use the following configuration: You can define ```` as you like, so long as it’s unique between all defined services and matches in both the application and services configuration. The example above leverages [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships. That is, it uses default endpoints behind-the-scenes, providing a [relationship](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) (the network address a service is accessible from) that is identical to the name of that service. Depending on your needs, instead of default endpoint configuration, you can use [explicit endpoint configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships). With the above definition, the application container now has [access to the service](#use-in-app) via the relationship ```` and its corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. : # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: : service: endpoint: http ``` You can define ```` and ```` as you like, so long as it’s unique between all defined services and relationships and matches in both the application and services configuration. The example above leverages [explicit endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships. Depending on your needs, instead of explicit endpoint configuration, you can use [default endpoint configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships). With the above definition, the application container now has [access to the service](#use-in-app) via the relationship ```` and its corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). ###### Example configuration ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: chrome-headless: service: chrome-headless endpoint: http services: # The name of the service container. Must be unique within a project. chrome-headless: type: chrome-headless:120 ``` ###### Use in app After configuration, include [Puppeteer](https://www.npmjs.com/package/puppeteer) as a dependency: ```bash {} pnpm add puppeteer ``` ```bash {} yarn add puppeteer ``` Configuration for a project looks similar to the following: ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "myapp" type: "nodejs:22" [...] # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: chrome-headless: service: chrome-headless endpoint: http services: # The name of the service container. Must be unique within a project. chrome-headless: type: chrome-headless:120 ``` This configuration defines a single application (`myapp`), whose source code exists in the `/myapp` directory. `myapp` has access to the `chrome-headless` service, via a relationship whose name is [identical to the service name](#2-define-the-relationship) (as per [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships). From this, `myapp` can retrieve access credentials to the service through the [relationship environment variable](https://docs.upsun.com/add-services/elasticsearch.md#relationship-reference). ```bash {location="myapp/.environment"} # Set environment variables for individual credentials, # For more information, please visit https://docs.upsun.com/development/variables.html#service-environment-variables. export CHROME_IP=${CHROME_HEADLESS_IP} export CHROME_PORT=${CHROME_HEADLESS_PORT} # Combine into a single base URL to be used within app. export CHROME_BASEURL="http://${CHROME_IP}:${CHROME_PORT}" ``` The above file — `.environment` in the `myapp` directory — is automatically sourced by Upsun into the runtime environment, so that the variable `CHROME_BASEURL` can be used within the application to connect to the service. Note that `CHROME_BASEURL` and all Upsun [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) like `CHROME_HEADLESS_HOST`, are environment-dependent. Unlike the build produced for a given commit, they can't be reused across environments and only allow your app to connect to a single service instance on a single environment. A file very similar to this is generated automatically for your when using the `upsun ify` command to [migrate a codebase to Upsun](https://docs.upsun.com/get-started.md). Puppeteer allows your application to [create screenshots](https://pptr.dev/#?product=Puppeteer&version=v13.0.1&show=api-pagescreenshotoptions), [emulate a mobile device](https://pptr.dev/#?product=Puppeteer&version=v13.0.1&show=api-pageemulateoptions), [generate PDFs](https://pptr.dev/#?product=Puppeteer&version=v13.0.1&show=api-pagepdfoptions), and much more. ### InfluxDB (Database service) InfluxDB is a time series database optimized for high-write-volume use cases such as logs, sensor data, and real-time analytics. It exposes an HTTP API for client interaction. See the [InfluxDB documentation](https://docs.influxdata.com/influxdb) for more information. ##### Supported versions You can select the major and minor version. Patch versions are applied periodically for bug fixes and the like. When you deploy your app, you always get the latest available patches. - 2.7 - 2.3 ##### Deprecated versions The following versions are still available in your projects, but they're at their end of life and are no longer receiving security updates from upstream. - 2.2 - 1.8 - 1.7 - 1.3 - 1.2 To ensure your project remains stable in the future, switch to a [supported version](#supported-versions). See more information on [how to upgrade to version 2.3 or later](#upgrade-to-version-23-or-later). ##### Relationship reference For each service [defined via a relationship](#usage-example) to your application, Upsun automatically generates corresponding environment variables within your application container, in the ``$_`` format. Here is example information available through the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) themselves, or through the [``PLATFORM_RELATIONSHIPS`` environment variable](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). For some advanced use cases, you can use the [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). The structure of the ``PLATFORM_RELATIONSHIPS`` environment variable can be obtained by running ``upsun relationships`` in your terminal: ```json {} { "host": "influxdb.internal", "hostname": "azertyuiopqsdfghjklm.influxdb.service._.eu-1.platformsh.site", "cluster": "azertyuiopqsdf-main-bvxea6i", "service": "influxdb", "type": "influxdb:2.7", "rel": "influxdb", "scheme": "http", "username": "admin", "password": "ChangeMe", "port": 8086, "path": null, "query": { "org": "main", "bucket": "main", "api_token": "azertyuiopqsdfghjklm1234567890" }, "fragment": null, "public": false, "host_mapped": false, "ip": "123.456.78.90" } ``` Here is an example of how to gather [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables) information in a [.environment](https://docs.upsun.com/development/variables/set-variables.md#use-env-files): ```bash {location=".environment"} # Decode the built-in credentials object variable. export RELATIONSHIPS_JSON=$(echo $PLATFORM_RELATIONSHIPS | base64 --decode) # Set environment variables for individual credentials. export APP_INFLUXDB_HOST="$(echo $RELATIONSHIPS_JSON | jq -r '.influxdb[0].host')" ``` ##### Usage example ###### 1. Configure the service To define the service, use the `influxdb` type: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. : type: influxdb: ``` Note that changing the name of the service replaces it with a brand new service and all existing data is lost. Back up your data before changing the service. ###### 2. Define the relationship To define the relationship, use the following configuration: You can define ```` as you like, so long as it’s unique between all defined services and matches in both the application and services configuration. The example above leverages [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships. That is, it uses default endpoints behind-the-scenes, providing a [relationship](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) (the network address a service is accessible from) that is identical to the name of that service. Depending on your needs, instead of default endpoint configuration, you can use [explicit endpoint configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships). With the above definition, the application container now has [access to the service](#use-in-app) via the relationship ```` and its corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. : # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: : service: endpoint: influxdb ``` You can define ```` and ```` as you like, so long as it’s unique between all defined services and relationships and matches in both the application and services configuration. The example above leverages [explicit endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships. Depending on your needs, instead of explicit endpoint configuration, you can use [default endpoint configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships). With the above definition, the application container now has [access to the service](#use-in-app) via the relationship ```` and its corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). ###### Example configuration ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: influxdb: service: influxdb endpoint: influxdb services: # The name of the service container. Must be unique within a project. influxdb: type: influxdb:2.7 ``` ###### Use in app To use the configured service in your app, add a configuration file similar to the following to your project. ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "myapp" [...] # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: influxdb: service: influxdb endpoint: influxdb service: influxdb: type: influxdb:2.7 ``` This configuration defines a single application (`myapp`), whose source code exists in the `/myapp` directory. `myapp` has access to the `influxdb` service, via a relationship whose name is [identical to the service name](#2-define-the-relationship) (as per [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships). From this, ``myapp`` can retrieve access credentials to the service through the [relationship environment variables](#relationship-reference). ```bash {location="myapp/.environment"} # Set environment variables for common InfluxDB credentials. # For more information, please visit https://docs.upsun.com/development/variables.html#service-environment-variables. export INFLUX_USER=${INFLUXDB_USERNAME} export INFLUX_HOST=${INFLUXDB_HOST} export INFLUX_ORG=$(echo $INFLUXDB_QUERY | jq -r ".org") export INFLUX_TOKEN=$(echo $INFLUXDB_QUERY | jq -r ".api_token") export INFLUX_BUCKET=$(echo $INFLUXDB_QUERY | jq -r ".bucket") ``` The above file — ``.environment`` in the ``myapp`` directory — is automatically sourced by Upsun into the runtime environment, so that the variable ``INFLUX_HOST`` can be used within the application to connect to the service. Note that ``INFLUX_HOST``, and all [Upsun-service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) like ``INFLUXDBDATABASE_HOST``, are environment-dependent. Unlike the build produced for a given commit, they can’t be reused across environments and only allow your app to connect to a single service instance on a single environment. A file very similar to this is generated automatically for your when using the ``upsun ify`` command to [migrate a codebase to Upsun](https://docs.upsun.com/get-started.md). ##### Export data To export your data from InfluxDB, follow these steps: 1. Install and set up the [`influx` CLI](https://docs.influxdata.com/influxdb/cloud/tools/influx-cli/). 2. Connect to your InfluxDB service with the [Upsun CLI](https://docs.upsun.com../administration/cli/_index.md): ```bash upsun tunnel:single ``` This opens an SSH tunnel to your InfluxDB service on your current environment and produces output like the following: ```bash SSH tunnel opened to at: http://127.0.0.1:30000 ``` 3. Get the username, password and token from the [relationship](#relationship-reference) by running the following command: ```bash upsun relationships -P ``` 4. Adapt and run [InfluxDB's CLI export command](https://docs.influxdata.com/influxdb/v2.3/reference/cli/influx/backup/). ``` bash influx backup --host --token ``` ##### Upgrade to version 2.3 or later ###### From a previous 2.x version From version 2.3 onward, the structure of relationships changes. If you're using a prior 2.x version, your app might currently rely on pulling the `bucket`, `org`, `api_token`, or `user` values available in the [`PLATFORM_RELATIONSHIPS` environment variable](#relationship-reference). If so, to ensure your upgrade is successful, make the following changes to your connection logic: - Rename the `user` key to `username`. - Move the `org`, `bucket` and `api_token` keys so they're contained in a dictionary under the `query` key. If you're relying on any other attributes connecting to InfluxDB, they remain accessible as environment variable from the [service environment variable](#relationship-reference), aside from those addressed above: ###### From a 1.x version From version 2.3 onward, InfluxDB includes an upgrade utility that can convert databases from previous versions to version 2.3 or later. To upgrade from a 1.x version to 2.3 or later, change the service version in your `.upsun/config.yaml` file and push your project. Any existing data you had in your 1.x system is automatically upgraded for you into the 2.3+ system. **Note**: During an upgrade from a 1.x version to a 2.3 version or later, a new admin password and a new admin API token are automatically generated. Previous credentials can’t be retained. You can retrieve your new credentials through the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). ### Kafka (Message queue service) Apache Kafka is an open-source stream-processing software platform. It is a framework for storing, reading and analyzing streaming data. See the [Kafka documentation](https://kafka.apache.org/documentation) for more information. ##### Supported versions You can select the major and minor version. Patch versions are applied periodically for bug fixes and the like. When you deploy your app, you always get the latest available patches. - 3.7 - 3.6 - 3.4 - 3.2 ##### Relationship reference For each service [defined via a relationship](#usage-example) to your application, Upsun automatically generates corresponding environment variables within your application container, in the ``$_`` format. Here is example information available through the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) themselves, or through the [``PLATFORM_RELATIONSHIPS`` environment variable](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). You can obtain the complete list of available service environment variables in your app container by running ``upsun ssh env``. Note that the information about the relationship can change when an app is redeployed or restarted or the relationship is changed. So your apps should only rely on the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) directly rather than hard coding any values. For some advanced use cases, you can use the [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). The structure of the ``PLATFORM_RELATIONSHIPS`` environment variable can be obtained by running ``upsun relationships`` in your terminal: ```json {} { "service": "kafka", "ip": "123.456.78.90", "hostname": "azertyuiopqsdfghjklm.kafka.service._.eu-1.platformsh.site", "cluster": "azertyuiop-main-7rqtwti", "host": "kafka.internal", "rel": "kafka", "scheme": "kafka", "type": "kafka:3.7", "port": 9092 } ``` Here is an example of how to gather [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables) information in a [.environment](https://docs.upsun.com/development/variables/set-variables.md#use-env-files): ```bash {location=".environment"} # Decode the built-in credentials object variable. export RELATIONSHIPS_JSON=$(echo $PLATFORM_RELATIONSHIPS | base64 --decode) # Set environment variables for individual credentials. export APP_KAFKA_HOST="$(echo $RELATIONSHIPS_JSON | jq -r '.kafka[0].host')" ``` ##### Usage example ###### 1. Configure the service To define the service, use the ``kafka`` type: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. : type: kafka: ``` Note that changing the name of the service replaces it with a brand new service and all existing data is lost. Back up your data before changing the service. ###### 2. Define the relationship To define the relationship, use the following configuration: You can define ```` as you like, so long as it’s unique between all defined services and matches in both the application and services configuration. The example above leverages [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships. That is, it uses default endpoints behind-the-scenes, providing a [relationship](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) (the network address a service is accessible from) that is identical to the name of that service. Depending on your needs, instead of default endpoint configuration, you can use [explicit endpoint configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships). With the above definition, the application container (````) now has [access to the service](https://docs.upsun.com/add-services/kafka.md#use-in-app) via the relationship ```` and its corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. : # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: : service: endpoint: kafka ``` You can define ```` and ```` as you like, so long as it’s unique between all defined services and relationships and matches in both the application and services configuration. The example above leverages [explicit endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships. Depending on your needs, instead of explicit endpoint configuration, you can use [default endpoint configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships). With the above definition, the application container now has [access to the service](#use-in-app) via the relationship ```` and its corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). ###### Example configuration ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: kafka: service: kafka endpoint: kafka services: # The name of the service container. Must be unique within a project. kafka: type: kafka:3.7 ``` ###### Use in app To use the configured service in your app, add a configuration file similar to the following to your project. ```ruby {} ##### With the ruby-kafka gem # Producer require "kafka" kafka = Kafka.new(["kafka.internal:9092"], client_id: "my-application") kafka.deliver_message("Hello, World!", topic: "greetings") # Consumer kafka.each_message(topic: "greetings") do |message| puts message.offset, message.key, message.value end ``` ### MariaDB/MySQL (database service) Upsun supports both MariaDB and Oracle MySQL to manage your relational databases. Their infrastructure setup is nearly identical, though they differ in some features. See the [MariaDB documentation](https://mariadb.org/learn/) or [MySQL documentation](https://dev.mysql.com/doc/refman/en/) for more information. ##### Supported versions You can select the major and minor version. Patch versions are applied periodically for bug fixes and the like. When you deploy your app, you always get the latest available patches. The service types `mariadb` and `mysql` both refer to MariaDB. The service type `oracle-mysql` refers to MySQL as released by Oracle, Inc. Other than the value for their `type`, MySQL and MariaDB have the same behavior and the rest of this page applies to both of them. | **`mariadb`** | **`mysql`** | **`oracle-mysql`** | |---------------|-------------|--------------------| | - 11.4 - 11.2 - 11.0 - 10.11 - 10.6 - 10.5 - 10.4 | - 11.0 - 10.11 - 10.6 - 10.5 - 10.4 - 10.3 | - 8.0 - 5.7 | ###### Deprecated versions The following versions are [deprecated](https://docs.upsun.com/glossary.md#deprecated-versions). They're available, but they aren't receiving security updates from upstream and aren't guaranteed to work. They'll be removed in the future, so migrate to one of the [supported versions](#supported-versions). | **`mariadb`** | **`mysql`** | **`oracle-mysql`** | |----------------------------------|---------------|-------------------------| | - 10.2 - 10.1 - 10.3 - 10.0 - 5.5 | - 10.2 - 10.1 - 10.3 - 10.0 - 5.5 | | ###### Upgrade When upgrading your service, skipping versions may result in data loss. Upgrade sequentially from one supported version to another (10.5 -> 10.6 -> 10.11 -> 11.0), and check that each upgrade commit translates into an actual deployment. To upgrade, update the service version in your [service configuration](https://docs.upsun.com...md). ###### Change the service type To change the service type: 1. [Export your data](#exporting-data). **Note**: Changing the service type, especially when done repeatedly, may result in data loss. Backing up your data is therefore crucial. 2. Remove the old service from your [service configuration](https://docs.upsun.com...md). 3. Specify a new service type. 4. [Import your data](#importing-data) into the new service. ###### Downgrade You can't downgrade to a previous version and retain your data. To downgrade your database, follow these steps: 1. [Export your data](#exporting-data). 1. Remove the old service from your [service configuration](https://docs.upsun.com...md). 1. Add a new service with a different name and your desired version. 1. [Import your data](#importing-data) into the new service. ##### Relationship reference For each service [defined via a relationship](#usage-example) to your application, Upsun automatically generates corresponding environment variables within your application container, in the ``$_`` format. Here is example information available through the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) themselves, or through the [``PLATFORM_RELATIONSHIPS`` environment variable](development/variables/use-variables.md#use-provided-variables). ###### MariaDB reference For some advanced use cases, you can use the [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). The structure of the ``PLATFORM_RELATIONSHIPS`` environment variable can be obtained by running ``upsun relationships`` in your terminal. ```json {} { "username": "user", "scheme": "mysql", "service": "mariadb", "fragment": null, "ip": "123.456.78.90", "hostname": "azertyuiopqsdfghjklm.mariadb.service._.eu-1.platformsh.site", "port": 3306, "cluster": "azertyuiop-main-7rqtwti", "host": "mariadb.internal", "rel": "mysql", "path": "main", "query": { "is_master": true }, "password": "", "type": "mariadb:11.4", "public": false, "host_mapped": false } ``` Example on how to gather [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables) information in a [.environment](https://docs.upsun.com/development/variables/set-variables.md#use-env-files): ```bash {location=".environment"} # Decode the built-in credentials object variable. export RELATIONSHIPS_JSON=$(echo $PLATFORM_RELATIONSHIPS | base64 --decode) # Set environment variables for individual credentials. export APP_DATABASE_HOST=$(echo $PLATFORM_RELATIONSHIPS | base64 --decode | jq -r ".mariadb[0].host") ``` ###### Oracle MySQL reference For some advanced use cases, you can use the [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). The structure of the ``PLATFORM_RELATIONSHIPS`` environment variable can be obtained by running ``upsun relationships`` in your terminal. ```json {} { "username": "user", "scheme": "mysql", "service": "oracle-mysql", "fragment": null, "ip": "123.456.78.90", "hostname": "azertyuiopqsdfghjklm.oracle-mysql.service._.eu-1.platformsh.site", "port": 3306, "cluster": "azertyuiop-main-afdwftq", "host": "oracle_mysql.internal", "rel": "mysql", "path": "main", "query": { "is_master": true }, "password": "", "type": "oracle-mysql:8.0", "public": false, "host_mapped": false } ``` Example on how to gather [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables) information in a [.environment](https://docs.upsun.com/development/variables/set-variables.md#use-env-files): ```bash {location=".environment"} # Decode the built-in credentials object variable. export RELATIONSHIPS_JSON=$(echo $PLATFORM_RELATIONSHIPS | base64 --decode) # Set environment variables for individual credentials. export APP_ORACLE_HOST="$(echo $RELATIONSHIPS_JSON | jq -r '.oraclemysql[0].host')" ``` ##### Usage example Configure your service with at least 256 MB in disk space. ###### 1. Configure the service To define the service, use the ``mariadb`` or ``mysql`` type for MariaDB or the ``oracle-mysql`` type for Oracle MySQL : ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. : type: mariadb: ``` Note that changing the name of the service replaces it with a brand new service and all existing data is lost. Back up your data before changing the service. ###### 2. Define the relationship To define the relationship, use the following configuration: You can define ```` as you like, so long as it’s unique between all defined services and matches in both the application and services configuration. The example above leverages [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships. That is, it uses default endpoints behind-the-scenes, providing a [relationship](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) (the network address a service is accessible from) that is identical to the name of that service. Depending on your needs, instead of default endpoint configuration, you can use [explicit endpoint configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships). With the above definition, the application container (````) now has [access to the service](#use-in-app) via the relationship ```` and its corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. : # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: : service: endpoint: mysql ``` You can define ```` and ```` as you like, so long as it’s unique between all defined services and relationships and matches in both the application and services configuration. The example above leverages [explicit endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships. Depending on your needs, instead of explicit endpoint configuration, you can use [default endpoint configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships). With the above definition, the application container now has [access to the service](#use-in-app) via the relationship ```` and its corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). ###### MariaDB example ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: mariadb: service: mariadb endpoint: mysql services: # The name of the service container. Must be unique within a project. mariadb: type: mariadb:11.4 ``` ###### OracleMySQL example ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: oracle-mysql: service: oracle-mysql_service endpoint: mysql service: # The name of the service container. Must be unique within a project. oracle-mysql_service: type: oracle-mysql:8.0 ``` ###### Use in app To use the configured service in your app, add a configuration file similar to the following to your project. ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "myapp" [...] # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: mariadb: service: mariadb endpoint: mysql service: mariadb: type: mariadb:11.4 ``` This configuration defines a single application (``myapp``), whose source code exists in the ``/myapp`` directory. ``myapp`` has access to the ``mariadb`` service, via a relationship whose name is [identical to the service name](#2-define-the-relationship) (as per [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships). From this, ``myapp`` can retrieve access credentials to the service through the [relationship environment variables](#relationship-reference). ```bash {location="myapp/.environment"} # Set environment variables for individual credentials. # For more information, please visit https://docs.upsun.com/development/variables.html#service-environment-variables. export DB_CONNECTION=${MARIADB_SCHEME} export DB_USERNAME=${MARIADB_USERNAME} export DB_PASSWORD=${MARIADB_PASSWORD} export DB_HOST=${MARIADB_HOST} export DB_PORT=${MARIADB_PORT} export DB_DATABASE=${MARIADB_PATH} # Surface connection string variable for use in app. export DATABASE_URL="${DB_CONNECTION}://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_DATABASE}" ``` The above file — ``.environment`` in the ``myapp`` directory — is automatically sourced by Upsun into the runtime environment, so that the variable ``MARIADB_URL`` can be used within the application to connect to the service. Note that ``DATABASE_URL``, and all Upsun [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) like ``MARIADB_HOST``, are environment-dependent. Unlike the build produced for a given commit, they can’t be reused across environments and only allow your app to connect to a single service instance on a single environment. A file very similar to this is generated automatically for your when using the ``upsun ify`` command to [migrate a codebase to Upsun](https://docs.upsun.com/get-started.md). ###### Configure connections There may be cases where you want to configure a database connection manually. To get the URL to connect to the database, run the following command: ```bash upsun ssh env ``` The result is the complete [information for all relationships](#relationship-reference) with an additional `DATABASE_URL` property, defined on step [Use in app](#use-in-app).
Use the `DATABASE_URL` property as your connection. You can obtain the complete list of available service environment variables in your app container by running ``upsun ssh env``. Note that the information about the relationship can change when an app is redeployed or restarted or the relationship is changed. So your apps should only rely on the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) directly rather than hard coding any values. You can also see a guide on how to [convert the `PLATFORM_RELATIONSHIPS` environment variable to a different form](https://support.platform.sh/hc/en-us/community/posts/16439596373010). ##### Configuration options You can configure your MySQL service in the [services configuration](https://docs.upsun.com...md) with the following options: | Name | Type | Version | Description | | ------------ | ----------------------- | ---------------------------------- | ----------- | | `schemas` | An array of `string`s | 10.0+ | All databases to be created. Defaults to a single `main` database. | | `endpoints` | An endpoints dictionary | 10.0+ | Endpoints with their permissions. See [multiple databases](#multiple-databases). | | `properties` | A properties dictionary | MariaDB: 10.1+; Oracle MySQL: 8.0+ | Additional properties for the database. Equivalent to using a `my.cnf` file. See [property options](#configure-the-database). | Example configuration: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. mariadb: type: mariadb:11.4 configuration: schemas: - main endpoints: mysql: default_schema: main privileges: main: admin properties: max_allowed_packet: 64 ``` ##### Access the service directly You can access the service using the Upsun CLI by running `upsun sql`. You can also access it from you app container via [SSH](https://docs.upsun.com../../development/ssh.md). From your [relationship data](#relationship-reference), you need: `MARIADB_HOST`, `MARIADB_PORT`, `MARIADB_USERNAME`, `MARIADB_PATH` values. Then run the following command: ```bash mysql -h -P -u ``` Assuming the values from the [MariaDB reference](#mariadb-reference), that would be: ```bash mysql -h mariadb.internal -P 3306 -u user main ``` If your database relationship has a password, pass the `-p` switch and enter the password when prompted: ```bash mysql -p -h mariadb.internal -P 3306 -u user main ``` ##### Define permissions With version `10.0` or later, you can define multiple users with different permissions for your database. To do so, define multiple endpoints in your [service configuration](#configuration-options). For each endpoint you add, you can define the following properties: | Name | Type | Required | Description | | ---------------- | ------------------------ | -------- | ----------- | | `default_schema` | `string` | | Which of the defined schemas to default to. If not specified, the `path` property of the relationship is `null` and so tools such as the Upsun CLI can't access the relationship. | | `privileges` | A permissions dictionary | | For each of the defined schemas, what permissions the given endpoint has. | Possible permissions: | Name | Type | Description | | ----------- | ------------- | --------------------------------------------------- | | Read-only | `ro` | Can select, create temporary tables, and see views. | | Read-write | `rw` | In addition to read-only permissions, can also insert, update, delete, manage and execute events, execute routines, create and drop indexes, manage and execute triggers, and lock tables. | | Admin | `admin` | In addition to read-write permissions, can also create, drop, and alter tables; create views; and create and alter routines. | | Replication | `replication` | For [replicating databases](https://docs.upsun.com/add-services/mysql/mysql-replication.md). In addition to read-only permissions, can also lock tables. | ##### Multiple databases With version `10.0` or later, you can define multiple databases. To do so, define multiple `schemas` in your [service configuration](#configuration-options). You can also specify multiple `endpoints` for [permissions](#define-permissions). If neither `schemas` nor `endpoints` is included, it's equivalent to the following default: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. mariadb: type: mariadb:11.4 configuration: schemas: - main endpoints: mysql: default_schema: main privileges: main: admin ``` If either `schemas` or `endpoints` are defined, no default is applied and you have to specify the full configuration. **Note**: Removing a schema from the list of ``schemas`` on further deployments results in the deletion of the schema. ###### Multiple databases example The following configuration example creates a single MariaDB service named `mariadb` with two databases, `main` and `legacy`. Access to the database is defined through three endpoints: * `admin` has full access to both databases. * `reporter` has SELECT query access to `main` but no access to `legacy`. * `importer` has SELECT/INSERT/UPDATE/DELETE (but not DDL) access to `legacy` but no access to `main`. ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. mariadb: type: mariadb:11.4 configuration: schemas: - main - legacy endpoints: admin: default_schema: main privileges: main: admin legacy: admin reporter: privileges: main: ro importer: default_schema: legacy privileges: legacy: rw ``` Expose these endpoints to your app as relationships in your [app configuration](https://docs.upsun.com../../create-apps/_index.md): ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "myapp" [...] # Relationships enable access from this app to a given service. # The example below shows configuration with explicitly set service names and endpoints. # See the Application reference for all options for defining relationships and endpoints. relationships: database: service: mariadb endpoint: admin reports: service: mariadb endpoint: reporter imports: service: mariadb endpoint: importer ``` These relationships are then available in the [service environment variables](#relationship-reference). Each has its own credentials, prefixed with the relationship name, you can use to connect to the given database. ##### Configure the database For MariaDB 10.1 and later and Oracle MySQL 8.0 and later, you can set some configuration properties (equivalent to using a `my.cnf` file). In your settings, add the `properties` key to the `configuration` key. It offers the following properties: | Name | Type | Default | Description | |---------------------------------------|-----------|--------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `max_allowed_packet` | `integer` | `16` | The maximum size for packets in MB. Can be from `1` to `100`. | | `default_charset` | `string` | `utf8mb4` after February 2020 and `latin1` before | The default character set. Affects any tables created after it's set. | | `default_collation` | `string` | `utf8mb4_unicode_ci` after February 2020 and `latin1` before | The default collation. Affects any tables created after it's set. | | `optimizer_switch` | `string` | | A place to set various server optimization variables. See the [MariaDB documentation](https://mariadb.com/kb/en/optimizer-switch/). | | `optimizer_use_condition_selectivity` | `integer` | `4` in version 10.4.1+ and `1` before that | Which statistics are used by the optimizer. From `1` to `5`. See the [MariaDB documentation](https://mariadb.com/kb/en/server-system-variables/#optimizer_use_condition_selectivity). | | `innodb_adaptive_hash_index` | `integer` | `0` in version 10.5+ and `1` before that | Enable/Disable InnoDB Hash Index. See the [MariaDB documentation](https://mariadb.com/kb/en/innodb-system-variables/#innodb_adaptive_hash_index). | | `max_heap_table_size` | `integer` | `32` | The maximum size for user-created MEMORY tables in MB. Can be from `1` to `4096`. | | `table_definition_cache` | `integer` | `400` | The number of table definitions that can be cached. See the [MariaDB documentation](https://mariadb.com/kb/en/server-system-variables/#table_definition_cache). | | `table_open_cache` | `integer` | `400` | The maximum number of open tables cached in one table cache instance. See the [MariaDB documentation](https://mariadb.com/kb/en/server-system-variables/#table_open_cache). | | `wsrep_sync_wait` | `integer` | `0` (Disabled) | Ensure execution of statements in fully synced nodes. See the [MariaDB documentation](https://mariadb.com/kb/en/galera-cluster-system-variables/#wsrep_sync_wait). | An example of setting these properties: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. mariadb: type: mariadb:11.4 configuration: properties: max_allowed_packet: 64 default_charset: utf8mb4 default_collation: utf8mb4_unicode_ci ``` You can also change a table's character set and collation through `ALTER TABLE` commands: ```sql -- To change defaults when creating new tables: ALTER DATABASE main CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- To change defaults when creating new columns: ALTER TABLE table_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- To convert existing data: ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ``` For further details, see the [MariaDB documentation](https://mariadb.com/kb/en/character-set-and-collation-overview/). **Note**: MariaDB configuration properties like [max_connections](https://mariadb.com/docs/server/ref/mdb/system-variables/max_connections/) and [innodb_buffer_pool_size](https://mariadb.com/kb/en/innodb-buffer-pool/#innodb_buffer_pool_size) are not directly configurable from ``configuration.properties`` in your services configuration. They can, however, be set indirectly, which can be useful for solving ``Too many connection`` errors. See [the troubleshooting documentation](https://docs.upsun.com/add-services/mysql/troubleshoot.md#too-many-connections) for more details. ##### Password generation When you connect your app to a database, an empty password is generated for the database by default. This can cause issues with your app. To generate real passwords for your database, define custom endpoints in your [service configuration](#1-configure-the-service). For each custom endpoint you create, you get an automatically generated password, similarly to when you create [multiple databases](#multiple-databases). Note that you can't customize these automatically generated passwords. After your custom endpoints are exposed as relationships in your [app configuration](https://docs.upsun.com../../create-apps.md), you can retrieve the password for each endpoint through the `PLATFORM_RELATIONSHIPS` [environment variable](https://docs.upsun.com../../development/variables/use-variables.md#use-provided-variables) within your [application containers](https://docs.upsun.com/development/variables/use-variables.md#access-variables-in-your-app). The password value changes automatically over time, to avoid downtime its value has to be read dynamically by your app. Globally speaking, having passwords hard-coded into your codebase can cause security issues and should be avoided. When you switch from the default configuration with an empty password to custom endpoints, make sure your service name remains unchanged. Failure to do so results in the creation of a new service, which removes any existing data from your database. ##### Storage Engine It’s best to use the InnoDB storage engine wherever possible instead of MyISAM. If MyISAM tables have been inadvertently created or imported in your environments (if you see ``ENGINE=MyISAM`` in the response to ``SHOW CREATE TABLE EXISTING_TABLE``), convert them to use the InnoDB storage engine as follows: 1. Rename the existing table. ```text RENAME TABLE ; ``` 1. Create a new table from the data in the existing table. ```text CREATE TABLE SELECT * from ; ``` Now when you run `SHOW CREATE TABLE `, you see `ENGINE=InnoDB`. ##### Service timezone To change the timezone for a given connection, run `SET time_zone = ;`. ##### Exporting data To download all data from your SQL database, use the Upsun CLI. If you have a single SQL database, the following command exports all data to a local file: ```bash upsun db:dump ``` If you have multiple SQL databases, you are prompted for which one to export. You can also specify a database by its relationship name: ```bash upsun db:dump --relationship ``` ###### Compression By default, the file is uncompressed. To compress it, use the `--gzip` (`-z`) option: ```bash upsun db:dump --gzip ``` ###### Using the output in bash To pipe the result to another command, use the `--stdout` option. For example, to create a bzip2-compressed file, run: ```bash upsun db:dump --stdout | bzip2 > dump.sql.bz2 ``` ##### Importing data To load data into a database, pipe an SQL dump through the `upsun sql` command, like so: ```bash upsun sql **Note**: Importing a database backup is a destructive operation. It overwrites data already in your database. It’s best to run it against an empty database. If not, make a backup or do a database export before importing. ##### Sanitizing data To ensure people who review code changes can't access personally identifiable information stored in your database, [sanitize your preview environments](https://docs.upsun.com../../development/sanitize-db.md). ##### Replication There is no on-site primary/replica support in your environments. In rare cases (such as for certain backup purposes), you can also enable [remote replication](https://docs.upsun.com/add-services/mysql/mysql-replication.md) to your own replica data. The replica isn't available to your application. ##### Troubleshoot If you run into issues, [troubleshoot MySQL](https://docs.upsun.com/add-services/mysql/troubleshoot.md). #### MariaDB/MySQL External Replication In rare cases, it may be useful to maintain a replica instance of your MySQL/MariaDB database outside of Upsun. Normally an automated backup is better for short-term usage and a `mysqldump` for longer term storage, but in some cases the data set is large enough that `mysqldump` is prohibitive. In that case, you can enable external replication using an extra permission. Note that this guide covers the Upsun side; you need to set up and maintain your own replica instance. Consult the MySQL or MariaDB documentation for steps to do so. ###### Create a replication user To set up replication you need to create a replication-enabled user. For each database that you'd like to replicate, you need to assign a `replication` permission/role, under a corresponding `endpoint`: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. mariadb: type: mariadb:11.4 configuration: schemas: - main endpoints: # Restate the default user to be used by your application. mysql: default_schema: main privileges: main: admin replicator: privileges: main: replication ``` This creates a `replicator` user, and grants read-only and table locking rights on the `main` database (namely `Select_priv`, `Show_view_priv`, `Create_tmp_table_priv`, `Lock_tables_priv` privileges) along with global replication rights (namely `Repl_slave_priv` and `Repl_client_priv` privileges) and flushing rights (`Reload_priv` used for flushing before reading the binary log position). If there is at least one `replication` permission defined, the bin-logging is enabled on the primary server, which is essential for the replication. ###### Define a relationship for the new endpoint Even if you won't be accessing the replication endpoint from your application, you still need to expose it to an application as a relationship so that you can connect to it over SSH. Add a new relationship to your application container: ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" [...] # Relationships enable an app container's access to a service. relationships: database: service: mariadb endpoint: mysql replication: service: mariadb endpoint: replicator ``` ###### Getting the Primary's Binary Log Co-ordinates Open the MySQL CLI to the `replication` relationship, either by accessing the credentials while on the app container or using the following command. ```bash upsun sql -r replication ``` Now you need to prevent any changes to the data while you view the binary log position. You'll use this to tell the replica at exactly which point it should start replicating from. On the primary server, flush and lock all tables by running `FLUSH TABLES WITH READ LOCK`. Keep this session running - exiting it releases the lock. Get the current position in the binary log by running `SHOW MASTER STATUS`: ```sql mysql> FLUSH TABLES WITH READ LOCK; Query OK, 0 rows affected (0.016 sec) mysql> SHOW MASTER STATUS; +-----------------+----------+--------------+------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | +-----------------+----------+--------------+------------------+ | binlogs.000002 | 1036 | dflt | | +-----------------+----------+--------------+------------------+ ``` Record the `File` and `Position` details. If binary logging has just been enabled, these are blank. Now, with the lock still in place, copy the data from the primary to the replica. Login to the app container, then run: ```sh # Dump the data from primary. Note that it dumps only the databases, which "replicator" user has access to. $ mysqldump --all-databases --single-transaction -h database.internal -P 3306 -u replicator -p > /path/to/dump.sql ``` Download the dump file, then move it to the server where your replica lives to import it. ```bash # Copy the dump to your replica $ mysql -u root UNLOCK TABLES; ``` ###### Setting up the replica ####### Configuring the replica As mentioned above you have to set up a replica on your own. Assuming that you have a running MariaDB/MySQL replica instance, give the replica a unique `server_id` (distinct from primary). You can find out primary's `server_id` by running: ```sql mysql> SHOW VARIABLES LIKE 'server_id'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | server_id | 1 | +---------------+-------+ ``` Then set a distinct `server_id` number (e.g. server_id+1) in your replica config (e.g. `my.cnf`) under: ``` [mysqld] server_id=2 ``` And reload the replica instance for the changes to take an effect. ####### Set up SSH tunneling You need to set up an SSH tunnel from the replica server to the primary, tunneled through the application. To do so using the Upsun CLI, run the following (replacing `` with the name of your production branch): ```bash upsun tunnel:open --project --environment ``` This opens local SSH tunnels to all services accessible from the application. In practice, you may be better served by setting up the tunnel manually using SSH. Consult the SSH documentation for the best way to do so. **Note**: The SSH connection is interrupted every time the environment redeploys. For replication to continue you must setup an auto-restart for the connection. There are many ways to do so that are out of the scope of this documentation. ####### Starting the Replica Once the data has been imported, you are ready to start replicating. Begin by running a `CHANGE MASTER TO`, making sure that `MASTER_LOG_FILE` matches the file and `MASTER_LOG_POS` the position returned by the earlier `SHOW MASTER STATUS` on the Upsun database. For example: ```sql mysql> CHANGE MASTER TO MASTER_HOST='', MASTER_USER='replicator', MASTER_PASSWORD='', MASTER_PORT=3306, MASTER_LOG_FILE='binlogs.000002', MASTER_LOG_POS=1036, MASTER_CONNECT_RETRY=10; ``` Where `` varies depending on the SSH tunneling configuration you have, and the `` can be obtained by running `upsun ssh env`. Now start the replica with the `START SLAVE` command: ```sql mysql> START SLAVE; ``` Check that the replication is working by executing the `SHOW SLAVE STATUS` command: ```sql mysql> SHOW SLAVE STATUS \G ``` If replication is working correctly, the values of both `Slave_IO_Running` and `Slave_SQL_Running` should be `Yes`: ```sql Slave_IO_Running: Yes Slave_SQL_Running: Yes ``` ####### [Optional/Troubleshooting] Skipping invalid binary log queries In some cases, after applying primary's dump to the replica and starting the replica, you might experience replication errors (`Slave_SQL_Running: No` and `Error:` in the output of `SHOW SLAVE STATUS \G` above). Each of such errors needs a careful inspection, but you might be able to just skip some of them. For example: ```sql mysql> STOP SLAVE; SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1; START SLAVE; mysql> SHOW SLAVE STATUS \G ``` In case you have multiple errors you would need to repeat the steps above (preferred) or set `SQL_SLAVE_SKIP_COUNTER` (which corresponds to skipping the next N events from the primary) to something greater. #### Troubleshoot MySQL For more general information, see how to [troubleshoot development](https://docs.upsun.com/development/troubleshoot.md). ###### Lock wait timeout If a process running in your application acquired a lock from MySQL for a long period of time, you receive MySQL error messages like this: ```sql SQLSTATE[HY000]: General error: 1205 Lock wait timeout exceeded; ``` This is typically caused by one of the following: * There are multiple places acquiring locks in different order. For example, code path 1 first locks record A and then locks record B, while code path 2 first locks record B and then locks record A. * There is a long running background process executed by your application that holds the lock until it ends. If you're using [MariaDB 10+](https://docs.upsun.com/add-services/mysql.md), use the SQL query `SHOW FULL PROCESSLIST \G` to list DB queries waiting for locks. To determine where to debug, find output like the following: ```sql Command: Query Time: ... State: Waiting for table metadata lock Info: SELECT ... ``` To find active background processes, run `ps aufx` on your application container. Make sure that locks are acquired in a pre-defined order and released as soon as possible. ###### Definer/invoker of view lack rights to use them There is a single MySQL user, so you can not use "DEFINER" Access Control mechanism for Stored Programs and Views. When creating a `VIEW`, you may need to explicitly set the `SECURITY` parameter to `INVOKER`: ```sql CREATE OR REPLACE SQL SECURITY INVOKER VIEW `view_name` AS SELECT ``` ###### Server has gone away ####### Disk space issues Errors such as `PDO Exception 'MySQL server has gone away'` are usually the result of exhausting your available disk space. Get an estimate of current disk usage using the CLI command `upsun db:size`. Just keep in mind it's an estimate and not exact. Allocate more space to the service by running the `upsun resources:set` command. For more information, see how to [manage resources](https://docs.upsun.com/manage-resources.md). As table space can grow rapidly, it's usually advisable to make your database mount size twice the size reported by the `db:size` command. You may want to add a [low-disk warning](https://docs.upsun.com../../integrations/notifications.md#low-disk-warning) to learn about low disk space before it becomes an issue. ####### Packet size limitations `MySQL server has gone away` errors may be caused by the size of the database packets. If so, the logs may show warnings like `Error while sending QUERY packet` before the error. One way to resolve the issue is to use the [`max_allowed_packet` parameter](https://docs.upsun.com/add-services/mysql.md#configure-the-database). ####### Worker timeout `MySQL server has gone away` errors may be caused by server timeouts. MySQL has a built-in timeout for idle connections, which defaults to 10 minutes. Most typical web connections end long before that's ever approached, but a long-running worker may idle and not need the database for longer than the timeout, leading to a "server has gone away" message. The best approach is to wrap your connection logic in code that detects a "server has gone away" exception and tries to re-establish the connection. Alternatively, if your worker is idle for too long it can self-terminate. Upsun automatically restarts the worker process and the new process can establish a new database connection. ###### Too many connections You may get the following [error message](https://mariadb.com/kb/en/e1040/): `Error 1040: Too many connections`. A common way to solve this issue is to increase the `max_connections` property in your MariaDB service configuration. However, on Upsun, you **cannot** configure `max_connections` directly. ####### Quick fix You cannot configure `max_connections` directly in Upsun service configurations. However, to solve `Error 1040`, you can increase `max_connections` indirectly. Given the following services configuration for MariaDB: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. mariadb: type: mariadb:11.4 configuration: properties: max_allowed_packet: 16 ``` And assuming you have set the resources for that service using the following CLI command: ```bash upsun resources:set --size mariadb:1 ``` `max_connections` in this case is `332` as [set by Upsun](#how-it-works): To **increase** `max_connections`, you can **either**: - **decrease** `max_allowed_packet` (for example, `16` → `15` results in `max_connections=355`) - or **increase** `size` using the `resources:set` command (for example, `1` → `2` results in `max_connections=500`) ####### How it works Behind the scenes, `max_connections` is calculated from values that you _can_ change: 1. **`max_allowed_packet`**: `max_allowed_packet` is [directly configurable](https://docs.upsun.com/add-services/mysql.md#configure-the-database) in your `.upsun/config.yaml` file with an integer value. The default value of `16` is shown below to illustrate: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. mariadb: type: mariadb:11.4 configuration: properties: max_allowed_packet: 16 ``` 1. **The memory available to the service**: Resources are provisioned to Upsun containers according to your definition via the API, often through the `resources:set` CLI command: ```bash upsun resources:set --size mariadb:1 ``` The memory for a given container from its `size` depends on its [container profile](https://docs.upsun.com/manage-resources/adjust-resources.md#advanced-container-profiles). For example, [MariaDB](https://docs.upsun.com/manage-resources/adjust-resources.md#default-container-profiles) has a `HIGH_MEMORY` [container profile](https://docs.upsun.com/manage-resources/adjust-resources.md#advanced-container-profiles). For `--size mariadb:1`, it means 1 CPU and 2432 MB of memory. If we assume the configuration above, where: - `--size mariadb:1`, which we know is `2432` MB, referred to below as `application_size` - `mariadb.configuration.properties.max_allowed_packet: 16` - You are using the default `HIGH_MEMORY` profile assigned to MariaDB containers. [Changing the container profile](https://docs.upsun.com/manage-resources/adjust-resources.md#adjust-a-container-profile) changes the behavior below. `max_allowed_packet` is `332`, which is determined by Upsun according to: \begin{aligned} \texttt{max_connections} = \text{int}\Biggl[ \min \left( \frac{\texttt{FREE_MEMORY}}{\texttt{max_allowed_packet}}, 500 \right) \Biggr] \end{aligned} This calculation uses three additional calculations: \begin{aligned} \texttt{FREE_MEMORY} = \texttt{AVAILABLE_MEMORY} - \left( 50 + \texttt{innodb_buffer_pool_size} \right) \newline \newline \texttt{AVAILABLE_MEMORY} = (\texttt{application_size} * 2) + 512 \newline \newline \texttt{innodb_buffer_pool_size} = \frac{\text{int}\left( 0.75 \cdot \texttt{application_size} \right)}{1024^{2}} \end{aligned} So for our current example, where: \begin{aligned} \texttt{application_size} = 2432 \newline \texttt{max_allowed_packet} = 16 \end{aligned} You get: \begin{aligned} \texttt{innodb_buffer_pool_size} = \frac{\text{int}\left( 0.75 \cdot \texttt{application_size} \right)}{1024^{2}} = \frac{\text{int}\left( 0.75 \cdot \texttt{1280} \right)}{1024^{2}} \approx 1.7395 \times 10^{-3} \end{aligned} \begin{aligned} \texttt{AVAILABLE_MEMORY} = (\texttt{application_size} * 2) + 512 = (1280 * 2) + 512 = 5376 \end{aligned} \begin{aligned} \texttt{FREE_MEMORY} = \texttt{AVAILABLE_MEMORY} - \left( 50 + \texttt{innodb_buffer_pool_size} \right) \newline \newline \texttt{FREE_MEMORY} = 3072 - \left( 50 + 0.0009155... \right) = 5325.998... \end{aligned} \begin{aligned} \texttt{max_connections} = \text{int}\Biggl[ \min \left( \frac{\texttt{FREE_MEMORY}}{\texttt{max_allowed_packet}}, 500 \right) \Biggr] = \text{int}\Biggl[ \min \left( \frac{3021.999084}{16}, 500 \right) \Biggr] = \text{int}\Biggl[ 332.87... \Biggr] \end{aligned} \begin{aligned} \texttt{max_connections} = 332 \end{aligned} The following table provides additional example calculations of `max_connections` for all `size` settings and for a number of `max_allow_packet` settings. MariaDB ``max_connections`` ``application_size````size`` (memory in MB) 0.1 (448 MB) | 0.25 (832 MB) | 0.5 (1408 MB) | 1 (2432 MB) | 2 (4032 MB) | 4 (6720 MB) | 6 (9024 MB) | 8 (11200 MB) | 1(min) | 500 | 500 | 500 | 500 | 500 | 500 | 500 | 500 | 2 | 500 | 500 | 500 | 500 | 500 | 500 | 500 | 500 | 8 | 169 | 265 | 409 | 500 | 500 | 500 | 500 | 500 | 16(default) | 84 | 132 | 204 | 332 | 500 | 500 | 500 | 500 | 32 | 42 | 66 | 102 | 166 | 266 | 434 | 500 | 500 | 64 | 21 | 33 | 51 | 83 | 133 | 217 | 289 | 357 | 100(max) | 13 | 21 | 32 | 53 | 85 | 139 | 185 | 228 | **Note**: The maximum value for ``max_connections`` is 500, indicated with italicized integers in the table. Also, you can **increase** ``max_connections`` in your environments by either: - **decreasing** the ``max_allow_packet`` value in your service configuration - or **increasing** the service’s resources by using the CLI command ``resources:set`` and the ``--size`` flag ### Memcached (Object cache) Memcached is a simple in-memory object store well-suited for application level caching. See the [Memcached documentation](https://memcached.org) for more information. Both Memcached and Redis can be used for application caching. As a general rule, Memcached is simpler and thus more widely supported while Redis is more robust. Upsun recommends using Redis if possible but Memcached is fully supported if an application favors that cache service. ##### Supported versions You can select the major and minor version. Patch versions are applied periodically for bug fixes and the like. When you deploy your app, you always get the latest available patches. - 1.6 - 1.5 - 1.4 ##### Relationship reference For each service [defined via a relationship](#usage-example) to your application, Upsun automatically generates corresponding environment variables within your application container, in the ``$_`` format. Here is example information available through the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) themselves, or through the [``PLATFORM_RELATIONSHIPS`` environment variable](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). For some advanced use cases, you can use the [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). The structure of the ``PLATFORM_RELATIONSHIPS`` environment variable can be obtained by running ``upsun relationships`` in your terminal: ```json {} { "service": "memcached", "ip": "123.456.78.90", "hostname": "azertyuiopqsdfghjklm.memcached.service._.eu-1.platformsh.site", "cluster": "azertyuiopqsdf-main-afdwftq", "host": "memcached.internal", "rel": "memcached", "scheme": "memcached", "type": "memcached:1.6", "port": 11211 } ``` Here is an example of how to gather [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables) information in a [.environment](https://docs.upsun.com/development/variables/set-variables.md#use-env-files): ```bash {location=".environment"} # Decode the built-in credentials object variable. export RELATIONSHIPS_JSON=$(echo $PLATFORM_RELATIONSHIPS | base64 --decode) # Set environment variables for individual credentials. export APP_MEMCACHED_HOST="$(echo $RELATIONSHIPS_JSON | jq -r '.memcached[0].host')" ``` ##### Usage example ###### 1. Configure the service To define the service, use the ``memcached`` type: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. : type: memcached: ``` Note that changing the name of the service replaces it with a brand new service and all existing data is lost. Back up your data before changing the service. ###### 2. Define the relationship To define the relationship, use the following configuration: You can define ```` as you like, so long as it’s unique between all defined services and matches in both the application and services configuration. The example above leverages [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships. That is, it uses default endpoints behind-the-scenes, providing a [relationship](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) (the network address a service is accessible from) that is identical to the name of that service. With the above definition, the application container now has [access to the service](#use-in-app) via the relationship ```` and its corresponding [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. : # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: : ":memcached" ``` You can define ```` and ```` as you like, so long as it’s unique between all defined services and relationships and matches in both the application and services configuration. The example above leverages [explicit endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships. Depending on your needs, instead of explicit endpoint configuration, you can use [default endpoint configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships). With the above definition, the application container now has [access to the service](#use-in-app) via the relationship ```` and its corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). For PHP, enable the [extension](https://docs.upsun.com/languages/php/extensions.md) for the service: ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. : # PHP extensions. runtime: extensions: - memcached # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: : ":memcached" ``` For Python, include the proper dependency: ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. : # Build dependencies per runtime. dependencies: python: python-memcached: '*' # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: : ":memcached" ``` ###### Example configuration ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: memcached: "memcached:memcached" services: # The name of the service container. Must be unique within a project. memcached: type: memcached:1.6 ``` ###### Use in app To use the configured service in your app, add a configuration file similar to the following to your project. ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" # PHP extensions. runtime: extensions: - memcached [...] # Relationships enable access from this app to a given service. # See the Application reference for all options for defining relationships and endpoints. relationships: memcached: service: memcached endpoint: memcached service: memcached: type: memcached:1.6 ``` This configuration defines a single application (`myapp`), whose source code exists in the `/myapp` directory. `myapp` has access to the `influxdb` service, via a relationship whose name is [identical to the service name](#2-define-the-relationship) (as per [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships). From this, ``myapp`` can retrieve access credentials to the service through the [relationship environment variables](#relationship-reference). ```bash {location="myapp/.environment"} # Surface a Memcached connection string for use in app. # For more information, please visit https://docs.upsun.com/development/variables.html#service-environment-variables. export CACHE_URL="${MEMCACHED_HOST}:${MEMCACHED_PORT}" ``` The above file — ``.environment`` in the ``myapp`` directory — is automatically sourced by Upsun into the runtime environment, so that the variable ``CACHE_URL`` can be used within the application to connect to the service. Note that ``CACHE_URL``, and all Upsun [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) like ``MEMCACHEDCACHE_HOST``, are environment-dependent. Unlike the build produced for a given commit, they can’t be reused across environments and only allow your app to connect to a single service instance on a single environment. A file very similar to this is generated automatically for your when using the ``upsun ify`` command to [migrate a codebase to Upsun](https://docs.upsun.com/get-started.md). ##### Accessing Memcached directly To access the Memcached service directly you can use `netcat` as Memcached doesn't have a dedicated client tool. Assuming your Memcached relationship is named `memcached`, the host name `MEMCACHED_HOST` and port number `MEMCACHED_PORT` obtained from the [service environment variable](#relationship-reference) would be `memcached.internal` and `11211`. Open an [SSH session](https://docs.upsun.com/development/ssh.md) and access the Memcached server as follows: ```bash {location="Terminal"} netcat memcached.internal 11211 ``` You can obtain the complete list of available service environment variables in your app container by running ``upsun ssh env``. Note that the information about the relationship can change when an app is redeployed or restarted or the relationship is changed. So your apps should only rely on the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) directly rather than hard coding any values. ### MongoDB (Database service) MongoDB is a cross-platform, document-oriented database.For more information on using MongoDB, see [MongoDB’s own documentation](https://docs.mongodb.com/manual/). ##### Supported versions You can select the major and minor version. Patch versions are applied periodically for bug fixes and the like. When you deploy your app, you always get the latest available patches. - 7.0 - 6.0 - 5.0 - 4.4 ###### Deprecated versions The following versions are [deprecated](https://docs.upsun.com/glossary.md#deprecated-versions). They're available, but they aren't receiving security updates from upstream and aren't guaranteed to work. They'll be removed in the future, so migrate to one of the [supported versions](#supported-versions). - 4.2 - 4.0 ###### Legacy edition Previous non-Enterprise versions are available in your projects (and are listed below), but they're at their [end of life](https://www.mongodb.com/support-policy/legacy) and are no longer receiving security updates from upstream. **Warning**: Downgrades of MongoDB aren’t supported. MongoDB updates its own data files to a new version automatically but can’t downgrade them. If you want to experiment with a later version without committing to it use a preview environment. ###### Deprecated versions The following versions are [deprecated](https://docs.upsun.com/glossary.md#deprecated-versions). They're available, but they aren't receiving security updates from upstream and aren't guaranteed to work. They'll be removed in the future, so migrate to one of the [supported versions](#supported-versions). - 4.0.3 - 3.6 - 3.4 - 3.2 - 3.0 ##### Relationship reference For each service [defined via a relationship](#usage-example) to your application, Upsun automatically generates corresponding environment variables within your application container, in the ``$_`` format. Here is example information available through the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) themselves, or through the [``PLATFORM_RELATIONSHIPS`` environment variable](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). For some advanced use cases, you can use the [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). The structure of the ``PLATFORM_RELATIONSHIPS`` environment variable can be obtained by running ``upsun relationships`` in your terminal: ```json {} { "username": "main", "scheme": "mongodb", "service": "mongodb", "ip": "123.456.78.90", "hostname": "azertyuiopqsdfghjklm.mongodb.service._.eu-1.platformsh.site", "cluster": "azertyuiop-main-7rqtwti", "host": "mongodb.internal", "rel": "mongodb", "query": { "is_master": true }, "path": "main", "password": null, "type": "mongodb-enterprise:7.0", "port": 27017 } ``` Here is an example of how to gather [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables) information in a [.environment](https://docs.upsun.com/development/variables/set-variables.md#use-env-files): ```bash {location=".environment"} # Decode the built-in credentials object variable. export RELATIONSHIPS_JSON=$(echo $PLATFORM_RELATIONSHIPS | base64 --decode) # Set environment variables for individual credentials. export APP_MONGODBDATABASE_HOST="$(echo $RELATIONSHIPS_JSON | jq -r '.mongodb[0].host')" ``` ##### Usage example ###### Enterprise edition example ####### 1. Configure the service To define the service, use the ``mongodb-enterprise`` type: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. : type: mongodb-enterprise: ``` Note that changing the name of the service replaces it with a brand new service and all existing data is lost. Back up your data before changing the service. ####### 2. Define the relationship To define the relationship, use the following configuration: You can define ```` as you like, so long as it’s unique between all defined services and matches in both the application and services configuration. The example above leverages [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships. That is, it uses default endpoints behind-the-scenes, providing a [relationship](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) (the network address a service is accessible from) that is identical to the name of that service. Depending on your needs, instead of default endpoint configuration, you can use [explicit endpoint configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships). With the above definition, the application container (````) now has [access to the service](#use-in-app) via the relationship ```` and its corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. : # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: : service: endpoint: mongodb ``` You can define ```` and ```` as you like, so long as it’s unique between all defined services and relationships and matches in both the application and services configuration. The example above leverages [explicit endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships. Depending on your needs, instead of explicit endpoint configuration, you can use [default endpoint configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships). With the above definition, the application container now has [access to the service](#use-in-app) via the relationship ```` and its corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). For PHP, enable the [extension](https://docs.upsun.com/languages/php/extensions.md) for the service: ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. : # PHP extensions. runtime: extensions: - mongodb # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: : service: endpoint: mongodb ``` ####### Example configuration ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # PHP extensions. runtime: extensions: - mongodb # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: mongodb-enterprise: service: mongodb-enterprise endpoint: mongodb services: # The name of the service container. Must be unique within a project. mongodb-enterprise: type: mongodb-enterprise:7.0 ``` ###### Legacy edition example ####### 1. Configure the service To define the service, use the ``mongodb`` type: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. : type: mongodb: ``` Note that changing the name of the service replaces it with a brand new service and all existing data is lost. Back up your data before changing the service. ####### 2. Define the relationship To define the relationship, use the following configuration: You can define ```` as you like, so long as it’s unique between all defined services and matches in both the application and services configuration. The example above leverages [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships. That is, it uses default endpoints behind-the-scenes, providing a [relationship](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) (the network address a service is accessible from) that is identical to the name of that service. Depending on your needs, instead of default endpoint configuration, you can use [explicit endpoint configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships). With the above definition, the application container (````) now has [access to the service](#use-in-app) via the relationship ```` and its corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. : # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: : service: endpoint: mongodb ``` You can define ```` and ```` as you like, so long as it’s unique between all defined services and relationships and matches in both the application and services configuration. The example above leverages [explicit endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships. Depending on your needs, instead of explicit endpoint configuration, you can use [default endpoint configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships). With the above definition, the application container now has [access to the service](#use-in-app) via the relationship ```` and its corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). For PHP, enable the [extension](https://docs.upsun.com/languages/php/extensions.md) for the service: ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. : # PHP extensions. runtime: extensions: - mongodb # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: : service: endpoint: mongodb ``` ####### Example configuration ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # PHP extensions. runtime: extensions: - mongodb # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: mongodb: service: mongodb endpoint: mongodb services: # The name of the service container. Must be unique within a project. mongodb: type: mongodb:4.0.3 ``` ###### Use in app To use the configured service in your app, add a configuration file similar to the following to your project. ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" # PHP extensions. runtime: extensions: - mongodb [...] # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: mongodb: service: mongodb endpoint: mongodb service: mongodb: type: mongodb-enterprise:7.0 ``` This configuration defines a single application (`myapp`), whose source code exists in the `/myapp` directory. `myapp` has access to the `mongodb` service, via a relationship whose name is [identical to the service name](#2-define-the-relationship) (as per [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships). From this, ``myapp`` can retrieve access credentials to the service through the [relationship environment variables](#relationship-reference). ```bash {location="myapp/.environment"} # Set environment variables for individual credentials. # For more information, please visit https://docs.upsun.com/development/variables.html#service-environment-variables. export DB_CONNECTION=="${MONGODB_SCHEME}" export DB_USERNAME="${MONGODB_USERNAME}" export DB_PASSWORD="${MONGODB_PASSWORD}" export DB_HOST="${MONGODB_HOST}" export DB_PORT="${MONGODB_PORT}" export DB_DATABASE="${MONGODB_PATH}" # Surface connection string variable for use in app. export DATABASE_URL="${DB_CONNECTION}://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_DATABASE}" ``` The above file — ``.environment`` in the ``myapp`` directory — is automatically sourced by Upsun into the runtime environment, so that the variable ``DATABASE_URL`` can be used within the application to connect to the service. Note that ``DATABASE_URL``, and all Upsun [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) like ``MONGODB_HOST``, are environment-dependent. Unlike the build produced for a given commit, they can’t be reused across environments and only allow your app to connect to a single service instance on a single environment. A file very similar to this is generated automatically for your when using the ``upsun ify`` command to [migrate a codebase to Upsun](https://docs.upsun.com/get-started.md). ##### Access the service directly You can access MongoDB from you app container via [SSH](https://docs.upsun.com../development/ssh.md). Get the `host` from your [relationship](#relationship-reference). Then run the following command: ```bash mongo ``` With the example value, that would be the following: ```bash mongo mongodb.internal ``` You can obtain the complete list of available service environment variables in your app container by running ``upsun ssh env``. Note that the information about the relationship can change when an app is redeployed or restarted or the relationship is changed. So your apps should only rely on the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) directly rather than hard coding any values. ##### Exporting data The most straightforward way to export data from a MongoDB database is to open an SSH tunnel to it and export the data directly using MongoDB's tools. First, open an SSH tunnel with the Upsun CLI: ```bash upsun tunnel:open ``` That opens an SSH tunnel to all services on your current environment and produce output like the following: ```bash SSH tunnel opened on port 30000 to relationship: mongodb ``` The port may vary in your case. You also need to obtain the user, password, and database name from the relationships array, as above. Then, connect to that port locally using `mongodump` (or your favorite MongoDB tools) to export all data in that server: ```bash mongodump --port 30000 -u main -p main --authenticationDatabase main --db main ``` (If necessary, vary the `-u`, `-p`, `--authenticationDatabase` and `--db` flags.) As with any other shell command it can be piped to another command to compress the output or redirect it to a specific file. For further references, see the [official `mongodump` documentation](https://docs.mongodb.com/database-tools/mongodump/). ##### Upgrading To upgrade to 6.0 from a version earlier than 5.0, you must successively upgrade major releases until you have upgraded to 5.0. For example, if you are running a 4.2 image, you must upgrade first to 4.4 and then upgrade to 5.0 before you can upgrade to 6.0. For more details on upgrading and how to handle potential application backward compatibility issues, see the [MongoDB release notes](https://docs.mongodb.com/manual/release-notes). **Note**: Make sure you first test your migration on a separate branch. Also, be sure to take a backup of your production environment **before** you merge this change. Downgrading isn't supported. If you want, for whatever reason, to downgrade you should create a mongodump, remove the service, recreate the service, and import your dump. ### Network Storage The Network Storage service enables a new kind of [mount](https://docs.upsun.com../create-apps/app-reference/single-runtime-image.md#mounts) that refers to a shared service rather than to a local directory. This service allows you to store data and share it between different apps. ##### Supported versions You can select the major and minor version. Patch versions are applied periodically for bug fixes and the like. When you deploy your app, you always get the latest available patches. - 2.0 This service is the Upsun network storage implementation, not the version of a third-party application. **Note**: It isn’t possible to upgrade or downgrade the network storage service version while keeping existing data in place. Changing the service version requires that the service be reinitialized. Any change to the service version results in existing data becoming inaccessible. ###### Deprecated versions The following versions are [deprecated](https://docs.upsun.com/glossary.md#deprecated-versions). They're available, but they aren't receiving security updates from upstream and aren't guaranteed to work. They'll be removed in the future, so migrate to one of the [supported versions](#supported-versions). - 1.0 ##### Usage example ###### 1. Configure the service To define the service, use the ``network-storage`` type: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. : type: network-storage: ``` `` must be [RFC 1123](https://tools.ietf.org/html/rfc1123) compliant, and as such it must: - Contain at most 63 characters - Contain only lowercase alphanumeric characters or `-` (underscores `_` are not allowed) - Start with an alphanumeric character - End with an alphanumeric character This is due to the fact that `` is used as hostname for the network storage. Note that changing the name of the service replaces it with a brand new service and all existing data is lost. Back up your data before changing the service. ###### 2. Add the mount To define the mount accessible by your application, use the following configuration: ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. : mounts: : source: service service: source_path: services: # The name of the service container. Must be unique within a project. : type: network-storage: ``` - `` is the path to your mount within the app container (relative to the app’s root). - `` is the name you [defined in step 1](#1-configure-the-service). - `` specifies where the mount points inside the service. If the `source_path` is an empty string (`""`), your mount points to the entire service. If you don’t define a `source_path`, Upsun uses the `MOUNT_PATH` as default value, without leading or trailing slashes. For example, if your mount lives in the `/my/files/` directory within your app container, it will point to a `my/files` directory within the service. ###### Example configuration ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: mounts: 'my/files': source: service service: network-storage source_path: files services: # The name of the service container. Must be unique within a project. network-storage: type: network-storage:2.0 ``` ##### Multi-application usage If your project contains [multiple apps](https://docs.upsun.com../create-apps/multi-app.md), they may [share `storage` mounts](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#share-a-mount-between-several-apps). Alternatively, they may use shared `service` mounts. If the `source_path` is the same for both apps, the files are shared between the two applications even if the mount location is different. It's also possible to have one app mount a `source_path` that's a subdirectory of another application's mount. For example: ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. app1: # The location of the application's code. source: root: "app1" [...] mounts: # The path to your mount within the app container (relative to the app's root). 'web/uploads': # Specifies that the mount points to a network storage service that can be shared between apps. source: service # The name of the network storage service the mount points to. service: network-storage # Specifies where your mount points inside the external directory that is mounted to your app container. source_path: uploads # The name of the app container. Must be unique within a project. app2: # The location of the application's code. source: root: "app2" [...] mounts: # The path to your mount within the app container (relative to the app's root). 'process': # Specifies that the mount points to a network storage service that can be shared between apps. source: service # The name of the network storage service the mount points to. service: network-storage # Specifies where your mount points inside the external directory that is mounted to your app container. # Since the target is the uploads directory app1's mount already points to, # the network storage service is effectively shared between app1 and app2. source_path: uploads/incoming # The path to your mount within the app container (relative to the app's root). 'done': # Specifies that the mount points to a network storage service that can be shared between apps. source: service # The name of the network storage service the mount points to. service: network-storage # Specifies where your mount points inside the external directory that is mounted to your app container. # Since the target is the uploads directory app1's mount already points to, # the network storage service is effectively shared between app1 and app2. source_path: uploads/done ``` In this example, `app1` has access to the entire `uploads` directory by writing to `web/uploads`. `app2` has two mounts that it can write to: `process` and `done`. The `process` mount refers to the same directory as the `web/uploads/incoming` directory does on `app1`, and the `done` mount refers to the same directory as the `web/uploads/done` directory on `app1`. ##### How do I give my workers access to my main application’s files? If you need to use a worker with access to the same file mount as your web-serving app, define all the necessary mounts as `service` mounts. The following example assumes a Network Storage service named `files` has been defined in `.upsun/config.yaml`. Drupal files directories are shared between the `web` and `worker` instances, while the Drush backup directory is unique to the `web` instance. ```yaml {location=".upsun/config.yaml"} applications: myapp: source: root: "/" type: "php:8.4" [...] mounts: # The public and private files directories are # network mounts shared by web and workers. 'web/sites/default/files': source: service service: files source_path: files 'private': source: service service: files source_path: private # The backup, temp, and cache directories for # Drupal's CLI tools don't need to be shared between web and workers. # It wouldn't hurt anything to make them network # shares, however. '/.drush': source: storage source_path: drush 'tmp': source: tmp source_path: tmp 'drush-backups': source: storage source_path: drush-backups '/.console': source: storage source_path: console # Crons run on the web container, so they have the # same mounts as the web container. crons: drupal: spec: '*/20 * * * *' commands: start: 'cd web ; drush core-cron' # The worker defined here also has the same 6 mounts; # 2 of them are shared with the web container, # the other 4 are local to the worker. workers: queue: commands: start: | cd web && drush queue-run myqueue ``` ##### How can I migrate data from a `storage` mount to a `service` mount? Network Storage `service` mounts can be shared between different apps, while `storage` mounts can only be shared between different _instances_ of the same app. To move data from a `storage` mount to a `service` one, follow these instructions. Assuming you have the following `storage` mount: ```yaml {location=".upsun/config.yaml"} applications: myapp: [...] mounts: web/uploads: source: storage source_path: uploads ``` 1. Add a new `network-storage` service to your configuration: ```yaml {location=".upsun/config.yaml"} applications: myapp: [...] mounts: web/uploads: source: storage source_path: uploads services: # The name of the service container. Must be unique within a project. network-storage: type: network-storage:2.0 ``` **Note**: Make sure you [allocate enough disk space](https://docs.upsun.com/manage-resources/adjust-resources.md#vertical-scaling) to your ``network-storage`` service for your existing files with some buffer. 2. Add a new `service` mount, named `new-uploads`: ```yaml {location=".upsun/config.yaml"} applications: myapp: [...] mounts: web/uploads: source: storage source_path: uploads new-uploads: source: service service: network-storage source_path: uploads services: # The name of the service container. Must be unique within a project. network-storage: type: network-storage:2.0 ``` Note that each mount is on a different storage service, which is why they can have the same `source_path`. 3. Deploy your changes. 4. Copy all your files from the `storage` (`web/uploads`) mount to the `service` (`new-uploads`) mount using `rsync`: ```bash rsync -avz web/uploads/* new-uploads/ ``` 5. Reverse the mounts. To do so, rename the `storage` mount to `old-uploads`, and point the `web/uploads` directory to the `service` mount: ```yaml {location=".upsun/config.yaml"} applications: myapp: [...] mounts: old-uploads: source: storage source_path: uploads web/uploads: source: service service: network-storage source_path: uploads services: # The name of the service container. Must be unique within a project. network-storage: type: network-storage:2.0 ``` 6. Push your changes and check that the files are now accessible from the `service` mount (now named `web/uploads`). To check that no files were lost during the transfer, run the following command: ```bash rsync -avz old-uploads/* web/uploads/ ``` 7. Delete the contents of the `old-uploads` `storage` mount before removing it. 8. Push your changes again. ### OpenSearch (search service) OpenSearch is a distributed RESTful search engine built for the cloud. See the [OpenSearch documentation](https://opensearch.org/docs/latest/) for more information. To switch from Elasticsearch, follow the same procedure as for [upgrading](#upgrading). ##### Supported versions In the list below, notice that there you only specify the major version. Each version represents a rolling release of the latest minor version available from the upstream. The latest compatible minor version and patches are applied automatically. - 2 - 1 You can see the latest minor and patch versions of OpenSearch available from the [`2.x`](https://opensearch.org/lines/2x.md) and [`1.x`](https://opensearch.org/lines/1x.md) (1.3) release lines. ##### Deprecated versions The following versions are still available in your projects, but they're at their end of life and are no longer receiving security updates from upstream, or are no longer the recommended way to configure the service on Upsun. - 1.2 - 1.1 To ensure your project remains stable in the future, switch to [a supported version](#supported-versions). ##### Relationship reference For each service [defined via a relationship](#usage-example) to your application, Upsun automatically generates corresponding environment variables within your application container, in the ``$_`` format. Here is example information available through the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) themselves, or through the [``PLATFORM_RELATIONSHIPS`` environment variable](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). For some advanced use cases, you can use the [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). The structure of the ``PLATFORM_RELATIONSHIPS`` environment variable can be obtained by running ``upsun relationships`` in your terminal: ```json {} { "username": null, "scheme": "http", "service": "opensearch", "fragment": null, "ip": "169.254.99.100", "hostname": "azertyuiopqsdfghjklm.opensearch.service._.eu-1.platformsh.site", "port": 9200, "cluster": "azertyuiopqsdf-main-7rqtwti", "host": "opensearch.internal", "rel": "opensearch", "path": null, "query": [], "password": "ChangeMe", "type": "opensearch:2", "public": false, "host_mapped": false } ``` Here is an example of how to gather [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables) information in a [.environment](https://docs.upsun.com/development/variables/set-variables.md#use-env-files): ```bash {location=".environment"} # Decode the built-in credentials object variable. export RELATIONSHIPS_JSON=$(echo $PLATFORM_RELATIONSHIPS | base64 --decode) # Set environment variables for individual credentials. export APP_OPENSEARCH_HOST="$(echo $RELATIONSHIPS_JSON | jq -r '.opensearch[0].host')" ``` ##### Usage example ###### 1. Configure the service To define the service, use the ``opensearch`` type: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. : type: opensearch: ``` Note that changing the name of the service replaces it with a brand new service and all existing data is lost. Back up your data before changing the service. ###### 2. Define the relationship To define the relationship, use the following configuration: You can define ```` as you like, so long as it’s unique between all defined services and matches in both the application and services configuration. The example above leverages [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships. That is, it uses default endpoints behind-the-scenes, providing a [relationship](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) (the network address a service is accessible from) that is identical to the name of that service. Depending on your needs, instead of default endpoint configuration, you can use [explicit endpoint configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships). With the above definition, the application container (````) now has [access to the service](#use-in-app) via the relationship ```` and its corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. : # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: : service: endpoint: opensearch ``` You can define ```` and ```` as you like, so long as it’s unique between all defined services and relationships and matches in both the application and services configuration. The example above leverages [explicit endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships. Depending on your needs, instead of explicit endpoint configuration, you can use [default endpoint configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships). With the above definition, the application container now has [access to the service](#use-in-app) via the relationship ```` and its corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). ###### Example configuration ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: opensearch: service: opensearch endpoint: opensearch services: # The name of the service container. Must be unique within a project. opensearch: type: opensearch:2 ``` ###### Use in app To use the configured service in your app, add a configuration file similar to the following to your project. ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "myapp" [...] # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: opensearch: service: opensearch endpoint: opensearch services: # The name of the service container. Must be unique within a project. opensearch: type: opensearch:2 ``` This configuration defines a single application (`myapp`), whose source code exists in the `/myapp` directory. `myapp` has access to the `opensearch` service, via a relationship whose name is [identical to the service name](#2-define-the-relationship) (as per [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships). From this, ``myapp`` can retrieve access credentials to the service through the [relationship environment variables](#relationship-reference). ```bash {location="myapp/.environment"} # Set environment variables for individual credentials. # For more information, please visit https://docs.upsun.com/development/variables.html#service-environment-variables. export OS_SCHEME=${OPENSEARCH_SCHEME} export OS_HOST=${OPENSEARCH_HOST} export OS_PORT=${OPENSEARCH_PORT} # Surface more common OpenSearch connection string variables for use in app. export OS_USERNAME=${OPENSEARCH_USERNAME} export OS_PASSWORD=${OPENSEARCH_PASSWORD} export OPENSEARCH_HOSTS=[\"$OS_SCHEME://$OS_HOST:$OS_PORT\"] ``` The above file — ``.environment`` in the ``myapp`` directory — is automatically sourced by Upsun into the runtime environment, so that the variable ``OPENSEARCH_HOSTS`` can be used within the application to connect to the service. Note that ``OPENSEARCH_HOSTS``, and all Upsun [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) like ``OPENSEARCH_HOST``, are environment-dependent. Unlike the build produced for a given commit, they can’t be reused across environments and only allow your app to connect to a single service instance on a single environment. A file very similar to this is generated automatically for your when using the ``upsun ify`` command to [migrate a codebase to Upsun](https://docs.upsun.com/get-started.md). **Note**: When you create an index on OpenSearch, don’t specify the ``number_of_shards`` or ``number_of_replicas`` settings in your OpenSearch API call. These values are set automatically based on available resources. ##### Authentication By default, OpenSearch has no authentication. No username or password is required to connect to it. You may optionally enable HTTP Basic authentication. To do so, include the following in your `.upsun/config.yaml` configuration: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. opensearch: type: opensearch:2 configuration: authentication: enabled: true ``` That enables mandatory HTTP Basic auth on all requests. The credentials are available in any relationships that point at that service, in the `OPENSEARCH_USERNAME` and `OPENSEARCH_PASSWORD` [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). You can obtain the complete list of available service environment variables in your app container by running ``upsun ssh env``. Note that the information about the relationship can change when an app is redeployed or restarted or the relationship is changed. So your apps should only rely on the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) directly rather than hard coding any values. This functionality is generally not required if OpenSearch isn't exposed on its own public HTTP route. However, certain applications may require it, or it allows you to safely expose OpenSearch directly to the web. To do so, add a route to `.upsun/config.yaml` that has `opensearch:opensearch` as its upstream (where `opensearch` is whatever you named the service). For example: ```yaml {location=".upsun/config.yaml"} routes: "https://www.os.{default}/": type: redirect to: "https://os.{default}/" "https://os.{default}/": type: upstream upstream: "opensearch:opensearch" services: # The name of the service container. Must be unique within a project. opensearch: configuration: authentication: enabled: true ``` ##### Plugins OpenSearch offers a number of plugins. To enable them, list them under the `configuration.plugins` key in your `.upsun/config.yaml` file, like so: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. opensearch: configuration: plugins: - analysis-icu ``` In this example you'd have the ICU analysis plugin and the size mapper plugin. If there is a publicly available plugin you need that isn't listed here, [contact support](https://docs.upsun.com/learn/overview/get-support.md). ###### Available plugins This is the complete list of plugins that can be enabled: | Plugin | Description | 1 | 2 | |-------------------------|-------------------------------------------------------------------------------------------|-----|---| | `analysis-icu` | Support ICU Unicode text analysis | * | * | | `analysis-kuromoji` | Japanese language support | * | * | | `analysis-nori` | Integrates Lucene Nori analysis module into OpenSearch | * | * | | `analysis-phonetic` | Phonetic analysis | * | * | | `analysis-smartcn` | Smart Chinese Analysis Plugins | * | * | | `analysis-stempel` | Stempel Polish Analysis Plugin | * | * | | `analysis-ukrainian` | Ukrainian language support | * | * | | `ingest-attachment` | Extract file attachments in common formats (such as PPT, XLS, and PDF) | * | * | | `mapper-annotated-text` | Adds support for text fields with markup used to inject annotation tokens into the index | * | * | | `mapper-murmur3` | Murmur3 mapper plugin for computing hashes at index-time | * | * | | `mapper-size` | Size mapper plugin, enables the `_size` meta field | * | * | | `repository-s3` | Support for using S3 as a repository for Snapshot/Restore | * | * | | `transport-nio` | Support for NIO transport | * | * | ###### Plugin removal Removing plugins previously added in your `.upsun/config.yaml` file doesn't automatically uninstall them from your OpenSearch instances. This is deliberate, as removing a plugin may result in data loss or corruption of existing data that relied on that plugin. Removing a plugin usually requires reindexing. To permanently remove a previously enabled plugin, [upgrade the service](#upgrading) to create a new instance of OpenSearch and migrate to it. In most cases it isn't necessary as an unused plugin has no appreciable impact on the server. ##### Upgrading The OpenSearch data format sometimes changes between versions in incompatible ways. OpenSearch doesn't include a data upgrade mechanism as it's expected that all indexes can be regenerated from stable data if needed. To upgrade (or downgrade) OpenSearch, use a new service from scratch. There are two ways to do so. ###### Destructive In your `.upsun/config.yaml` file, change the version *and* name of your OpenSearch service. Be sure to also update the reference to the now changed service name in it's corresponding application's `relationship` block. When you push that to Upsun, the old service is deleted and a new one with the new name is created with no data. You can then have your application reindex data as appropriate. This approach has the downsides of temporarily having an empty OpenSearch instance, which your application may or may not handle gracefully, and needing to rebuild your index afterward. Depending on the size of your data that could take a while. ###### Transitional With a transitional approach, you temporarily have two OpenSearch services. Add a second OpenSearch service with the new version a new name and give it a new relationship in `.upsun/config.yaml`. You can optionally run in that configuration for a while to allow your application to populate indexes in the new service as well. Once you're ready to switch over, remove the old OpenSearch service and relationship. You may optionally have the new OpenSearch service use the old relationship name if that's easier for your app to handle. Your application is now using the new OpenSearch service. This approach has the benefit of never being without a working OpenSearch instance. On the downside, it requires two running OpenSearch servers temporarily, each of which consumes resources and needs adequate disk space. Depending on the size of your data, that may be a lot of disk space. ### PostgreSQL (Database service) PostgreSQL is a high-performance, standards-compliant relational SQL database. See the [PostgreSQL documentation](https://www.postgresql.org/docs/9.6/index.md) for more information. ##### Supported versions You can select the major version. But the latest compatible minor version is applied automatically and can’t be overridden. Patch versions are applied periodically for bug fixes and the like. When you deploy your app, you always get the latest available patches. - 17 - 16 - 15 - 14 - 13 - 12 **Note**: You can’t upgrade to PostgreSQL 12 with the ``postgis`` extension enabled. For more details, see how to [upgrade to PostgreSQL 12 with ](#upgrade-to-postgresql-12-with-the-postgis-extension). ###### Deprecated versions The following versions are [deprecated](https://docs.upsun.com/glossary.md#deprecated-versions). They're available, but they aren't receiving security updates from upstream and aren't guaranteed to work. They'll be removed in the future, so migrate to one of the [supported versions](#supported-versions). - 11 - 10 - 9.6 - 9.5 - 9.4 - 9.3 ##### Relationship reference For each service [defined via a relationship](#usage-example) to your application, Upsun automatically generates corresponding environment variables within your application container, in the ``$_`` format. Here is example information available through the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) themselves, or through the [``PLATFORM_RELATIONSHIPS`` environment variable](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). For some advanced use cases, you can use the [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). The structure of the ``PLATFORM_RELATIONSHIPS`` environment variable can be obtained by running ``upsun relationships`` in your terminal: ```json {} { "username": "main", "scheme": "pgsql", "service": "postgresql", "fragment": null, "ip": "123.456.78.90", "hostname": "azertyuiopqsdfghjklm.postgresql.service._.eu-1.platformsh.site", "port": 5432, "cluster": "azertyuiopqsdf-main-afdwftq", "host": "postgresql.internal", "rel": "postgresql", "path": "main", "query": { "is_master": true }, "password": "ChangeMe", "type": "postgresql:17", "public": false, "host_mapped": false } ``` Here is an example of how to gather [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables) information in a [.environment](https://docs.upsun.com/development/variables/set-variables.md#use-env-files): ```bash {location=".environment"} # Decode the built-in credentials object variable. export RELATIONSHIPS_JSON=$(echo $PLATFORM_RELATIONSHIPS | base64 --decode) # Set environment variables for individual credentials. export APP_POSTGRESQL_HOST="$(echo $RELATIONSHIPS_JSON | jq -r '.postgresql[0].host')" ``` ##### Usage example ###### 1. Configure the service To define the service, use the ``postgresql`` type: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. : type: postgresql: ``` Note that changing the name of the service replaces it with a brand new service and all existing data is lost. Back up your data before changing the service. ###### 2. Define the relationship To define the relationship, use the following configuration: You can define ```` as you like, so long as it’s unique between all defined services and matches in both the application and services configuration. The example above leverages [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships. That is, it uses default endpoints behind-the-scenes, providing a [relationship](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) (the network address a service is accessible from) that is identical to the name of that service. Depending on your needs, instead of default endpoint configuration, you can use [explicit endpoint configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships). With the above definition, the application container (````) now has access to the service via the relationship ```` and its corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. : # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: : service: endpoint: postgresql ``` You can define ```` and ```` as you like, so long as it’s unique between all defined services and relationships and matches in both the application and services configuration. The example above leverages [explicit endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships. Depending on your needs, instead of explicit endpoint configuration, you can use [default endpoint configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships). With the above definition, the application container now has [access to the service](#use-in-app) via the relationship ```` and its corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). For PHP, enable the [extension](https://docs.upsun.com/languages/php/extensions.md) for the service: ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. : # PHP extensions. runtime: extensions: - pdo_pgsql # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: : service: endpoint: postgresql ``` ###### Example configuration ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # PHP extensions. runtime: extensions: - pdo_pgsql # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: postgresql: service: postgresql endpoint: postgresql services: # The name of the service container. Must be unique within a project. postgresql: type: postgresql:17 ``` ###### Use in app To use the configured service in your app, add a configuration file similar to the following to your project. ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "myapp" # PHP extensions. runtime: extensions: - pdo_pgsql [...] # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: postgresql: service: postgresql endpoint: postgresql services: # The name of the service container. Must be unique within a project. postgresql: type: postgresql:17 ``` This configuration defines a single application (`myapp`), whose source code exists in the `/myapp` directory. `myapp` has access to the `postgresql` service, via a relationship whose name is [identical to the service name](#2-define-the-relationship) (as per [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships). From this, ``myapp`` can retrieve access credentials to the service through the [relationship environment variables](#relationship-reference). ```bash {location="myapp/.environment"} # Set environment variables for individual credentials. # For more information, please visit https://docs.upsun.com/development/variables.html#service-environment-variables. export DB_CONNECTION="${POSTGRESQL_SCHEME}" export DB_USERNAME="${POSTGRESQL_USERNAME}" export DB_PASSWORD="${POSTGRESQL_PASSWORD}" export DB_HOST="${POSTGRESQL_HOST}" export DB_PORT="${POSTGRESQL_PORT}" export DB_DATABASE="${POSTGRESQL_PATH}" # Surface connection string variable for use in app. export DATABASE_URL="${DB_CONNECTION}://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_DATABASE}" ``` The above file — ``.environment`` in the ``myapp`` directory — is automatically sourced by Upsun into the runtime environment, so that the variable ``DATABASE_URL`` can be used within the application to connect to the service. Note that ``DATABASE_URL``, and all Upsun [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) like ``POSTGRESQL_HOST``, are environment-dependent. Unlike the build produced for a given commit, they can’t be reused across environments and only allow your app to connect to a single service instance on a single environment. A file very similar to this is generated automatically for your when using the ``upsun ify`` command to [migrate a codebase to Upsun](https://docs.upsun.com/get-started.md). ##### Access the service directly Access the service using the Upsun CLI by running `upsun sql`. You can also access it from your app container via [SSH](https://docs.upsun.com../development/ssh.md). From your [relationship data](#relationship-reference), you need: `POSTGRESQL_USERNAME`, `POSTGRESQL_HOST`, and `POSTGRESQL_PORT`. Then run the following command: ```bash psql -U -h -p ``` Using the values from the [example](#relationship-reference), that would be: ```bash psql -U main -h postgresql.internal -p 5432 ``` You can obtain the complete list of available service environment variables in your app container by running ``upsun ssh env``. Note that the information about the relationship can change when an app is redeployed or restarted or the relationship is changed. So your apps should only rely on the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) directly rather than hard coding any values. ##### Exporting data The easiest way to download all data in a PostgreSQL instance is with the Upsun CLI. If you have a single SQL database, the following command exports all data using the `pg_dump` command to a local file: ```bash upsun db:dump ``` If you have multiple SQL databases it prompts you which one to export. You can also specify one by relationship name explicitly: ```bash upsun db:dump --relationship postgresql ``` By default the file is uncompressed. If you want to compress it, use the `--gzip` (`-z`) option: ```bash upsun db:dump --gzip ``` You can use the `--stdout` option to pipe the result to another command. For example, if you want to create a bzip2-compressed file, you can run: ```bash upsun db:dump --stdout | bzip2 > dump.sql.bz2 ``` It is also possible to generate the dump locally if you have the `pg_dump` command installed with `upsun tunnel:single`. The command will first ask for the service and then will provide a prompt for the URI string that you can use. For example: ```bash pg_dump -d postgresql://REPLACE_URI_FROM_OUTPUT -f dump.sql ``` ##### Importing data Make sure that the imported file contains objects with cleared ownership and `IF EXISTS` clauses. For example, you can create a DB dump with following parameters: ```bash pg_dump --no-owner --clean --if-exists ``` The easiest way to load data into a database is to pipe an SQL dump through the `upsun sql` command, like so: ```bash upsun sql **Note**: Importing a database backup is a destructive operation. It overwrites data already in your database. Taking a backup or a database export before doing so is strongly recommended. ##### Sanitizing data To ensure people who review code changes can't access personally identifiable information stored in your database, [sanitize your preview environments](https://docs.upsun.com../development/sanitize-db/postgresql.md). ##### Set locale for database You can choose your locale when a database is created by setting locale-related variables. There are three ways to set a locale option, as detailed in the table below: | Name | Type | Default | Description | |--------|-----------|----------|--------------| | `default_ctype` | `string` | `C.UTF-8` | The default character classification. Affects any tables created after it's set.| | `default_collation` | `string`|`C.UTF-8`| The default collation rules. Affects any tables created after it's set.| | `default_charset` | `string` | `UTF8` | The default encoding character set. Affects any tables created after it's set.| ##### Multiple databases If you are using version `10`, `11`, `12`, `13`, or later of this service, it's possible to define multiple databases as well as multiple users with different permissions. To do so requires defining multiple endpoints. Under the `configuration` key of your service there are two additional keys: * `databases`: This is a YAML array listing the databases that should be created. If not specified, a single database named `main` is created. Note that removing a schema from the list of `schemas` on further deployments results in **the deletion of the schema.** * `endpoints`: This is a nested YAML object defining different credentials. Each endpoint may have access to one or more schemas (databases), and may have different levels of permission for each. The valid permission levels are: * `ro`: Using this endpoint only `SELECT` queries are allowed. * `rw`: Using this endpoint `SELECT` queries as well as `INSERT`/`UPDATE`/`DELETE` queries are allowed. * `admin`: Using this endpoint all queries are allowed, including DDL queries (`CREATE TABLE`, `DROP TABLE`, etc.). Consider the following illustrative example: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. postgresql: type: "postgresql:17" configuration: databases: - main - legacy endpoints: admin: privileges: main: admin legacy: admin reporter: default_database: main privileges: main: ro importer: default_database: legacy privileges: legacy: rw ``` This example creates a single PostgreSQL service named `postgresql`. The server has two databases, `main` and `legacy` with three endpoints created. * `admin`: has full access to both databases. * `reporter`: has `SELECT` query access to the `main` database, but no access to `legacy`. * `importer`: has `SELECT`/`INSERT`/`UPDATE`/`DELETE` access (but not DDL access) to the `legacy` database. It doesn't have access to `main`. If a given endpoint has access to multiple databases you should also specify which is listed by default in the relationships array. If one isn't specified, the `path` property of the relationship is `null`. While that may be acceptable for an application that knows the name of the database it's connecting to, automated tools like the Upsun CLI can't access the database on that relationship. For that reason, defining the `default_database` property is always recommended. Once these endpoints are defined, you need to expose them to your application as a relationship. Continuing with the above example, your `relationships` in `.upsun/config.yaml` might look like: ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: source: root: "/" [...] # Relationships enable access from this app to a given service. # The example below shows configuration with explicitly set service names and endpoints. # See the Application reference for all options for defining relationships and endpoints. relationships: database: service: postgresql endpoint: admin reports: service: postgresql endpoint: reporter imports: service: postgresql endpoint: importer services: # The name of the service container. Must be unique within a project. postgresql: type: "postgresql:17" configuration: databases: - main - legacy endpoints: admin: privileges: main: admin legacy: admin reporter: default_database: main privileges: main: ro importer: default_database: legacy privileges: legacy: rw ``` Each database is accessible to your application through the `database`, `reports`, and `imports` relationships. They'll be available in the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) and all have the same structure documented [above](#relationship-reference), but with different credentials. You can use those to connect to the appropriate database with the specified restrictions using whatever the SQL access tools are for your language and application. A service configuration without the `configuration` block defined is equivalent to the following default values: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. postgresql: type: "postgresql:17" configuration: databases: - main endpoints: postgresql: default_database: main privileges: main: admin ``` If you do not define `database` but `endpoints` are defined, then the single database `main` is created with the following assumed configuration: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. postgresql: type: "postgresql:17" configuration: databases: - main endpoints: ``` Alternatively, if you define multiple databases but no endpoints, a single user `main` is created with `admin` access to each of your databases, equivalent to the configuration below: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. postgresql: type: "postgresql:17" configuration: databases: - firstdb - seconddb - thirddb endpoints: main: firstdb: admin seconddb: admin thirddb: admin ``` ##### Password generation When you connect your app to a database, an empty password is generated for the database by default. This can cause issues with your app. To generate real passwords for your database, define custom endpoints in your [service configuration](#1-configure-the-service). For each custom endpoint you create, you get an automatically generated password, similarly to when you create [multiple databases](#multiple-databases). Note that you can't customize these automatically generated passwords. After your custom endpoints are exposed as relationships in your [app configuration](https://docs.upsun.com../../create-apps.md), you can retrieve the password for each endpoint through the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) within your [application containers](https://docs.upsun.com/development/variables/use-variables.md#access-variables-in-your-app). The password value changes automatically over time, to avoid downtime its value has to be read dynamically by your app. Globally speaking, having passwords hard-coded into your codebase can cause security issues and should be avoided. When you switch from the default configuration with an empty password to custom endpoints, make sure your service name remains unchanged. Failure to do so results in the creation of a new service, which removes any existing data from your database. ##### Service timezone To change the timezone for the current session, run `SET TIME ZONE ;`. ##### Extensions Upsun supports a number of PostgreSQL extensions. To enable them, list them under the `configuration.extensions` key in your `.upsun/config.yaml` file, like so: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. postgresql: type: "postgresql:17" configuration: extensions: - pg_trgm - hstore ``` In this case, you have `pg_trgm` installed, providing functions to determine the similarity of text based on trigram matching, and `hstore` providing a key-value store. ###### Available extensions The following is the extensive list of supported extensions. Note that you can't currently add custom extensions not listed here. * `address_standardizer` - Used to parse an address into constituent elements. Generally used to support geocoding address normalization step. * `address_standardizer_data_us` - For standardizing addresses based on US dataset example * `adminpack` - administrative functions for PostgreSQL * `autoinc` - functions for auto-incrementing fields * `bloom` - bloom access method - signature file based index (requires 9.6 or higher) * `btree_gin` - support for indexing common data types in GIN * `btree_gist` - support for indexing common data types in GiST * `chkpass` - data type for auto-encrypted passwords * `citext` - data type for case-insensitive character strings * `cube` - data type for multidimensional cubes * `dblink` - connect to other PostgreSQL databases from within a database * `dict_int` - text search dictionary template for integers * `dict_xsyn` - text search dictionary template for extended synonym processing * `earthdistance` - calculate great-circle distances on the surface of the Earth * `file_fdw` - foreign-data wrapper for flat file access * `fuzzystrmatch` - determine similarities and distance between strings * `hstore` - data type for storing sets of (key, value) pairs * `insert_username` - functions for tracking who changed a table * `intagg` - integer aggregator and enumerator (obsolete) * `intarray` - functions, operators, and index support for 1-D arrays of integers * `isn` - data types for international product numbering standards * `lo` - Large Object maintenance * `ltree` - data type for hierarchical tree-like structures * `moddatetime` - functions for tracking last modification time * `pageinspect` - inspect the contents of database pages at a low level * `pg_buffercache` - examine the shared buffer cache * `pg_freespacemap` - examine the free space map (FSM) * `pg_prewarm` - prewarm relation data (requires 9.6 or higher) * `pg_stat_statements` - track execution statistics of all SQL statements executed * `pg_trgm` - text similarity measurement and index searching based on trigrams * `pg_visibility` - examine the visibility map (VM) and page-level visibility info (requires 9.6 or higher) * `pgcrypto` - cryptographic functions * `pgrouting` - pgRouting Extension (requires 9.6 or higher) * `pgrowlocks` - show row-level locking information * `pgstattuple` - show tuple-level statistics * `plpgsql` - PL/pgSQL procedural language * `postgis` - PostGIS geometry, geography, and raster spatial types and functions * `postgis_sfcgal` - PostGIS SFCGAL functions * `postgis_tiger_geocoder` - PostGIS tiger geocoder and reverse geocoder * `postgis_topology` - PostGIS topology spatial types and functions * `postgres_fdw` - foreign-data wrapper for remote PostgreSQL servers * `refint` - functions for implementing referential integrity (obsolete) * `seg` - data type for representing line segments or floating-point intervals * `sslinfo` - information about SSL certificates * `tablefunc` - functions that manipulate whole tables, including `crosstab` * `tcn` - Triggered change notifications * `timetravel` - functions for implementing time travel * `tsearch2` - compatibility package for pre-8.3 text search functions (obsolete, only available for 9.6 and 9.3) * `tsm_system_rows` - TABLESAMPLE method which accepts number of rows as a limit (requires 9.6 or higher) * `tsm_system_time` - TABLESAMPLE method which accepts time in milliseconds as a limit (requires 9.6 or higher) * `unaccent` - text search dictionary that removes accents * `uuid-ossp` - generate universally unique identifiers (UUIDs) * `vector` - Open-source [vector](https://github.com/pgvector/pgvector) similarity search for PostgreSQL 11+ * `xml2` - XPath querying and XSLT **Note**: You can’t upgrade to PostgreSQL 12 with the ``postgis`` extension enabled. For more details, see how to [upgrade to PostgreSQL 12 with ](#upgrade-to-postgresql-12-with-the-postgis-extension). ##### Notes ###### Could not find driver If you see this error: `Fatal error: Uncaught exception 'PDOException' with message 'could not find driver'`, this means you are missing the `pdo_pgsql` PHP extension. You need to enable it in your `.upsun/config.yaml` ([see above](#1-configure-the-service)). ##### Upgrading PostgreSQL 10 and later include an upgrade utility that can convert databases from previous versions to version 10 or later. If you upgrade your service from a previous version of PostgreSQL to version 10 or above, it upgrades automatically. The utility can't upgrade PostgreSQL 9 versions, so upgrades from PostgreSQL 9.3 to 9.6 aren't supported. Upgrade straight to version 11 instead. **Note**: Make sure you first test your migration on a separate branch. Also, be sure to take a backup of your production environment **before** you merge this change. **Warning**: Downgrading isn’t supported. If you need to downgrade, dump to SQL, remove the service, recreate the service, and import your dump. ###### Upgrade to PostgreSQL 12 with the `postgis` extension You can't upgrade to PostgreSQL 12 with the `postgis` extension enabled. It involves a change to a major version that results in a failed deployment that requires support intervention to fix. Upgrading from 12 to a higher version is possible. If you need to upgrade to version 12, follow the same steps recommended for downgrading: 1. Dump the database. 2. Remove the service. 3. Create a new service with PostgreSQL 12. 4. Import the dump to that service. ### RabbitMQ (message queue service) [RabbitMQ](https://www.rabbitmq.com/documentation.md) is a message broker that supports multiple messaging protocols, such as the Advanced Message Queuing Protocol (AMQP). It gives your apps a common platform to send and receive messages and your messages a safe place to live until they're received. ##### Supported versions You can select the major and minor version. Patch versions are applied periodically for bug fixes and the like. When you deploy your app, you always get the latest available patches. - 4.0 - 3.13 - 3.12 ###### Deprecated versions The following versions are [deprecated](https://docs.upsun.com/glossary.md#deprecated-versions). They're available, but they aren't receiving security updates from upstream and aren't guaranteed to work. They'll be removed in the future, so migrate to one of the [supported versions](#supported-versions). - 3.11 - 3.10 - 3.9 - 3.8 - 3.7 - 3.6 - 3.5 ##### Relationship reference For each service [defined via a relationship](#usage-example) to your application, Upsun automatically generates corresponding environment variables within your application container, in the ``$_`` format. Here is example information available through the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) themselves, or through the [``PLATFORM_RELATIONSHIPS`` environment variable](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). For some advanced use cases, you can use the [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). The structure of the ``PLATFORM_RELATIONSHIPS`` environment variable can be obtained by running ``upsun relationships`` in your terminal: ```json {} { "username": "guest", "scheme": "amqp", "service": "rabbitmq", "fragment": null, "ip": "123.456.78.90", "hostname": "azertyuiopqsdfghjklm.rabbitmq.service._.eu-1.platformsh.site", "port": 5672, "cluster": "azertyuiopqsdf-main-afdwftq", "host": "rabbitmq.internal", "rel": "rabbitmq", "path": null, "query": [], "password": "ChangeMe", "type": "rabbitmq:4.0", "public": false, "host_mapped": false } ``` Here is an example of how to gather [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables) information in a [.environment](https://docs.upsun.com/development/variables/set-variables.md#use-env-files): ```bash {location=".environment"} # Decode the built-in credentials object variable. export RELATIONSHIPS_JSON=$(echo $PLATFORM_RELATIONSHIPS | base64 --decode) # Set environment variables for individual credentials. export APP_RABBITMQ_HOST="$(echo $RELATIONSHIPS_JSON | jq -r '.rabbitmq[0].host')" ``` ##### Usage example ###### 1. Configure the service To define the service, use the ``rabbitmq`` type: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. : type: rabbitmq: ``` Note that changing the name of the service replaces it with a brand new service and all existing data is lost. Back up your data before changing the service. ###### 2. Define the relationship To define the relationship, use the following configuration: You can define ```` as you like, so long as it’s unique between all defined services and matches in both the application and services configuration. The example above leverages [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships. That is, it uses default endpoints behind-the-scenes, providing a [relationship](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) (the network address a service is accessible from) that is identical to the name of that service. Depending on your needs, instead of default endpoint configuration, you can use [explicit endpoint configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships). With the above definition, the application container (````) now has access to the service via the relationship ```` and its corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. : # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: : service: endpoint: rabbitmq ``` You can define ```` and ```` as you like, so long as it’s unique between all defined services and relationships and matches in both the application and services configuration. The example above leverages [explicit endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships. Depending on your needs, instead of explicit endpoint configuration, you can use [default endpoint configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships). With the above definition, the application container now has [access to the service](#use-in-app) via the relationship ```` and its corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). ###### Example configuration ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: rabbitmq: service: rabbitmq endpoint: rabbitmq services: # The name of the service container. Must be unique within a project. rabbitmq: type: rabbitmq:4.0 ``` ###### Use in app To use the configured service in your app, add a configuration file similar to the following to your project. ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "myapp" [...] # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: rabbitmq: service: rabbitmq endpoint: rabbitmq services: # The name of the service container. Must be unique within a project. rabbitmq: type: rabbitmq:4.0 ``` This configuration defines a single application (`myapp`), whose source code exists in the `/myapp` directory. `myapp` has access to the `rabbitmq` service, via a relationship whose name is [identical to the service name](#2-define-the-relationship) (as per [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships). From this, ``myapp`` can retrieve access credentials to the service through the [relationship environment variables](#relationship-reference). ```bash {location="myapp/.environment"} # Set environment variables for individual credentials. # For more information, please visit https://docs.upsun.com/development/variables.html#service-environment-variables. export QUEUE_SCHEME=${RABBITMQ_SCHEME} export QUEUE_USERNAME=${RABBITMQ_USERNAME} export QUEUE_PASSWORD=${RABBITMQ_PASSWORD} export QUEUE_HOST=${RABBITMQ_HOST} export QUEUE_PORT=${RABBITMQ_PORT} # Set a single RabbitMQ connection string variable for AMQP. export AMQP_URL="${QUEUE_SCHEME}://${QUEUE_USERNAME}:${QUEUE_PASSWORD}@${QUEUE_HOST}:${QUEUE_PORT}/" ``` The above file — ``.environment`` in the ``myapp`` directory — is automatically sourced by Upsun into the runtime environment, so that the variable ``AMQP_URL`` can be used within the application to connect to the service. Note that ``AMQP_URL``, and all Upsun [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) like ``RABBITMQ_HOST``, are environment-dependent. Unlike the build produced for a given commit, they can’t be reused across environments and only allow your app to connect to a single service instance on a single environment. A file very similar to this is generated automatically for your when using the ``upsun ify`` command to [migrate a codebase to Upsun](https://docs.upsun.com/get-started.md). ##### Connect to RabbitMQ When debugging, you may want to connect directly to your RabbitMQ service. You can connect in multiple ways: - An [SSH tunnel](#via-ssh) - A [web interface](#access-the-management-ui) In each case, you need the login credentials that you can obtain from the [relationship](#relationship-reference). ###### Via SSH To connect directly to your RabbitMQ service in an environment, open an SSH tunnel with the [Upsun CLI](https://docs.upsun.com../administration/cli.md). To open an SSH tunnel to your service with port forwarding, run the following command: ```bash upsun tunnel:single --gateway-ports ``` Then configure a RabbitMQ client to connect to this tunnel using the credentials from the [relationship](#relationship-reference). See a [list of RabbitMQ client libraries](https://www.rabbitmq.com/devtools.md). ###### Access the management UI RabbitMQ offers a [management plugin with a browser-based UI](https://www.rabbitmq.com/management.md). You can access this UI with an SSH tunnel. To open a tunnel, follow these steps. 1. SSH into your app container with a flag for local port forwarding: 2. ```bash ssh $(upsun ssh --pipe) -L 15672:.internal:15672 ``` is the [name you defined](#2-define-the-relationship). 2. Open `http://localhost:15672` in your browser. Log in using the username and password from the [relationship](#relationship-reference). ##### Configuration options You can configure your RabbitMQ service in the [services configuration](#1-configure-the-service) with the following options: | Name | Type | Required | Description | |----------|-------------------|----------|------------------------------------------------------| | `vhosts` | List of `string`s | No | Virtual hosts used for logically grouping resources. | You can configure additional [virtual hosts](https://www.rabbitmq.com/vhosts.md), which can be useful for separating resources, such as exchanges, queues, and bindings, into their own namespaces. To create virtual hosts, add them to your configuration as in the following example: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. rabbitmq: type: "rabbitmq:4.0" configuration: vhosts: - host1 - host2 ``` ##### Upgrading When upgrading RabbitMQ, skipping major versions (e.g. 3.7 -> 3.11) [is not supported](https://www.rabbitmq.com/upgrade.md#rabbitmq-version-upgradability). Make sure you upgrade sequentially (3.7 -> 3.8 -> 3.9 -> 3.10 -> 3.11) and that each upgrade commit translates into an actual deployment. ### Redis (Object cache) [Redis](https://redis.io/documentation) is a multi-model database that allows you to store data in memory for high-performance data retrieval and key-value storage. Upsun supports two different Redis configurations: - [Persistent](#persistent-redis): to set up fast persistent storage for your application - [Ephemeral](#ephemeral-redis): to set up a non-persistent cache for your application ##### Supported versions You can select the major and minor version. Patch versions are applied periodically for bug fixes and the like. When you deploy your app, you always get the latest available patches. - 7.2 - 7.0 - 6.2 ###### Deprecated versions The following versions are [deprecated](https://docs.upsun.com/glossary.md#deprecated-versions). They're available, but they aren't receiving security updates from upstream and aren't guaranteed to work. They'll be removed in the future, so migrate to one of the [supported versions](#supported-versions). - 6.0 - 5.0 - 4.0 - 3.2 - 3.0 - 2.8 Note that versions 3.0 and higher support up to 64 different databases per instance of the service, while Redis 2.8 only supports a single database. ##### Service types Depending on your needs, you can set up Redis as [persistent](#persistent-redis) or [ephemeral](#ephemeral-redis). ##### Relationship reference For each service [defined via a relationship](#usage-example) to your application, Upsun automatically generates corresponding environment variables within your application container, in the ``$_`` format. Here is example information available through the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) themselves, or through the [``PLATFORM_RELATIONSHIPS`` environment variable](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). For some advanced use cases, you can use the [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). The structure of the ``PLATFORM_RELATIONSHIPS`` environment variable can be obtained by running ``upsun relationships`` in your terminal: ```json {} { "username": null, "scheme": "redis", "service": "redis", "fragment": null, "ip": "123.456.78.90", "hostname": "azertyuiopqsdfghjklm.redis.service._.eu-1.platformsh.site", "port": 6379, "cluster": "azertyuiopqsdf-main-7rqtwti", "host": "redis.internal", "rel": "redis", "path": null, "query": [], "password": null, "type": "redis:7.2", "public": false, "host_mapped": false } ``` Here is an example of how to gather [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables) information in a [.environment](https://docs.upsun.com/development/variables/set-variables.md#use-env-files): ```bash {location=".environment"} # Decode the built-in credentials object variable. export RELATIONSHIPS_JSON=$(echo $PLATFORM_RELATIONSHIPS | base64 --decode) # Set environment variables for individual credentials. export APP_REDIS_HOST="$(echo $RELATIONSHIPS_JSON | jq -r '.redis[0].host')" ``` The format of the relationship is identical whether your Redis service is [ephemeral](#ephemeral-redis) or [persistent](#persistent-redis). ##### Persistent Redis By default, Redis is an ephemeral service that stores data in memory. This allows for fast data retrieval, but also means data can be lost when a container is moved or shut down. To solve this issue, configure your Redis service as persistent. Persistent Redis stores data on a disk, restoring it if the container restarts. To switch from persistent to ephemeral Redis, set up a new service with a different name. **Warning**: Upsun sets the maximum amount of memory (``maxmemory``) Redis can use for the data set, and it cannot be amended. It is defined by comparing the following values and keeping the lower of the two: - Disk size/6 (based on a [recommendation from Redis](https://docs.redis.com/latest/rs/installing-upgrading/install/plan-deployment/hardware-requirements/#productionenvironment)) - The amount of memory allocated to the service container For instance, if your Redis container has 3072 MB of disk space and 1024 MB of memory, only 512 MB of RAM are actually available to the service (3072/6 = 512). But if your Redis container has 3072 MB of disk space and 256 MB of memory, only 256 MB of RAM are actually available to the service (as per the container limit). ###### Usage example ####### 1. Configure the service To define the service, use the `redis-persistent` endpoint: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. : type: redis-persistent: ``` Note that changing the name of the service replaces it with a brand new service and all existing data is lost. Back up your data before changing the service. ####### 2. Define the relationship To define the relationship, use the `redis` endpoint : You can define ```` as you like, so long as it’s unique between all defined services and matches in both the application and services configuration. The example above leverages [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships. That is, it uses default endpoints behind-the-scenes, providing a [relationship](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) (the network address a service is accessible from) that is identical to the name of that service. Depending on your needs, instead of default endpoint configuration, you can use [explicit endpoint configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships). With the above definition, the application container now has [access to the service](#use-in-app) via the relationship ```` and its corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. : # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: : service: endpoint: redis ``` You can define ```` and ```` as you like, so long as it’s unique between all defined services and relationships and matches in both the application and services configuration. The example above leverages [explicit endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships. Depending on your needs, instead of explicit endpoint configuration, you can use [default endpoint configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships). With the above definition, the application container now has [access to the service](#use-in-app) via the relationship ```` and its corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). For PHP, enable the [extension](https://docs.upsun.com/languages/php/extensions.md) for the service: ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. : # PHP extensions. runtime: extensions: - redis # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: : service: endpoint: redis ``` ###### Configuration example ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. : source: root: "myapp" [...] # PHP extensions. runtime: extensions: - redis # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: redis: service: redis endpoint: redis services: # The name of the service container. Must be unique within a project. redis: type: redis-persistent:7.2 ``` ###### Use in app To use the configured service in your app, add a configuration file similar to the following to your project. ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. : source: root: "myapp" # PHP extensions. runtime: extensions: - redis [...] # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: redis: service: redis endpoint: redis services: # The name of the service container. Must be unique within a project. redis: type: redis-persistent:7.2 ``` This configuration defines a single application (`myapp`), whose source code exists in the `/myapp` directory. `myapp` has access to the `redis` service, via a relationship whose name is [identical to the service name](#2-define-the-relationship) (as per [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships). From this, ``myapp`` can retrieve access credentials to the service through the [relationship environment variables](#relationship-reference). ```bash {location="myapp/.environment"} # Set environment variables for individual credentials. # For more information, please visit https://docs.upsun.com/development/variables.html#service-environment-variables. export CACHE_HOST="${REDIS_HOST}" export CACHE_PORT="${REDIS_PORT}" export CACHE_PASSWORD="${REDIS_PASSWORD}" export CACHE_SCHEME="${REDIS_SCHEME}" # Surface a Redis connection string for use in app. export CACHE_URL="${CACHE_SCHEME}://${CACHE_PASSWORD}@${CACHE_HOST}:${CACHE_PORT}" ``` The above file — ``.environment`` in the ``myapp`` directory — is automatically sourced by Upsun into the runtime environment, so that the variable ``CACHE_URL`` can be used within the application to connect to the service. Note that ``CACHE_URL``, and all Upsun [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) like ``REDIS_HOST``, are environment-dependent. Unlike the build produced for a given commit, they can’t be reused across environments and only allow your app to connect to a single service instance on a single environment. A file very similar to this is generated automatically for your when using the ``upsun ify`` command to [migrate a codebase to Upsun](https://docs.upsun.com/get-started.md). ##### Ephemeral Redis By default, Redis is an ephemeral service that serves as a non-persistent cache. Ephemeral Redis stores data only in memory and requires no disk space. When the service reaches its memory limit, it triggers a cache cleanup. To customize those cache cleanups, set up an [eviction policy](#eviction-policy). Make sure your app doesn't rely on ephemeral Redis for persistent storage as it can cause issues. For example, if a container is moved during region maintenance, the `deploy` and `post_deploy` hooks don't run and an app that treats the cache as permanent shows errors. To prevent data from getting lost when a container is moved or shut down, you can use the [persistent Redis](#persistent-redis) configuration. Persistent Redis provides a cache with persistent storage. ###### Usage example ####### 1. Configure the service To define the service, use the `redis` endpoint: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. : type: redis: ``` Note that changing the name of the service replaces it with a brand new service and all existing data is lost. Back up your data before changing the service. ####### 2. Define the relationship To define the relationship, use the `redis` endpoint : You can define ```` as you like, so long as it’s unique between all defined services and matches in both the application and services configuration. The example above leverages [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships. That is, it uses default endpoints behind-the-scenes, providing a [relationship](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) (the network address a service is accessible from) that is identical to the name of that service. Depending on your needs, instead of default endpoint configuration, you can use [explicit endpoint configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships). With the above definition, the application container now has [access to the service](#use-in-app) via the relationship ```` and its corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. : # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: : service: endpoint: redis ``` You can define ```` and ```` as you like, so long as it’s unique between all defined services and relationships and matches in both the application and services configuration. The example above leverages [explicit endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships. Depending on your needs, instead of explicit endpoint configuration, you can use [default endpoint configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships). With the above definition, the application container now has [access to the service](#use-in-app) via the relationship ```` and its corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). For PHP, enable the [extension](https://docs.upsun.com/languages/php/extensions.md) for the service: ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. : source: root: "myapp" [...] # PHP extensions. runtime: extensions: - redis # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: : service: endpoint: redis services: # The name of the service container. Must be unique within a project. : type: redis: ``` ###### Configuration example ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: source: root: "myapp" [...] # PHP extensions. runtime: extensions: - redis # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: redis: service: redis endpoint: redis services: # The name of the service container. Must be unique within a project. redis: type: redis:7.2 ``` ###### Use in app To use the configured service in your app, add a configuration file similar to the following to your project. ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: source: root: "myapp" [...] # PHP extensions. runtime: extensions: - redis # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: redis: service: redis endpoint: redis services: # The name of the service container. Must be unique within a project. redis: type: redis:7.2 ``` This configuration defines a single application (`myapp`), whose source code exists in the `/myapp` directory. `myapp` has access to the `redis` service, via a relationship whose name is [identical to the service name](#2-define-the-relationship) (as per [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships). From this, ``myapp`` can retrieve access credentials to the service through the [relationship environment variables](#relationship-reference). ```bash {location="myapp/.environment"} # Set environment variables for individual credentials. # For more information, please visit https://docs.upsun.com/development/variables.html#service-environment-variables. export CACHE_HOST="${REDIS_HOST}" export CACHE_PORT="${REDIS_PORT}" export CACHE_PASSWORD="${REDIS_PASSWORD}" export CACHE_SCHEME="${REDIS_SCHEME}" # Surface a Redis connection string for use in app. export CACHE_URL="${CACHE_SCHEME}://${CACHE_PASSWORD}@${CACHE_HOST}:${CACHE_PORT}" ``` The above file — ``.environment`` in the ``myapp`` directory — is automatically sourced by Upsun into the runtime environment, so that the variable ``CACHE_URL`` can be used within the application to connect to the service. Note that ``CACHE_URL``, and all Upsun [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) like ``REDIS_HOST``, are environment-dependent. Unlike the build produced for a given commit, they can’t be reused across environments and only allow your app to connect to a single service instance on a single environment. A file very similar to this is generated automatically for your when using the ``upsun ify`` command to [migrate a codebase to Upsun](https://docs.upsun.com/get-started.md). ##### Multiple databases Redis 3.0 and above support up to 64 databases. But you can't set up different access rights to each database. When you set up a relationship connection, access to all of the databases is automatically granted. The way to access a particular database depends on the [client library](https://redis.io/clients) you're using: To manage [thread safety](https://github.com/redis/redis-py/blob/master/docs/advanced_features.rst#user-content-a-note-about-threading), the Python library suggests using separate client instances for each database: ```python {} import os from redis import Redis database0 = Redis(host=os.getenv('REDIS_HOST'), port=os.getenv('REDIS_PORT'), db=0) database1 = Redis(host=os.getenv('REDIS_HOST'), port=os.getenv('REDIS_PORT'), db=1) ``` Use the Redis [select](https://redis.io/commands/select): ```javascript {} const redis = require('redis'); const client = redis.createClient(process.env.REDIS_PORT, process.env.REDIS_HOST); await client.SELECT(0); // switch to DB 0 await client.set('x', '42'); // write 42 to x await client.MOVE('x', 1); // move to DB 1 await client.SELECT(1); // switch to DB 1 const value = await client.get('x'); // returns 42 ``` ##### Eviction policy When Redis reaches its memory limit, it triggers a cache cleanup. To customize those cache cleanups, set up an eviction policy such as the following: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. redis: type: "redis:7.2" configuration: maxmemory_policy: allkeys-lfu ``` The following table presents the possible values: | Value | Policy description | |-------------------|-------------------------------------------------------------------------------------------------------------| | `allkeys-lru` | Removes the oldest cache items first. This is the default policy when `maxmemory_policy` isn't set. | | `noeviction` | New items aren’t saved when the memory limit is reached. | | `allkeys-lfu` | Removes least frequently used cache items first. | | `volatile-lru` | Removes least recently used cache items with the `expire` field set to `true`. | | `volatile-lfu` | Removes least frequently used cache items with the `expire` field set to `true`. | | `allkeys-random` | Randomly removes cache items to make room for new data. | | `volatile-random` | Randomly removes cache items with the `expire` field set to `true`. | | `volatile-ttl` | Removes cache items with the `expire` field set to `true` and the shortest remaining `time-to -live` value. | For more information on the different policies, see the official [Redis documentation](https://redis.io/docs/reference/eviction/). ##### Access your Redis service After you've [configured your Redis service](#usage-example), you can access it using either the Upsun CLI or through the [Redis CLI](https://redis.io/docs/ui/cli/). ###### Upsun CLI Unlike the Redis CLI, connecting via the Upsun CLI does not require additional authentication steps if you are already authenticated in your terminal. Access your Redis service by running the command: ```bash upsun redis ``` ###### Redis CLI Retrieve the hostname and port you can connect to through the `PLATFORM_RELATIONSHIPS` [environment variable](https://docs.upsun.com../../development/variables/use-variables.md#use-provided-variables). To do so, run the `upsun relationships` command. After you've retrieved the hostname and port, [open an SSH session](https://docs.upsun.com../development/ssh.md). To access your Redis service, run the following command: ```bash redis-cli -h -p ``` If you have a Grid project, note that the `CONFIG GET` and `CONFIG SET` admin commands are restricted. To get the current configuration, run the following command: ```bash redis-cli -h -p info ``` ##### Use Redis as a handler for PHP sessions A PHP session allows you to store different data for each user through a unique session ID. By default, PHP handles sessions using files. But you can use Redis as a session handler, which means Redis stores and retrieves the data saved into sessions. To set up Redis as your session handler, add a configuration similar to the following: ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: source: root: "myapp" type: "php:8.4" # PHP extensions. runtime: extensions: - redis # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: redissession: service: redissession endpoint: redis variables: php: session.save_handler: redis session.save_path: "tcp://:" web: locations: '/': root: 'web' passthru: '/index.php' services: # The name of the service container. Must be unique within a project. redissession: type: "redis-persistent:7.2" ``` ### Solr (Search service) Apache Solr is a scalable and fault-tolerant search index. Solr search with generic schemas provided, and a custom schema is also supported. See the [Solr documentation](https://lucene.apache.org/solr/6_3_0/index.md) for more information. ##### Supported versions You can select the major and minor version. Patch versions are applied periodically for bug fixes and the like. When you deploy your app, you always get the latest available patches. - 9.6 - 9.4 - 9.2 - 9.1 - 8.11 ###### Deprecated versions The following versions are [deprecated](https://docs.upsun.com/glossary.md#deprecated-versions). They're available, but they aren't receiving security updates from upstream and aren't guaranteed to work. They'll be removed in the future, so migrate to one of the [supported versions](#supported-versions). - 8.6 - 8.4 - 8.0 - 7.7 - 7.6 - 6.6 - 6.3 - 4.10 - 3.6 ##### Relationship reference For each service [defined via a relationship](#usage-example) to your application, Upsun automatically generates corresponding environment variables within your application container, in the ``$_`` format. Here is example information available through the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) themselves, or through the [``PLATFORM_RELATIONSHIPS`` environment variable](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). For some advanced use cases, you can use the [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables.md#service-environment-variables). The structure of the ``PLATFORM_RELATIONSHIPS`` environment variable can be obtained by running ``upsun relationships`` in your terminal: ```json {} { "username": null, "scheme": "solr", "service": "solr", "fragment": null, "ip": "123.456.78.90", "hostname": "azertyuiopqsdfghjklm.solr.service._.eu-1.platformsh.site", "port": 8080, "cluster": "azertyuiopqsdf-main-afdwftq", "host": "solr.internal", "rel": "solr", "path": "solr\/collection1", "query": [], "password": null, "type": "solr:9.6", "public": false, "host_mapped": false } ``` Here is an example of how to gather [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables) information in a [.environment](https://docs.upsun.com/development/variables/set-variables.md#use-env-files): ```bash {location=".environment"} # Decode the built-in credentials object variable. export RELATIONSHIPS_JSON=$(echo $PLATFORM_RELATIONSHIPS | base64 --decode) # Set environment variables for individual credentials. export APP_SOLR_HOST="$(echo $RELATIONSHIPS_JSON | jq -r '.solr[0].host')" ``` ##### Usage example ###### 1. Configure the service To define the service, use the ``solr`` type: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. : type: solr: ``` Note that changing the name of the service replaces it with a brand new service and all existing data is lost. Back up your data before changing the service. ###### 2. Define the relationship To define the relationship, use the following configuration: You can define ```` as you like, so long as it’s unique between all defined services and matches in both the application and services configuration. The example above leverages [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships. That is, it uses default endpoints behind-the-scenes, providing a [relationship](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) (the network address a service is accessible from) that is identical to the name of that service. Depending on your needs, instead of default endpoint configuration, you can use [explicit endpoint configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships). With the above definition, the application container (````) now has access to the service via the relationship ```` and its corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. : # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: : service: endpoint: solr ``` You can define ```` and ```` as you like, so long as it’s unique between all defined services and relationships and matches in both the application and services configuration. The example above leverages [explicit endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships. Depending on your needs, instead of explicit endpoint configuration, you can use [default endpoint configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships). With the above definition, the application container now has [access to the service](#use-in-app) via the relationship ```` and its corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). ###### Example configuration ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: solr: service: solr endpoint: solr services: # The name of the service container. Must be unique within a project. solr: type: solr:9.6 ``` ###### Use in app To use the configured service in your app, add a configuration file similar to the following to your project. ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "myapp" [...] # Relationships enable access from this app to a given service. # The example below shows configuration with an explicitly set service name and endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: solr: service: solr endpoint: solr services: # The name of the service container. Must be unique within a project. solr: type: solr:9.6 ``` This configuration defines a single application (`myapp`), whose source code exists in the `/myapp` directory. `myapp` has access to the `solr` service, via a relationship whose name is [identical to the service name](#2-define-the-relationship) (as per [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships). From this, ``myapp`` can retrieve access credentials to the service through the [relationship environment variables](#relationship-reference). ```bash {location="myapp/.environment"} # Set environment variables for individual credentials. # For more information, please visit https://docs.upsun.com/development/variables.html#service-environment-variables. export QUEUE_SCHEME=${SOLR_SCHEME} export QUEUE_USERNAME=${SOLR_USERNAME} export QUEUE_PASSWORD=${SOLR_PASSWORD} export QUEUE_HOST=${SOLR_HOST} export QUEUE_PORT=${SOLR_PORT} # Set a single RabbitMQ connection string variable for AMQP. export AMQP_URL="${QUEUE_SCHEME}://${QUEUE_USERNAME}:${QUEUE_PASSWORD}@${QUEUE_HOST}:${QUEUE_PORT}/" ``` The above file — ``.environment`` in the ``myapp`` directory — is automatically sourced by Upsun into the runtime environment, so that the variable ``SEARCH_URL`` can be used within the application to connect to the service. Note that ``SEARCH_URL``, and all Upsun [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) like ``SOLR_HOST``, are environment-dependent. Unlike the build produced for a given commit, they can’t be reused across environments and only allow your app to connect to a single service instance on a single environment. A file very similar to this is generated automatically for your when using the ``upsun ify`` command to [migrate a codebase to Upsun](https://docs.upsun.com/get-started.md). ##### Solr 4 For Solr 4, Upsun supports only a single core per server called `collection1`. You must provide your own Solr configuration via a `core_config` key in your `.upsun/config.yaml`: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. solr: type: "solr:4.10" configuration: core_config: !archive "" ``` points to a directory in the Git repository, in or below the `.upsun/` folder. This directory needs to contain everything that Solr needs to start a core. At the minimum, `solrconfig.xml` and `schema.xml`. For example, place them in `.upsun/solr/conf/` such that the `schema.xml` file is located at `.upsun/solr/conf/schema.xml`. You can then reference that path like this - ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. solr: type: "solr:4.10" configuration: core_config: !archive "solr/conf/" ``` ##### Solr 6 and later For Solr 6 and later Upsun supports multiple cores via different endpoints. Cores and endpoints are defined separately, with endpoints referencing cores. Each core may have its own configuration or share a configuration. It is best illustrated with an example. ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. solr: type: solr:9.6 configuration: cores: mainindex: conf_dir: !archive "core1-conf" extraindex: conf_dir: !archive "core2-conf" endpoints: main: core: mainindex extra: core: extraindex ``` The above definition defines a single Solr 9.6 server. That server has 2 cores defined: - `mainindex` — the configuration for which is in the `.upsun/core1-conf` directory - `extraindex` — the configuration for which is in the `.upsun/core2-conf` directory. It then defines two endpoints: `main` is connected to the `mainindex` core while `extra` is connected to the `extraindex` core. Two endpoints may be connected to the same core but at this time there would be no reason to do so. Additional options may be defined in the future. Each endpoint is then available in the relationships definition in `.upsun/config.yaml`. For example, to allow an application to talk to both of the cores defined above its configuration should contain the following: ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: type: "php:8.4" source: root: "myapp" [...] # Relationships enable access from this app to a given service. # The example below shows configuration with explicitly set service names and endpoints. # See the Application reference for all options for defining relationships and endpoints. relationships: solrsearch1: service: solr endpoint: main solrsearch2: service: solr endpoint: extra services: # The name of the service container. Must be unique within a project. solr: type: solr:9.6 configuration: cores: mainindex: conf_dir: !archive "core1-conf" extraindex: conf_dir: !archive "core2-conf" endpoints: main: core: mainindex extra: core: extraindex ``` That is, the application's environment would include a `solrsearch1` relationship that connects to the `main` endpoint, which is the `mainindex` core, and a `solrsearch2` relationship that connects to the `extra` endpoint, which is the `extraindex` core. The relationships array would then look something like the following: ```json { "solrsearch1": [ { "path": "solr/mainindex", "host": "248.0.65.197", "scheme": "solr", "port": 8080 } ], "solrsearch2": [ { "path": "solr/extraindex", "host": "248.0.65.197", "scheme": "solr", "port": 8080 } ] } ``` ###### Configsets For even more customizability, it's also possible to define Solr configsets. For example, the following snippet would define one configset, which would be used by all cores. Specific details can then be overridden by individual cores using `core_properties`, which is equivalent to the Solr `core.properties` file. ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. solr: type: solr:9.6 configuration: configsets: mainconfig: !archive "configsets/solr8" cores: english_index: core_properties: | configSet=mainconfig schema=english/schema.xml arabic_index: core_properties: | configSet=mainconfig schema=arabic/schema.xml endpoints: english: core: english_index arabic: core: arabic_index ``` In this example, `.upsun/configsets/solr8` contains the configuration definition for multiple cores. There are then two cores created: - `english_index` uses the defined configset, but specifically the `.upsun/configsets/solr8/english/schema.xml` file - `arabic_index` is identical except for using the `.upsun/configsets/solr8/arabic/schema.xml` file. Each of those cores is then exposed as its own endpoint. Note that not all core properties features make sense to specify in the `core_properties`. Some keys, such as `name` and `dataDir`, aren't supported, and may result in a `solrconfig` that fails to work as intended, or at all. ###### Default configuration ####### Default for version 9+ If you don't specify any configuration, the following default is used: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. solr: type: solr:9.6 configuration: cores: collection1: conf_dir: !archive "example" endpoints: solr: core: collection1 ``` The example configuration directory is equivalent to the [Solr example configuration set](https://github.com/apache/solr/tree/main/solr/server/solr/configsets/sample_techproducts_configs/conf). This default configuration is designed only for testing. You are strongly recommended to define your own configuration with a custom core and endpoint. ####### Default for versions below 9 If you don't specify any configuration, the following default is used: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. solr: type: solr:8.4 configuration: cores: collection1: {} endpoints: solr: core: collection1 ``` The default configuration is based on an older version of the Drupal 8 Search API Solr module that is no longer in use. You are strongly recommended to define your own configuration with a custom core and endpoint. ###### Limitations The recommended maximum size for configuration directories (zipped) is 2MB. These need to be monitored to ensure they don't grow beyond that. If the zipped configuration directories grow beyond this, performance declines and deploys become longer. The directory archives are compressed and string encoded. You could use this bash pipeline ```bash echo $(($(tar czf - . | base64 | wc -c )/(1024*1024))) Megabytes ``` inside the directory to get an idea of the archive size. The configuration directory is a collection of configuration data, like a data dictionary, e.g. small collections of key/value sets. The best way to keep the size small is to restrict the directory context to plain configurations. Including binary data like plugin `.jar` files inflates the archive size, and isn't recommended. ##### Accessing the Solr server administrative interface Because Solr uses HTTP for both its API and admin interface it's possible to access the admin interface over an SSH tunnel. ```bash upsun tunnel:single --relationship ``` By default, this opens a tunnel at `127.0.0.1:30000`. You can now open `http://localhost:30000/solr/` in a browser to access the Solr admin interface. Note that you can't create indexes or users this way, but you can browse the existing indexes and manipulate the stored data. ##### Available plugins This is the complete list of plugins that are available and loaded by default: | Plugin | Description | 8.11 | 9.x | |------------------------------------------------------------------------------------|--------------------------------------------------------|------|-----| | [JTS](https://solr.apache.org/guide/8_1/spatial-search.md#jts-and-polygons-flat) | Library for creating and manipulating vector geometry. |* |* | | [ICU4J](https://solr.apache.org/guide/8_3/language-analysis.md) | Library providing Unicode and globalization support. |* |* | ##### Upgrading The Solr data format sometimes changes between versions in incompatible ways. Solr doesn't include a data upgrade mechanism as it is expected that all indexes can be regenerated from stable data if needed. To upgrade (or downgrade) Solr you need to use a new service from scratch. There are two ways of doing that. ###### Destructive In your `.upsun/config.yaml` file, change the version of your Solr service *and* its name. Be sure to also update the reference to the now changed service name in it's corresponding application's `relationship` block. When you push that to Upsun, the old service is deleted and a new one with the name is created, with no data. You can then have your application re-index data as appropriate. This approach has the downside of temporarily having an empty Solr instance, which your application may or may not handle gracefully, and needing to rebuild your index afterward. Depending on the size of your data that could take a while. ###### Transitional For a transitional approach you temporarily have two Solr services. Add a second Solr service with the new version a new name and give it a new relationship in `.upsun/config.yaml`. You can optionally run in that configuration for a while to allow your application to populate indexes in the new service as well. Once you're ready to cut over, remove the old Solr service and relationship. You may optionally have the new Solr service use the old relationship name if that's easier for your application to handle. Your application is now using the new Solr service. This approach has the benefit of never being without a working Solr instance. On the downside, it requires two running Solr servers temporarily, each of which consumes resources and need adequate disk space. Depending on the size of your data that may be a lot of disk space. ### Varnish Varnish is a popular HTTP proxy server, often used for caching. You usually don't need it with Upsun as the standard router includes HTTP cache and a CDN would cover more advanced uses. But you can include Varnish as a service. ##### Supported versions You can select the major and minor version. Patch versions are applied periodically for bug fixes and the like. When you deploy your app, you always get the latest available patches. - 7.6 - 7.3 - 7.2 - 6.0 ##### How it works All incoming requests go through the [standard router](https://docs.upsun.com../define-routes.md). The Varnish service sits between the router and all apps in the project. ``` mermaid graph LR A(Request) -->B(Router) B --> C{Varnish} C -->D[App 1] C -->E[App 2] ``` ##### Usage example ###### 1. Configure the service To define the service, use the `varnish` type: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. : type: varnish: relationships: : ':http' configuration: vcl: !include type: string path: config.vcl ``` Note that changing the name of the service replaces it with a brand new service and all existing data is lost. Back up your data before changing the service. The `relationships` block defines the connection between Varnish and your app. You can define ```` as you like. ```` should match your app's `name` in the [app configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md). The `configuration` block must reference a VCL file inside the `.upsun` directory. The `path` defines the file relative to the `.upsun` directory. ####### Example configuration ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: ... services: # The name of the service container. Must be unique within a project. varnish: type: varnish:7.6 relationships: application: 'myapp:http' configuration: vcl: !include type: string path: config.vcl ``` Notice the `relationship` (`application`) defined for the service `varnish` granting access to the application container `myapp`. ###### 2. Create a VCL template To tell Varnish how to handle traffic, in the `.upsun` directory add a [Varnish Configuration Language (VCL) template](https://www.varnish-software.com/developers/tutorials/example-vcl-template/). This template is supplemented by automatic additions from Upsun. So you MUST NOT include certain features that you might elsewhere: - A `vcl_init()` function: The function is automatically generated based on the relationships you defined in Step 1. Each defined relationship results in a backend with the same name. - The VCL version at the start: This is automatically generated. - Imports for `std` or `directors`: These are already imported. You can import other [modules](#include-modules). The file MUST include: - A definition of which backend to use in a `vcl_recv()` subroutine. The logic varies based on whether you have one or more apps. **Note**: Misconfigured VCL files can result in incorrect and confusing behavior that’s hard to debug. Upsun doesn’t help with VCL configuration options beyond the basic connection logic documented here. You can see any compilation errors with the [stats endpoint](#stats-endpoint). ####### Example VCL template with one app To serve one app, your VCL template needs at least the following function: ```bash {location="config.vcl" } sub vcl_recv { set req.backend_hint = .backend(); } ``` Where `` is the name of the relationship you defined in [Step 1](#1-configure-the-service). With the [example configuration](#example-configuration), that would be the following: ```bash {location="true/config.vcl"} sub vcl_recv { set req.backend_hint = application.backend(); } ``` ####### Example VCL template with multiple apps If you have multiple apps fronted by the same Varnish instance, your VCL templates needs logic to determine where each request is forwarded. For example, you might have the following configuration for two apps: ```yaml {location=".upsun/config.yaml"} # The name of the service container. Must be unique within a project. services: varnish: type: varnish:7.6 relationships: blog: service: blog endpoint: http main: service: myapp endpoint: http configuration: vcl: !include type: string path: config.vcl applications: # The name of the app container. Must be unique within a project. blog: # The location of the application's code. source: root: "backends/blog" # The type of the application to build. type: "php:8.4" # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "backends/main" # The type of the application to build. type: "nodejs:8.4" ``` You could then define that all requests to `/blog/` go to the `blog` app and all other requests to the other app: ```bash {location="true/config.vcl"} sub vcl_recv { if (req.url ~ "^/blog/") { set req.backend_hint = blog.backend(); } else { set req.backend_hint = main.backend(); } } ``` ###### 3. Route incoming requests to Varnish Edit your [route definitions](https://docs.upsun.com../define-routes.md) to point to the Varnish service you just created. Also disable the router cache as Varnish now provides caching. To forward all incoming requests to Varnish rather than your app, you could have the following: ```yaml {location=".upsun/config.yaml"} routes: "https://{default}/": type: upstream upstream: "varnish:http" cache: enabled: false ``` Varnish forwards requests to your app based on the specified VCL template. ##### Include modules You can include the following optional modules in your VCL templates to add additional features: - `cookie` - `header` - `saintmode` - `softpurge` - `tcp` - `var` - `vsthrottle` - `xkey` To use them, add an import to your template such as the following: ```bash {location="true/config.vcl"} import xkey; ``` ##### Circular relationships At this time, Upsun doesn't support circular relationships between services and apps. That means you can't add a relationship from an app fronted by Varnish to the Varnish service. If you do so, then one of the relationships is skipped and the connection doesn't work. ##### Rate limit connections Sometimes you want to ensure that users, whether human or machine, can't overload your app with requests. One tool to help is using Varnish to limit the rate at which connections can be made. For example, say you want to make sure no one can make more than 20 requests within 10 seconds. If they do, you want to block them from any more requests for 2 minutes. To do so, [import the `vsthrottle` module](#include-modules) and add logic similar to the following to your VCL template: ```bash {location="true/config.vcl"} import vsthrottle; sub vcl_recv { # The Upsun router provides the real client IP as X-Client-IP # This replaces client.identity in other implementations if (vsthrottle.is_denied(req.http.X-Client-IP, 20, 10s, 120s)) { # Client has exceeded 20 requests in 10 seconds. # When this happens, block that IP for the next 120 seconds. return (synth(429, "Too Many Requests")); } # Set the standard backend for handling requests that aren't limited set req.backend_hint = application.backend(); } ``` ##### Clear cache with a push You may want at times to clear a specific part of your cache when you know the content is outdated. With Varnish, you can clear the content with [purging and banning](https://varnish-cache.org/docs/trunk/users-guide/purging.md). The following example shows how to set up purging. 1. Add an access control list to your VCL template: ```bash {location="true/config.vcl"} acl purge { "localhost"; "192.0.2.0"/24; } ``` This list ensures that only requests from the listed IPs are accepted. Choose which IPs to allow. If you are sending requests from an app, checkout the [outbound IPs for the region](https://docs.upsun.com../development/regions.md#public-ip-addresses). Alternatively, you could code in a token that must be sent with the request. 2. Add purge handling: ```bash {location="true/config.vcl"} sub vcl_recv { if (req.method == "PURGE") { # The Upsun router provides the real client IP as X-Client-IP # Use std.ip to convert the string to an IP for comparison if (!std.ip(req.http.X-Client-IP, "0.0.0.0") ~ purge) { # Deny all purge requests not from the allowed IPs return(synth(403,"Not allowed.")); } # Purge cache for allowed requests return (purge); } ... } ``` **Note**: The snippet above has been produced for Varnish 7.x. If using a different version, consult the [Varnish documentation](https://varnish-cache.org/docs/) for potential differences in syntax and required parameters. 3. Set up cache purging to suit your needs. The following cURL call gives an example of how this can work: ```bash curl -X PURGE "" ``` ##### Stats endpoint The Varnish service also offers an `http+stats` endpoint, which provides access to some Varnish analysis and debugging tools. You can't use it from an app fronted by Varnish because of the restriction with [circular relationships](#circular-relationships). To access the stats, create a **separate app** (`stats-app`) with a relationship *to* Varnish, but not *from* it. Define [app configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md) similar to the following: ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. stats-app: # The location of the application's code. source: root: "stats" # The type of the application to build. type: "python:3.9" # Unique relationship _to_ Varnish from 'stats-app', where no relationship # is defined _from_ Varnish to the same app, to avoid circular relationships. relationships: varnishstats: service: varnish endpoint: http+stats # The name of the app container. Must be unique within a project. main-app: # The location of the application's code. source: root: "backends/main" # The type of the application to build. type: "nodejs:22" services: # The name of the service container. Must be unique within a project. varnish: type: varnish:7.6 # Unique relationship _from_ Varnish _to_ 'main-app', where no relationship # is defined _to_ Varnish to the same app, to avoid circular relationships. relationships: main: service: "main-app" endpoint: "http configuration: vcl: !include type: string path: config.vcl ``` You choose any valid name and type. When the app is deployed, the app can access the Varnish service over HTTP to get diagnostic information. The following paths are available: - `/`: returns any error logged when generating the VCL template failed - `/config`: returns the generated VCL template - `/stats`: returns the output of `varnishstat` - `/logs`: returns a streaming response of `varnishlog` To access the Varnish stats endpoint from the command line: 1. Connect to your stats app [using SSH](https://docs.upsun.com../development/ssh/_index.md): `upsun ssh --app stats-app` (replace `stats-app` with the name you gave the app). 2. Display the [relationships array](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) with `echo $PLATFORM_RELATIONSHIPS | base64 -d | jq .`, 3. Query Varnish with `curl :/stats`, replacing `` and `` with the values from Step 2. ### Vault key management service The Vault key management service (KMS) provides key management and access control for your secrets. The Upsun Vault KMS offers the [transit secrets engine](https://developer.hashicorp.com/vault/docs/secrets/transit) to sign, verify, encrypt, decrypt, and rewrap information. Vault doesn't store the data sent to the transit secrets engine, so it can be viewed as encryption as a service. To store secrets such as API keys, create sensitive [environment variables](https://docs.upsun.com../development/variables.md). ##### Supported versions You can select the major and minor version. Patch versions are applied periodically for bug fixes and the like. When you deploy your app, you always get the latest available patches. - 1.12 ##### Relationship reference For each service [defined via a relationship](#usage-example) to your application, Upsun automatically generates corresponding environment variables within your application container, in the ``$_`` format. Here is example information available through the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) themselves, or through the [``PLATFORM_RELATIONSHIPS`` environment variable](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). For some advanced use cases, you can use the [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). The structure of the ``PLATFORM_RELATIONSHIPS`` environment variable can be obtained by running ``upsun relationships`` in your terminal: ```json {} { "username": "", "scheme": "http", "service": "vault-kms", "fragment": "", "ip": "123.456.78.90", "instance_ips": [ "123.456.78.90" ], "hostname": "azertyuiopqsdfghjklm.vault-kms.service._.eu-1.platformsh.site", "port": 8200, "cluster": "azertyuiopqsdf-main-7rqtwti", "host": "vault_secret.internal", "rel": "sign", "path": "\/", "query": { "is_master": true }, "password": "ChangeMe", "type": "vault-kms:1.12", "public": false, "host_mapped": false } ``` Here is an example of how to gather [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables) information in a [.environment](https://docs.upsun.com/development/variables/set-variables.md#use-env-files): ```bash {location=".environment"} # Decode the built-in credentials object variable. export RELATIONSHIPS_JSON=$(echo $PLATFORM_RELATIONSHIPS | base64 --decode) # Set environment variables for individual credentials. export APP_VAULT_HOST=="$(echo $RELATIONSHIPS_JSON | jq -r '.vault_secret[0].host')" ``` ##### Usage example ###### 1. Configure the service To define the service, use the `vault-kms` type: ```yaml {location=".upsun/config.yaml"} services: # The name of the service container. Must be unique within a project. : type: vault-kms: configuration: endpoints: : - policy: key: type: ``` Note that changing the name of the service replaces it with a brand new service and all existing data is lost. Back up your data before changing the service. - is the name you choose to identify the service. - is a supported version of the service. - is an identifier you choose for the endpoint. - is the name of the key to be stored in the Vault KMS. - is one of the available [policies](#policies) based on what you want to accomplish. - The `type` is one of: - `sign`: for signing payloads, with the type `ecdsa-p256` - `encrypt` (for encrypt`chacha20-poly1305`). The `type` can't be changed after creation. You can create multiple endpoints, such as to have key management separate from key use. 512 MB is the minimum required disk space for the Vault KMS service. ###### 2. Define the relationship To define the relationship, use the following configuration: ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. : # Relationships enable access from this app to a given service. relationships: : service: endpoint: services: # The name of the service container. Must be unique within a project. : type: vault-kms: configuration: endpoints: : - policy: key: type: ``` You can define `` as you like, so long as it's unique between all defined services and matches in both the application and services configuration. The example above leverages [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) configuration for relationships. That is, it uses default endpoints behind-the-scenes, providing a [relationship](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) (the network address a service is accessible from) that is identical to the _name_ of that service. Depending on your needs, instead of default endpoint configuration, you can use [explicit endpoint configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships). With the above definition, the application container (````) now has access to the service via the relationship ```` and its corresponding [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). If you split the service into multiple endpoints, define multiple relationships. ###### Example configuration ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: relationships: vault_secret: "vault-kms:manage_keys" services: # The name of the service container. Must be unique within a project. vault-kms: type: vault-kms:1.12 configuration: endpoints: manage_keys: - policy: admin key: vault-sign type: sign - policy: sign key: vault-sign type: sign - policy: verify key: vault-sign type: sign ``` ##### Multiple endpoints example ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: relationships: vault_manage: service: vault-kms endpoint: management vault_sign: service: vault-kms endpoint: sign_and_verify services: # The name of the service container. Must be unique within a project. vault-kms: type: vault-kms:1.12 configuration: endpoints: management: - policy: admin key: admin-key type: sign sign_and_verify: - policy: sign key: signing-key type: sign - policy: verify key: signing-key type: sign ``` ##### Use Vault KMS To connect your app to the Vault KMS, use a token that's defined in the [service environment variables](#relationship-reference). With this token for authentication, you can use any of the policies you [defined in your `.upsun/config.yaml` file](#1-configure-the-service). You can obtain the complete list of available service environment variables in your app container by running ``upsun ssh env``. Note that the information about the relationship can change when an app is redeployed or restarted or the relationship is changed. So your apps should only rely on the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) directly rather than hard coding any values. The following examples use cURL as an example, which you could do in a hook or after accessing your app with SSH. Adapt the examples for your app's language. ###### Get the token To make any calls to the Vault KMS, you need your token. Get it from the [service environment variables](#relationship-reference): ```bash echo ${_PASSWORD}" ``` `` is the relationship name you [defined in your `.upsun/config.yaml` file](#2-define-the-relationship). You can also store this as a variable: ```bash VAULT_TOKEN=${_PASSWORD} ``` A given token is valid for one year from its creation. ###### Get the right URL The [service environment variable](#relationship-reference) also contains the information you need to construct a URL for contacting the Vault KMS: the `host` and `port`. Assign it to a variable as follows: ```bash VAULT_URL=${_HOST}:${_PORT} ``` `` is the name you [defined in your `.upsun/config.yaml` file](#2-define-the-relationship). ###### Manage your keys Your key names are [defined in your `.upsun/config.yaml` file](#1-configure-the-service). You can manage them if you've set an [admin policy](#policies) for them. To get information on a key, such as its expiration date, run the following command: ```bash curl \ --header "X-Vault-Token: $VAULT_TOKEN" \ http://"$VAULT_URL"/v1/transit/keys/"$KEY_NAME" | jq . ``` `$KEY_NAME` is the name in your `.upsun/config.yaml` file. To rotate the version of your key, run the following command: ```bash curl \ --header "X-Vault-Token: $VAULT_TOKEN" \ http://"$VAULT_URL"/v1/transit/keys/"$KEY_NAME">/rotate \ --request POST ``` ###### Sign and verify payloads If you've set [sign and verify policies](#policies), you can use your keys to sign and verify various payloads, such as a JSON Web Token (JWT) for authentication in your app. Note that all payloads (all plaintext data) must be base64-encoded. To sign a specific payload, run the following command: ```bash curl \ --header "X-Vault-Token: $VAULT_TOKEN" \ http://$VAULT_URL/v1/transit/sign/"$KEY_NAME"/sha2-512 \ --data "{\"input\": \"$(echo SECRET | base64)\"}" ``` The string at the end of the URL denotes the specific [hash algorithm used by the Vault KMS](https://www.vaultproject.io/api-docs/secret/transit#hash_algorithm). You get back a JSON object that includes the signature for the payload: ```json { "request_id": "a58b549f-1356-4028-d191-4c9cd585ca25", ... "data": { "key_version": 1, "signature": "vault-kms:v1:MEUCIAiN4UtXh..." }, ... } ``` You can then use `data.signature` to sign things such as a JWT. To verify a payload, run the following command: ```bash curl \ --header "X-Vault-Token: $VAULT_TOKEN" \ http://"$VAULT_URL"/v1/transit/verify/"$KEY_NAME"/sha2-512 \ --data " { \"input\": \"$(echo SECRET | base64)\", \"signature\": \"$SIGNATURE\" }" ``` You get back a JSON object that includes whether or not the signature is valid: ```json { "request_id": "5b624718-fd9d-37f6-8b95-b387379d2648", ... "data": { "valid": true }, ... } ``` A `true` value means the signature matches and a `false` value means it doesn't. ###### Encrypt and decrypt data If you've set [encrypt and decrypt policies](#policies), you can use your keys to encrypt and decrypt any data you want. Note that all of plaintext data you work with must be base64-encoded. To sign a specific payload, run the following command: ```bash curl \ --header "X-Vault-Token: $VAULT_TOKEN" \ http://$VAULT_URL/v1/transit/encrypt/"$KEY_NAME" \ --data "{\"plaintext\": \"$(echo SECRET | base64)\"}" ``` You get back a JSON object that includes your encrypted data: ```json { "request_id": "690d634a-a4fb-bdd6-9947-e895578b79d5", ... "data": { "ciphertext": "vault-kms:v1:LEtOWSwh3N...", "key_version": 1 }, ... } ``` To decrypt data that you've already encrypted, run the following command: ```bash curl \ --header "X-Vault-Token: $VAULT_TOKEN" \ http://"$VAULT_URL"/v1/transit/decrypt/"$KEY_NAME" \ --data " { \"ciphertext\": \"$CIPHERTEXT\" }" ``` You get back a JSON object that your decrypted data base64-encoded: ```json { "request_id": "bbd411ca-6ed7-aa8b-8177-0f35055ce613", ... "data": { "plaintext": "U0VDUkVUCg==" }, ... } ``` To get the value un-encoded, add `| jq -r ".data.plaintext" | base64 -d` to the end of the `curl` command. ####### Rewrap encrypted data If you have already encrypted data and you have [changed your key version](#manage-your-keys), you can rewrap the encrypted data with the new key. Assuming `$CIPHERTEXT` stores your encrypted data (`vault:v1:LEtOWSwh3N...`), run the following command: ```bash curl \ --header "X-Vault-Token: $VAULT_TOKEN" \ http://"$VAULT_URL"/v1/transit/rewrap/"$KEY_NAME" \ --data " { \"ciphertext\": \"$CIPHERTEXT\" }" ``` In the JSON object that's returned, you can notice that the `ciphertext` is different (and now includes the new key version as a prefix) as is the `key_version`: ```json { ... "data": { "ciphertext": "vault-kms:v2:ICRi0yAlH...", "key_version": 2 }, ... } ``` ##### Policies | Policy | Endpoint | Capabilities | Purpose | | --------- | -------- | ------------ | ------- | | `admin` | `transit/keys/${KEY}` | `read` | Access to key properties and various functions performed on keys such as rotation and deletion | | | `transit/keys/${KEY}/*` | `read`, `create`, `update`, `delete` | | | `sign` | `transit/sign/${KEY}/${HASH_ALGORITHM}` | `read`, `update` | Signing payloads with an existing key | | `verify` | `transit/verify/${KEY}/${HASH_ALGORITHM}` | `read`, `update` | Verifying already signed payloads | | `encrypt` | `transit/encrypt/${KEY}` | `read`, `update` | Encrypting data with an existing key | | `decrypt` | `transit/decrypt/${KEY}` | `read`, `update` | Decrypting data with an existing key | | `rewrap` | `transit/rewrap/${KEY}` | `read`, `update` | Re-encrypting data with a new key version without revealing the secret | ### Server Side Includes (SSI) SSI commands enable you to include files within other pages. At its most basic, you can include files within other ones so as not to repeat yourself. Start by enabling SSI: ```yaml {location=".upsun/config.yaml"} routes: "https://{default}/": type: upstream upstream: "myapp:http" ssi: enabled: true ``` Then create a file you want to include elsewhere: ```html {location="includes/example.html"} This content can be reused ``` And include it in another file: ```html {location="index.html"} This content is unique to this page. ``` And your final rendered page includes the other file: ```html {location="index.html"} This content is unique to this page. This content can be reused ``` ##### Caching and dynamic content You can use SSI to have [caching](https://docs.upsun.com/define-routes/cache.md) and dynamic content in one. So one file is cached, while another updates dynamically. For example, you can activate SSI on one route with cache disabled and enable cache on another route: ```yaml {location=".upsun/config.yaml"} routes: "https://{default}/": type: upstream upstream: "myapp:http" ssi: enabled: true cache: enabled: false "https://{default}/cache": type: upstream upstream: "myapp:http" cache: enabled: true ``` Then create a page that displays the current date and time and is cached for 60 seconds (the example uses PHP, but any server-side language would work): ```php {location="cache/example.php"} ``` Then you can visit `index.php` and refresh the page a few times. You see the first number updating to the current time, while the second (included) one only changes every 60 seconds. For more on SSI, see the [nginx documentation](https://nginx.org/en/docs/http/ngx_http_ssi_module.md). ### HTTP cache Upsun supports HTTP caching at the server level. Caching is enabled by default, but is only applied to ``GET`` and ``HEAD`` requests. The cache can be controlled using the `cache` key in your `.upsun/config.yaml` file. If a request can be cached, Upsun builds a cache key from several request properties and stores the response associated with this key. When a request comes with the same cache key, the cached response is reused. When caching is on... * you can configure cache behavior for different location blocks in your `.upsun/config.yaml`; * the router respects whatever cache headers are sent by the application; * cookies bypass the cache; * responses with the `Cache-Control` header set to `Private`, `No-Cache`, or `No-Store` aren't cached. You should _not_ use the Upsun HTTP cache if you're using [Varnish](https://docs.upsun.com../add-services/varnish.md) or an external CDN such as [Fastly](https://docs.upsun.com../domains/cdn/fastly.md) or [Cloudflare](https://docs.upsun.com../domains/cdn/cloudflare.md). Mixing cache services together most likely results in caches that are stale and can't be cleared. For more details, see [best practices on HTTP caching](https://docs.upsun.com/learn/bestpractices/http-caching.md). ##### Basic usage The HTTP cache is enabled by default, however you may wish to override this behavior. To configure the HTTP cache, add a `cache` key to your route. You may like to start with the defaults: ```yaml {location=".upsun/config.yaml"} routes: https://{default}/: type: upstream upstream: myapp:http cache: enabled: true default_ttl: 0 cookies: ['*'] headers: ['Accept', 'Accept-Language'] ``` ##### Example In this example, requests are cached based on the URI, the `Accept` header, `Accept-Language` header, and `X-Language-Locale` header. Any response that lacks a `Cache-Control` header is cached for 60 seconds. The presence of any cookie in the request disables caching of that response. ```yaml {location=".upsun/config.yaml"} routes: https://{default}/: type: upstream upstream: myapp:http cache: enabled: true headers: ['Accept', 'Accept-Language', 'X-Language-Locale'] cookies: ['*'] default_ttl: 60 ``` ##### How it works ###### The cache key If a request can be cached, Upsun builds a cache key from several request properties and stores the response associated with this key. When a request comes with the same cache key, the cached response is reused. There are two parameters that let you control this key: `headers` and `cookies`. The default value for these keys are the following: ```yaml {location=".upsun/config.yaml"} routes: https://{default}/: # ... cache: enabled: true cookies: ['*'] headers: ['Accept', 'Accept-Language'] ``` ###### Duration The cache duration is decided based on the `Cache-Control` response header value. If no `Cache-Control` header is in the response, then the value of `default_ttl` key is used. ###### Conditional requests Conditional requests using `If-Modified-Since` and `If-None-Match` are both supported. The web server doesn't honor the `Pragma` request header. ###### Cache revalidation When the cache is expired (indicated by `Last-Modified` header in the response) the web server sends a request to your application with `If-Modified-Since` header. If the `If-None-Match` header is sent in the conditional request when `Etag` header is set in the cached response, your application can extend the validity of the cache by replying `HTTP 304 Not Modified`. ###### Flushing The HTTP cache doesn't support a complete cache flush, but you can invalidate the cache by setting `cache: false`. Alternatively, the cache clears on a rebuild, so triggering a rebuild (pushing a new commit) effectively causes a complete cache flush. ##### Cache configuration properties ###### `enabled` Turns the cache on or off for a route. **Note**: Regular expressions in routes are **not** supported. ###### Allowing only specific cookies Some applications use cookies to invalidate cache responses, but expect other cookies to be ignored. This is a case of allowing only a subset of cookies to invalidate the cache. ```yaml {location=".upsun/config.yaml"} routes: https://{default}/: # ... cache: enabled: true cookies: ["MYCOOKIE"] ``` ###### Cache HTTP and HTTPS separately using the `Vary` header Set the Vary header to `X-Forwarded-Proto` [custom request header](https://docs.upsun.com/development/headers.md) to render content based on the request protocol (i.e. HTTP or HTTPS). By adding `Vary: X-Forwarded-Proto` to the response header, HTTP and HTTPS content would be cached separately. ###### Cache zipped content separately Use `Vary: Accept-Encoding` to serve different content depending on the encoding. Useful for ensuring that gzipped content isn't served to clients that can't read it. ### HTTPS Using HTTPS for your site helps ensure your users' information remains secure. HTTPS provides enhanced security thanks to the following characteristics: - With HTTPS, data is encrypted so user activity can't be tracked and user information can't be stolen. - HTTPS prevents the corruption of files transferred from a web server to a website and vice-versa. - HTTPS also authenticates websites, which helps build trust with your users. To enable HTTPS on your site, you need [Transport Layer Security (TLS) certificates](#tls-certificates). ##### TLS certificates Upsun automatically provides TLS certificates for all sites and environments. These certificates are issued at no charge by [Let's Encrypt](https://letsencrypt.org/) and cover most needs. They're valid for 90 days and automatically renewed 28 days before expiration. To use them, you only need to [specify HTTPS routes](https://docs.upsun.com../define-routes/https.md#enable-https). Note that [limitations](https://docs.upsun.com../define-routes/https.md#lets-encrypt-limitations) apply. If you encounter issues with the TLS certificates provided by Upsun, check that [TLS encryption is up-and-running](https://docs.upsun.com../domains/troubleshoot.md#verify-ssltls-encryption). If you don't want to use the TLS certificates provided by Upsun, configure your own [third-party TLS certificates](https://docs.upsun.com../domains/steps/tls.md). ###### Let's Encrypt limitations When you use the Let's Encrypt [TLS certificates](#tls-certificates) provided by Upsun, the following limitations apply. Let's Encrypt allows a maximum of 100 hostnames per certificate. You can have 1 Let's Encrypt certificate for each of your environments. If you define both a `{default}` and a `www.{default}` route for each domain you use, you can add up to 50 hostnames. Going over this limitation results in a warning on deploy and no new TLS certificates are issued. If you need more hostnames, you can obtain additional certificates or a wildcard certificate from a [third-party issuer](https://docs.upsun.com../domains/steps/tls.md). Alternatively, consider splitting your project up into multiple Upsun projects. Please note that when using multiple domains, the Common Name (CN) to which the certificate is issued to is not guaranteed to be the same on each certificate renewal. ###### Certificate renewals When you use the [TLS certificates](#tls-certificates) provided by Upsun, certificate renewals are automatic. They trigger a redeployment of your environment. During this redeployment, required security and system upgrades are applied to your containers. So the duration of the redeployment depends on what needs to be upgraded. ##### Enable HTTPS To enable HTTPS, add a routing configuration similar to the following: ```yaml {location=".upsun/config.yaml"} routes: "https://{default}/": type: upstream upstream: "myapp:http" "https://www.{default}/": type: redirect to: "https://{default}/" ``` All traffic to your domain is then sent to your app. The `www` subdomain redirects to the [default domain](https://docs.upsun.com../define-routes.md#default). This also includes redirecting requests from HTTP to HTTPS. For more information, see how to [define routes](https://docs.upsun.com../define-routes.md). ##### Optional: Configure TLS connections When you [specify HTTPS routes](#enable-https), you can use the `tls` setting to further configure your TLS connections. ###### Enforce TLS 1.3 Although you can still use TLS 1.2, TLS 1.3 is faster and more secure. To instruct your web server to automatically reject TLS 1.2 connections, enforce TLS 1.3 using the `min_version` setting: ```yaml {location=".upsun/config.yaml"} routes: "https://{default}/": # ... tls: min_version: TLSv1.3 ``` Note that TLS versions older than 1.2 are deprecated and are rejected by default. ###### Enable HTTP Strict Transport Security (HSTS) [HSTS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security) forces clients to always communicate with your site over HTTPS. To enable HSTS, use `strict_transport_security` in a configuration similar to the following: ```yaml {location=".upsun/config.yaml"} routes: "https://{default}/": # ... tls: strict_transport_security: enabled: true include_subdomains: true preload: true ``` The following table presents the possible properties for `strict_transport_security`: | Name | Type | Default | Description | |----------------------|-----------|---------|------------------------------------------------------------------------------------------------| | `enabled` | `boolean` | `null` | If set to `true`, HSTS is enabled for 1 year. If set to `false`, other properties are ignored. | | `include_subdomains` | `boolean` | `false` | To specify whether HSTS applies to all subdomains. | | `preload` | `boolean` | `false` | To add your website to the [HSTS preload list](https://hstspreload.org/). Thanks to this list, most browsers are informed that your site requires HSTS before an HSTS header response is even issued. | Note that when you enable or disable HSTS, the entire domain is affected. Make sure you only add the HSTS configuration to a single route. Having different routes with conflicting HSTS configurations can cause issues. ###### Enable mTLS Standard TLS connections are useful to verify the identity of web servers and their certificates. But you can also instruct your web server to verify the identity of clients and their certificates. This allows you to restrict access to trusted users. To do so, enable mTLS by adding the following configuration: ```yaml {location=".upsun/config.yaml"} routes: "https://{default}/": # ... tls: client_authentication: "require" ``` By default, all valid TLS certificates issued by a legitimate certificate authority are accepted. But you can instruct your web server to only accept TLS certificates issued by specific or even custom certificate authorities. To do so, add a configuration similar to the following: ```yaml {location=".upsun/config.yaml"} routes: "https://{default}/": # ... tls: client_authentication: "require" client_certificate_authorities: - !include type: string path: root-ca1.crt - !include type: string path: root-ca2.crt ``` In this case, the certificate files are resolved relative to the `.upsun` directory. Alternatively, you can specify the certificates inline in the file: ```yaml {location=".upsun/config.yaml"} routes: "https://{default}/": # ... tls: client_authentication: "require" client_certificate_authorities: - | -----BEGIN CERTIFICATE----- ### Several lines of characters here ### -----END CERTIFICATE----- - | -----BEGIN CERTIFICATE----- ### Several lines of different characters here ### -----END CERTIFICATE----- ``` If you want to request a client certificate without _requiring_ the client to send one, you can set this by using `request` as a value for `client_authentication`: ```yaml {location=".upsun/config.yaml"} routes: "https://{default}/": # ... tls: client_authentication: "request" # ... ``` Requests on routes with mTLS configured that are passed through to your app will contain additional headers such as `X-Client-Verify` (with values like `Success` or `None` depending on whether a client certificate was presented and validated or not) and `X-Client-Cert` (with information about the client certificate that was used) that your application can use as required. ### Proxy routes **Warning**: Only use this feature to address edge cases where you need to proxy to another, outside project. **Do not use this for internal routing.** To expose your app to the outside world, see [how to define routes](https://docs.upsun.com/define-routes.md). Sometimes you want your app to pass requests on to a different Upsun project. Basic redirects only work within the same project, so use proxy routes for routes elsewhere. You can define an external proxy on your Upsun project by defining a route like the following: ```yaml {location=".upsun/config.yaml"} routes: https://{default}/foo: type: proxy to: https://www.example.com ``` This route passes requests for `https://{default}/foo/index.html` to `https://www.example.com/foo/index.html`. You can also define a proxy route to an URL composed of an IP address and a port: ```yaml {location=".upsun/config.yaml"} routes: https://{default}/foo: type: proxy to: https://192.0.2.0:8000 ``` ##### URL paths In the basic example above, the route preserves the URL path, `/foo`, in the request. If you want to proxy a route to `https://www.example.com` without the URL path `/foo`, add a trailing slash `/` to the `to` definition. ```yaml {location=".upsun/config.yaml"} routes: https://{default}/foo: type: proxy to: https://www.example.com/ ``` The trailing slash makes the proxy route interpret the location as having a different path. So requests for `https://{default}/foo/index.html` are forwarded to `https://www.example.com/index.html`. To override the URL path entirely, define a route that contains its own path. For example: ```yaml {location=".upsun/config.yaml"} routes: https://{default}/foo: type: proxy to: https://www.example.com/bar ``` This route passes requests for `https://{default}/foo/index.html` to `https://www.example.com/bar/index.html`. ##### Multiple apps with the same base URL You can use proxy routes to map a single domain to multiple Upsun projects with their own subdomain/domain names. You might have a need to access multiple projects, each hosting specific applications for different languages. You want to serve them all at the same base URL with different paths (`https://example.com/en`, `https://example.com/fr`, and so on). Because domains can't be reused at Upsun, you can't just set the same domain for all projects. Use proxy routes so a single project can access different projects using the same base URL. In the following example, a single project specifies proxy routes to three apps with the same `default` base URL. Each app handles a different language. ```yaml {location=".upsun/config.yaml"} routes: https://{default}/en: type: proxy to: https://en.example.com/ https://{default}/jp: type: proxy to: https://jp.example.com/ https://{default}/pt: type: proxy to: https://pt.example.com/ ``` The apps behind the proxy need to ensure links to assets are shown to the target domain. For example, by changing `https://en.example.com/style.css` to `https://example.com/en/style.css`. The following diagram shows the example project forwarding specific requests to the correct app. ``` mermaid sequenceDiagram participant User participant Project as Proxy project participant En as En project participant Jp as Jp project participant Pt as Pt project User->>+Project: example.com/en/index.html Project->>+En: en.example.com/index.html Note over En: Changes asset links En-->>-Project: index.html Project-->>-User: index.html User->>+Project: example.com/jp/index.html Project->>+Jp: jp.example.com/index.html Note over Jp: Changes asset links Jp-->>-Project: index.html Project-->>-User: index.html User->>+Project: example.com/pt/index.html Project->>+Pt: pt.example.com/index.html Note over Pt: Changes asset links Pt-->>-Project: index.html Project-->>-User: index.html ``` ###### Large projects This architecture makes the router of a single project into the central element of your app. This setup may make scaling more difficult as the router scales with the size of that project. The router can become a bottleneck for all external sites and acts as a single point of failure. For larger projects, you should handle multiple websites with the same base URL via a [CDN](https://docs.upsun.com../domains/cdn.md). ### Redirects Managing redirection rules is a common requirement for web applications, especially in cases where you do not want to lose incoming links that have changed or been removed over time. You can manage redirection rules on your Upsun projects in two different ways, which we describe here. If neither of these options satisfy your redirection needs, you can still implement redirects directly from within your application, which if implemented with the appropriate caching headers would be almost as efficient as using the configuration options provided by Upsun. ##### Whole-route redirects Using whole-route redirects, you can define very basic routes in your [`.upsun/config.yaml`](https://docs.upsun.com/define-routes.md) file whose sole purpose is to redirect. A typical use case for this type of route is adding or removing a `www.` prefix to your domain, as the following example shows: ```yaml {location=".upsun/config.yaml"} routes: https://{default}/: type: redirect to: https://www.{default}/ ``` The default HTTP status code for Whole-route redirects is `301`. See [Specify a HTTP status code](#specify-a-http-status-code) to change the status code that is used. ##### Partial redirects In the [`.upsun/config.yaml`](https://docs.upsun.com/define-routes.md) file you can also add partial redirect rules to existing routes: ```yaml {location=".upsun/config.yaml"} routes: https://{default}/: # ... redirects: expires: 1d paths: '/from': to: 'https://example.com/' '^/foo/(.*)/bar': to: 'https://example.com/$1' regexp: true ``` This format is richer and works with any type of route, including routes served directly by the application. The default HTTP status code for partial redirects is `302`. See [Specify a HTTP status code](#specify-a-http-status-code) to change the status code that is used. Two keys are available under `redirects`: | Key | Required | Description | | ------------------ | -------- | ----------- | | `expires` | No | The duration the redirect is cached. Examples of valid values include `3600s`, `1d`, `2w`, `3m`. To disable caching for all your redirects, set `expires` to `0`. You can also [disable caching on a specific redirect](#disable-caching-on-your-redirects). | | `paths` | Yes | The paths to be redirected | Each rule under `paths` is defined by a key describing: - The expression to match against the request path - A value object describing both the destination to redirect to, with detail on how to handle the redirection The value object is defined with the following keys: | Key | Required | Default | Description | | ------------------ | -------- | ----------- |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `to` | Yes | n/a | A relative URL - `'/destination'`, or absolute URL - `'https://example.com/'`. | | `regexp` | No | `false` | Specifies whether the path key should be interpreted as a PCRE regular expression. If you use a capturing group, the replace field (`$1`) has to come after a slash (`/`). [More information](#redirects-using-regular-expressions). | | `prefix` | No | `true`, but not supported if `regexp` is `true` | Specifies whether both the path and all its children or just the path itself should be redirected. [More information](#redirects-using-prefix-and-append_suffix). | | `append_suffix` | No | `true`, but not supported if `regexp` is `true` or if `prefix` is `false` | Determines if the suffix is carried over with the redirect. [More information](#redirects-using-prefix-and-append_suffix). | | `code` | No | n/a | HTTP status code. Valid status codes are `301`, `302`, `307`, and `308`. Defaults to `302` for [Partial redirects](#partial-redirects), and `301` for [Whole-route redirects](#whole-route-redirects). [More information](#specify-a-http-status-code). | | `expires` | No | Defaults to the `expires` value defined directly under the `redirects` key, but can be fine-tuned. To [disable caching on a specific redirect](#disable-caching-on-your-redirects), set `expires` to `0`. | The duration the redirect is cached for. [More information](#manage-caching). To set up partial redirects, you can use regular expressions (`regexp`). Alternatively, and in many cases, you can use the `prefix` and/or `append_suffix` keys to achieve the same results. Here are some examples to illustrate this and help you choose a method for your partial redirects: It achieves the same result as this basic redirect: ```yaml {} '/from': to: https://example.com/to ``` Consider this redirect using ``prefix``: ```yaml {} '/from': to: https//example.com/to prefix: false ``` It achieves the same result as this ``regexp`` redirect: ```yaml {} '^/from$': regexp: true to: https://example.com/to ``` Consider this redirect using ``append_suffix``: ```yaml {} '/from': to: https//example.com/to append_suffix: false ``` It achieves the same result as this ``regexp`` redirect: ```yaml {} '^/from(/.*|)$': regexp: true to: https://example.com/to ``` **Warning**: If you’re using ``regexp`` in a redirect, you can’t also use ``prefix`` and ``append_suffix``. Likewise, if you’re using ``prefix`` and ``append_suffix``, you can’t also use ``regexp``. ###### Redirects using regular expressions You can use regular expressions to configure your redirects. In the following example, a request to `https://example.com/foo/a/b/c/bar` redirects to `https://example.com/a/b/c`: ```yaml {location=".upsun/config.yaml"} routes: https://{default}/: type: upstream # ... redirects: paths: '^/foo/(.*)/bar': to: 'https://example.com/$1' regexp: true ``` The following special arguments in the `to` statement are available when `regexp` is set to `true`: - `$is_args` evaluates to `?` or empty string - `$args` evaluates to the full query string if any - `$arg_foo` evaluates to the value of the query parameter `foo` - `$uri` evaluates to the full URI of the request. ###### Redirects using `prefix` and `append_suffix` Instead of using regular expressions to configure your redirects, you might want to use the `prefix` and `append_suffix` keys. **Warning**: If you’re using ``regexp`` in a redirect, you can’t also use ``prefix`` and ``append_suffix``. Likewise, if you’re using ``prefix`` and ``append_suffix``, you can’t also use ``regexp``. When set to `true`, which is their default value, `prefix` and `append_suffix` are equivalent. For example: ```yaml {} routes: https://{default}/: type: upstream # ... redirects: paths: '/from': to: 'https://{default}/to' prefix: true ``` ```yaml {} routes: https://{default}/: type: upstream # ... redirects: paths: '/from': to: 'https://{default}/to' append_suffix: true ``` With both configurations: - `/from` redirects to `/to` - `/from/some/path` redirects to `/to/some/path` However, when set to `false`, `prefix` and `append_suffix` behave differently. For example, with the following configuration: ```yaml routes: https://{default}/: type: upstream # ... redirects: paths: '/from': to: 'https://{default}/to' prefix: true ``` A request to `/from/` redirects to `/to/some/path`, but a request to `/from/some/path` does not. And with the following configuration: ```yaml routes: https://{default}/: type: upstream # ... redirects: paths: '/from': to: 'https://{default}/to' append_suffix: false ``` A request to `/from/some/path` (and any path after `/from`) redirects to just `/to`. ###### Specify a HTTP status code To set a specific HTTP status code for your redirect, use the `code` key: ```yaml routes: https://{default}/: type: upstream # ... redirects: paths: '/from': to: 'https://example.com/' code: 308 '/here': to: 'https://example.com/there' ``` In this example, redirects from `/from` use a `308` HTTP status code, while redirects from `/here` default to `302` ("found", as long as the resource is indeed found as a result from the redirect). ###### Manage caching You can [set an expiration time on your redirects](#set-an-expiration-time-on-your-redirects) or even [disable caching](#disable-caching-on-your-redirects) on them. ####### Set an expiration time on your redirects You can specify how long you want your redirects to be cached for. To do so, use the `expires` key under the `redirects` key. In the following example, all redirects are cached for two weeks: ```yaml routes: https://{default}/: type: upstream # ... redirects: expires: 2w paths: '/from': to: 'https://example.com/' '/here': to: 'https://example.com/there' ``` If you want to set a different expiration time for a specific redirect, use the same `expires` key, but under the `paths` key. In the following example: - The first redirect uses the default expiration time set on all redirects and is cached for two weeks - The second redirect ignores the default expiration time set on all redirects, and is cached for three days instead ```yaml routes: https://{default}/: type: upstream # ... redirects: expires: 2w paths: '/from': to: 'https://example.com/' '/here': to: 'https://example.com/there' expires: 3d ``` **Note**: You can set an expiration time on a specific redirect (under the ``paths`` key) even if you haven’t defined a default expiration time on all your redirects (under the ``redirects`` key). The expiration time you set on a specific redirect (under the ``paths`` key) overwrites any default expiration time you may have set on all your redirects (under the ``redirects`` key). ####### Disable caching on your redirects To disable caching on all your redirects, set the `expires` key to `0` under the `redirects` key: ```yaml routes: https://{default}/: type: upstream # ... redirects: expires: 0 paths: '/from': to: 'https://example.com/' '/here': to: 'https://example.com/there' ``` To disable caching on a specific redirect only, set the `expires` key to `0` under the relevant path in the `paths` section. In the following example, caching is disabled on the second redirect only: ```yaml routes: https://{default}/: type: upstream # ... redirects: paths: '/from': to: 'https://example.com/' '/here': to: 'https://example.com/there' expires: 0 ``` ##### Other redirects ###### Application-driven redirects If neither whole-route or partial redirects satisfy your redirection needs, you can still implement redirects directly in your application. If sent with the appropriate caching headers, this is nearly as efficient as implementing the redirect through one of the two configurations described above. Implementing application-driven redirects depends on your own code or framework and is beyond the scope of this documentation. ###### Query-strings based redirects Upsun **does not** support redirects based on query strings. If you want to redirect based on query strings, this logic has to be implemented by your application. ### Resource initialization When you first deploy your project or add a new container to it, Upsun uses [default resources](#default-resources) unless you specify a [resource initialization strategy](#specify-a-resource-initialization-strategy). You can also use a specific resource initialization strategy when performing certain actions, such as [branching](#environment-branch), [merging](#environment-merge), and [activating](#environment-activation) an environment, or [restoring a backup](#backup-restoration). ##### Default resources Upsun allocates the following default resources to every container when deployed for the first time: | Resource type | Amount | | --------------------------- | ----------- | | CPU | 0.5 | | RAM | Depends on the [container profile](https://docs.upsun.com/manage-resources/adjust-resources.md#advanced-container-profiles). | | Disk size (only applicable if the app or service requires a disk) | 512 MB | If you don't want to use these default resources, you can specify a [resource initialization strategy](https://docs.upsun.com/manage-resources/resource-init.md#specify-a-resource-initialization-strategy). You can also [adjust resources](https://docs.upsun.com/manage-resources/adjust-resources.md) after your project or new container has been deployed. **Note**: For information on costs related to resource usage, see the [Upsun pricing page](https://upsun.com/pricing/). You can [monitor these costs](https://docs.upsun.com/administration/billing/monitor-billing.md) in the Console. ##### Specify a resource initialization strategy Upsun provides the following resource initialization strategies: | Strategy | Description | | ---------| ----------- | | `default` | Initializes new containers using the [Upsun default resources](#default-resources). This strategy applies when you first deploy your project (or new container) unless you explicitly specify a different strategy, or allocate resources manually via the `resources:set` CLI command. | | `manual` | With this strategy, the first deployment fails and you need to configure resources manually through [the Console](https://console.upsun.com/), or using `resources:set` in the CLI. This strategy allows you to set the exact resources you want, with a single deployment. Other strategies may require fine-tuning, and therefore generate a second deployment. In this case, your environment would run for a short time with unwanted resources, and both deployments would generate downtime.| | `minimum` | Initializes new containers using the Upsun minimum resources (see below). | | `parent` | Initializes new containers using the same resources as on the parent environment. If there is no parent environment, or if the container doesn't already exist on the parent, the `default` strategy applies instead. | | `child` | Initializes new containers using the same resources as on the child environment. Only relevant during merge activities. | | `backup` | When restoring a backup, initializes new containers using the same resources as when the backup was taken. | **More information on…**: **Upsun minimum resources** The following table shows the resources Upsun allocates to your containers when you opt for the ``minimum`` [resource initialization strategy](#specify-a-resource-initialization-strategy). | Container | CPU | RAM | Disk* | | .NET core | 0.1 | 64 MB | 0 MB | | Chrome Headless | 0.1 | 64 MB | None | | Elasticsearch | 0.1 | 448 MB | 256 MB | | Elasticsearch Premium | 0.1 | 448 MB | 256 MB | | Elixir | 0.1 | 64 MB | 0 MB | | Go | 0.1 | 64 MB | 0 MB | | InfluxDB | 0.1 | 448 MB | 256 MB | | Java | 0.1 | 448 MB | 0 MB | | Kafka | 0.1 | 448 MB | 512 MB | | Lisp | 0.1 | 64 MB | 0 MB | | MariaDB | 0.1 | 448 MB | 256 MB | | Memcached | 0.1 | 352 MB | None | | MongoDB | 0.1 | 448 MB | 256 MB | | MongoDB Premium | 0.1 | 448 MB | 256 MB | | Network Storage | 0.1 | 448 MB | 256 MB | | Node.js | 0.1 | 64 MB | 0 MB | | OpenSearch | 0.1 | 448 MB | 256 MB | | Oracle MySQL | 0.1 | 448 MB | 256 MB | | PHP | 0.1 | 64 MB | 0 MB | | PostgreSQL | 0.1 | 448 MB | 256 MB | | Python | 0.1 | 64 MB | 0 MB | | RabbitMQ | 0.1 | 448 MB | 256 MB | | Redis ephemeral | 0.1 | 352 MB | None | | Redis persistent | 0.1 | 352 MB | 256 MB | | Ruby | 0.1 | 64 MB | 0 MB | | Rust | 0.1 | 64 MB | 0 MB | | Solr | 0.1 | 448 MB | 256 MB | | Varnish | 0.1 | 448 MB | None | | Vault KMS | 0.1 | 448 MB | 256 MB | * The disk size is set to ``None`` when the container never uses disk, and to ``0 MB`` when the container doesn’t require disk but can use it. You can specify a resource initialization strategy when performing the following actions: | Action | Available strategies | Default | |-----------------------------------------------------------------------|------------------------------------------|----------| | [First deployment](#first-deployment) | `parent`, `default`, `minimum`, `manual` | `parent` | | [Environment branch](#environment-branch) | `parent`, `default`, `minimum` | `parent` | | [Environment merge](#environment-merge) | `child`, `default`, `minimum`, `manual` | `child` | | [Environment activation](#environment-activation) | `parent`, `default`, `minimum` | `parent` | | [Backup restoration](#backup-restoration) | `backup`, `parent`, `default`, `minimum` | `backup` | ###### First deployment **Resource initialization strategies**: Available: ``parent``, ``default``, ``minimum``, ``manual`` Default: ``parent`` You can define [which resource initialization strategy](#specify-a-resource-initialization-strategy) Upsun uses to allocate resources when you first deploy your project or add a new container. For example, to use the ``minimum`` strategy for your deployment, run the following command: ```bash {location="Terminal"} upsun push --resources-init=minimum ``` **Note**: Alternatively, you can use the official Git syntax for [push options](https://docs.upsun.com/environments.md#push-options): ```bash {location="Terminal"} git push upsun -o resources.init=minimum ``` Note that you can specify a different resource initialization strategy for each of your deployments. If you’re using a [source integration](https://docs.upsun.com/integrations.md), you can use the ``--resources-init`` flag to specify a resource initialization strategy. **Note**: Once a resource initialization strategy is specified for your source integration, it applies to **all** the deployments you launch through that source integration. To specify a resource initialization strategy when [creating your source integration](https://docs.upsun.com/integrations/source.md), include the ``--resources-init`` flag in your source integration options. For example, if you [set up a GitHub integration](https://docs.upsun.com/integrations/source/github.md), use the following options: ```bash {location="Terminal"} platform integration:add \ --project \ --type github \ --repository \ --token \ --base-url --resources-init ``` To specify a resource initialization strategy for an existing source integration, run the following command: ```bash {location="Terminal"} upsun integration:update --resources-init= ``` For example, to use the ``minimum`` strategy for your deployment, run the the following command: ```bash {location="Terminal"} upsun integration:update --resources-init=minimum ``` ###### Environment branch **Resource initialization strategies**: Available: ``parent``, ``default``, ``minimum`` Default: ``parent`` By default, when you [branch an environment](https://docs.upsun.com/glossary.md#branch) to create a new child environment, the child environment inherits all the resources from its parent. However, you can specify a different [resource initialization strategy](#specify-a-resource-initialization-strategy). **Note**: When you branch an environment, regardless of the strategy you specified, Upsun checks if the child environment’s disk size is at least equivalent to the parent’s. If not, the parent environment’s disk size is automatically applied to the child environment. This ensures the branching can succeed. For example, to use the ``minimum`` resource initialization strategy, run the following command: ```bash {location="Terminal"} upsun environment:branch --resources-init=minimum ``` - Navigate to the environment you want to branch from. - Click Branch **Branch**. - Enter a name and a type for the new environment. - Select an initialization strategy from the proposed list. - Click **Branch**. ###### Environment merge **Resource initialization strategies**: Available: ``child``, ``default``, ``minimum``, ``manual`` Default: ``child`` When you [merge](https://docs.upsun.com/glossary.md#merge) a child environment into its parent environment, any apps and services you created on the child are merged and therefore created on the parent. When this happens, any new app or service container created on the parent environment is granted the same resources as on the child environment. However, you can specify a different resource initialization strategy. **Note**: Any other container already running on the parent environment keeps its resources. For example, to use the ``manual`` resource initialization strategy, run the following command: ```bash {location="Terminal"} upsun environment:merge --resources-init=manual ``` - Navigate to the environment you want to merge into its parent. - Click Merge **Merge**. - Select an initialization strategy from the proposed list. **Note**: The list of strategies is only displayed if a new app or service is included in the merge. - Click **Merge**. ###### Environment activation **Resource initialization strategies**: Available: ``parent``, ``default``, ``minimum`` Default: ``parent`` When you activate an environment, Upsun uses the same resource allocation as on the parent environment. If there is no parent environment, the [`default` resource initialization strategy](#default-resources) applies. You can also specify a different resource initialization strategy using the CLI. To do so, run the following command: ```bash {location="Terminal"} upsun environment:activate --resources-init= ``` For example, to use the `minimum` resource initialization strategy, run the following command: ```bash {location="Terminal"} upsun environment:activate --resources-init=minimum ``` **Note**: [Setting resources](https://docs.upsun.com/manage-resources/adjust-resources.md) on a inactive environment using the Console or the CLI automatically activates it. ###### Backup restoration **Resource initialization strategies**: Available: ``backup``, ``parent``, ``default``, ``minimum`` Default: ``backup`` For example, to use the ``minimum`` resource initialization strategy, run the following command: ```bash {location="Terminal"} upsun backup:restore --resources-init=minimum ``` When you [restore a backup](https://docs.upsun.com/environments/restore.md) using the Console, it is restored to your current environment. The resources of every container already running on the environment are reverted to their original state when the backup was taken. **Note**: If you don’t want to restore the resources from when the backup was taken, opt out of restoring the resources. To do so, when you restore your backup, use the ``--no-resources`` option. If you deleted containers after backing up but before restoring, they are recreated using the ``backup`` strategy. Meaning, they are granted the same resources as in the backup. **Note**: If you don’t want to restore previously deleted containers, opt out of restoring the code. To do so, restore the backup using the CLI, and use the ``--no-code`` option. ##### Environment sync [Syncing an environment](https://docs.upsun.com/glossary.md#sync) means merging changes from a parent environment into a child environment. You can sync: - Only the code - Only the data (databases, files) - Only the resources (CPU and RAM, instances, and disk space) - Any combination of the three (code and data, data and resources, etc.) **Note**: When you sync the data, Upsun checks if the child environment’s disk size is at least equivalent to the parent’s. If not, the parent environment’s disk size is automatically applied to the child environment. This ensures the sync can succeed. - Sync only code: ```bash {location="Terminal"} upsun sync code ``` - Sync only data: ```bash {location="Terminal"} upsun sync data ``` - Sync everything: ```bash {location="Terminal"} upsun sync code data resources ``` You can adjust the command depending on the exact combination of elements you want to sync. - Navigate to your Production environment. - Click **Sync**. - Select the sync options you want from the proposed list. - Select **Sync resources from Production into Staging**. - Click **Sync**. ### Resource configuration When you first deploy your project, or add a new app or service to it, Upsun allocates [default resources](https://docs.upsun.com/manage-resources/resource-init.md#default-resources) to each of your containers. If you don't want to use those default resources, define a different [resource initialization strategy](https://docs.upsun.com/manage-resources/resource-init.md#specify-a-resource-initialization-strategy). After the initial deployment, or if you opt for the `Manual` [resource initialization strategy](https://docs.upsun.com/manage-resources/resource-init.md#specify-a-resource-initialization-strategy), you can adjust container resources manually. To do so, follow the instructions on this page. Upsun allows you to configure resources (CPU, RAM, and disk) per environment for each app and service. You can also add instances for each app depending on your needs. For example, you can scale vertically and allocate more resources to your production and staging environments than to your development environments. This flexibility allows you to optimize performance and costs. You can also scale horizontally if your apps are struggling with high load, or if you're expecting a traffic spike, by adding more instances for your apps and workers. **Note**: For information on costs related to resource usage, see the [Upsun pricing page](https://upsun.com/pricing/). You can [monitor these costs](https://docs.upsun.com/administration/billing/monitor-billing.md) in the Console. ##### Vertical scaling To define how much CPU, RAM, and disk storage you want to allocate to each individual container, follow these steps: Example 2: The following command allocates ``640 MB`` of disk to the ``backend`` app, and ``2048 MB`` to the ``database`` service: ```bash {location="Terminal"} upsun resources:set --disk backend:640,database:2048 ``` Example 3: You can also use wildcards. For example, if you have two apps named ``frontend`` and ``backend``, you could allocate the same CPU and RAM combination to both by using the following command: ```bash {location="Terminal"} upsun resources:set --size '*end:0.1' ``` - Open your project. - Click the **Configure resources** button in the project card or the **App & Services** panel: ![Project card](https://docs.upsun.com/images/flexible-resources/configure-button-project-card.png) - For each app and service, select a CPU & RAM combination, and enter the amount of disk/storage you want to allocate. ![Configure your resources on the current environment window](https://docs.upsun.com/images/flexible-resources/configure-flexible-resources.png) **Note**: The values from the **CPU & RAM** menu depend on the [container profile](#advanced-container-profiles) of each instance. If you deploy several instances of your app, the selected CPU & RAM combination isn’t divided between those instances. Each instance benefits from the full, selected CPU & RAM. - Click **Save**. You environment is redeployed, which causes a short downtime. ##### Horizontal scaling For apps and workers, you can also define how many instances you want to deploy. To do so, follow these steps: **Note**: When you have several instances of an app, the Upsun router randomly distributes requests to available instances. For example, to scale your ``myapp`` app to 3 instances, run the following command: ```bash {location="Terminal"} upsun resources:set --count myapp:3 ``` You can also set the same instance count for all your apps using a wildcard. To do so, run the following command: ```bash {location="Terminal"} upsun resources:set --count '*:' ``` For example, to scale all your apps to 3 instances, run the following command: ```bash {location="Terminal"} upsun resources:set --count '*:3' ``` **Note**: For further guidance on how to set resources using the CLI, run the ``upsun resources:set --help`` command. After you’ve set the number of instances for your apps and workers, your environment is redeployed. If you’ve made no other changes, this redeployment causes no downtime. If the redeployment fails after you’ve run ``upsun resources:set``, you may need to set the resources again. - Open your project. - Click the **Configure resources** button in the project card or the **App & Services** panel: ![Project card](https://docs.upsun.com/images/flexible-resources/configure-button-project-card.png) - For each of your apps and workers, select the number of instances you want to deploy. ![Configure your resources on the current environment window](https://docs.upsun.com/images/flexible-resources/configure-flexible-resources.png) **Note**: If you deploy several instances of your app, the [selected CPU & RAM combination](#vertical-scaling) isn’t divided between those instances. Each instance benefits from the full, selected CPU & RAM. - Click **Save**. Your environment is redeployed. If you’ve only made changes to the number of instances for your apps and workers, this redeployment causes no downtime. ##### Advanced: Container profiles By default, Upsun allocates a container profile to each app and service depending on the range of resources it's expected to need. Each container profile gives you access to a specific list of CPU and RAM combinations. Using the Upsun CLI or Console, you can then pick a CPU and RAM combination for each of your apps and services. There are four container profiles available: `HIGH_CPU`, `BALANCED`, `HIGH_MEMORY`, and `HIGHER_MEMORY`. The following table displays the different CPU and RAM combinations each container profile provides: | CPU | `HIGH_CPU` | `BALANCED` | `HIGH_MEMORY` | `HIGHER_MEMORY` | | ---- | ------------ | ---------- | ------------- | --------------- | | 0.1 | 64 MB | 352 MB | 448 MB | 864 MB | | 0.25 | 128 MB | 640 MB | 832 MB | 1472 MB | | 0.5 | 224 MB | 1088 MB | 1408 MB | 2368 MB | | 1 | 384 MB | 1920 MB | 2432 MB | 3840 MB | | 2 | 704 MB | 2800 MB | 4032 MB | 6336 MB | | 4 | 1216 MB | 4800 MB | 6720 MB | 10496 MB | | 6 | 1728 MB | 6080 MB | 9024 MB | 14080 MB | | 8 | 2240 MB | 7296 MB | 11200 MB | 17408 MB | You can check which container profile is set for an app or service in your project from the Console. To do so, navigate to your environment and select the app or service in the tree on the left-hand side: ![Apps and services tree](https://docs.upsun.com/images/flexible-resources/check-container-profile.png "0.25") For information on resource-related costs, see the [Upsun pricing page](https://upsun.com/pricing/). ###### Default container profiles The following table shows the default container profiles Upsun applies when first deploying your project. | Container | Default profile | |-------------------------|------------------| | Chrome Headless | HIGH_CPU | | ClickHouse | HIGH_MEMORY | | .NET | HIGH_CPU | | Elasticsearch | HIGH_MEMORY | | Elasticsearch Premium | HIGH_MEMORY | | Elixir | HIGH_CPU | | Go | HIGH_CPU | | Gotenberg | HIGH_MEMORY | | InfluxDB | HIGH_MEMORY | | Java | HIGH_MEMORY | | Kafka | HIGH_MEMORY | | Lisp | HIGH_CPU | | MariaDB | HIGH_MEMORY | | Memcached | BALANCED | | MongoDB | HIGH_MEMORY | | MongoDB Premium | HIGH_MEMORY | | Network Storage | HIGH_MEMORY | | NodeJS | HIGH_CPU | | OpenSearch | HIGH_MEMORY | | Oracle Java | HIGH_MEMORY | | Oracle MySQL | HIGH_MEMORY | | PHP | HIGH_CPU | | PostgreSQL | HIGH_MEMORY | | Python | HIGH_CPU | | RabbitMQ | HIGH_MEMORY | | Redis ephemeral | BALANCED | | Redis persistent | BALANCED | | Ruby | HIGH_CPU | | Rust | HIGH_CPU | | Solr | HIGH_MEMORY | | Varnish | HIGH_MEMORY | | Vault KMS | HIGH_MEMORY | ###### Adjust a container profile In most cases, it's best not to adjust container profiles. As a best practice, Upsun recommends adjusting the profile of a container **only if the CPU/RAM ratio doesn’t match how the container scales**, taking into account both production and preview (staging and development) environments. To adjust a container profile, amend the value of the `container_profile` key in your configuration: ```yaml {location=".upsun/config.yaml"} applications: : container_profile: HIGH_MEMORY services: : type: : container_profile: HIGHER_MEMORY ``` ### Project build resources When you push changes through Git, your applications are first built, then deployed. During the build process, Upsun creates a build image for each of your application, as a dedicated build container, and runs your build hooks inside that build container. The duration of the build process is directly linked to the amount of resources (CPU and RAM) allocated to that build container. Every Upsun project includes a fixed amount of build resources per month: - 2.5 hours of build CPU - 5 hours of build memory You can adjust the amount of build resources that a project can use. - Run the following command: ```bash {} upsun resources:build:set ``` - Enter the amount of CPU. - Enter the amount of RAM. Additional build resources (CPU and RAM) are billed by the hour. For more information on the costs incurred, see the [Upsun pricing page](https://upsun.com/pricing/). **Note**: Make sure that your build process supports using extra build resources. Otherwise, the duration of your builds will remain the same despite adding more resources. ### C#/.NET Core p:last-child]:mb-0 [&>h3]:mt-0 rounded-lg" > ###### Note You can now use composable image (BETA) to install runtimes and tools in your application container. To find out more, see the [dedicated documentation page](https://docs.upsun.com/create-apps/app-reference/composable-image.md). Upsun supports deploying .NET applications by allowing developers to define a build process and pass its variables to the .NET Core build environment. ##### Supported versions You can select the major and minor version. Patch versions are applied periodically for bug fixes and the like. When you deploy your app, you always get the latest available patches. - 7.0 - 6.0 - 8.0 ###### Specify the language To use .Net Core, specify `dotnet` as your [app's `type`](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#types): ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. : type: 'dotnet:' ``` For example: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'dotnet:8.0' ``` ##### Building the application To build basic applications in .NET containers, it's enough to use the [`dotnet publish` command](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-publish) with the default [framework-dependent deployment](https://docs.microsoft.com/en-us/dotnet/core/deploying/#publish-framework-dependent): ```yaml {location=".upsun/config.yaml"} applications: myapp: type: 'dotnet:8.0' hooks: build: | set -xe dotnet publish --output "$PLATFORM_OUTPUT_DIR" \ -p:UseRazorBuildServer=false \ -p:UseSharedCompilation=false ``` where `PLATFORM_OUTPUT_DIR` is the output directory for compiled languages available at build time. Typically, .NET Core builds start a collection of build servers, which are helpful for repeated builds. On Upsun, however, if this process isn't disabled, the build process doesn't finish until the idle timeout is reached. As a result, you should include `-p` toggles that disable the Razor compiler for dynamic CSHTML pages (`UseRazorBuildServer`) and the .NET MSBuild compiler (`UseSharedCompilation`). If you want multiple builds for your application, make sure to call `dotnet build-server shutdown` at the end of your build hook. ##### Running the application .NET Core applications should be started using the `web.commands.start` directive in `.upsun/config.yaml`. This ensures that the command starts at the right moment and stops gracefully when a redeployment needs to be executed. Also, should the program terminate for any reason, it's automatically restarted. Note that the start command _must_ run in the foreground. Incoming requests are passed to the application using either a TCP (default) or Unix socket. The application must use the [appropriate environment variable](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#where-to-listen) to determine the URI to listen on. For a TCP socket ([recommended](https://go.microsoft.com/fwlink/?linkid=874850)), the application must listen on `http://127.0.0.1`, using the `PORT` environment variable. There is an Nginx server sitting in front of your application. Serving static content via Nginx is recommended, as this allows you to control headers (including cache headers) and also has marginal performance benefits. Note that HTTPS is also terminated at the Nginx proxy, so the `app.UseHttpsRedirection();` line in `Startup.cs` should be removed. To force HTTPS-only, refer to the [routes documentation](https://docs.upsun.com../define-routes/https.md#enable-https). The following example configures an environment to serve the static content folders commonly found in [ASP.NET MVC](https://dotnet.microsoft.com/apps/aspnet/mvc) templates using Nginx, while routing other traffic to the .NET application. ```yaml {location=".upsun/config.yaml"} applications: myapp: type: 'dotnet:8.0' web: locations: "/": root: "wwwroot" allow: true passthru: true rules: # Serve these common asset types with customs cache headers. \.(jpe?g|png|gif|svgz?|css|js|map|ico|bmp|eot|woff2?|otf|ttf)$: allow: true expires: 300s commands: start: "dotnet WebApplication1.dll" ``` You can also route all requests to the application unconditionally: ```yaml {location=".upsun/config.yaml"} applications: myapp: type: 'dotnet:8.0' web: locations: "/": allow: false passthru: true commands: start: "dotnet WebApplication1.dll" ``` ### Elixir p:last-child]:mb-0 [&>h3]:mt-0 rounded-lg" > ###### Note You can now use composable image (BETA) to install runtimes and tools in your application container. To find out more, see the [dedicated documentation page](https://docs.upsun.com/create-apps/app-reference/composable-image.md). Upsun supports building and deploying applications written in Elixir. There is no default flavor for the build phase, but you can define it explicitly in your build hook. Upsun Elixir images support both committed dependencies and download-on-demand. The underlying Erlang version is 22.0.7. ##### Supported versions You can select the major and minor version. Patch versions are applied periodically for bug fixes and the like. When you deploy your app, you always get the latest available patches. - 1.18 - 1.15 - 1.14 ###### Specify the language To use Elixir, specify `elixir` as your [app's `type`](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#types): ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. : type: 'elixir:' ``` For example: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'elixir:1.18' ``` ##### Built-in variables Upsun exposes relationships and other configuration as [environment variables](https://docs.upsun.com../development/variables.md). Most notably, it allows a program to determine at runtime what HTTP port it should listen on and what the credentials are to access [other services](https://docs.upsun.com../add-services.md). To get the `PORT` environment variable (the port on which your web application is supposed to listen) you would: ```elixir String.to_integer(System.get_env("PORT") || "8888") ``` Some of the environment variables are in JSON format and are base64 encoded. You would need to import a JSON parsing library such as [JSON](https://hexdocs.pm/json/readme.md) or [Poison](https://hexdocs.pm/poison/api-reference.md) to read those. (There is an example for doing this to decode the `PLATFORM_RELATIONSHIPS` environment variable in the section [below](#accessing-services-manually).) **Tip**: Remember ``config/prod.exs`` is evaluated at **build time** and has no access to runtime configuration. Use ``config/releases.exs`` to configure your runtime environment. ##### Building and running the application If you are using Hex to manage your dependencies, you need to specify the `MIX_ENV` environment variable: ```yaml {location=".upsun/config.yaml"} applications: myapp: type: 'elixir:1.18' variables: env: MIX_ENV: 'prod' ``` The `SECRET_KEY_BASE` variable is generated automatically based on the [`PLATFORM_PROJECT_ENTROPY` variable](https://docs.upsun.com../development/variables/use-variables.md#use-provided-variables). You can change it. Include in your build hook the steps to retrieve a local Hex and `rebar`, and then run `mix do deps.get, deps.compile, compile` on your application to build a binary. ```yaml {location=".upsun/config.yaml"} applications: myapp: type: 'elixir:1.18' hooks: build: | mix local.hex --force mix local.rebar --force mix do deps.get --only prod, deps.compile, compile ``` **Note**: That build hook works for most cases and assumes that your ``mix.exs`` file is located at [your app root](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#root-directory). Assuming `mix.exs` is present at your app root and your build hook matches the above, you can then start it from the `web.commands.start` directive. The following basic app configuration is sufficient to run most Elixir applications. ```yaml {location=".upsun/config.yaml"} applications: myapp: type: 'elixir:1.18' variables: env: MIX_ENV: 'prod' hooks: build: | mix local.hex --force mix local.rebar --force mix do deps.get --only prod, deps.compile, compile web: commands: start: mix phx.server locations: /: allow: false passthru: true ``` Note that there is still an Nginx proxy server sitting in front of your application. If desired, certain paths may be served directly by Nginx without hitting your application (for static files, primarily) or you may route all requests to the Elixir application unconditionally, as in the example above. ##### Dependencies The recommended way to handle Elixir dependencies on Upsun is using Hex. You can commit a `mix.exs` file in your repository and the system downloads the dependencies in your `deps` section using the build hook above. ```elixir defp deps do [ {:platformshconfig, "~> 0.1.0"} ] end ``` ##### Accessing Services You can access service credentials to connect to [managed services](https://docs.upsun.com/add-services/) from environment variables present in the application container. Consult each of the individual service documentation to see how to retrieve and surface credentials into your application. - [ClickHouse](https://docs.upsun.com/add-services/clickhouse.md#usage-example) - [Elasticsearch](https://docs.upsun.com/add-services/elasticsearch.md#use-in-app) - [Gotenberg](https://docs.upsun.com/add-services/gotenberg.md#usage-example) - [Headless Chrome](https://docs.upsun.com/add-services/headless-chrome.md#use-in-app) - [InfluxDB](https://docs.upsun.com/add-services/influxdb.md#use-in-app) - [Kafka](https://docs.upsun.com/add-services/kafka.md#use-in-app) - [MariaDB/MySQL](https://docs.upsun.com/add-services/mysql.md#use-in-app) - [Memcached](https://docs.upsun.com/add-services/memcached.md#use-in-app) - [MongoDB](https://docs.upsun.com/add-services/mongodb.md#use-in-app) - [Network Storage](https://docs.upsun.com/add-services/network-storage.md#usage-example) - [OpenSearch](https://docs.upsun.com/add-services/opensearch.md#use-in-app) - [PostgreSQL](https://docs.upsun.com/add-services/postgresql.md#use-in-app) - [RabbitMQ](https://docs.upsun.com/add-services/rabbitmq.md#use-in-app) - [Redis](https://docs.upsun.com/add-services/redis.md#use-in-app) - [Solr](https://docs.upsun.com/add-services/solr.md#use-in-app) - [Varnish](https://docs.upsun.com/add-services/varnish.md#usage-example) - [Vault KMS](https://docs.upsun.com/add-services/vault.md#use-vault-kms) ###### Accessing Services Manually The services configuration is available in the environment variable `PLATFORM_RELATIONSHIPS`. Given a [relationship](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships) defined in `.upsun/config.yaml`: ```yaml {location=".upsun/config.yaml"} applications: myapp: type: 'elixir:1.18' [...] # Relationships enable an app container's access to a service. # The example below shows simplified configuration leveraging a default service # (identified from the relationship name) and a default endpoint. # See the Application reference for all options for defining relationships and endpoints. relationships: postgresql: ``` Assuming you have in `mix.exs` the Poison library to parse JSON: ```elixir defp deps do [ {:poison, "~> 3.0"} ] end ``` And assuming you use `ecto` you could put in `config/config.exs`: ```elixir relationships = Poison.decode!(Base.decode64!(System.get_env("PLATFORM_RELATIONSHIPS"))) [postgresql_config | _tail] = relationships["postgresql"] config :my_app, Repo, database: postgresql_config["path"], username: postgresql_config["username"], password: postgresql_config["password"], hostname: postgresql_config["host"] ``` and setup Ecto during the deploy hook: ```yaml {location=".upsun/config.yaml"} applications: myapp: hooks: deploy: | mix do ecto.setup ``` ### Go p:last-child]:mb-0 [&>h3]:mt-0 rounded-lg" > ###### Note You can now use composable image (BETA) to install runtimes and tools in your application container. To find out more, see the [dedicated documentation page](https://docs.upsun.com/create-apps/app-reference/composable-image.md). Upsun supports building and deploying applications written in Go using Go modules. They’re compiled during the Build hook phase, and support both committed dependencies and download-on-demand. ##### Supported versions You can select the major and minor version. Patch versions are applied periodically for bug fixes and the like. When you deploy your app, you always get the latest available patches. - 1.23 - 1.22 - 1.21 - 1.20 ###### Specify the language To use Go, specify `golang` as your [app's `type`](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#types): ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. : type: 'golang:' ``` For example: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'golang:1.23' ``` ###### Deprecated versions The following versions are [deprecated](https://docs.upsun.com/glossary.md#deprecated-versions). They're available, but they aren't receiving security updates from upstream and aren't guaranteed to work. They'll be removed in the future, so migrate to one of the [supported versions](#supported-versions). - 1.19 - 1.18 - 1.17 - 1.16 - 1.15 - 1.14 - 1.13 - 1.12 - 1.11 - 1.10 - 1.9 - 1.8 ##### Go toolchain auto download Even though you select a specific version of Go, starting in Go 1.21, the `go` command will automatically download and use a different toolchain version as requested by the `toolchain` directive in `go.mod`, or the `GOTOOLCHAIN` environmental variable (see [Go Toolchains](https://go.dev/doc/toolchain)). **Note**: Still, it is important to keep your chosen version of Go updated in your yaml configuration file. This will ensure that you are using the most up to date software for your projects. ##### Go modules The recommended way to handle Go dependencies on Upsun is using Go module support in Go 1.11 and later. That allows the build process to use `go build` directly without any extra steps, and you can specify an output executable file of your choice. (See the examples below.) ##### Building and running the application Assuming your `go.mod` and `go.sum` files are present in your repository, your application can be built with the command `go build`, to produce a working executable. You can then start it from the `web.commands.start` directive. Note that the start command _must_ run in the foreground. If the program terminates for any reason it is automatically restarted. The following basic `.upsun/config.yaml` file is sufficient to run most Go applications. ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'golang:1.23' hooks: build: | # Modify this line if you want to build differently or # use an alternate name for your executable. go build -o bin/app web: upstream: socket_family: tcp protocol: http commands: # If you change the build output in the build hook above, update this line as well. start: ./bin/app locations: /: # Route all requests to the Go app, unconditionally. allow: false passthru: true ``` Note that there is still an Nginx proxy server sitting in front of your application. If desired, certain paths may be served directly by Nginx without hitting your application (for static files, primarily) or you may route all requests to the Go application unconditionally, as in the example above. ##### Accessing services To access various [services](https://docs.upsun.com../add-services.md) with Go, see the following examples. The individual service pages have more information on configuring each service. You can access service credentials to connect to [managed services](https://docs.upsun.com/add-services/) from environment variables present in the application container. Consult each of the individual service documentation to see how to retrieve and surface credentials into your application. - [ClickHouse](https://docs.upsun.com/add-services/clickhouse.md#usage-example) - [Elasticsearch](https://docs.upsun.com/add-services/elasticsearch.md#use-in-app) - [Gotenberg](https://docs.upsun.com/add-services/gotenberg.md#usage-example) - [Headless Chrome](https://docs.upsun.com/add-services/headless-chrome.md#use-in-app) - [InfluxDB](https://docs.upsun.com/add-services/influxdb.md#use-in-app) - [Kafka](https://docs.upsun.com/add-services/kafka.md#use-in-app) - [MariaDB/MySQL](https://docs.upsun.com/add-services/mysql.md#use-in-app) - [Memcached](https://docs.upsun.com/add-services/memcached.md#use-in-app) - [MongoDB](https://docs.upsun.com/add-services/mongodb.md#use-in-app) - [Network Storage](https://docs.upsun.com/add-services/network-storage.md#usage-example) - [OpenSearch](https://docs.upsun.com/add-services/opensearch.md#use-in-app) - [PostgreSQL](https://docs.upsun.com/add-services/postgresql.md#use-in-app) - [RabbitMQ](https://docs.upsun.com/add-services/rabbitmq.md#use-in-app) - [Redis](https://docs.upsun.com/add-services/redis.md#use-in-app) - [Solr](https://docs.upsun.com/add-services/solr.md#use-in-app) - [Varnish](https://docs.upsun.com/add-services/varnish.md#usage-example) - [Vault KMS](https://docs.upsun.com/add-services/vault.md#use-vault-kms) ### Java p:last-child]:mb-0 [&>h3]:mt-0 rounded-lg" > ###### Note You can now use composable image (BETA) to install runtimes and tools in your application container. To find out more, see the [dedicated documentation page](https://docs.upsun.com/create-apps/app-reference/composable-image.md). Java is a general-purpose programming language, and one of the most popular in the world today. Upsun supports Java runtimes that can be used with build management tools such as Gradle, Maven, and Ant. ##### Supported versions You can select the major version. But the latest compatible minor version is applied automatically and can’t be overridden. Patch versions are applied periodically for bug fixes and the like. When you deploy your app, you always get the latest available patches. ###### OpenJDK versions: - 21 - 19 - 18 - 17 - 11 - 8 These versions refer to the headless packages of OpenJDK. To save space and reduce potential vulnerabilities, they don't contain GUI classes, which can't be used on the server. ###### Specify the language To use Java, specify `java` as your [app's `type`](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#types): ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. : type: 'java:' ``` For example: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'java:21' ``` ##### Support build automation Upsun supports the most common project management tools in the Java ecosystem, including: * [Gradle](https://gradle.org/) * [Maven](https://maven.apache.org/) * [Ant](https://ant.apache.org/) ###### Manage Maven versions Java containers come with a version of Maven already installed. You may need to use a specific different version to manage your project. If the version you need differs from the version on your container, you can install the specific version that you need. Add something like the following to your [app configuration](https://docs.upsun.com../../create-apps/_index.md): ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'java:21' variables: env: MAVEN_VERSION: hooks: build: | curl -sfLO "https://dlcdn.apache.org/maven/maven-3/$MAVEN_VERSION/binaries/apache-maven-$MAVEN_VERSION-bin.tar.gz" tar -zxf apache-maven-$MAVEN_VERSION-bin.tar.gz export PATH="$PWD/apache-maven-$MAVEN_VERSION/bin:$PATH" mvn --version mvn clean package ``` ##### Other JVM languages It’s worth remembering that the JVM by its specification [doesn't read Java code](https://docs.oracle.com/javase/specs/jvms/se8/html/index.md), but bytecode. So within the JVM, it’s possible to [run several languages](https://en.wikipedia.org/wiki/List_of_JVM_languages). Upsun supports several of them, such as Kotlin, Groovy, and Scala, so long as that language works with any build automation that Upsun supports. | Article | Link | | ------------------------------------------------------------ | ------------------------------------------------------------ | | [Kotlin and Spring](https://platform.sh/blog/2019/ready-to-have-fun-try-kotlin-and-spring/) | [Source](https://github.com/platformsh-templates/spring-kotlin) | | [Scala and Spring](https://dzone.com/articles/spring-scala-cloud-psh) | [Source](https://github.com/platformsh-examples/scala) | **Note**: While the table above shows examples for Platform.sh rather than for Upsun, the same rules apply with only slight changes in configuration. ##### Accessing services You can access service credentials to connect to [managed services](https://docs.upsun.com/add-services/) from environment variables present in the application container. Consult each of the individual service documentation to see how to retrieve and surface credentials into your application. - [ClickHouse](https://docs.upsun.com/add-services/clickhouse.md#usage-example) - [Elasticsearch](https://docs.upsun.com/add-services/elasticsearch.md#use-in-app) - [Gotenberg](https://docs.upsun.com/add-services/gotenberg.md#usage-example) - [Headless Chrome](https://docs.upsun.com/add-services/headless-chrome.md#use-in-app) - [InfluxDB](https://docs.upsun.com/add-services/influxdb.md#use-in-app) - [Kafka](https://docs.upsun.com/add-services/kafka.md#use-in-app) - [MariaDB/MySQL](https://docs.upsun.com/add-services/mysql.md#use-in-app) - [Memcached](https://docs.upsun.com/add-services/memcached.md#use-in-app) - [MongoDB](https://docs.upsun.com/add-services/mongodb.md#use-in-app) - [Network Storage](https://docs.upsun.com/add-services/network-storage.md#usage-example) - [OpenSearch](https://docs.upsun.com/add-services/opensearch.md#use-in-app) - [PostgreSQL](https://docs.upsun.com/add-services/postgresql.md#use-in-app) - [RabbitMQ](https://docs.upsun.com/add-services/rabbitmq.md#use-in-app) - [Redis](https://docs.upsun.com/add-services/redis.md#use-in-app) - [Solr](https://docs.upsun.com/add-services/solr.md#use-in-app) - [Varnish](https://docs.upsun.com/add-services/varnish.md#usage-example) - [Vault KMS](https://docs.upsun.com/add-services/vault.md#use-vault-kms) #### Moving a Java application to Platform.sh p:last-child]:mb-0 [&>h3]:mt-0 rounded-lg" > ####### Note You can now use composable image (BETA) to install runtimes and tools in your application container. To find out more, see the [dedicated documentation page](https://docs.upsun.com/create-apps/app-reference/composable-image.md). It is common to have a Java application that you want to migrate to Upsun. Upsun supports several styles of Java application, such as monolith, microservices, stateful, and stateless. ###### Minimum Requirement To run a Java application at Upsun you need: * [A supported Java version](https://docs.upsun.com/languages/java.md#supported-versions) * [A build management tool](https://docs.upsun.com/languages/java.md#support-build-automation) * [Gradle](https://docs.gradle.org/current/userguide/gradle_wrapper.md) * [Maven](https://maven.apache.org/) * [Maven Wrapper](https://www.baeldung.com/maven-wrapper) * [Ant](https://ant.apache.org/) * A Git Repository: * [GitHub](https://docs.upsun.com/integrations/source/github.md) * [BitBucket](https://docs.upsun.com/integrations/source/bitbucket.md) * [GitLab](https://docs.upsun.com/integrations/source/gitlab.md) * The default Git repository provided by Upsun **Note**: A container application can’t be bigger than **8 GB** of memory. For more details, see [tuning](https://docs.upsun.com/languages/java/tuning.md). ###### Monolith/Single Application To start a Java application, you need to understand the [Upsun structure](https://docs.upsun.com/learn/overview/structure.md). You will need to configure your [application](https://docs.upsun.com../../create-apps/_index.md), [routes](https://docs.upsun.com../../define-routes.md), and [services](https://docs.upsun.com../../add-services.md). ####### Application ```yaml {location=".upsun/config.yaml"} applications: myapp: type: 'java:' hooks: build: [2] web: commands: start: [3] ``` 1. [A Java version](https://docs.upsun.com/languages/java.md#supported-versions), e,g.: `java:21` 2. [Hooks define what happens when building the application](https://docs.upsun.com../../create-apps/hooks.md). This build process typically generates an executable file such as a uber-jar. For example, `mvn clean package`. 3. [The commands key defines the command to launch the application](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#web-commands). For example, `java -jar file.jar`. 4. In the start's command needs to receive the port where the application will execute thought the `PORT` environment. That's best when your app follows the port bind principle. For example, `java -jar jar --port=$PORT`. **Note**: Be aware that after the build, it creates a read-only system. You have the [mount option to create a writable folder](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#mounts). ####### Route ```yaml {location=".upsun/config.yaml"} routes: "https://{default}/": type: upstream upstream: "myapp:http" [1] "https://www.{default}/": type: redirect to: "https://{default}/" applications: myapp: type: 'java:' hooks: build: [2] web: commands: start: [3] ``` 1. It defines the application will link in the route. For example,`"myapp:http"`. **Note**: Application instances have a limited amount of memory at build time, which has a maximum of 8 GB. At runtime that limit depends on [the resources you have defined for your application container](https://docs.upsun.com/manage-resources.md) using ``upsun resources:set``. A stateless application can be scaled horizontally to multiple application instances with ``upsun resources:set`` or by using Varnish in a [load balancer](https://support.platform.sh/hc/en-us/community/posts/16439676899474) configuration. ###### Microservices You have the option to use several languages in microservices. If you're using Java there are several options to aggregate these services into a microservices: * [Maven Modules](https://maven.apache.org/guides/mini/guide-multiple-modules.md) * [Gradle Multi-project](https://guides.gradle.org/creating-multi-project-builds/) * [Git submodules](https://docs.upsun.com/development/submodules.md) [Upsun supports multiple applications](https://docs.upsun.com../../create-apps/multi-app.md) and there are two options: * One application YAML file to each application * Aggregate all applications in a single file with an `.upsun/config.yaml` file | Article | Content | | ------------------------------------------------------------ | ------------------------------------------------------------ | | [Microservices in the cloud, part two](https://platform.sh/blog/2019/microservices-in-the-cloud-part-two/) | [Source](https://github.com/EventosJEspanol/latin-america-micro-profile) | | [Microservices in the cloud, part one](https://platform.sh/blog/2019/microservices-in-the-cloud-part-one/) | [Source](https://github.com/EventosJEspanol/latin-america-micro-profile) | | [Multiple Applications](https://support.platform.sh/hc/en-us/community/posts/16439649733010) | [Source](https://github.com/platformsh-examples/tomcat-multi-app) | | [Configure multi-applications with `.upsun/config.yaml`](https://support.platform.sh/hc/en-us/community/posts/16439676928274) | [Source](https://github.com/platformsh-examples/tomcat-multi-app-applications) | **Note**: You can load balance to some or [all applications in the project cluster](https://support.platform.sh/hc/en-us/community/posts/16439662235026). While the table above shows examples for Platform.sh rather than for Upsun, the same rules apply with only slight changes in configuration. ###### Access to managed services Upsun provides [managed services](https://docs.upsun.com/add-services.md) such as databases, cache and search engines. However, you can use a database or any services such as a transition process, just be aware of the [firewall](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#firewall). When applications need to access a service, it is important to include the [`relationships` key](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#relationships). By default an application may not talk to any other container without a `relationship` explicitly allowing access. To connect to a service from your deployed application, you need to pass the relationships information into your application's configuration. The way to do so varies with the application. The most common mechanisms are listed below. ####### Overwrite If you are using a framework that follows the [Twelve-Factor App](https://12factor.net/) methodology, particularly the [third point](https://12factor.net/config), you can configure the application directly from environment variables. Examples of such frameworks include Spring, Eclipse MicroProfile Config, Quarkus, and Micronauts. Service credentials are available within the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables), or the [`PLATFORM_RELATIONSHIPS` environment variable](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). This sets environment variables with the names your app needs, and the values from [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables). This variable is a base64-encoded JSON object with keys of the relationship name and values of arrays of relationship endpoint definitions. Upsun supports the [jq](https://stedolan.github.io/jq/), which allows to extract information from this JSON. ```bash {location=".environment"} export DB_HOST=`echo $PLATFORM_RELATIONSHIPS | base64 --decode | jq -r ".postgresql[0].host"` ``` This sets environment variables with names your app needs and the values from [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). | Article | Source | | ------------------------------------------------------------ | ------------------------------------------------------------ | | [Spring Data MongoDB](https://support.platform.sh/hc/en-us/community/posts/16439654854802) | [Source](https://github.com/platformsh-examples/java-overwrite-configuration/tree/master/spring-mongodb) | | [Jakarta EE/MicroProfile Config](https://support.platform.sh/hc/en-us/community/posts/16439700735122) | [Source](https://github.com/platformsh-examples/java-overwrite-configuration/tree/master/jakarta-nosql) | | [Spring Data JPA](https://support.platform.sh/hc/en-us/community/posts/16439669562130) | [Source](https://github.com/platformsh-examples/java-overwrite-configuration/tree/master/spring-jpa) | | [Payara JPA](https://support.platform.sh/hc/en-us/community/posts/16439658290194) | [Source](https://github.com/platformsh-examples/java-overwrite-configuration/blob/master/payara/README.md) | **Note**: While the table above shows examples for Platform.sh rather than for Upsun, the same rules apply with only slight changes in configuration. To reduce the number of lines in the application file and to make it cleaner, you have the option to move the variable environment to another file: a [`.environment` file](https://docs.upsun.com../../development/variables/set-variables.md#set-variables-via-script). **Example:** You can obtain relationship information through the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) themselves, or through the [`PLATFORM_RELATIONSHIPS` environment variable](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). Say your application has a relationship named ``postgresql`` to a database service named `postgresql`: This sets environment variables with the names your app needs, and the values from [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables).This ``PLATFORM_RELATIONSHIPS`` variable is a base64-encoded JSON object with keys of the relationship name and values of arrays of relationship endpoint definitions. Upsun supports the [jq](https://stedolan.github.io/jq/), which allows to extract information from this JSON. ```bash {location=".environment"} export DB_HOST=`echo $PLATFORM_RELATIONSHIPS | base64 --decode | jq -r ".postgresql[0].host"` export DB_PASSWORD=`echo $PLATFORM_RELATIONSHIPS | base64 --decode | jq -r ".postgresql[0].password"` export DB_USER=`echo $PLATFORM_RELATIONSHIPS | base64 --decode | jq -r ".postgresql[0].username"` export DB_DATABASE=`echo $PLATFORM_RELATIONSHIPS | base64 --decode | jq -r ".postgresql[0].path"` export JDBC=jdbc:postgresql://${HOST}/${DATABASE} export JAVA_MEMORY=-Xmx$(jq .info.limits.memory /run/config.json)m export JAVA_OPTS="$JAVA_MEMORY -XX:+ExitOnOutOfMemoryError" ``` This sets environment variables with names your app needs and the values from [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). This `.environment` file can interact to each application file. **Example:** ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'java:21' hooks: build: ./mvnw package -DskipTests -Dquarkus.package.uber-jar=true relationships: postgresql: web: commands: start: java -jar $JAVA_OPTS $CREDENTIAL -Dquarkus.http.port=$PORT jarfile.jar ``` #### Performance tuning Java p:last-child]:mb-0 [&>h3]:mt-0 rounded-lg" > ####### Note You can now use composable image (BETA) to install runtimes and tools in your application container. To find out more, see the [dedicated documentation page](https://docs.upsun.com/create-apps/app-reference/composable-image.md). There are a number of settings that can be adjusted for each application to optimize its performance on Upsun. ###### Memory limits The JVM generally requires specifying a maximum memory size it is allowed to use, using the `Xmx` parameter. That should be set based on the available memory on the application container, which varies with its size. To extract the container-scaled value on the command line, use `$(jq .info.limits.memory /run/config.json)`. You should also set the `ExitOnOutOfMemoryError`. When you enable this option, the JVM exits on the first occurrence of an out-of-memory error. Upsun will restart the application automatically. These are the recommended parameters for running a Java application. Thus, the command to use to start a Java application is: ```bash java -jar -Xmx$(jq .info.limits.memory /run/config.json)m -XX:+ExitOnOutOfMemoryError //The rest of the arguments and the jar file. ``` ###### Garbage collection When migrating the application to a cloud environment, it is often essential to analyze the Garbage Collector's log and behavior. For this, there are two options: * Placing the log into the Upsun `/var/log/app.log` file (which captures `STDOUT`). * Creating a log file specifically for the GC. To use the `STDOUT` log, you can add the parameter `-XX: + PrintGCDetails`, E.g.: ```bash java -jar -Xmx$(jq .info.limits.memory /run/config.json)m -XX:+ExitOnOutOfMemoryError -XX:+PrintGCDetails //The rest of the arguments and the jar file. ``` Java supports a number of different garbage collection strategies. Which one is optimal for your application varies depending on your available memory, Java version, and application profile. Determining which is best for your application is out of scope, but the main options and how to enable them are: | Name | Command Flag | Description | | ------------- |:-------------:| -----:| |Serial Garbage Collector|-XX:+UseSerialGC|This is the simplest GC implementation, as it basically works with a single thread.| |Parallel Garbage Collector|-XX:+UseParallelGC|Unlike Serial Garbage Collector, this uses multiple threads for managing heap space. But it also freezes other application threads while performing GC.| |CMS Garbage Collector|-XX:+USeParNewGC|The Concurrent Mark Sweep (CMS) implementation uses multiple garbage collector threads for garbage collection. It's for applications that prefer shorter garbage collection pauses, and that can afford to share processor resources with the garbage collector while the application is running.| |G1 Garbage Collector|-XX:+UseG1GC|Garbage First, G1, is for applications running on multiprocessor machines with large memory space.| The default strategy on Java 9 and later is G1. The GC strategy to use can be set in the start line with: ####### Serial ```bash java -jar -Xmx$(jq .info.limits.memory /run/config.json)m -XX:+ExitOnOutOfMemoryError -XX:+PrintGCDetails -XX:+UseSerialGC //The rest of the arguments and the jar file. ``` ####### Parallel Garbage Collector ```bash java -jar -Xmx$(jq .info.limits.memory /run/config.json)m -XX:+ExitOnOutOfMemoryError -XX:+PrintGCDetails -XX:+UseParallelGC //The rest of the arguments and the jar file. ``` ####### CMS Garbage Collector ```bash java -jar -Xmx$(jq .info.limits.memory /run/config.json)m -XX:+ExitOnOutOfMemoryError -XX:+PrintGCDetails -XX:+USeParNewGC //The rest of the arguments and the jar file. ``` ####### G1 ```bash java -jar -Xmx$(jq .info.limits.memory /run/config.json)m -XX:+ExitOnOutOfMemoryError -XX:+PrintGCDetails -XX:+UseG1GC //The rest of the arguments and the jar file. ``` ###### Java 8 Optimization Ideally, all applications should run the latest LTS release of the JVM at least. That is currently Java 11. Java 11 has a number of performance improvements, particularly on container-based environments such as Upsun. However, in many cases, this isn't possible. If you are still running on Java 8 there are two additional considerations. The default garbage collector for Java 8 is Parallel GC. In most cases G1 will offer better performance. We recommend enabling it, as above. Furthermore, there is the `UseStringDeduplication` flag which works to eliminate duplicate `String`s within the GC process. That flag can save between 13% to 30% of memory, depending on application. However, this can impact on the pause time of your app. ```bash java -jar -Xmx$(jq .info.limits.memory /run/config.json)m -XX:+UseG1GC -XX:+UseStringDeduplication -XX:+ExitOnOutOfMemoryError -XX:+PrintGCDetails ``` ###### References * [Introduction to Garbage Collection Tuning](https://docs.oracle.com/en/java/javase/14/gctuning/introduction-garbage-collection-tuning.md#GUID-326EB4CF-8C8C-4267-8355-21AB04F0D304) ### JavaScript/Node.js p:last-child]:mb-0 [&>h3]:mt-0 rounded-lg" > ###### Note You can now use composable image (BETA) to install runtimes and tools in your application container. To find out more, see the [dedicated documentation page](https://docs.upsun.com/create-apps/app-reference/composable-image.md). Node.js is a popular asynchronous JavaScript runtime. Deploy scalable Node.js apps of all sizes on Upsun. You can also develop a microservice architecture mixing JavaScript and other apps with [multi-app projects](https://docs.upsun.com../../create-apps/multi-app.md). ##### Supported versions You can select the major version. But the latest compatible minor version is applied automatically and can’t be overridden. Patch versions are applied periodically for bug fixes and the like. When you deploy your app, you always get the latest available patches. - 22 - 20 - 18 ###### Specify the language To use Node.js, specify ``nodejs`` as your [app’s type](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#types): ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. : type: 'nodejs:' ``` For example: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'nodejs:22' ``` To use a specific version in a container with a different language, [use a version manager](node-version.md). ###### Deprecated versions The following versions are [deprecated](https://docs.upsun.com/glossary.md#deprecated-versions). They're available, but they aren't receiving security updates from upstream and aren't guaranteed to work. They'll be removed in the future, so migrate to one of the [supported versions](#supported-versions). - 16 - 14 - 12 - 10 - 8 - 6 - 4.8 - 4.7 - 0.12 ##### Usage example To use JavaScript with Node.js on Upsun, configure your [app configuration](https://docs.upsun.com../../create-apps.md) (a complete example is included at the end). ###### 1. Specify the version Choose a version from the [list of supported versions](#supported-versions) and add it to your app configuration: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'nodejs:22' ``` ###### 2. Specify any global dependencies Add the following to your app configuration: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'nodejs:22' dependencies: nodejs: sharp: "*" ``` These are now available as commands, the same as installing with `npm install -g`. ###### 3. Build your app Include any commands needed to build and setup your app in the `hooks`, as in the following example: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'nodejs:22' dependencies: nodejs: sharp: "*" hooks: build: | npm run setup-assets npm run build ``` ###### 4. Start your app Specify a command to start serving your app (it must be a process running in the foreground): ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'nodejs:22' dependencies: nodejs: sharp: "*" hooks: build: | npm run setup-assets npm run build web: commands: start: node index.js ``` ###### 5. Listen on the right port Make sure your Node.js application is configured to listen over the port given by the environment. ```js // Load the http module to create an http server. const http = require('http'); const PORT = process.env.PORT || 8888; const server = http.createServer(function (request, response) { response.writeHead(200, {"Content-Type": "application/json"}); response.end("Hello world!"); }); // Listen on the port from the Upsun configuration server.listen(PORT, () => { console.log(`Server is listening on port: ${PORT}`); }); ``` ###### Complete example A complete basic app configuration looks like the following: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. 'node-app': type: 'nodejs:22' dependencies: nodejs: sharp: "*" hooks: build: | npm run setup-assets npm run build web: commands: start: "node index.js" ``` ##### Dependencies By default, Upsun assumes you're using npm as a package manager. If your code has a `package.json`, the following command is run as part of the default [build flavor](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#build): ```bash npm prune --userconfig .npmrc && npm install --userconfig .npmrc ``` This means you can specify configuration in a `.npmrc` file in [your app root](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#root-directory). ###### Use Yarn as a package manager To switch to Yarn to manage dependencies, follow these steps: 1. Turn off the default use of npm: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'nodejs:22' build: flavor: none ``` 2. Specify the version of Yarn you want: ```json {location="package.json"} { ... "packageManager": "yarn@3.2.1" } ``` What you do next depends on the versions of Yarn and Node.js you want. - Enable Corepack (which is opt-in): ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" type: 'nodejs:22' dependencies: nodejs: corepack: "*" ``` - Use Corepack to run Yarn in your build hook: ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" type: 'nodejs:22' hooks: build: | corepack yarn install ``` - Add Yarn as a global dependency: ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" type: 'nodejs:22' dependencies: nodejs: yarn: "1.22.19" ``` - Install dependencies in the ``build`` hook: ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" type: 'nodejs:22' hooks: build: | yarn --frozen-lockfile ``` ###### Use Bun as a package manager **Availability** [Bun is available as a runtime and package manager](https://platform.sh/blog/bun-support-is-here/) for Node.js **versions 20 or above**. To switch to Bun to manage dependencies, use the following configuration: ```yaml {location=".upsun/config.yaml"} applications: # The name of your app. myapp: # Choose Node.js version 20 or above. type: 'nodejs:20' # Override the default Node.js build flavor. build: flavor: none # Use Bun to install the dependencies. hooks: build: bun install ``` ####### Use Bun as a runtime You can even [use Bun as a runtime](https://platform.sh/blog/bun-support-is-here/) by adjusting the `start` command as follows: ```yaml {location=".upsun/config.yaml"} applications: # The name of your app. myapp: # Choose Node.js version 20 or above. type: 'nodejs:20' # Override the default Node.js build flavor. build: flavor: none # Use Bun to install the dependencies. hooks: build: bun install # In the start command replace node with Bun. web: commands: start: 'bun app.js' ``` ##### Connecting to services You can access service credentials to connect to [managed services](https://docs.upsun.com/add-services/) from environment variables present in the application container. Consult each of the individual service documentation to see how to retrieve and surface credentials into your application. - [ClickHouse](https://docs.upsun.com/add-services/clickhouse.md#usage-example) - [Elasticsearch](https://docs.upsun.com/add-services/elasticsearch.md#use-in-app) - [Gotenberg](https://docs.upsun.com/add-services/gotenberg.md#usage-example) - [Headless Chrome](https://docs.upsun.com/add-services/headless-chrome.md#use-in-app) - [InfluxDB](https://docs.upsun.com/add-services/influxdb.md#use-in-app) - [Kafka](https://docs.upsun.com/add-services/kafka.md#use-in-app) - [MariaDB/MySQL](https://docs.upsun.com/add-services/mysql.md#use-in-app) - [Memcached](https://docs.upsun.com/add-services/memcached.md#use-in-app) - [MongoDB](https://docs.upsun.com/add-services/mongodb.md#use-in-app) - [Network Storage](https://docs.upsun.com/add-services/network-storage.md#usage-example) - [OpenSearch](https://docs.upsun.com/add-services/opensearch.md#use-in-app) - [PostgreSQL](https://docs.upsun.com/add-services/postgresql.md#use-in-app) - [RabbitMQ](https://docs.upsun.com/add-services/rabbitmq.md#use-in-app) - [Redis](https://docs.upsun.com/add-services/redis.md#use-in-app) - [Solr](https://docs.upsun.com/add-services/solr.md#use-in-app) - [Varnish](https://docs.upsun.com/add-services/varnish.md#usage-example) - [Vault KMS](https://docs.upsun.com/add-services/vault.md#use-vault-kms) ##### Frameworks All major Javascript/Node.js web frameworks can be deployed on Upsun. See dedicated guides for deploying and working with them: - [Express](https://docs.upsun.com/get-started/stacks/express.md) - [Next.js](https://docs.upsun.com/get-started/stacks/nextjs.md) - [Strapi](https://docs.upsun.com/get-started/stacks/strapi.md) #### Debugging p:last-child]:mb-0 [&>h3]:mt-0 rounded-lg" > ####### Note You can now use composable image (BETA) to install runtimes and tools in your application container. To find out more, see the [dedicated documentation page](https://docs.upsun.com/create-apps/app-reference/composable-image.md). Effectively debugging web apps takes effort, especially when an HTTP request goes through multiple layers before reaching your web app. Follow the steps below to debug a specific app. You can choose to debug in an environment deployed to Upsun or with your app running locally but connected to deployed services. In either case, make sure to debug in a preview environment. For more general information, see how to [troubleshoot development](https://docs.upsun.com/development/troubleshoot.md). ###### 1. Create a new environment Start by creating a new environment completely isolated from production but with the same data for debugging: ```bash upsun branch debug-branch ``` ###### 2. Get access To access deployed apps and services, open tunnels to everything your app has relationships with: ```bash {} upsun tunnel:open ``` In the same terminal, set the relevant environment variables: ```bash {} export PLATFORM_RELATIONSHIPS="$(upsun tunnel:info --encode)" export PORT=8888 ``` ###### 3. Run your app in inspect mode In the same terminal as the previous step, run the following command: ```bash {} node --inspect ``` Replace `` with the file defined for [your app's `start` command](https://docs.upsun.com/languages/nodejs.md#4-start-your-app). You get output something like this: ```bash Debugger listening on ws://127.0.0.1:9229/10701e5d-d627-4180-a967-d47a924c93c0 For help, see: https://nodejs.org/en/docs/inspector Listening on port 8888 ``` ###### 4. (If debugging remotely) Forward the debugger port locally In another terminal, create an SSH tunnel that forwards to the 9229 port: ```bash ssh -N -L 9229:localhost:9229 $(upsun ssh --pipe) ``` ###### 5. Connect the debugger You can now connect the debugger as if you were debugging a local application. See examples with some common tools: Use the ``Node.js: Attach`` debugger option. If you haven’t created the option: - On the **Run and Debug** tab, click ``create a launch.json file``. - Select ``Node.js`` as the environment. - In the ``configurations`` array, start IntelliSense (usually ctrl+space). - Select ``Node.js: Attach``. - Make sure the port is the same as in [step 4 above](#4-if-debugging-remotely-forward-the-debugger-port-locally). Once you have the option: In the **Run and Debug** tab, select ``Attach`` from the menu and click **Start Debugging** (the green arrow). See more on [Node.js debugging in Visual Studio Code](https://code.visualstudio.com/docs/nodejs/nodejs-debugging). Now when you load the site at your deployed URL (if debugging remote) or localhost (if debugging locally), the local debugger you've attached is called. Set breakpoints: Directly in your source files. ###### Other issues ####### pm2 process manager blocks other processes If you're using the [`pm2` process manager](https://github.com/unitech/pm2) to start your app from a script, you might find it daemonizes itself and blocks other processes (such as backups) by constantly respawning. This may happen even if you use the `--no-daemon` flag. Instead of using a script, call `pm2 start` directly in your [`start` command](https://docs.upsun.com/languages/nodejs.md#4-start-your-app). #### Manage Node.js versions p:last-child]:mb-0 [&>h3]:mt-0 rounded-lg" > ####### Note You can now use composable image (BETA) to install runtimes and tools in your application container. To find out more, see the [dedicated documentation page](https://docs.upsun.com/create-apps/app-reference/composable-image.md). Each Upsun container image includes a specific language in a specific version. A set of dependencies is also provided based on that language version. This ensures that your application container is as small and efficient as possible. Therefore, by default, when you use a Upsun container image, you use the Node.js version that's included in that image, if any. If you want to use a different Node.js version, use a version manager to install it yourself. You can use one of the following version managers: - [Use `n`](#use-n) - [Use `nvm`](#use-nvm) Both of the recommendations use a `.nvmrc` file to specify the desired Node.js version. You could also specify a different file or use [environment variables](https://docs.upsun.com../../development/variables.md). ###### Use `n` The [`n` package](https://github.com/tj/n) works for various Unix-like systems, including Windows Subsystem for Linux. 1. Add the desired Node.js version to your environment using `.nvmrc`, `.n-node-version`, `.node-version`, or `package.json`. Create a ``.n-node-version`` or ``.node-version`` file in [your app root](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#root-directory): ```yaml {location=".n-node-version or .node-version"} 16.13.2 ``` Add an ``engines.node`` property to your ``package.json``. This property accepts either an exact version or a range: ```json {location="package.json"} { "engines": { "node": ">=0.10.3 <15" } } ``` 2. Add it as a dependency: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'python:3.9' dependencies: nodejs: n: "*" ``` Adding it as a dependency ensures it's cached for future builds. 3. Set the location of the `n` files using the `N_PREFIX` environment variable: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'python:3.9' dependencies: nodejs: n: "*" variables: env: N_PREFIX: /app/.global ``` 4. Install the specified version of Node.js in a [`build` hook](https://docs.upsun.com../../create-apps/hooks/hooks-comparison.md#build-hook): ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'python:3.9' dependencies: nodejs: n: "*" variables: env: N_PREFIX: /app/.global hooks: build: | # Exit the hook on any failure set -e # Install the version specified in the .nvmrc file n auto # Reset the location hash to recognize the newly installed version hash -r ``` Now your hooks should be able to use the specified version of Node.js. You can verify this by running `node -v`. Your final app configuration should look something like this: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'python:3.9' dependencies: nodejs: n: "*" variables: env: N_PREFIX: /app/.global hooks: build: | # Exit the hook on any failure set -e # Install the version specified in the .nvmrc file n auto # Reset the location hash to recognize the newly installed version hash -r ``` ###### Use `nvm` [Node Version Manager (`nvm`)](https://github.com/nvm-sh/nvm) is a bash script for managing Node.js versions. You can use it to: - Make a specific version available in the build and optionally the runtime container. - Control the specific versions to be installed with [environment variables](https://docs.upsun.com../../development/variables.md), meaning you can also have different versions in different environments. To use `nvm`, follow these steps: 1. Define which `nvm` version to use using an [environment variable](https://docs.upsun.com../../development/variables.md). Add it to your [app configuration](https://docs.upsun.com../../create-apps/_index.md): ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'python:3.9' variables: env: # Update for your desired NVM version. NVM_VERSION: v0.39.3 ``` 2. Define your desired Node.js version using an environment variable. For your base version, set it in your app configuration: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'python:3.9' variables: env: # Update these for your desired NVM and Node versions. NVM_VERSION: v0.39.3 NODE_VERSION: v18.14.2 ``` To get different versions in different environments, [set environment-specific variables](https://docs.upsun.com../../development/variables/set-variables.md#create-environment-specific-variables). 3. Add a `.nvm` directory to your cache in your [build hook](https://docs.upsun.com../../create-apps/hooks/_index.md): ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'python:3.9' variables: env: # Update these for your desired NVM and Node versions. NVM_VERSION: v0.39.3 NODE_VERSION: v18.14.2 hooks: build: | set -e unset NPM_CONFIG_PREFIX export NVM_DIR="$PLATFORM_APP_DIR/.nvm" # Link cache with app if [ ! -d "$PLATFORM_CACHE_DIR/.nvm" ]; then mkdir -p $PLATFORM_CACHE_DIR/.nvm fi ln -s $PLATFORM_CACHE_DIR/.nvm $NVM_DIR ``` **Note**: Instead of using a symlink between your cache and application directories, you might need to copy the content of ``$PLATFORM_CACHE_DIR/.nvm`` into ``$PLATFORM_APP_DIR/.nvm`` manually. To do so, run the following command: ```bash {} rsync -av $PLATFORM_CACHE_DIR/.nvm $PLATFORM_APP_DIR ``` 4. Use the cache directory and install based on the variables if not present: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'python:3.9' variables: env: # Update these for your desired NVM and Node versions. NVM_VERSION: v0.39.3 NODE_VERSION: v18.14.2 hooks: build: | ... # Check for Node.js version and install if not present if [ ! -d "$PLATFORM_CACHE_DIR/.nvm/versions/node/$NODE_VERSION" ]; then # Get nvm install script if correct version not present export NVM_INSTALL_FILE="${PLATFORM_CACHE_DIR}/nvm_${NVM_VERSION}_install.sh" if [ ! -f "$NVM_INSTALL_FILE" ]; then wget -nc -O "$NVM_INSTALL_FILE" "https://raw.githubusercontent.com/nvm-sh/nvm/$NVM_VERSION/install.sh" fi # Install, automatically using NODE_VERSION bash $NVM_INSTALL_FILE fi # Activate nvm [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # Use the specified version nvm use "$NODE_VERSION" ``` 5. Optional: To use the specified Node.js version in the runtime container and not just the build, activate `nvm` via [script](https://docs.upsun.com../../development/variables/set-variables.md#set-variables-via-script): ```bash {location=".environment"} unset NPM_CONFIG_PREFIX export NVM_DIR="$PLATFORM_APP_DIR/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" ``` Your final app configuration should look something like the following: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'python:3.9' variables: env: # Update these for your desired NVM and Node versions. NVM_VERSION: v0.39.3 NODE_VERSION: v18.14.2 hooks: build: | set -e unset NPM_CONFIG_PREFIX export NVM_DIR="$PLATFORM_APP_DIR/.nvm" # Link cache with app if [ ! -d "$PLATFORM_CACHE_DIR/.nvm" ]; then mkdir -p $PLATFORM_CACHE_DIR/.nvm fi ln -s $PLATFORM_CACHE_DIR/.nvm $NVM_DIR # Check for Node.js version and install if not present if [ ! -d "$PLATFORM_CACHE_DIR/.nvm/versions/node/$NODE_VERSION" ]; then # Get nvm install script if correct version not present export NVM_INSTALL_FILE="${PLATFORM_CACHE_DIR}/nvm_${NVM_VERSION}_install.sh" if [ ! -f "$NVM_INSTALL_FILE" ]; then wget -nc -O "$NVM_INSTALL_FILE" "https://raw.githubusercontent.com/nvm-sh/nvm/$NVM_VERSION/install.sh" fi # Install, automatically using NODE_VERSION bash $NVM_INSTALL_FILE fi # Activate nvm [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # Use the specified version nvm use "$NODE_VERSION" ``` ### Lisp p:last-child]:mb-0 [&>h3]:mt-0 rounded-lg" > ###### Note You can now use composable image (BETA) to install runtimes and tools in your application container. To find out more, see the [dedicated documentation page](https://docs.upsun.com/create-apps/app-reference/composable-image.md). Upsun supports building and deploying applications written in Lisp using Common Lisp (the SBCL version) with ASDF and Quick Lisp support. They’re compiled during the Build phase, and support both committed dependencies and download-on-demand. ##### Supported versions You can select the major and minor version. Patch versions are applied periodically for bug fixes and the like. When you deploy your app, you always get the latest available patches. - 3.3 - 3.2 - 3.1 - 3.0 ###### Specify the language To use Lisp, specify `lisp` as your [app's `type`](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#types): ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. : type: 'lisp:' ``` For example: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'lisp:2.1' ``` ##### Assumptions Upsun is making assumptions about your application to provide a more streamlined experience. These assumptions are the following: - Your `.asd` file is named like your system name. For example `example.asd` has `(defsystem example ...)`. Upsun will then run `(asdf:make :example)` on your system to build a binary. If you don't want these assumptions, you can disable this behavior by specifying in your `.upsun/config.yaml`: ```yaml {location=".upsun/config.yaml"} applications: myapp: type: 'lisp:2.1' build: flavor: none ``` ##### Dependencies The recommended way to handle Lisp dependencies on Upsun is using ASDF. Commit a `.asd` file in your repository and the system will automatically download the dependencies using QuickLisp. ##### QuickLisp options If you wish to change the distributions that QuickLisp is using, you can specify those as follows, specifying a distribution name, its URL and, an optional version: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. : type: 'lisp:' runtime: quicklisp: : url: "..." version: "..." ``` For example: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'lisp:2.1' runtime: quicklisp: quicklisp: url: 'http://beta.quicklisp.org/dist/quicklisp.txt' version: '2019-07-11' ``` ##### Built-in variables Upsun exposes relationships and other configuration as [environment variables](https://docs.upsun.com../development/variables.md). To get the `PORT` environment variable (the port on which your web application is supposed to listen): ```lisp (parse-integer (uiop:getenv "PORT")) ``` ##### Building and running the application Assuming `example.lisp` and `example.asd` are present in your repository, the app is automatically built on push. You can then start it from the `web.commands.start` directive. Note that the start command _must_ run in the foreground. Should the program terminate for any reason it's automatically restarted. In the example below the app sleeps for a very, very long time. You could also choose to join the thread of your web server, or use other methods to make sure the program doesn't terminate. The following basic `.upsun/config.yaml` file is sufficient to run most Lisp applications. ```yaml {location=".upsun/config.yaml"} applications: myapp: type: 'lisp:2.1' web: commands: start: ./example locations: /: allow: false passthru: true ``` Note that a proxy server is still in front of your app. If desired, certain paths may be served directly by the router without hitting your app (for static files, primarily) or you may route all requests to the Lisp application unconditionally, as in the example above. ##### Accessing Services The services configuration is available in the environment variable `PLATFORM_RELATIONSHIPS`. To parse them, add the dependencies to your `.asd` file: ```lisp :depends-on (:jsown :babel :s-base64) ``` The following is an example of accessing a PostgreSQL instance: ```lisp (defun relationships () (jsown:parse (babel:octets-to-string (with-input-from-string (in (uiop:getenv "PLATFORM_RELATIONSHIPS")) (s-base64:decode-base64-bytes in))))) ``` Given a relationship defined in `.upsun/config.yaml`: ```yaml {location=".upsun/config.yaml"} applications: myapp: type: 'lisp:2.1' relationships: # Please note: Legacy definition of the relationship is still supported: # More information: https://docs.platform.sh/create-apps/app-reference/single-runtime-image.html#relationships postgresql: service: 'postgresql' endpoint: 'postgresql' ``` The following would access that relationship, and provide your Lisp program the credentials to connect to a PostgreSQL instance. Add this to your `.asd` file: ```lisp :depends-on (:postmodern) ``` Then in your program you could access the PostgreSQL instance as follows: ```lisp (defvar *pg-spec* nil) (defun setup-postgresql () (let* ((pg-relationship (first (jsown:val (relationships) "postgresql"))) (database (jsown:val pg-relationship "path")) (username (jsown:val pg-relationship "username")) (password (jsown:val pg-relationship "password")) (host (jsown:val pg-relationship "host"))) (setf *pg-spec* (list database username password host))) (postmodern:with-connection *pg-spec* (unless (member "example_table" (postmodern:list-tables t) :test #'string=) (postmodern:execute "create table example_table ( a_field TEXT NOT NULL UNIQUE, another_field TEXT NOT NULL UNIQUE ")))) ``` ##### Example The following is a basic example of a Hunchentoot-based web app (you can find the corresponding `.asd` and Upsun `.yaml` files in the example): ```lisp (defpackage #:example (:use :hunchentoot :cl-who :cl) (:export main)) (in-package #:example) (define-easy-handler (greet :uri "/hello") (name) (with-html-output-to-string (s) (htm (:body (:h1 "hello, " (str name)))))) (defun main () (let ((acceptor (make-instance 'easy-acceptor :port (parse-integer (uiop:getenv "PORT"))))) (start acceptor) (sleep most-positive-fixnum))) ``` Notice how it gets the `PORT` from the environment and how it sleeps at the end, as `(start acceptor)` immediately yields and Upsun requires apps to run in the foreground. ### PHP **Note**: You can now use the Upsun composable image (BETA) to install runtimes and tools in your application container. To find out more about this feature, see the [dedicated documentation page](https://docs.upsun.com/create-apps/app-reference/composable-image.md). Also, see how you can [modify your PHP runtime when using the composable image](#modify-your-php-runtime-when-using-the-composable-image). ##### Supported versions You can select the major and minor version. Patch versions are applied periodically for bug fixes and the like. When you deploy your app, you always get the latest available patches. - 8.4 - 8.3 - 8.2 - 8.1 Note that from PHP versions 7.1 to 8.1, the images support the Zend Thread Safe (ZTS) version of PHP. ###### Specify the language To use PHP, specify `php` as your [app's `type`](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#types): ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. : type: 'php:' ``` For example: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'php:8.4' ``` ###### Deprecated versions The following versions are [deprecated](https://docs.upsun.com/glossary.md#deprecated-versions). They're available, but they aren't receiving security updates from upstream and aren't guaranteed to work. They'll be removed in the future, so migrate to one of the [supported versions](#supported-versions). - 8.0 - 7.4 - 7.3 - 7.2 - 7.1 - 7.0 - 5.6 - 5.5 - 5.4 ##### Usage example Configure your app to use PHP on Upsun. ###### 1. Specify the version Choose a [supported version](#supported-versions) and add it to your [app configuration](https://docs.upsun.com../../create-apps/_index.md): ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'php:8.4' ``` ###### 2. Serve your app To serve your app, define what (and how) content should be served by setting the [`locations` parameter](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#locations). Usually, it contains the two following (optional) keys: - `root` for the document root, the directory to which all requests for existing `.php` and static files (such as `.css`, `.jpg`) are sent. - `passthru` to [define a front controller](https://docs.upsun.com../../create-apps/web/php-basic.md#set-different-rules-for-specific-locations) to handle nonexistent files. The value is a file path relative to the [app root](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#root-directory). **Note**: For enhanced security, when setting ``passthru`` to ``true``, you might also want to add the following configuration: - Set ``scripts`` to ``false``. This prevents PHP scripts from being executed from the specified location. - Set ``allow`` to ``false``. By default, when PHP scripts aren’t executed, their source code is delivered. Setting ``allow`` to ``false`` allows you to keep the source code of your PHP scripts confidential. Adjust the `locations` block to fit your needs. In the following example, all requests made to your site's root (`/`) are sent to the `public` directory and nonexistent files are handled by `app.php`: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'php:8.4' web: locations: '/': root: 'public' passthru: '/app.php' ``` See how to [create a basic PHP app with a front controller](https://docs.upsun.com../../create-apps/web/php-basic.md). To have more control, you can define rules to specify which files you want to allow [from which location](https://docs.upsun.com../../create-apps/web/php-basic.md#set-different-rules-for-specific-locations). ###### Complete example A complete basic app configuration looks like the following: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'php:8.4' web: locations: '/': root: 'public' passthru: '/app.php' ``` ##### Dependencies Up to PHP version 8.1, it's assumed that you're using [Composer](https://getcomposer.org/) 1.x to manage dependencies. If you have a `composer.json` file in your code, the default [build flavor is run](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#build): ```bash composer --no-ansi --no-interaction install --no-progress --prefer-dist --optimize-autoloader ``` To use Composer 2.x on your project, either use PHP 8.2+ or, in your app configuration, add the following [dependency](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#dependencies): ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'php:8.4' [...] dependencies: php: composer/composer: '^2' ``` Adding a dependency to the [dependencies block](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#dependencies) makes it available globally. So you can then use included dependencies as commands within your app container. You can add multiple global dependencies to the dependencies block, such as [Node.js](https://docs.upsun.com../nodejs.md#2-specify-any-global-dependencies). If you want to have more control over Composer or if you don't want to use Composer at all, adapt the [build flavor](#change-the-build-flavor). You can also use a [private, authenticated third-party Composer repository](https://docs.upsun.com/languages/php/composer-auth.md). ###### Change the build flavor If you need more control over the dependency management, you can either use your custom build flavor or interact with Composer itself through [its environment variables](https://getcomposer.org/doc/03-cli.md#environment-variables). You can remove the default build flavor and run your own commands for complete control over your build. Set the build flavor to `none` and add the commands you need to your `build` hook, as in the following example: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'php:8.4' [...] build: flavor: none hooks: build: | set -e composer install --no-interaction --no-dev ``` That installs production dependencies with Composer but not development dependencies. The same can be achieved by using the default build flavor and [adding the `COMPOSER_NO_DEV` variable](https://docs.upsun.com../../development/variables/set-variables.md). See more on [build flavors](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#build). ###### Alternative repositories In addition to the standard `dependencies` format, you can specify alternative repositories for Composer to use as global dependencies. So you can install a forked version of a global dependency from a custom repository. To install from an alternative repository: 1. Set an explicit `require` block: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'php:8.4' [...] dependencies: php: require: "platformsh/client": "2.x-dev" ``` This is equivalent to `composer require platform/client 2.x-dev`. 2. Add the repository to use: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'php:8.4' [...] dependencies: php: require: "platformsh/client": "2.x-dev" repositories: - type: vcs url: "git@github.com:platformsh/platformsh-client-php.git" ``` That installs `platformsh/client` from the specified repository URL as a global dependency. For example, to install Composer 2 and the `platform/client 2.x-dev` library from a custom repository, use the following: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'php:8.4' [...] dependencies: php: composer/composer: '^2' require: "platformsh/client": "2.x-dev" repositories: - type: vcs url: "git@github.com:platformsh/platformsh-client-php.git" ``` ##### Connect to services You can access service credentials to connect to [managed services](https://docs.upsun.com/add-services/) from environment variables present in the application container. Consult each of the individual service documentation to see how to retrieve and surface credentials into your application. - [ClickHouse](https://docs.upsun.com/add-services/clickhouse.md#usage-example) - [Elasticsearch](https://docs.upsun.com/add-services/elasticsearch.md#use-in-app) - [Gotenberg](https://docs.upsun.com/add-services/gotenberg.md#usage-example) - [Headless Chrome](https://docs.upsun.com/add-services/headless-chrome.md#use-in-app) - [InfluxDB](https://docs.upsun.com/add-services/influxdb.md#use-in-app) - [Kafka](https://docs.upsun.com/add-services/kafka.md#use-in-app) - [MariaDB/MySQL](https://docs.upsun.com/add-services/mysql.md#use-in-app) - [Memcached](https://docs.upsun.com/add-services/memcached.md#use-in-app) - [MongoDB](https://docs.upsun.com/add-services/mongodb.md#use-in-app) - [Network Storage](https://docs.upsun.com/add-services/network-storage.md#usage-example) - [OpenSearch](https://docs.upsun.com/add-services/opensearch.md#use-in-app) - [PostgreSQL](https://docs.upsun.com/add-services/postgresql.md#use-in-app) - [RabbitMQ](https://docs.upsun.com/add-services/rabbitmq.md#use-in-app) - [Redis](https://docs.upsun.com/add-services/redis.md#use-in-app) - [Solr](https://docs.upsun.com/add-services/solr.md#use-in-app) - [Varnish](https://docs.upsun.com/add-services/varnish.md#usage-example) - [Vault KMS](https://docs.upsun.com/add-services/vault.md#use-vault-kms) ##### PHP settings You can configure your PHP-FPM runtime configuration by specifying the [runtime in your app configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#runtime). In addition to changes in runtime, you can also change the PHP settings. Some commonly used settings are: | Name | Default | Description | |------|---------|-------------| | `max_execution_time` | `300` | The maximum execution time, in seconds, for your PHP scripts and apps. A value of `0` means there are no time limits. | | `max_file_uploads` | `20` | The maximum number of files that can be uploaded in each request. | | `max_input_time` | `60` | The maximum time in seconds that your script is allowed to receive input (such as for file uploads). A value of `-1` means there are no time limits. | | `max_input_vars` | `1000` | The maximum number of input variables that are accepted in each request. | | `memory_limit` | `128M` | The memory limit, in megabytes, for PHP. Ensure that the PHP memory limit is set to a lower value than your environment's memory. | | `post_max_size` | `64M` | The maximum size, in megabytes, per uploaded file. To upload larger files, increase the value. | | `zend.assertions` | `-1` | Assertions are optimized and have no impact at runtime. Set assertions to `1` for your local development system. [See more on assertions](https://www.php.net/manual/en/regexp.reference.assertions). | | `opcache.memory_consumption` | `64` | The number of megabytes available for [the OPcache](https://docs.upsun.com/languages/php/tuning.md#opcache-preloading). For large apps with many files, increase this value. | | `opcache.validate_timestamps` | `On` | If your app doesn't generate compiled PHP, you can [disable this setting](https://docs.upsun.com/languages/php/tuning.md#disable-opcache-timestamp-validation). | ###### Retrieve the default values To retrieve the default PHP values, run the following [CLI command](https://docs.upsun.com../../administration/cli/_index.md): ```bash upsun ssh "php --info" ``` To get specific default values, use grep. For example, to get the value for `opcache.memory_consumption`, run the following command: ```bash upsun ssh "php --info" | grep opcache.memory_consumption ``` ###### Retrieve the settings To see the settings used on your environment: 1. Find the PHP configuration files with the following [CLI command](https://docs.upsun.com../../administration/cli/_index.md): ```bash upsun ssh "php --ini" ``` The output is something like the following: ```bash Configuration File (php.ini) Path: /etc/php/8.0-zts/cli Loaded Configuration File: /etc/php/8.0-zts/cli/php.ini Scan for additional .ini files in: /etc/php/8.0-zts/cli/conf.d Additional .ini files parsed: (none) ``` 2. Display the configuration file by adapting the following command with the output from step 1: ```bash upsun ssh "cat " ``` ###### Customize PHP settings You can customize PHP values for your app in two ways. The recommended method is to use variables. For more information, see how to use [PHP-specific variables](https://docs.upsun.com/development/variables.md#php-specific-variables). You can provide a custom ``php.ini`` file at the [app root](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#root-directory). Using this method isn’t recommended since it offers less flexibility and is more error-prone. Consider using variables instead. For example, to change the PHP memory limit, use the following configuration: ```ini {location="php.ini"} memory_limit = 256M ``` If you're using [PHP-CLI](#execution-mode), you need to take into account the default settings of PHP-CLI when you customize your PHP settings. The default settings of PHP-CLI can't be overwritten and are the following: ```text max_execution_time=0 max_input_time=-1 memory_limit=-1 ``` ###### Disable functions for security A common recommendation for securing PHP installations is disabling built-in functions frequently used in remote attacks. By default, Upsun doesn't disable any functions. If you're sure a function isn't needed in your app, you can disable it. For example, to disable `pcntl_exec` and `pcntl_fork`, add the following to your [app configuration](https://docs.upsun.com../../create-apps/_index.md): ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'php:8.4' variables: php: disable_functions: "pcntl_exec,pcntl_fork" ``` Common functions to disable include: | Name | Description | |------|-------------| | `create_function` | This function has been replaced by anonymous functions and shouldn't be used anymore. | | `exec`, `passthru`, `shell_exec`, `system`, `proc_open`, `popen` | These functions allow a PHP script to run a bash shell command. Rarely used by web apps except for build scripts that might need them. | | `pcntl_*` | The `pcntl_*` functions are responsible for process management. Most of them cause a fatal error if used within a web request. Cron tasks or workers may need them. Most are usually safe to disable. | | `curl_exec`, `curl_multi_exec` | These functions allow a PHP script to make arbitrary HTTP requests. If you're using HTTP libraries such as Guzzle, don't disable them. | | `show_source` | This function shows a syntax highlighted version of a named PHP source file. Rarely useful outside of development. | ##### Execution mode PHP has two execution modes you can choose from: - The command line interface mode (PHP-CLI) is the mode used for command line scripts and standalone apps. This is the mode used when you're logged into your container via SSH, for [crons](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#crons), and usually also for [alternate start commands](#alternate-start-commands). To use PHP-CLI, run your script with `php `, where is a file path relative to the [app root](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#root-directory). - The Common Gateway Interface mode (PHP-CGI) is the mode used for web apps and web requests. This is the default mode when the `start` command isn't explicitly set. To use PHP-CGI, run your script with a symlink: `/usr/bin/start-php-app `, where is a file path relative to the [app root](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#root-directory). With PHP-CGI, PHP is run using the FastCGI Process Manager (PHP-FPM). ##### Alternate start commands To specify an alternative process to run your code, set a `start` command. For more information about the start command, see the [web commands reference](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#web-commands). By default, start commands use PHP-CLI. Find out how and when to use each [execution mode](#execution-mode). Note that the `start` command must run in the foreground and is executed before the [deploy hook](https://docs.upsun.com../../create-apps/hooks/hooks-comparison.md). That means that PHP-FPM can't run simultaneously with another persistent process such as [ReactPHP](https://github.com/platformsh-examples/platformsh-example-reactphp) or [Amp](https://github.com/platformsh-examples/platformsh-example-amphp). If you need multiple processes, they have to run in separate containers. See some generic examples on how to use alternate start commands: - Add your web server’s code in a PHP file. - Specify an alternative ``start`` command by adapting the following: ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "myapp" web: commands: start: /usr/bin/start-php-app ``` - Configure the container to listen on a TCP socket: ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "myapp" web: upstream: socket_family: tcp protocol: http ``` When you listen on a TCP socket, the ``$PORT`` environment variable is automatically set. See more options on how to [configure where requests are sent](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#upstream). You might have to configure your app to connect via the ``$PORT`` TCP socket, especially when using web servers such as [Swoole](https://docs.upsun.com/languages/php/swoole.md) or [Roadrunner](https://github.com/roadrunner-server/roadrunner). - Optional: Override redirects to let the custom web server handle them: ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "myapp" locations: "/": passthru: true scripts: false allow: false ``` To execute runtime-specific tasks (such as clearing cache) before your app starts, follow these steps: - Create a separate shell script that includes all the commands to be run. - Specify an alternative ``start`` command by adapting the following: ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "myapp" web: commands: start: bash && /usr/bin/start-php-app ``` is the bash script created in step 1. is a file path relative to the [app root](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#root-directory). ##### Foreign function interfaces PHP 7.4 introduced support for [foreign function interfaces (FFIs)](https://en.wikipedia.org/wiki/Foreign_function_interface). FFIs allow your PHP program to call routines or use services written in C or Rust. Note: FFIs are only intended for advanced use cases. Use with caution. If you are using C code, you need `.so` library files. Either place these files directly in your repository or compile them in a makefile using `gcc` in your [build hook](https://docs.upsun.com../../create-apps/hooks/hooks-comparison.md#build-hook). Note: The `.so` library files shouldn't be located in a publicly accessible directory. If you are compiling Rust code, use the build hook to [install Rust](https://doc.rust-lang.org/stable/book/ch01-01-installation.md). To leverage FFIs, follow these steps: 1. [Enable and configure OPcache preloading](https://docs.upsun.com/languages/php/tuning.md#enable-opcache-preloading). 2. Enable the FFI extension: ```yaml {location=".upsun/config.yaml"} applications: myapp: type: 'php:8.4' runtime: extensions: - ffi ``` 3. Make sure that your [preload script](https://docs.upsun.com/languages/php/tuning.md#opcache-preloading) calls the `FFI::load()` function. Using this function in preload is considerably faster than loading the linked library on each request or script run. 4. If you are running FFIs from the command line, enable the preloader by adding the following configuration: ```yaml {location=".upsun/config.yaml"} applications: myapp: type: 'php:8.4' variables: php: opcache.enable_cli: true ``` 5. Run your script with the following command: ```bash php ``` ##### Frameworks All major PHP web frameworks can be deployed on Upsun. See dedicated guides for deploying and working with them: - [Laravel](https://docs.upsun.com/get-started/stacks/laravel.md) - [Symfony](https://docs.upsun.com/get-started/stacks/symfony.md) ##### Modify your PHP runtime when using the composable image **Note**: This section is only relevant when using the Upsun [composable image (BETA)](https://docs.upsun.com/create-apps/app-reference/composable-image.md). The following table presents the possible modifications you can make to your PHP primary runtime using the `stack` key and composable image. Each modification should be listed below the stack chosen (i.e. `extensions` are enabled under `.applications.frontend.stack[0]["php@8.3"].extensions` for PHP 8.3). See the example below for more details. | Name | Type | Description | |-----------------------------|-------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------| | `extensions` | List of `string`s OR [extensions definitions](https://docs.upsun.com/create-apps/app-reference/composable-image#php-extensions-and-python-packages) | [PHP extensions](https://docs.upsun.com/languages/php/extensions.md) to enable. | | `disabled_extensions` | List of `string`s | [PHP extensions](https://docs.upsun.com/languages/php/extensions.md) to disable. | | `request_terminate_timeout` | `integer` | The timeout for serving a single request after which the PHP-FPM worker process is killed. | | `sizing_hints` | A [sizing hints definition](https://docs.upsun.com/create-apps/app-reference/composable-image.md#sizing-hints) | The assumptions for setting the number of workers in your PHP-FPM runtime. | | `xdebug` | An Xdebug definition | The setting to turn on [Xdebug](https://docs.upsun.com/languages/php/xdebug.md). | Here is an example configuration: ```yaml {location=".upsun/config.yaml"} applications: frontend: stack: - "php@8.3": extensions: - apcu # A PHP extension made available to the PHP runtime - sodium - xsl - pdo_sqlite xdebug: idekey: YOUR_KEY disabled_extensions: - gd request_terminate_timeout: 200 sizing_hints: request_memory: 45 reserved_memory: 70 - "php83Extensions.apcu" # A PHP extension made available to all runtimes. - "python@3.12" - "python312Packages.yq" ``` **Note**: You can also set your [app’s runtime timezone](https://docs.upsun.com/create-apps/timezone.md). #### Extensions **Note**: You can now use the [Upsun composable image (BETA)](https://docs.upsun.com/create-apps/app-reference/composable-image.md) to install runtimes and tools in your application container. When using the composable image, see how you can: - [Manage PHP extensions](https://docs.upsun.com/create-apps/app-reference/composable-image.md#php-extensions-and-python-packages) - [Modify your PHP runtime](https://docs.upsun.com/languages/php.md#modify-your-php-runtime-when-using-the-composable-image) PHP has a number of [extensions](https://pecl.php.net/) developed by members of the community. Some of them are available for Upsun containers. You can define the PHP extensions you want to enable or disable: ```yaml {location=".upsun/config.yaml"} applications: myapp: type: 'php:8.4' runtime: extensions: - raphf - http - igbinary - redis disabled_extensions: - sqlite3 ``` You can also [include configuration options](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#extensions) for specific extensions. The following table shows all extensions that are available (Avail) and on by default (Def). You can turn on the available ones with the `extensions` key and turn off those on by default with the `disabled_extensions` key. (Extensions marked with `*` are built in and can't be turned off.) | Extension | 5.4 | 5.5 | 5.6 | 7.0 | 7.1 | 7.2 | 7.3 | 7.4 | 8.0 | 8.1 | 8.2 | 8.3 | 8.4 | | ``amqp`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``apc`` | Avail | ``apcu`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``apcu_bc`` | Avail Avail Avail Avail Avail | ``applepay`` | Avail Avail Avail Avail | ``bcmath`` | Def Def Def Def Def Def Def Def Def Def | ``blackfire`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``bz2`` | Avail Def Def Def Def Def Def Def Def Def | ``calendar`` | Def Def Def Def Def Def Def Def Def Def | ``ctype`` | Def Def Def Def Def Def Def Def Def Def | ``curl`` | Def Def Def Def Def Def Def Def Def Def Def Def Def | ``datadog`` | Avail Avail | ``dba`` | Def Def Def Def Def Def Def Def Def Def | ``dom`` | Def Def Def Def Def Def Def Def Def Def | ``enchant`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``event`` | Avail Avail Avail Avail Avail Avail Avail Avail | ``exif`` | Def Def Def Def Def Def Def Def Def Def | ``ffi`` | Avail Avail Avail Avail Avail | ``fileinfo`` | Def Def Def Def Def Def Def Def Def Def | ``ftp`` | Def Def Def Def Def Def Def Def Def Def | ``gd`` | Def Def Def Def Def Def Def Def Def Def Def Def Def | ``gearman`` | Avail Avail Avail | ``geoip`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``gettext`` | Def Def Def Def Def Def Def Def Def Def | ``gmp`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``gnupg`` | Avail Avail | ``http`` | Avail Avail Avail Avail Avail Avail Avail Avail | ``iconv`` | Def Def Def Def Def Def Def Def Def Def | ``igbinary`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``imagick`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail with``webp`` Avail with``webp`` Avail with``webp`` Avail with``webp`` | ``imap`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``interbase`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``intl`` | Def Def Def Def Def Def Def Def Def Def Def Def Def | ``ioncube`` | Avail Avail Avail Avail Avail Avail Avail Avail | ``json`` | Def Def Def Def Def Def * * * * * | ``ldap`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``mailparse`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``mbstring`` | Def Def Def Def Def Def Def Def Def Def | ``mcrypt`` | Def Def Def Avail Avail | ``memcache`` | Avail Avail Avail | ``memcached`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``mongo`` | Avail Avail Avail | ``mongodb`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``msgpack`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``mssql`` | Avail Avail Avail | ``mysql`` | Def Def Def Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``mysqli`` | Def Def Def Def Def Def Def Def Def Def Def Def Def | ``mysqlnd`` | Def Def Def Def Def Def Def Def Def Def Def Def Def | ``newrelic`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``oauth`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``odbc`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``opcache`` | Def Def Def Def Def Def Def Def Def Def Def | ``openswoole`` | Avail Avail | ``opentelemetry`` | Avail Avail | ``pdo`` | Def Def Def Def Def Def Def Def Def Def Def Def Def | ``pdo_dblib`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``pdo_firebird`` | Avail Avail Avail Avail Avail Avail Avail Avail | ``pdo_mysql`` | Def Def Def Def Def Def Def Def Def Def Def Def Def | ``pdo_odbc`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``pdo_pgsql`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``pdo_sqlite`` | Def Def Def Def Def Def Def Def Def Def Def Def Def | ``pdo_sqlsrv`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``pecl-http`` | Avail | ``pgsql`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``phar`` | Def Def Def Def Def Def Def Def Def Def | ``phpdbg`` | Avail | ``pinba`` | Avail Avail Avail | ``posix`` | Def Def Def Def Def Def Def Def Def Def | ``propro`` | Avail | ``protobuf`` | Avail | ``pspell`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``pthreads`` | Avail Avail | ``raphf`` | Avail Avail Avail Avail Avail Avail Avail | ``rdkafka`` | Avail Avail Avail | ``readline`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``recode`` | Avail Avail Avail Avail Avail Avail Avail | ``redis`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``shmop`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``simplexml`` | Def Def Def Def Def Def Def Def Def Def | ``snmp`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``soap`` | Def Def Def Def Def Def Def Def Def Def | ``sockets`` | Def Def Def Def Def Def Def Def Def Def | ``sodium`` | Avail Avail Avail Avail Avail Avail Avail Avail | ``sourceguardian`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``spplus`` | Avail Avail | ``sqlite3`` | Def Def Def Def Def Def Def Def Def Def Def Def Def | ``sqlsrv`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``ssh2`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``swoole`` | Avail Avail | ``sybase`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``sysvmsg`` | Def Def Def Def Def Def Def Def Def Def | ``sysvsem`` | Def Def Def Def Def Def Def Def Def Def | ``sysvshm`` | Def Def Def Def Def Def Def Def Def Def | ``tideways`` | Avail Avail Avail Avail Avail Avail Avail Avail | ``tideways_xhprof`` | Avail Avail Avail Avail Avail Avail Avail | ``tidy`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``tokenizer`` | Def Def Def Def Def Def Def Def Def Def | ``uuid`` | Avail Avail Avail Avail Avail Avail Avail Avail | ``uv`` | Avail | ``wddx`` | Avail Avail Avail Avail Avail | ``xcache`` | Avail Avail | ``xdebug`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``xhprof`` | Avail Avail Avail | ``xml`` | Def Def Def Def Def Def Def Def Def Def | ``xmlreader`` | Def Def Def Def Def Def Def Def Def Def | ``xmlrpc`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``xmlwriter`` | Def Def Def Def Def Def Def Def Def Def | ``xsl`` | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail | ``yaml`` | Avail Avail Avail Avail Avail Avail Avail Avail | ``zbarcode`` | Avail Avail Avail Avail | ``zendopcache`` | Def * * * * * * * * * * * * | ``zip`` | Def Def Def Def Def Def Def Def Def Def Some built-in modules are always on: - `date` - `filter` - `hash` - `json` (from 8.0) - `libxml` - `openssl` - `pcntl` - `pcre` - `Reflection` - `session` - `SPL` - `standard` - `Zend OPcache` (from 5.5) - `zlib` To see a complete list of the compiled PHP extensions, run the following [CLI command](https://docs.upsun.com../../administration/cli/_index.md): ```bash upsun ssh "php -m" ``` ###### Custom PHP extensions It's possible to use an extension not listed here, but it takes slightly more work: 1. Download the `.so` file for the extension as part of your build hook using `curl` or similar. It can also be added to your Git repository if the file isn't publicly downloadable, but committing large binary blobs to Git is generally not recommended. 2. Load the extension using an absolute path by [customizing the PHP settings](https://docs.upsun.com/languages/php.md#customize-php-settings) For example, if the extension is named `spiffy.so` and is in your [app root](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#root-directory), your configuration looks like the following: ```yaml {location=".upsun/config.yaml"} applications: myapp: type: 'php:8.4' variables: php: extension: /app/spiffy.so ``` #### PHP performance tuning p:last-child]:mb-0 [&>h3]:mt-0 rounded-lg" > ####### Note You can now use composable image (BETA) to install runtimes and tools in your application container. To find out more, see the [dedicated documentation page](https://docs.upsun.com/create-apps/app-reference/composable-image.md). Once your app is up and running it still needs to be kept fast. Upsun offers a wide degree of flexibility in how PHP behaves, but that does mean you may need to take a few steps to ensure your site is running optimally. The following recommendations are guidelines only. They're also listed in about the order to investigate them. ###### Upgrade to PHP 8 To make a PHP-based site run faster, the first step is to upgrade the PHP version. Upgrading the PHP version might require changes to your app. For more details and recommendations, see the [PHP migration guides](https://www.php.net/manual/en/migration80.php). To change your PHP version, change the [`type` in your app configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#types). Before merging to production, test the change on a branch and make sure that your app is working as expected. ###### Optimize the FPM worker count PHP-FPM uses a fixed number of simultaneous worker processes to handle incoming requests. If more simultaneous requests are received than the number of workers, then some requests wait until worker processes are available. The default worker count is set to a conservative default value. To determine and set the optimal value for your app, see [PHP-FPM sizing](https://docs.upsun.com/languages/php/fpm.md). ###### OPcache preloading OPcache preloading loads selected files into shared memory, making their content (functions, classes) globally available for requests. It also removes the need to include these files later. When OPcache is correctly configured, it can result in significant improvements to both CPU and memory usage. Consult your framework's documentation to see if there are recommendations for optimal preload configuration or ready-to-use preload scripts. OPcache is only available on PHP 7.4+ and uses PHP-CGI. If your PHP version doesn't support OPcache, this is a good reason to upgrade. Note that the only way to clear the preload cache is by [restarting PHP-FPM](#restart-php-fpm). If you have [disabled OPcache timestamp validation](#disable-opcache-timestamp-validation), you need to clear the OPcache explicitly on deployment (which can be done by restarting PHP-FPM). ####### Enable OPcache preloading To enable preloading, add a variable that specifies a preload script: ```yaml {location=".upsun/config.yaml"} applications: myapp: type: 'php:8.4' variables: php: opcache.preload: '' ``` `` is a file path relative to the [app root](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#root-directory). It may be any PHP script that calls `opcache_compile_file()`. The following example uses a `preload.php` file as the preload script. This script loads all `.php` files in the `vendor` directory (and subdirectories): ```php {location="preload.php"} $file) { // This is the important part! opcache_compile_file($file[0]); } ``` ####### Configure OPcache OPcache needs to be tuned before production usage and can be configured the [same way as PHP](https://docs.upsun.com/languages/php.md#customize-php-settings). Let the app run for a while before tuning OPcache since the preload script may change some of the configuration. ######## Set the maximum number of cached files `opcache.max_accelerated_files` is the maximum number of files that OPcache can cache at once. If this value is lower than the number of files in the app, the cache becomes less effective because it starts [thrashing](https://en.wikipedia.org/wiki/Thrashing_(computer_science)). To determine the maximum number of files to cache, follow these steps: 1. Connect to the container via SSH using the [CLI](https://docs.upsun.com../../development/ssh.md) by running `upsun ssh`. 2. Determine roughly how many `.php` files your app has by running this command from [your app root](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#root-directory): ```bash find . -type f -name '*.php' | wc -l ``` Note that the returned valued is an approximation. Some apps have PHP code in files that don't end in `.php` or files that are generated at runtime. 3. Set `opcache.max_accelerated_files` to a value slightly higher than the returned number. PHP automatically rounds the value up to the next highest prime number. An example configuration: ```yaml {location=".upsun/config.yaml"} applications: myapp: type: 'php:8.4' variables: php: 'opcache.max_accelerated_files': 22000 ``` ######## Set memory consumption `opcache.memory_consumption` is the total memory (in megabytes) that OPcache can use with FastCGI. If the app uses more than this, the cache starts [thrashing](https://en.wikipedia.org/wiki/Thrashing_(computer_science)) and becomes less effective. Determining the optimal limit to memory consumption requires executing code via a web request to get adequate statistics. [CacheTool](https://github.com/gordalina/cachetool) is an open-source tool to help you get the statistics. To determine the total amount of memory to use, follow these steps: 1. Connect to the container via SSH using the [CLI](https://docs.upsun.com../../development/ssh.md) by running `upsun ssh`. 2. Change to the `/tmp` directory (or any other non-web-accessible writable directory) with `cd /tmp`. 3. Download CacheTool with `curl -sLO https://github.com/gordalina/cachetool/releases/latest/download/cachetool.phar`. 4. Make CacheTool executable with `chmod +x cachetool.phar`. 5. Check the OPcache status for FastCGI commands by running the following command: ```bash php cachetool.phar opcache:status --fcgi=$SOCKET ``` The `--fcgi=$SOCKET` option ensures the PHP-FPM process on the server connects through the right socket. 6. Analyze the output to determine the optimal value for `opcache.memory_consumption`. The most important values from CacheTool's output are the following: - `Memory used` - `Memory free` - `Oom restarts` (out of memory restarts) If the value is different than 0, you don't have enough memory allocated to OPcache. If `Memory free` is too low or `Oom Restarts` too high, set a higher value for memory consumption. 7. Set `opcache.memory_consumption`. Note: The unit for `opcache.memory_consumption` is megabytes. An example configuration: ```yaml {location=".upsun/config.yaml"} applications: myapp: type: 'php:8.4' variables: php: 'opcache.memory_consumption': 96 ``` 8. [Restart PHP-FPM](#restart-php-fpm) and make sure that OPcache works as expected by rerunning CacheTool with the following command: ```bash php cachetool.phar opcache:status --fcgi=$SOCKET ``` 9. Remove CacheTool by deleting the `cachetools.phar` file with `rm -rf cachetools.phar`. ####### Disable OPcache timestamp validation By default, OPcache checks that the cached version of a file is always up-to-date. This means that every time a cached file is used, OPcache compares it to the file on disk. If that file has changed, it gets reloaded and re-cached. This allows to support apps that generate compiled PHP code from user configuration. If you know your code isn't going to change outside a new deployment, you can disable that check and get a small performance improvement. Timestamp validation can be disabled by adding the following variable to your [app configuration](https://docs.upsun.com../../create-apps/_index.md): ```yaml {location=".upsun/config.yaml"} applications: myapp: type: 'php:8.4' variables: php: 'opcache.validate_timestamps': 0 ``` When you have disabled OPcache timestamp validation, you need to explicitly clear OPcache on deployment by [restarting PHP-FPM](#restart-php-fpm). Note: If your app generates PHP code at runtime based on user configuration, don't disable timestamp validation. Doing so would prevent updates to the generated code from being loaded. ###### Restart PHP-FPM To force a restart of PHP-FPM: 1. Connect to your app container via SSH using the [CLI](https://docs.upsun.com../../development/ssh.md) by running `upsun ssh`. 2. Run `pkill -f -u "$(whoami)" php-fpm`. ###### Optimize your code To optimize your app, consider using a [profiler](https://docs.upsun.com../../increase-observability/application-metrics.md). A profiler helps determine what slow spots can be found and addressed and helps improve performance. #### PHP-FPM sizing p:last-child]:mb-0 [&>h3]:mt-0 rounded-lg" > ####### Note You can now use composable image (BETA) to install runtimes and tools in your application container. To find out more, see the [dedicated documentation page](https://docs.upsun.com/create-apps/app-reference/composable-image.md). PHP-FPM helps improve your app's performance by maintaining pools of workers that can process PHP requests. This is particularly useful when your app needs to handle a high number of simultaneous requests. By default, Upsun automatically sets a maximum number of PHP-FPM workers for your app. This number is calculated based on three parameters: - The container memory: the amount of memory you can allot for PHP processing depending on [your defined application resources](https://docs.upsun.com/manage-resources.md). - The request memory: the amount of memory an average PHP request is expected to require. - The reserved memory: the amount of memory you need to reserve for tasks that aren't related to requests. The number is calculated as follows: ![The sum of container memory minus reserved memory divided by request memory](https://docs.upsun.com/images/php/PHP-FPM-Workers-Calculation.png "0.2") Note that when the resulting number is a decimal, it's rounded up to set the maximum number of workers. Also, the minimum number of PHP-FPM workers is 2. To adjust the maximum number of PHP-FPM workers depending on your app's needs, follow the instructions on this page. ###### Before you begin You need: - An up-and-running web app in PHP, complete with [PHP-FPM](https://www.php.net/manual/en/install.fpm.php) - The [Upsun CLI](https://docs.upsun.com../../administration/cli.md) Note that the memory settings mentioned on this page are different from the [`memory_limit` PHP setting](https://docs.upsun.com/languages/php.md). The `memory_limit` setting is the maximum amount of memory a single PHP process can use before it's automatically terminated. ###### 1. Estimate the optimal request memory for your app To determine what the optimal request memory is for your app, you can refer to your PHP access logs. Run a command similar to: ```bash upsun log --lines 5000 php.access | awk '{print $6}' | sort -n | uniq -c ``` This command takes into account the last 5,000 requests that reached PHP-FPM. You can adjust this number depending on the amount of traffic on your site. In the output, you can see how many requests used how much memory, in KB. For example: ```bash 2654 2048 431 4096 584 8192 889 10240 374 12288 68 46384 ``` The output shows that: - The majority of requests peaked at 2,048 KB of memory. - Most other requests used up to around 10 MB of memory. - A few requests used up to around 12 MB of memory. - Only 68 requests peaked at around 46 MB of memory. In this situation, you might want to be cautious and [set your request memory](#2-adjust-the-maximum-number-of-php-fpm-workers) to 12 MB. Setting a lower request memory presents a risk of allowing more concurrent requests. This can result in memory swapping and latencies. ###### 2. Adjust the maximum number of PHP-FPM workers By default, the request memory is set to 45 MB and the reserved memory is set to 70 MB. These values allow most programs to run, but you can amend them to fit your needs. To do so, adjust your [app configuration](https://docs.upsun.com../../create-apps.md). Under `runtime` in the [`sizing_hints` setting](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#sizing-hints), set the values for `reserved_memory` and `request_memory`. For example, if you estimate your [optimal request memory](#1-estimate-the-optimal-request-memory-for-your-app) to be 110 MB and your reserved memory to be 80 MB, you can use: ```yaml {location=".upsun/config.yaml"} applications: myapp: type: 'php:8.4' runtime: sizing_hints: request_memory: 110 reserved_memory: 80 ``` Note that the minimum value for the `request_memory` key is 10 MB and the minimum value for the `reserved_memory` key is 70 MB. If you set lower values, they're automatically overridden with those minimums. To check the maximum number of PHP-FPM workers available to your app, run the following command, where `children` refers to PHP-FPM workers: ```bash upsun ssh "grep -e '^pm.max_children' /etc/php/*/fpm/php-fpm.conf" ``` You get output similar to the following: ```bash pm.max_children = 5 ``` #### Using Xdebug p:last-child]:mb-0 [&>h3]:mt-0 rounded-lg" > ####### Note You can now use composable image (BETA) to install runtimes and tools in your application container. To find out more, see the [dedicated documentation page](https://docs.upsun.com/create-apps/app-reference/composable-image.md). [Xdebug](https://xdebug.org/) is a real-time debugger extension for PHP. While usually used for local development, it can also be helpful for debugging aberrant behavior on the server. As configured on Upsun, it avoids any runtime overhead for non-debug requests, even in production, and only allows connections via SSH tunnels to avoid any security issues. Note that Xdebug runs only on your app containers. So you can't use it for [worker containers](https://docs.upsun.com../../create-apps/workers.md). Also, note that if you use a [custom start command](https://docs.upsun.com/languages/php.md#alternate-start-commands), Xdebug is automatically disabled. ###### Before you begin The following table shows the PHP versions where Xdebug is available: | 5.4 | 5.5 | 5.6 | 7.0 | 7.1 | 7.2 | 7.3 | 7.4 | 8.0 | 8.1 | 8.2 | 8.3 | 8.4 | | Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail Avail You also need: - The Upsun [CLI](https://docs.upsun.com../../administration/cli.md) - A Xdebug-compatible IDE installed on your machine. For setup instructions, consult your IDE's Xdebug documentation, such as that for [PHPStorm](https://www.jetbrains.com/help/phpstorm/configuring-xdebug.md). ###### 1. Set up Xdebug Xdebug runs as a second PHP-FPM process used only for debugging requests, leaving the normal process unaffected. To enable Xdebug, add the following to your [app configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md): ```yaml {location=".upsun/config.yaml"} applications: myapp: type: 'php:8.4' runtime: xdebug: idekey: ``` can be any arbitrary alphanumeric string. When that key is defined, Upsun starts a second PHP-FPM process on the container that's identically configured but also has Xdebug enabled. Only incoming requests that have an Xdebug cookie or query parameter set are forwarded to the debug PHP-FPM process. All other requests are directed to the normal PHP-FPM process and thus have no performance impact. If you have enabled the [router cache](https://docs.upsun.com../../define-routes/cache.md), you need to explicitly add the Xdebug cookie (`XDEBUG_SESSION`) to the cookie allowlist. Depending on the cookies already listed, the result should look similar to the following: ```yaml {location=".upsun/config.yaml"} applications: myapp: type: 'php:8.4' runtime: xdebug: idekey: routes: "https://{default}/": # ... cache: enabled: true cookies: ['/^SS?ESS/', 'XDEBUG_SESSION'] ``` Xdebug has several configuration options available. They can be set the same way as any other [PHP setting](https://docs.upsun.com/languages/php.md#php-settings). For a full list of available options, consult the [Xdebug documentation](https://xdebug.org/docs/). ###### 2. Use Xdebug ####### Open a tunnel To open an SSH tunnel to the server from a local checkout of your app, run the following [CLI command](https://docs.upsun.com../../administration/cli.md) : ```bash upsun environment:xdebug ``` That SSH tunnel allows your IDE and the server to communicate debug information securely. By default, Xdebug operates on port `9003`. Generally, it's best to configure your IDE to use that port. To use an alternate port, use the `--port` flag. To close the tunnel and terminate the debug connection, press Ctrl + C. ####### Install an Xdebug helper While Xdebug can be triggered from the browser by adding a special query parameter, the preferred way is to use a browser plugin helper. Helpers are available for [Firefox](https://addons.mozilla.org/en-US/firefox/addon/xdebug-helper-for-firefox/) and [Chrome](https://chrome.google.com/webstore/detail/xdebug-helper/eadndfjplgieldjbigjakmdgkmoaaaoc). Their respective plugin pages document how to trigger them when needed. ###### 3. Configure your IDE Follow the instructions for your IDE, such as those for [PHPStorm](https://www.jetbrains.com/help/phpstorm/configuring-xdebug.md). The common steps for setup usually include: 1. Configuring the Xdebug debug port and making sure it's set to the expected value (`9003` as default or the value you chose with `--port` when opening the tunnel). 2. Making sure that external connections are allowed. 3. Adding a new server for your Upsun environment. The Host should be the hostname of the environment on Upsun you are debugging. The Port should always be `443` and the Debugger set to `Xdebug`. 4. Ensuring path mappings is enabled. This lets you define what remote paths on the server correspond to what path on your local machine. In the majority of cases you can just define [your app root](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#root-directory) to map to `myapp`. 5. Listening for connections. 6. Starting debugging. While in listen mode, start the `upsun xdebug` tunnel. Use the Xdebug helper plugin for your browser to enable debugging. Set a break point in your app, then load a page in your browser. The request should pause at the break point and allow you to examine the running app. #### Custom Redis versions p:last-child]:mb-0 [&>h3]:mt-0 rounded-lg" > ####### Note You can now use composable image (BETA) to install runtimes and tools in your application container. To find out more, see the [dedicated documentation page](https://docs.upsun.com/create-apps/app-reference/composable-image.md). [Redis](https://docs.upsun.com../../add-services/redis.md) is a popular structured key-value service, supported by Upsun. It's frequently used for caching. ###### Install PhpRedis The [PhpRedis](https://github.com/phpredis/phpredis) extension is available on Upsun's PHP container images. The extension has been known to break its API between versions when removing deprecated functionality. The version available on each application image is the latest available at the time that PHP version was built, which if your app is sensitive to PhpRedis versions may not be ideal. It may happen that the version of the PhpRedis extension available for your PHP version isn't compatible with your app and upgrading your app isn't feasible. If so, use the following script as an alternative to download and compile a precise version of the extension. **Note**: Do not use this approach unless you really need to. Using the provided PhpRedis extension is preferred in the majority of cases. To ease the installation of a customer version of PhpRedis, use a [PhpRedis install script](https://github.com/platformsh/snippets/blob/main/src/install-phpredis.sh). Invoke this script from your build hook, specifying a version. Any tagged version of the library is acceptable: ```yaml {location=".upsun/config.yaml"} applications: myapp: type: 'php:8.4' hooks: build: | set -e # Install PhpRedis v5.3.7: curl -fsS https://raw.githubusercontent.com/platformsh/snippets/main/src/install-phpredis.sh | { bash /dev/fd/3 5.3.7 ; } 3<&0 ``` ###### Install Relay Relay is a [Redis](https://docs.upsun.com../../add-services/redis.md) client similar to [PhpRedis](https://github.com/phpredis/phpredis) and [Predis](https://github.com/predis/predis). It's intended to be a drop-in replacement for those libraries. That PHP extension is also a shared in-memory cache like APCu. All retrieved keys are held in the PHP master process’ memory, which is shared across all FPM workers. That means if the FPM Worker #1 fetches the `users:count` key from Redis, all other FPM workers instantaneously retrieve that key from Relay without having to communicate with Redis. To ease the installation of a customer version of Relay, use the [Relay install script](https://github.com/platformsh/snippets/blob/main/src/install-relay.sh). Invoke this script from your build hook, specifying a version. Any tagged version of the library is acceptable: ```yaml {location=".upsun/config.yaml"} applications: myapp: type: 'php:8.4' hooks: build: | set -e # Install Relay v0.6.0: curl -fsS https://raw.githubusercontent.com/platformsh/snippets/main/src/install-relay.sh | { bash /dev/fd/3 v0.6.0 ; } 3<&0 ``` ###### Change extension or version To change the Redis extension or the version you are using, update the build hook and clear the build cache: `upsun project:clear-build-cache`. The new version is *not* be used until you clear the build cache. There's no need to declare the extension in the `runtime` block. That's only for pre-built extensions. ###### What these scripts do 1. Download the Relay/PhpRedis source code. 2. Check out the version specified in the build hook. 3. Compile the extension. 4. Copy the resulting `relay.so`/`redis.so` file to [your app root](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#root-directory). 5. Add a line to the `php.ini` file in your app root to enable the extension, creating the file if necessary. If the script doesn't find a `$PLATFORM_CACHE_DIR` directory defined, it exits silently. So if you run the build hook locally, it has no effect. #### Swoole p:last-child]:mb-0 [&>h3]:mt-0 rounded-lg" > ####### Note You can now use composable image (BETA) to install runtimes and tools in your application container. To find out more, see the [dedicated documentation page](https://docs.upsun.com/create-apps/app-reference/composable-image.md). Swoole is a PHP extension that extends PHP core with a coroutine based asynchronous network application framework designed for building large scale concurrent systems. Unlike PHP-FPM’s stateless operating, Swoole relies on establishing persistent connections with every user, sending and receiving data in real-time. [Swoole](https://github.com/swoole/swoole-src) and [Open Swoole](https://openswoole.com/) are two forked libraries pursuing that goal. **Note**: The ``swoole`` and ``openswoole`` extensions are [available by default](https://docs.upsun.com/languages/php/extensions.md) on Upsun PHP 8.2 Upsun containers. For other versions of PHP, you can install both extensions manually by following the instructions on this page. You need: - PHP 7.3+ for Swoole - PHP 7.4.0+ for Open Swoole - The [Swoole installation script](https://raw.githubusercontent.com/platformsh/snippets/main/src/install_swoole.sh). **Note**: Currently, the installation script is compatible with PHP <=8.0. It is **not** compatible with PHP 8.3, and the ``swoole`` and ``openswoole`` extensions are **not** available on Upsun PHP 8.3 containers yet. ###### Install Install the PHP extension for Swoole or Open Swoole during the build. Take advantage of an [installation script](https://raw.githubusercontent.com/platformsh/snippets/main/src/install_swoole.sh). You need to pass 2 parameters: * Which Swoole project to use: `openswoole` or `swoole` * Which version to install ```yaml {location=".upsun/config.yaml"} applications: app: type: 'php:' hooks: build: | set -e ... curl -fsS https://raw.githubusercontent.com/platformsh/snippets/main/src/install_swoole.sh | { bash /dev/fd/3 openswoole 4.11.0 ; } 3 ###### Use Override the default web server with a [custom start command](https://docs.upsun.com/languages/php.md#alternate-start-commands). Octane should listen on a TCP socket. ```yaml {location=".upsun/config.yaml"} applications: myapp: type: 'php:8.4' web: upstream: socket_family: tcp protocol: http commands: start: php --port=$PORT locations: "/": passthru: true scripts: false allow: false ``` #### Authenticated Composer repositories p:last-child]:mb-0 [&>h3]:mt-0 rounded-lg" > ####### Note You can now use composable image (BETA) to install runtimes and tools in your application container. To find out more, see the [dedicated documentation page](https://docs.upsun.com/create-apps/app-reference/composable-image.md). [Packagist](https://packagist.org/) is the primary Composer repository for public PHP packages. But you can also have Composer download PHP packages from a private, third-party Composer repository. To make sure Composer has the necessary credentials to do so, follow the instructions on this page. ###### Before you begin You need: - A Upsun project using [PHP](https://docs.upsun.com../php.md) and Composer - Credentials to access a private third-party Composer repository - The [Upsun CLI](https://docs.upsun.com../../administration/cli.md) ###### 1. Declare a private Composer repository To allow Composer to download packages from a private third-party repository, declare the repository in your Composer setup. ```json {location="composer.json"} { "repositories": [ { "type": "composer", "url": "https://" } ] } ``` ###### 2. Set up Composer authentication using a variable To allow Composer to successfully authenticate when accessing the declared private repository, set an [`env:COMPOSER_AUTH` variable](https://docs.upsun.com../../development/variables.md) for your project. To do so, run the following command: ```bash upsun variable:create --level project --name env:COMPOSER_AUTH \ --json true --visible-runtime false --sensitive true --visible-build true \ --value '{"http-basic": {"": {"username": "", "password": ""}}}' ``` The [`env:` prefix](https://docs.upsun.com../../development/variables.md#top-level-environment-variables) means that the variable is exposed as its own Unix environment variable. The `--visible-runtime false` and `--visible-build true` flags mean the variable is available to Composer only during the build. ###### 3. Clear your project's build cache For security reasons, make sure that the authentication credentials aren't cached in your project's build container. To do so, run the following command: ```bash upsun project:clear-build-cache ``` ###### Access dependencies downloaded from a private repository When you download a dependency from a private third-party Composer repository, that dependency is usually hosted in a [private Git repository](https://docs.upsun.com../../development/private-repository.md). Access to private Git repositories is restricted through the use of SSH keys. But most private Composer tools mirror tagged releases of dependencies and serve them directly without hitting the Git repository. To avoid having to authenticate against a remote Git repository, make sure your dependencies specify tagged releases. #### Troubleshoot PHP p:last-child]:mb-0 [&>h3]:mt-0 rounded-lg" > ####### Note You can now use composable image (BETA) to install runtimes and tools in your application container. To find out more, see the [dedicated documentation page](https://docs.upsun.com/create-apps/app-reference/composable-image.md). For more general information, see how to [troubleshoot development](https://docs.upsun.com/development/troubleshoot.md). ###### Server reached `max_children` If the server is receiving more concurrent requests than it has PHP processes allocated, you encounter a message like the following: ```text {location="/var/log/app.log"} WARNING: [pool web] server reached max_children setting (2), consider raising it ``` This means some requests have to wait until another finishes. Upsun sets the number of workers based on the available memory of your container and the estimated average memory size of each process. You have two ways to increase the number of workers: - Adjust the [worker sizing hints](https://docs.upsun.com/languages/php/fpm.md) for your project. - Add [additional resources](https://docs.upsun.com/manage-resources.md) with the `upsun resources:set` command ###### Execution timeout If your PHP app can't handle the amount of traffic or is slow, you encounter a message like the following: ```text {location="/var/log/app.log"} WARNING: [pool web] child 120, script '/app/public/index.php' (request: "GET /index.php") execution timed out (358.009855 sec), terminating ``` This means your PHP process is running longer than allowed. You can adjust the `max_execution_time` value in `php.ini`, but there is still a hard cap of 5 minutes on any web request. The most common causes of a timeout are an infinite loop (which is a bug that you should fix) or the work itself requires a long time to complete. For the latter case, you should consider putting the task into a background job. The following command identifies the 20 slowest requests in the past hour, which can provide an indication of what code paths to investigate. ```bash grep $(date +%Y-%m-%dT%H --date='-1 hours') /var/log/php.access.log | sort -k 4 -r -n | head -20 ``` If you see that the processing time of certain requests is slow (such as taking longer than 1000 ms), you should consider a [continuous observability solution](https://docs.upsun.com../../increase-observability/application-metrics.md) to monitor your app and help you improve the performance issue. Full access to [Blackfire.io](https://docs.upsun.com../../increase-observability/application-metrics/blackfire.md) is bundled with your PHP and Python Upsun projects. Otherwise, you may check if the following options are applicable: - Find the most visited pages and see if they can be cached and/or put behind a CDN. Refer to [how caching works](https://docs.upsun.com../../define-routes/cache.md). - Add [additional resources](https://docs.upsun.com/manage-resources.md) with the `upsun resources:set` command ###### Troubleshoot a crashed PHP process If your PHP process crashed with a segmentation fault, you encounter a message like the following: ```text {location="/var/log/app.log"} WARNING: [pool web] child 112 exited on signal 11 (SIGSEGV) after 7.405936 seconds from start ``` Either a PHP extension is hitting a segmentation fault or your PHP app code is crashing. Review recent changes in your app and try to find the root cause. You might want to use a tool such as [Xdebug](https://docs.upsun.com/languages/php/xdebug.md) for quicker troubleshooting. ###### Troubleshoot a killed PHP process If your PHP process is killed by the kernel, you encounter a message like the following: ```text {location="/var/log/app.log"} WARNING: [pool web] child 429 exited on signal 9 (SIGKILL) after 50.938617 seconds from start ``` That means the memory usage of your container exceeds the limit that's been allocated, so the kernel kills the offending process. To solve this issue, try the following approaches: - Check if the memory usage of your app is as expected and try to optimize it. - Use [sizing hints](https://docs.upsun.com/languages/php/fpm.md) to reduce the amount of PHP workers, which reduces the memory footprint. - Add [additional resources](https://docs.upsun.com/manage-resources.md) with the `upsun resources:set` command ###### Restart PHP processes stuck during a build or deployment If your [build or deployment is running longer than expected](https://docs.upsun.com../../development/troubleshoot.md#stuck-build-or-deployment), it might be because of a PHP process getting stuck. To restart your PHP processes, run the following command in your app container: ```bash pkill -f php-fpm ``` ###### Resource temporarily unavailable If all PHP workers are busy, you encounter a message like the following: ```text {location="/var/log/error.log"} connect() to unix:/run/app.sock failed (11: Resource temporarily unavailable) ``` This can be because too many requests are coming in at once or the requests are taking too long to be processed (such as with calls to external third-party servers without timeouts). To address the issue, you can: - Lower the memory consumption of each request so that the amount of PHP workers gets automatically raised. This can be customized with the `runtime.sizing_hints.request_memory` key in your `.upsun/config.yaml` file. For more details, consult [PHP-FPM sizing](https://docs.upsun.com/languages/php/fpm.md). - Add a [CDN](https://docs.upsun.com../../domains/cdn.md). - Set up [HTTP caching](https://docs.upsun.com/learn/bestpractices/http-caching.md). - Follow the global [performance tuning recommendations](https://docs.upsun.com/languages/php/tuning.md). - Remove stale plugins and extensions when using a CMS. - Add [additional resources](https://docs.upsun.com/manage-resources.md) with the `upsun resources:set` command ### Python p:last-child]:mb-0 [&>h3]:mt-0 rounded-lg" > ###### Note You can now use composable image (BETA) to install runtimes and tools in your application container. To find out more, see the [dedicated documentation page](https://docs.upsun.com/create-apps/app-reference/composable-image.md). Python is a general purpose scripting language often used in web development. You can deploy Python apps on Upsun using a server or a project such as [uWSGI](https://uwsgi-docs.readthedocs.io/en/latest/). ##### Supported versions You can select the major and minor version. Patch versions are applied periodically for bug fixes and the like. When you deploy your app, you always get the latest available patches. - 3.12 - 3.11 - 3.10 - 3.9 - 3.8 ###### Specify the language To use Python, specify ``python`` as your [app’s type](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#types): ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. : type: 'python:' ``` For example: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'python:3.9' ``` ###### Deprecated versions The following versions are [deprecated](https://docs.upsun.com/glossary.md#deprecated-versions). They're available, but they aren't receiving security updates from upstream and aren't guaranteed to work. They'll be removed in the future, so migrate to one of the [supported versions](#supported-versions). - 3.7 - 3.6 - 3.5 - 2.7* \* This version doesn't receive any updates at all. You are strongly recommended to upgrade to a supported version. ##### Usage example ###### Run your own server You can define any server to handle requests. Once you have it configured, add the following configuration to get it running on Upsun: 1. Specify one of the [supported versions](#supported-versions): ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'python:3.9' ``` 2. Install the requirements for your app. ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'python:3.9' dependencies: python3: pipenv: "2022.12.19" hooks: build: | set -eu pipenv install --system --deploy ``` 3. Define the command to start your web server: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'python:3.9' web: # Start your app with the configuration you define # You can replace the file location with your location commands: start: python server.py ``` You can choose from many web servers such as Daphne, Gunicorn, Hypercorn, and Uvicorn. See more about [running Python web servers](https://docs.upsun.com/languages/python/server.md). ###### Use uWSGI You can also use [uWSGI](https://uwsgi-docs.readthedocs.io/en/latest/) to manage your server. Follow these steps to get your server started. 1. Specify one of the [supported versions](#supported-versions): ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'python:3.9' ``` 2. Define the conditions for your web server: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'python:3.9' web: upstream: # Send requests to the app server through a unix socket # Its location is defined in the SOCKET environment variable socket_family: "unix" # Start your app with the configuration you define # You can replace the file location with your location commands: start: "uwsgi --ini conf/uwsgi.ini" locations: # The folder from which to serve static assets "/": root: "public" passthru: true expires: 1h ``` 3. Create configuration for uWSGI such as the following: ```ini {location="config/uwsgi.ini"} [uwsgi] # Unix socket to use to talk with the web server # Uses the variable defined in the configuration in step 2 socket = $(SOCKET) protocol = http # the entry point to your app wsgi-file = app.py ``` Replace `app.py` with whatever your file is. 4. Install the requirements for your app. ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'python:3.9' dependencies: python3: pipenv: "2022.12.19" hooks: build: | set -eu pipenv install --system --deploy ``` 5. Define the entry point in your app: ```python # You can name the function differently and pass the new name as a flag # start: "uwsgi --ini conf/uwsgi.ini --callable " def application(env, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) return [b"Hello world from Upsun"] ``` ##### Package management Your app container comes with pip pre-installed. For more about managing packages with pip, Pipenv, and Poetry, see how to [manage dependencies](https://docs.upsun.com/languages/python/dependencies.md). To add global dependencies (packages available as commands), add them to the `dependencies` in your [app configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#dependencies): ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'python:3.9' dependencies: python3: : ``` For example, to use `pipenv` to manage requirements and a virtual environment, add the following: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'python:3.9' dependencies: python3: pipenv: "2022.12.19" hooks: build: | set -eu pipenv install --system --deploy ``` ##### Connect to services The following examples show how to access various [services](https://docs.upsun.com../../add-services.md) with Python. For more information on configuring a given service, see the page for that service. You can access service credentials to connect to [managed services](https://docs.upsun.com/add-services/) from environment variables present in the application container. Consult each of the individual service documentation to see how to retrieve and surface credentials into your application. - [ClickHouse](https://docs.upsun.com/add-services/clickhouse.md#usage-example) - [Elasticsearch](https://docs.upsun.com/add-services/elasticsearch.md#use-in-app) - [Gotenberg](https://docs.upsun.com/add-services/gotenberg.md#usage-example) - [Headless Chrome](https://docs.upsun.com/add-services/headless-chrome.md#use-in-app) - [InfluxDB](https://docs.upsun.com/add-services/influxdb.md#use-in-app) - [Kafka](https://docs.upsun.com/add-services/kafka.md#use-in-app) - [MariaDB/MySQL](https://docs.upsun.com/add-services/mysql.md#use-in-app) - [Memcached](https://docs.upsun.com/add-services/memcached.md#use-in-app) - [MongoDB](https://docs.upsun.com/add-services/mongodb.md#use-in-app) - [Network Storage](https://docs.upsun.com/add-services/network-storage.md#usage-example) - [OpenSearch](https://docs.upsun.com/add-services/opensearch.md#use-in-app) - [PostgreSQL](https://docs.upsun.com/add-services/postgresql.md#use-in-app) - [RabbitMQ](https://docs.upsun.com/add-services/rabbitmq.md#use-in-app) - [Redis](https://docs.upsun.com/add-services/redis.md#use-in-app) - [Solr](https://docs.upsun.com/add-services/solr.md#use-in-app) - [Varnish](https://docs.upsun.com/add-services/varnish.md#usage-example) - [Vault KMS](https://docs.upsun.com/add-services/vault.md#use-vault-kms) ##### Sanitizing data By default, data is inherited automatically by each child environment from its parent. If you need to sanitize data in preview environments for compliance, see how to [sanitize databases](https://docs.upsun.com../../development/sanitize-db.md). ##### Frameworks All major Python web frameworks can be deployed on Upsun. See dedicated guides for deploying and working with them: - [Django](https://docs.upsun.com/get-started/stacks/django.md) - [Flask](https://docs.upsun.com/get-started/stacks/flask.md) #### Manage Python dependencies p:last-child]:mb-0 [&>h3]:mt-0 rounded-lg" > ####### Note You can now use composable image (BETA) to install runtimes and tools in your application container. To find out more, see the [dedicated documentation page](https://docs.upsun.com/create-apps/app-reference/composable-image.md). You can manage Python packages in different ways. Python images come with pip installed, but they're flexible enough so you can choose what package manager you want. This article describes how to configure major package management tools. This package management is different from global dependencies (packages available as commands), which you can add in your [app configuration](https://docs.upsun.com../../create-apps.md). See more about [managing global dependencies](https://docs.upsun.com/languages/python.md#package-management). ###### Pip [pip](https://pip.pypa.io/en/stable/) is the primary package installer for Python and comes installed on every Python container. You can use it to install packages from the Python Package Index and other locations. To manage packages with pip, commit a `requirements.txt` file with all of the dependencies needed for your app. Then install the packages in your [`build` hook](https://docs.upsun.com../../create-apps/hooks.md), such as by running the following command: `pip install -r requirements.txt`. The following sections present ideas to keep in mind to ensure repeatable deployments on Upsun. ####### pip version The version of pip on Python containers gets updated regularly. But it isn't guaranteed to be the latest version or the version that matches your local environment. You might want to define a specific version of pip in your deployments to further enforce repeatable builds. To do so, modify your [app configuration](https://docs.upsun.com../../create-apps.md), as in the following examples: ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "myapp" type: 'python:3.9' variables: env: PIP_VERSION: '22.3.1' hooks: build: | # Fail the build if any errors occur set -eu # Download a specific version of pip python3.9 -m pip install pip==$PIP_VERSION # Install dependencies pip install -r requirements.txt ``` ####### pip freeze You can write `requirements.txt` files in various ways. You can specify anything from the latest major to a specific patch version in a [requirement specifier](https://pip.pypa.io/en/stable/reference/requirement-specifiers/). Use `pip freeze` before committing your requirements to pin specific package versions. This ensures repeatable builds on Upsun with the same packages. ###### Pipenv [Pipenv](https://pipenv.pypa.io/en/latest/) is a package manager for Python that creates and manages a virtual environment for Python projects. Dependencies are tracked and defined within a `Pipfile`. It also generates a `Pipfile.lock` file to produce repeatable installs. You can specify the latest or a specific version of Pipenv in your deployments to ensure repeatable builds. Because Pipenv depends on pip, you might want to also specify the pip version. ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "myapp" type: 'python:3.9' variables: env: PIP_VERSION: '22.3.1' dependencies: python3: pipenv: '2022.12.19' hooks: build: | # Fail the build if any errors occur set -eu # Download a specific version of pip python3.9 -m pip install pip==$PIP_VERSION # Install dependencies # Include `--deploy` to fail the build if `Pipfile.lock` isn't up to date pipenv install --deploy ``` ###### Poetry [Poetry](https://python-poetry.org/docs/) is a tool for dependency management and packaging in Python. It allows you to declare the libraries your project depends on and manages them for you. Poetry offers a lock file to ensure repeatable installs and can build your project for distribution. It also creates and manages virtual environments to keep project work isolated from the rest of your system. To set up Poetry on Upsun, follow these steps: 1. Configure your virtual environment by setting two variables in your [app configuration](https://docs.upsun.com../../create-apps.md). - [`POETRY_VIRTUALENVS_IN_PROJECT`](https://python-poetry.org/docs/configuration/#virtualenvsin-project): Setting this to `true` places the virtual environment at the root of the app container: `/app/.venv`. - [`POETRY_VIRTUALENVS_CREATE`](https://python-poetry.org/docs/configuration/#virtualenvscreate): Setting this to `true` ensures that the same virtual environment created during the build hook is reused in subsequent steps. Set the variables as follows: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'python:3.9' variables: env: POETRY_VIRTUALENVS_IN_PROJECT: true POETRY_VIRTUALENVS_CREATE: true ``` 2. Install Poetry. You can specify the latest or a specific version of Poetry in your deployments to ensure repeatable builds. ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "myapp" type: 'python:3.9' dependencies: python3: poetry: '>=1.8' variables: env: POETRY_VIRTUALENVS_IN_PROJECT: true POETRY_VIRTUALENVS_CREATE: true hooks: build: | # Fail the build if any errors occur set -eu # Download the latest version of pip python3.9 -m pip install --upgrade pip # Install dependencies poetry install ``` 3. Make Poetry available outside the build hook. Although step 2 updated the `PATH` to make Poetry available during the build hook, it isn't enough to make it available at subsequent stages. To use Poetry in a start command, a deploy hook, or during SSH sessions, update the `PATH` in a [`.environment` file](https://docs.upsun.com../../development/variables/set-variables.md#set-variables-via-script). ```text {location=".environment"} # Updates PATH when Poetry is used, making it available during deploys, start commands, and SSH. if [ -n "$POETRY_VERSION" ]; then export PATH="/app/.local/bin:$PATH" fi ``` #### Web servers p:last-child]:mb-0 [&>h3]:mt-0 rounded-lg" > ####### Note You can now use composable image (BETA) to install runtimes and tools in your application container. To find out more, see the [dedicated documentation page](https://docs.upsun.com/create-apps/app-reference/composable-image.md). The Python ecosystem offers a number of web servers that can be used to deploy to Upsun. The following examples deploy a Django project named `myapp`. They assume a `myapp/wsgi.py` or `myapp/asgi.py` file with a callable `application`. Adjust the examples to fit your framework and app. ###### Gunicorn [Gunicorn](https://docs.gunicorn.org/) is a Python WSGI HTTP Server for Unix that operates on a pre-fork worker model. The Gunicorn server is broadly compatible with various web frameworks, light on server resource usage, and fast. To deploy with Gunicorn on Upsun , use one of the following examples to update your [app configuration](https://docs.upsun.com../../create-apps.md). The examples vary based on both your package manager (Pip, Pipenv, or Poetry) and whether your app listens on a TCP (default) or Unix (for running behind a proxy server) socket. For more information on upstream sockets and protocols, see the [application reference](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#upstream). The snippets below assume that Gunicorn has been added as a dependency to your `requirements.txt`, `Pipfile.lock`, or `poetry.lock`. ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" type: 'python:3.9' web: upstream: socket_family: unix commands: start: "gunicorn -w 4 -b unix:$SOCKET app.wsgi:application" locations: "/": passthru: true "/static": root: "static" expires: 1h allow: true ``` ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" type: 'python:3.9' web: commands: start: "pipenv run gunicorn -w 4 -b localhost:$PORT app.wsgi:application" locations: "/": passthru: true "/static": root: "static" expires: 1h allow: true ``` ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" type: 'python:3.9' web: upstream: socket_family: unix commands: start: "pipenv run gunicorn -w 4 -b unix:$SOCKET app.wsgi:application" locations: "/": passthru: true "/static": root: "static" expires: 1h allow: true ``` ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" type: 'python:3.9' web: commands: start: "poetry run gunicorn -w 4 -b localhost:$PORT app.wsgi:application" locations: "/": passthru: true "/static": root: "static" expires: 1h allow: true ``` ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" type: 'python:3.9' web: upstream: socket_family: unix commands: start: "poetry run gunicorn -w 4 -b unix:$SOCKET app.wsgi:application" locations: "/": passthru: true "/static": root: "static" expires: 1h allow: true ``` ####### Gunicorn workers These examples define four worker processes with `-w 4`. For more details on what you can configure, see the [Gunicorn documentation](https://docs.gunicorn.org/en/stable/faq.md#worker-processes). Workers can also be defined with a custom [worker class](https://docs.gunicorn.org/en/latest/settings.md#worker-class), such as [Uvicorn](https://www.uvicorn.org/#running-with-gunicorn), [gevent](https://www.gevent.org/), or [Tornado](https://www.tornadoweb.org/). For example, to add a Uvicorn worker class to the pip example for Unix, adjust the start command to the following: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'python:3.9' web: upstream: socket_family: unix commands: start: "gunicorn -w 4 -k uvicorn.workers.UvicornWorker -b unix:$SOCKET app.wsgi:application" ``` ###### Daphne [Daphne](https://github.com/django/daphne) is a HTTP, HTTP2 ,and WebSocket protocol server for ASGI and ASGI-HTTP, developed to power Django Channels. To deploy with Daphne on Upsun , use one of the following examples to update your [app configuration](https://docs.upsun.com../../create-apps.md). The examples vary based on both your package manager (Pip, Pipenv, or Poetry) and whether your app listens on a TCP (default) or Unix (for running behind a proxy server) socket. For more information on upstream sockets and protocols, see the [application reference](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#upstream). The snippets below assume that Daphne has been added as a dependency to your `requirements.txt`, `Pipfile.lock`, or `poetry.lock`. ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" type: 'python:3.9' web: upstream: socket_family: unix commands: start: "daphne -u $SOCKET app.asgi:application" locations: "/": passthru: true "/static": root: "static" expires: 1h allow: true ``` ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" type: 'python:3.9' web: commands: start: "pipenv run daphne -p $PORT app.asgi:application" locations: "/": passthru: true "/static": root: "static" expires: 1h allow: true ``` ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" type: 'python:3.9' web: upstream: socket_family: unix commands: start: "pipenv run daphne -u $SOCKET app.asgi:application" locations: "/": passthru: true "/static": root: "static" expires: 1h allow: true ``` ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" type: 'python:3.9' web: commands: start: "poetry run daphne -p $PORT app.asgi:application" locations: "/": passthru: true "/static": root: "static" expires: 1h allow: true ``` ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" type: 'python:3.9' web: upstream: socket_family: unix commands: start: "poetry run -u $SOCKET app.asgi:application" locations: "/": passthru: true "/static": root: "static" expires: 1h allow: true ``` ###### Uvicorn [Uvicorn](https://www.uvicorn.org/) is an ASGI web server implementation for Python. To deploy with Uvicorn on Upsun , use one of the following examples to update your [app configuration](https://docs.upsun.com../../create-apps.md). The examples vary based on both your package manager (Pip, Pipenv, or Poetry) and whether your app listens on a TCP (default) or Unix (for running behind a proxy server) socket. For more information on upstream sockets and protocols, see the [application reference](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#upstream). The snippets below assume that Uvicorn has been added as a dependency to your `requirements.txt`, `Pipfile.lock`, or `poetry.lock`. ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" type: 'python:3.9' web: upstream: socket_family: unix commands: start: "uvicorn app.asgi:application --uds $SOCKET --workers 4" locations: "/": passthru: true "/static": root: "static" expires: 1h allow: true ``` ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" type: 'python:3.9' web: commands: start: "pipenv run uvicorn app.asgi:application --port $PORT --workers 4" locations: "/": passthru: true "/static": root: "static" expires: 1h allow: true ``` ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" type: 'python:3.9' web: upstream: socket_family: unix commands: start: "pipenv run uvicorn app.asgi:application --uds $SOCKET --workers 4" locations: "/": passthru: true "/static": root: "static" expires: 1h allow: true ``` ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" type: 'python:3.9' web: commands: start: "poetry run uvicorn app.asgi:application --port $PORT --workers 4" locations: "/": passthru: true "/static": root: "static" expires: 1h allow: true ``` ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" type: 'python:3.9' web: upstream: socket_family: unix commands: start: "poetry run uvicorn app.asgi:application --uds $SOCKET --workers 4" locations: "/": passthru: true "/static": root: "static" expires: 1h allow: true ``` ####### Uvicorn workers These examples define four worker processes with `-w 4`. For more recommendations on this and other settings, see the [Uvicorn documentation](https://www.uvicorn.org/settings/#timeouts). Instead of the `-w` flag, you can also use the `WEB_CONCURRENCY` variable. See how to [set variables](https://docs.upsun.com../../development/variables/set-variables.md). ###### Hypercorn [Hypercorn](https://hypercorn.readthedocs.io/) is an ASGI and WSGI web server inspired by Gunicorn. To deploy with Hypercorn on Upsun , use one of the following examples to update your [app configuration](https://docs.upsun.com../../create-apps.md). The examples vary based on both your package manager (Pip, Pipenv, or Poetry) and whether your app listens on a TCP (default) or Unix (for running behind a proxy server) socket. For more information on upstream sockets and protocols, see the [application reference](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#upstream). The snippets below assume that Hypercorn has been added as a dependency to your `requirements.txt`, `Pipfile.lock`, or `poetry.lock`. ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" type: 'python:3.9' web: upstream: socket_family: unix commands: start: "hypercorn app.asgi:application -b unix:$SOCKET -w 4" locations: "/": passthru: true "/static": root: "static" expires: 1h allow: true ``` ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" type: 'python:3.9' web: commands: start: "pipenv run hypercorn app.asgi:application -b localhost:$PORT -w 4" locations: "/": passthru: true "/static": root: "static" expires: 1h allow: true ``` ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" type: 'python:3.9' web: upstream: socket_family: unix commands: start: "pipenv run hypercorn app.asgi:application -b unix:$SOCKET -w 4" locations: "/": passthru: true "/static": root: "static" expires: 1h allow: true ``` ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" type: 'python:3.9' web: commands: start: "poetry run hypercorn app.asgi:application -b localhost:$PORT -w 4" locations: "/": passthru: true "/static": root: "static" expires: 1h allow: true ``` ```yaml {location=".upsun/config.yaml"} applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "/" type: 'python:3.9' web: upstream: socket_family: unix commands: start: "poetry run hypercorn app.asgi:application -b unix:$SOCKET -w 4" locations: "/": passthru: true "/static": root: "static" expires: 1h allow: true ``` ####### Hypercorn workers These examples define four worker processes with `-w 4`. For more details on what you can configure, see the [Hypercorn documentation](https://hypercorn.readthedocs.io/en/latest/how_to_guides/configuring.md). Workers can also be defined with a custom [worker class](https://hypercorn.readthedocs.io/en/latest/how_to_guides/configuring.md#configuration-options), such as Asyncio, Uvloop, or Trio. For example, to add a Asyncio worker class to the pip example for Unix, adjust the start command to the following: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'python:3.9' web: upstream: socket_family: unix commands: start: "hypercorn app.asgi:application -b unix:$SOCKET -w 4 -k asyncio" ``` #### Manage Python versions in non-Python containers p:last-child]:mb-0 [&>h3]:mt-0 rounded-lg" > ####### Note You can now use composable image (BETA) to install runtimes and tools in your application container. To find out more, see the [dedicated documentation page](https://docs.upsun.com/create-apps/app-reference/composable-image.md). You may need to use a specific version of Python that isn't available in an app container for a different language. For example, a container might have a long-term support version, while you want the latest version. In such cases, use the [Pyenv version manager](https://github.com/pyenv/pyenv) to install the specific version you want to use. 1. Add your target Python version as a [variable](https://docs.upsun.com../../development/variables/_index.md): ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'php:8.4' variables: env: # Update for your desired Python version. PYTHON_VERSION: "3.11.0" ``` 2. Add Pyenv in a [`build` hook](https://docs.upsun.com../../create-apps/hooks/hooks-comparison.md#build-hook): ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'php:8.4' variables: env: # Update for your desired Python version. PYTHON_VERSION: "3.11.0" hooks: build: | # Exit the hook on any failure set -e # Clone Pyenv to the build cache if not present if [ ! -d "$PLATFORM_CACHE_DIR/.pyenv" ]; then mkdir -p $PLATFORM_CACHE_DIR/.pyenv git clone https://github.com/pyenv/pyenv.git $PLATFORM_CACHE_DIR/.pyenv fi # Pyenv environment variables export PYENV_ROOT="$PLATFORM_CACHE_DIR/.pyenv" export PATH="$PYENV_ROOT/bin:$PATH" # Initialize Pyenv if command -v pyenv 1>/dev/null 2>&1; then eval "$(pyenv init --path)" fi # Install desired Python version mkdir -p $PLATFORM_CACHE_DIR/.pyenv/versions if [ ! -d "$PLATFORM_CACHE_DIR/.pyenv/versions/$PYTHON_VERSION" ]; then pyenv install $PYTHON_VERSION fi # Set global Python version pyenv global $PYTHON_VERSION ``` Now your build hook can use the specified version of Python. You can verify this by running `python --version`. If you want this Python version to be available in the runtime environment, follow these steps: 1. Copy Pyenv to your runtime environment at the end of your build hook: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'php:8.4' hooks: build: | ... # Copy Pyenv directory to runtime directory cp -R $PLATFORM_CACHE_DIR/.pyenv $PLATFORM_APP_DIR # Rehash Pyenv for new (runtime) location PYENV_ROOT="$PLATFORM_APP_DIR/.pyenv" $PLATFORM_APP_DIR/.pyenv/bin/pyenv rehash ``` 2. Create an [`.environment` file](https://docs.upsun.com../../development/variables/set-variables.md#set-variables-via-script): ```bash touch .environment ``` 3. Update the PATH for the runtime environment: ```yaml {location=".environment"} export PATH=/app/.pyenv/bin:/app/.pyenv/shims:$PATH ``` Now the specified Python version is used in the runtime environment. ### Ruby p:last-child]:mb-0 [&>h3]:mt-0 rounded-lg" > ###### Note You can now use composable image (BETA) to install runtimes and tools in your application container. To find out more, see the [dedicated documentation page](https://docs.upsun.com/create-apps/app-reference/composable-image.md). Upsun supports deploying any Ruby application. Your application can use any Ruby application server such as Puma or Unicorn and deploying a Rails or a Sinatra app is very straight forward. ##### Supported versions You can select the major and minor version. Patch versions are applied periodically for bug fixes and the like. When you deploy your app, you always get the latest available patches. ###### Ruby MRI - 3.3 - 3.2 - 3.1 - 3.0 ###### Specify the language To use Ruby, specify `ruby` as your [app's `type`](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#types): ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. : type: 'ruby:' ``` For example: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'ruby:3.3' ``` ###### Deprecated versions The following versions are [deprecated](https://docs.upsun.com/glossary.md#deprecated-versions). They're available, but they aren't receiving security updates from upstream and aren't guaranteed to work. They'll be removed in the future, so migrate to one of the [supported versions](#supported-versions). - 2.7 - 2.6 - 2.5 - 2.4 - 2.3 ##### Puma based Rails configuration This example uses Puma to run a Ruby application. You could use any Ruby application server such as Unicorn. Configure the `.upsun/config.yaml` file with a few key settings as listed below. A complete example is included at the end of this section. 1. Specify the language of your application (available versions are listed above): ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'ruby:3.3' ``` 2. Setup environment variables. Rails runs by default on a preview environment. You can change the Rails/Bundler via those environment variables, some of which are defaults on Upsun. ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'ruby:3.3' variables: env: PIDFILE: "tmp/server.pid" # Allow to start puma directly even if `tmp/pids` directory is not created RAILS_ENV: "production" BUNDLE_WITHOUT: 'development:test' TARGET_RUBY_VERSION: '~>3.3' # this will allow to not fail on PATCH update of the image ``` The `SECRET_KEY_BASE` variable is generated automatically based on the [`PLATFORM_PROJECT_ENTROPY` variable](https://docs.upsun.com../development/variables/use-variables.md#use-provided-variables) but you can change it. Based on TARGET_RUBY_VERSION, we recommand to set on your Gemfile so next PATCH release of ruby doesn't fail the build: ```ruby ruby ENV["TARGET_RUBY_VERSION"] || File.read(File.join(File.dirname(__FILE__), ".ruby-version")).strip ``` 3. Build your application with the build hook. Assuming you have your dependencies stored in the `Gemfile` at [your app root](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#root-directory), create a hook like the following: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'ruby:3.3' ... hooks: build: | set -e bundle install bundle exec rails assets:precompile deploy: bundle exec rake db:migrate ``` These are installed as your project dependencies in your environment. You can also use the `dependencies` key to install global dependencies. These can be Ruby, Python, NodeJS, or PHP libraries. If you have assets, it's likely that you need NodeJS/yarn. ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'ruby:3.3' ... dependencies: nodejs: yarn: "*" ``` 4. Configure the command to start serving your application (this must be a foreground-running process) under the `web` section: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'ruby:3.3' ... web: upstream: socket_family: unix commands: # for puma start: "bundle exec puma -b unix://$SOCKET" # for unicorn # start: "bundle exec unicorn -l $SOCKET" ``` This assumes you have Puma as a dependency in your Gemfile: ```ruby gem "puma", ">= 5.0" ``` 5. Define the web locations your application is using: ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'ruby:3.3' ... web: locations: "/": root: "public" passthru: true expires: 1h allow: true ``` This configuration sets the web server to handle HTTP requests at `/static` to serve static files stored in `/app/static/` folder. Everything else is forwarded to your application server. 6. Create any Read/Write mounts. The root file system is read only. You must explicitly describe writable mounts. ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: type: 'ruby:3.3' ... mounts: "/log": source: tmp source_path: log "/storage": source: storage source_path: storage "/tmp": source: tmp source_path: tmp ``` This setting allows your application writing temporary files to `/app/tmp`, logs stored in `/app/log`, and active storage in `/app/storage`. You can define other read/write mounts (your application code itself being deployed to a read-only file system). Note that the file system is persistent and when you backup your cluster these mounts are also backed up. 7. Then, setup the routes to your application in `.upsun/config.yaml`. ```yaml {location=".upsun/config.yaml"} applications: ... routes: "https://{default}/": type: upstream upstream: "myapp:http" ``` ###### Complete app configuration Here is a complete `.upsun/config.yaml` file: ```yaml {location=".upsun/config.yaml"} # The name of the app, which must be unique within a project. applications: myapp: type: 'ruby:3.3' dependencies: nodejs: yarn: "*" relationships: mysql: variables: env: BUNDLE_CACHE_ALL: '1' # Default, Cache all gems, including path and git gems. BUNDLE_CLEAN: '1' # /!\ if you are working with Ruby<2.7 this doesn't work well, but should be safe on modern Rubies. BUNDLE_DEPLOYMENT: '1' # Default, Disallow changes to the Gemfile. BUNDLE_ERROR_ON_STDERR: '1' # Default. BUNDLE_WITHOUT: 'development:test' PIDFILE: "tmp/server.pid" # Allow to start puma directly even if `tmp/pids` directory is not created DEFAULT_BUNDLER_VERSION: "2.5.14" # In case none is mentioned in Gemfile.lock EXECJS_RUNTIME: 'Node' # If you need one on your assets https://github.com/rails/execjs#readme NODE_ENV: 'production' NODE_VERSION: v14.17.6 NVM_VERSION: v0.38.0 RACK_ENV: 'production' RAILS_ENV: 'production' RAILS_LOG_TO_STDOUT: '1' # Default RAILS_TMP: '/tmp' # Default hooks: build: | set -e echo "Installing NVM $NVM_VERSION" unset NPM_CONFIG_PREFIX export NVM_DIR="$PLATFORM_APP_DIR/.nvm" # install.sh will automatically install NodeJS based on the presence of $NODE_VERSION curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/$NVM_VERSION/install.sh | bash [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # we install the bundled bundler version and fallback to a default (in env vars above) export BUNDLER_VERSION="$(grep -A 1 "BUNDLED WITH" Gemfile.lock | tail -n 1)" || $DEFAULT_BUNDLER_VERSION echo "Install bundler $BUNDLER_VERSION" gem install --no-document bundler -v $BUNDLER_VERSION echo "Installing gems" # We copy the bundle directory to the Upsun cache directory for # safe keeping, then restore from there on the next build. That allows # bundler to skip downloading code it doesn't need to. [ -d "$PLATFORM_CACHE_DIR/bundle" ] && \ rsync -az --delete "$PLATFORM_CACHE_DIR/bundle/" vendor/bundle/ mkdir -p "$PLATFORM_CACHE_DIR/bundle" bundle install # synchronize updated cache for next build [ -d "vendor/bundle" ] && \ rsync -az --delete vendor/bundle/ "$PLATFORM_CACHE_DIR/bundle/" # precompile assets echo "Precompiling assets" # We copy the webpacker directory to the Upsun cache directory for # safe keeping, then restore from there on the next build. That allows # bundler to skip downloading code it doesn't need to. # https://guides.rubyonrails.org/asset_pipeline.html mkdir -p "$PLATFORM_CACHE_DIR/webpacker" mkdir -p "$RAILS_TMP/cache/webpacker" [ -d "$PLATFORM_CACHE_DIR/webpacker" ] && \ rsync -az --delete "$PLATFORM_CACHE_DIR/webpacker/" $RAILS_TMP/cache/webpacker/ # We dont need secret here https://github.com/rails/rails/issues/32947 SECRET_KEY_BASE=1 bundle exec rails assets:precompile rsync -az --delete $RAILS_TMP/cache/webpacker/ "$PLATFORM_CACHE_DIR/webpacker/" deploy: bundle exec rake db:migrate mounts: "/log": source: tmp source_path: log "/storage": source: storage source_path: storage "/tmp": source: tmp source_path: tmp web: upstream: socket_family: unix commands: # for puma start: "bundle exec puma -b unix://$SOCKET" # for unicorn # start: "bundle exec unicorn -l $SOCKET" locations: "/": root: "public" passthru: true expires: 1h allow: true routes: "https://{default}/": type: upstream upstream: "myapp:http" services: ... ``` ##### Configuring services This example assumes there is a MySQL instance. To configure it, [create a service](https://docs.upsun.com../add-services.md) such as the following: ```yaml {location=".upsun/config.yaml"} applications: ... routes: ... services: mysql: type: mysql:11.4 ``` ##### Connecting to services Once you have a service, link to it in your [app configuration](https://docs.upsun.com../create-apps/_index.md): ```yaml {location=".upsun/config.yaml"} applications: myapp: type: 'ruby:3.3' relationships: mysql: [...] routes: [...] services: mysql: type: mysql:11.4 ``` By using the following Ruby function calls, you can obtain the database details. ```ruby require "base64" require "json" relationships= JSON.parse(Base64.decode64(ENV['PLATFORM_RELATIONSHIPS'])) ``` This should give you something like the following: ```json { "mysql" : [ { "path" : "main", "query" : { "is_master" : true }, "port" : 3306, "username" : "user", "password" : "", "host" : "mysql.internal", "ip" : "246.0.241.50", "scheme" : "mysql" } ] } ``` For Rails, you can use the standard Rails `config/database.yml` with the values found with the snippet provided before. ##### Other tips - To speed up boot you can use the [Bootsnap gem](https://github.com/Shopify/bootsnap) and configure it with the local `/tmp`: ```ruby {location="config/boot.rb"} Bootsnap.setup(cache_dir: "/tmp/cache") ``` - For garbage collection tuning, you can read [this article](https://shopify.engineering/17489064-tuning-rubys-global-method-cache) and look for [discourse configurations](https://github.com/discourse/discourse_docker/blob/b259c8d38e0f42288fd279c9f9efd3cefbc2c1cb/templates/web.template.yml#L8) - New images are released on a regular basis to apply security patches. To avoid issues when such updates are performed, use ``` ruby ruby ENV["TARGET_RUBY_VERSION"] || File.read(File.join(File.dirname(__FILE__), ".ruby-version")).strip ``` in your `Gemfile`. ##### Troubleshooting By default, deployments have `BUNDLE_DEPLOYMENT=1` to ensure projects have a `Gemfile.lock` file. This is safer for version yank issues and other version upgrade breakages. You may encounter an error like the following during a build: ```txt W: bundler: failed to load command: rake (/app/.global/bin/rake) W: /app/.global/gems/bundler-2.3.5/lib/bundler/resolver.rb:268:in `block in verify_gemfile_dependencies_are_found!': Could not find gem 'rails (= 5.2.6)' in locally installed gems. (Bundler::GemNotFound) ``` To resolve this error: 1. Run `bundle install` with the same `ruby` and `bundler` versions defined in your `.upsun/config.yaml` file. 2. Push the `Gemfile.lock` to your repository. ### Rust p:last-child]:mb-0 [&>h3]:mt-0 rounded-lg" > ###### Note You can now use composable image (BETA) to install runtimes and tools in your application container. To find out more, see the [dedicated documentation page](https://docs.upsun.com/create-apps/app-reference/composable-image.md). Upsun supports building and deploying applications written in Rust. ##### Supported versions You can select the major version. But the latest compatible minor version is applied automatically and can’t be overridden. Patch versions are applied periodically for bug fixes and the like. When you deploy your app, you always get the latest available patches. - 1 ##### Dependencies The recommended way to handle Rust dependencies on Upsun is using Cargo. Commit a `Cargo.toml` and a `Cargo.lock` file in your repository so the system automatically downloads dependencies using Cargo. ##### Building and running your app Assuming your `Cargo.toml` and `Cargo.lock` files are present in your repository, you can build your app using the `cargo build` command to produce a working executable. You can then start it from the `web.commands.start` directive. Note that the start command _must_ run in the foreground. If the program terminates for any reason it is automatically restarted. The following basic [app configuration](https://docs.upsun.com../../create-apps.md) is sufficient to run most Rust apps. See the [complete example](#complete-example) below for more details. ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: # The language and version for your app. type: 'rust:1' hooks: build: cargo build web: commands: # Customize the start command with your own target. start: './target/debug/hello' locations: /: # Route all requests to the Rust app, unconditionally. allow: false passthru: true ``` Note that there is still an Nginx proxy server sitting in front of your application. If desired, certain paths may be served directly by Nginx without hitting your application (for static files, primarily) or you may route all requests to the Rust app unconditionally, as in the example above. ##### Built-in variables Upsun exposes relationships and other configuration as [environment variables](https://docs.upsun.com../development/variables.md). To get the `PORT` environment variable (the port on which your app is supposed to listen), use the following snippet: ```rust let port : String = env::var("PORT").unwrap_or(String::from("8888")); ``` Note that some of the environment variables are in JSON format and are base64 encoded. For example, to decode the `PLATFORM_RELATIONSHIPS` environment variable, use the following snippet: ```rust use base64::{Engine as _, engine::{general_purpose}}; use serde_json::Value; let bytes = general_purpose::STANDARD.decode(env::var("PLATFORM_RELATIONSHIPS").unwrap_or(String::new())).unwrap(); let psh_config: Value = serde_json::from_slice(&bytes).unwrap(); println!("{}", psh_config["database"]); ``` ##### Complete example Here is a basic hello world app to illustrate how you can use Rust with Upsun. It builds from a `hello.rs` file to serve a static `index.html`. Follow these steps: 1. [Install Rust and Cargo](https://www.rust-lang.org/tools/install). 2. Create a repository for your app and add the following `Cargo.toml` file: ```toml [package] name = "hello_world" version = "0.1.0" edition = "2021" [[bin]] name = "hello" path = "hello.rs" [dependencies] time = "0.1.12" regex = "0.1.41" base64 = "0.21.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" ``` 3. Add the following [app configuration](https://docs.upsun.com../../create-apps/_index.md): ```yaml {location=".upsun/config.yaml"} applications: # The app's name, which must be unique within the project. myapp: # The language and version for your app. type: 'rust:1' hooks: build: cargo build web: commands: # Customize the start command with your own target. start: './target/debug/hello' locations: /: # Route all requests to the Rust app, unconditionally. allow: false passthru: true ``` 4. To generate a `Cargo.lock` file, run the following command: ```bash cargo generate-lockfile ``` 5. Add the following `hello.rs` file: ```rust /* Simple HTTP Server */ /* Author : Ramesh Vyas */ use std::io::prelude::*; use std::net::TcpListener; use std::net::TcpStream; use std::fs; use std::env; fn main() { /* Creating a Local TcpListener at Port 8888 */ const HOST : &str ="127.0.0.1"; let port : String = env::var("PORT").unwrap_or(String::from("8888")); /* Concating Host address and Port to Create Final Endpoint */ let end_point : String = HOST.to_owned() + ":" + &port; /*Creating TCP Listener at our end point */ let listener = TcpListener::bind(end_point).unwrap(); println!("Web server is listening at port {}",port); /* Connecting to any incoming connections */ for stream in listener.incoming() { let _stream = stream.unwrap(); // Call Function to process any incomming connections handle_connection(_stream); } } fn handle_connection(mut stream: TcpStream) { let mut buffer = [0; 1024]; stream.read(&mut buffer).unwrap(); let get = b"GET / HTTP/1.1\r\n"; if buffer.starts_with(get) { let contents = fs::read_to_string("index.html").unwrap(); let response = format!( "HTTP/1.1 200 OK\r\nContent-Length: {}\r\n\r\n{}", contents.len(), contents ); stream.write(response.as_bytes()).unwrap(); stream.flush().unwrap(); } else { // some other request } } ``` ### Set up your local development environment To make changes to your app's code and test them without affecting your production environment, set up a local development environment on your computer. For the most effective testing, you want your local environment to match your Upsun environments. The best way to do this is to use a cross-platform tool based on Docker. This ensures the changes you make locally appear as they would on your Upsun environments. It also means you don't have to worry about configuring your machine with the various dependencies, certificates, and connections your app needs to run. The **recommended tool** for local development with Upsun is **[DDEV](https://docs.upsun.com/development/local/ddev.md)**. The integration with DDEV is maintained by Upsun to ensure it works smoothly. If you choose to use DDEV, follow the steps [on its page](https://docs.upsun.com/development/local/ddev.md). Otherwise, follow these steps to run your app on your computer. ##### Before you begin You need to have: - A Upsun account: new users can [register here](https://upsun.com/register/) - A working project - [Git](https://git-scm.com/downloads) - The [Upsun CLI](https://docs.upsun.com../../administration/cli.md) ##### 1. Get your code If you don't have your app code on your computer, download a copy. 1. Get your project ID by running `upsun projects`. 2. Get the code by running the following command: ```bash upsun get ``` Or pull from your [integrated Git repository](https://docs.upsun.com../../integrations/source.md). You can now access your code from the project directory on your computer. The CLI created a `.upsun/config.yaml/local` directory that's excluded from Git. It contains builds and local metadata about your project. You can now make changes to your project without pushing to Upsun each time to test them. Instead, you can locally build your application using the Upsun CLI. Note that if your app contains services, you need to open an SSH tunnel to connect to them. For more information, see how to [connect services](https://docs.upsun.com../../add-services#2-define-the-relationship). ##### 2. Connect to services If your app requires services to run, you have two options for developing locally: - [Tethered local development](https://docs.upsun.com/development/local/tethered.md) involves running your app on a local web server but keeping all other services on Upsun and connecting to them over an SSH tunnel. - [Untethered local development](https://docs.upsun.com/development/local/untethered.md) involves running your entire site locally, including all services. Choose the option that works for you and get your services running. #### Use DDEV for local development [DDEV](https://ddev.readthedocs.io/en/stable/) is an open-source tool for local development environments. It allows you to use Docker in your workflows while maintaining a GitOps workflow. You get fully containerized environments to run everything locally without having to install tools (including the Upsun CLI, PHP, and Composer) on your machine. This guide assumes you have a project already running with Upsun and you have the code on your computer. If you're starting from scratch, first [create a project](https://docs.upsun.com/get-started.md). ###### Before you begin Make sure your computer meets the [system requirements for DDEV](https://ddev.readthedocs.io/en/stable/#system-requirements). For the integration to run smoothly, you also need the following tools: - `jq` - `base64` - `perl` If you don't have these already installed, use your normal package manager. ###### 1. Install DDEV To install DDEV, follow the [DDEV documentation for your operating system](https://ddev.readthedocs.io/en/stable/users/install/ddev-installation/). This installs the self-contained `ddev` command-line interface (CLI). For more information on `ddev`, run `ddev help`. ###### 2. Add DDEV configuration to your project Get basic configuration set up for your project by running the following command: ```bash ddev config ``` Follow the prompts to add the correct DDEV configuration files to your repository. ###### 3. Add an API token To connect DDEV with your Upsun account, use a Upsun API token. First [create an API token](https://docs.upsun.com/administration/cli/api-tokens.md#2-create-an-api-token) in the Console. Then add the token to your DDEV configuration. You can do so globally (easiest for most people): ```bash ddev config global --web-environment-add=UPSUN _CLI_TOKEN= ``` You can also add the token only to the project: ```bash ddev config --web-environment-add=UPSUN _CLI_TOKEN= ``` ###### 4. Optional: Get your project data To get your environment data (files, database), run the following command: ```bash ddev pull upsun ``` To skip pulling files, add `--skip-files` to the command. To skip pulling a database, add `--skip-db` to the command. ###### 5. Run your project Now your project is ready to run: ```bash ddev start ``` This runs all your hooks and builds your project like on Upsun. The command returns the project URL `http://.ddev.site/` as well as a specific port on `http://127.0.0.1`. To see your project running, open one of these URLs. ###### What's next You've got a project running on a local web server. Now you can add customizations. For more ideas and options, see the [DDEV documentation](https://ddev.readthedocs.io/en/stable/). ####### Add environment variables If your project requires environment variables for its hooks or runtime, add them to the project's DDEV environment: ```yaml {location=".ddev/config.yaml"} web_environment: - : ``` To apply your changes, run the following command: ```bash ddev restart ``` #### Tethered local development To test changes locally, you can connect your locally running web server to service containers on an active Upsun environment. This method requires less configuration than tools such as [DDEV](https://docs.upsun.com/development/local/ddev.md), but may not perform well enough for everyday use. Because it replies on a local web server, it's also less consistent across your team. ###### Before you begin You need: - A local copy of the repository for a project running on Upsun. To get one, run ``upsun get ``. Alternatively, you can clone an integrated source repository and set the remote branch. To do so, run ``upsun project:set-remote ``. - The [Upsun CLI](https://docs.upsun.com/administration/cli.md) ###### Create the tethered connection 1. Create a new environment based on production. ```bash upsun branch new-feature ``` If you're using a [source integration](https://docs.upsun.com/integrations/source.md), open a merge/pull request. 1. To open an SSH tunnel to the new environment's services, run the following command: ```bash upsun tunnel:open ``` This command returns the addresses for SSH tunnels to all of your services. 1. Export the `PLATFORMSH_RELATIONSHIPS` environment variable with information from the open tunnel: ```bash export PLATFORM_RELATIONSHIPS="$(upsun tunnel:info --encode)" ``` 1. Run your application locally. Make sure it's set up to read configuration from Upsun environment variables. If you app relies on other Upsun environment configuration, such as routes or secret variables, make sure to mock those variables as well. Your options for running the app depend on the language and configuration. You can use the server for your language, install a copy of Nginx, or use a virtual machine or Docker image. 1. When you've finished your work, close the tunnels to your services by running the following command: ```bash upsun tunnel:close --all -y ``` ###### Connect to services directly With open tunnels to all your services, you can also connect to the running services directly. To get information on all running services, run the following command: ```bash upsun tunnels ``` You get a response similar to the following: ```bash +-------+---------------+-------------+-----+--------------+ | Port | Project | Environment | App | Relationship | +-------+---------------+-------------+-----+--------------+ | 30000 | abcdefg123456 | new-feature | app | cache | | 30001 | abcdefg123456 | new-feature | app | database | +-------+---------------+-------------+-----+--------------+ ``` You can use the port information to connect directly to a service. If you need more detailed information, such as a path or password, run the following command: ```bash upsun tunnel:info ``` You can use the information returned to connect to the remote database as if it were local. For example, the following command would connect to a MySQL database running through a tethered connection: ```bash mysql --host=127.0.0.1 --port= --user= --password= --database= ``` ###### Next steps You can now use your local environment to develop changes for review on Upsun environments. The following examples show how you can take advantage of that. ####### Onboard collaborators It's essential for every developer on your team to have a local development environment to work on. Place the local configuration into a script to ensure everyone has this. You can merge this change into production. 1. Create a new environment called `local-config`. 1. To set up a local environment for a new Upsun environment, create an executable script. ```bash touch init-local.sh && chmod +x init-local.sh ``` 1. Fill it with something similar to the following example, depending on your app and configuration: ```bash {location="init-local.sh"} #!/usr/bin/env bash ENVIRONMENT=$1 PARENT=$2 # Create the new environment upsun branch $ENVIRONMENT $PARENT # Open a tunnel to the current environment upsun tunnel:open --no-interaction # Mock Upsun environment variables export PLATFORM_RELATIONSHIPS="$(upsun tunnel:info --encode)" # Add any other variables you need # If necessary, install dependencies here # Add the command to run the server ``` 1. To commit and push the revisions, run the following command: ```bash git add . && git commit -m "Add local configuration" && git push upsun local-config ``` 1. Merge the change into production. Once the script is merged into production, any user can set up their local environment by running the following commands: ```bash upsun cd ./init-local.sh another-new-feature ``` #### Untethered local development It's possible to run your entire site locally on your computer. That way you get better performance as there's no extra latency to connect to a remote database and doesn't require an active Internet connection to work. But it does require running all necessary services (databases, search servers, and so on) locally. These can be set up however you prefer, although Upsun recommends using a virtual machine to make it easier to share configuration between developers. If you already have a development workflow in place that works for you, you can keep using it with virtually no changes. To synchronize data from an environment on Upsun, consult the documentation for each [service](https://docs.upsun.com../../add-services.md). Each service type has its own native data import/export process and Upsun doesn't get in the way of that. It's also straightforward to [download user files](https://docs.upsun.com/learn/tutorials/exporting.md) from your application using rsync. ### Variables overview Variables give you control over your project’s build process and runtime environment. You can set them in your code to make changes across your project or independent of the code for environment-specific settings. In this way, your app has additional information, such as database credentials, the host or port it can use, and which server to connect to. ##### Variable types You can set variables at different levels. All variables can be strings or base64-encoded JSON-serialized values. The following table defines what types of variables are available to you: | Type | Definer | Scope | Precedence | Build | Runtime | Uses | | -------------------------------------------------- | ----------- | ----------- | ---------- | ----- | -------- |----- | | [Application](https://docs.upsun.com/development/variables/set-variables.md#set-variables-in-your-app) | Application | Application | 4 | Yes | Yes | Non-secret values that are the same across all environments | | [Project](https://docs.upsun.com/development/variables/set-variables.md#create-project-variables) | User | Project | 3 | Yes | Yes | Secret values that are the same across all environments, such as database credentials | | [Environment](https://docs.upsun.com/development/variables/set-variables.md#create-environment-specific-variables) | User | Environment | 2 | Some | Yes | Values that vary by environment, such as which database to connect to or which payment API keys to use | | [Upsun](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables) | Pre-defined | Environment | 1 | Some | Yes | For information about your Upsun project | If there are conflicts between variables with the same name, variables [take precedence](#overrides) from 1 down. So Upsun-provided values (1) override environment variables (2), which override project variables (3), which override application-provided variables (4). All of the variables can also be [overridden via a script](https://docs.upsun.com/development/variables/set-variables.md#set-variables-via-script). ###### Choosing a variable type Choose how to set the variable based on what you are trying to do. Some environment variables should be the same for all environments. For example: - Build tool versions. If you have scripts that use specific versions of build tools (such as a [specific Node.js version](https://docs.upsun.com../../languages/nodejs/node-version.md)), You want the tools to be versioned along with your code so you can track the impact of changes. Set those variables [in the application](https://docs.upsun.com/development/variables/set-variables.md#set-variables-in-your-app). - Credentials for common services. If you have credentials for services shared across your environments, you don't want to commit these secrets to code. Set them as sensitive [project variables](https://docs.upsun.com/development/variables/set-variables.md#create-project-variables). Other configurations should vary between environment types. For example: - Service configuration for databases and such. This information be read from the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables), or the Upsun-provided [`PLATFORM_RELATIONSHIPS` variable](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). It varies by environment automatically. - Mode toggles such as enabling `debug` mode, disabling certain caches, and displaying more verbose errors. This information might vary by environment type and should be set on the [environment level](https://docs.upsun.com/development/variables/set-variables.md#create-environment-specific-variables). - API keys for remote services, especially payment gateways. If you have a different payment gateway for production and for testing, set its keys on the [environment level](https://docs.upsun.com/development/variables/set-variables.md#create-environment-specific-variables). ##### Overrides If the names of variables at different levels match, an environment variable overrides a variable with the same name in a parent environment and both override a project variable. All variables can also be [overridden via script](https://docs.upsun.com/development/variables/set-variables.md#set-variables-via-script). For an example of how the different levels work, suppose you have the following inheritable variables defined for the `main` environment: ```sh upsun var -e main Variables on the project Example (abcdef123456), environment main: +----------------+-------------+--------+---------+ | Name | Level | Value | Enabled | +----------------+-------------+--------+---------+ | system_name | project | Spiffy | | | system_version | project | 1.5 | | | api_key | environment | abc123 | true | | debug_mode | environment | 1 | true | +----------------+-------------+--------+---------+ ``` And the following variables defined for the `feature-x` environment, a child environment of `main`: ```sh upsun var -e feature-x Variables on the project Example (abcdef123456), environment feature-x: +----------------+-------------+--------+---------+ | Name | Level | Value | Enabled | +----------------+-------------+--------+---------+ | system_name | project | Spiffy | | | system_version | project | 1.5 | | | api_key | environment | def456 | true | | system_version | environment | 1.7 | true | +----------------+-------------+--------+---------+ ``` In the `main` environment, you can access `$PLATFORM_VARIABLES`: ```bash echo $PLATFORM_VARIABLES | base64 --decode | jq ``` The output looks like this: ```json { "system_name": "Spiffy", "system_version": "1.5", "api_key": "abc123", "debug_mode": "1" } ``` While in the `feature-x` environment, it looks like this: ```json { "system_name": "Spiffy", "system_version": "1.7", "api_key": "def456", "debug_mode": "1" } ``` To get a visual overview of which variables are overridden in an environment, navigate in the Console to that environment's variables settings. This example shows how it looks within the `feature-x` environment: ![The Console showing the variables split into environment and project ones, with the environment variables `api_key` and `system_version` labeled as overridden and `debug_mode` as inherited the project variable `system_version` labeled as inactive.](https://docs.upsun.com/images/management-console/variables-overridden.png "0.5") Project variables that conflict with environment variables are labeled as **Inactive**. Environment variables are labeled as **Inherited** when they get their value from a parent environment and as **Overridden** when there is a conflict and the parent environment's value doesn't apply. ##### Variable prefixes Certain variable name prefixes have special meanings. Some are defined by Upsun and apply automatically. Others are just available as a convention for your application code to follow. ###### Top-level environment variables By default, project and environment variables are only added to the `PLATFORM_VARIABLES` environment variable. You can also expose a variable as its own environment variable by giving it the prefix `env:`. For example, the variable `env:foo` creates an environment variable called `FOO`. (Note the automatic upper-casing.) ```bash upsun variable:create --name env:foo --value bar ``` You can then access that variable directly in your app container: ```bash echo $FOO bar ``` Note that environment variables with the `env:` prefix aren't added to the `PLATFORM_VARIABLES` environment variable. ###### PHP-specific variables Any variable with the prefix `php` is added to the PHP configuration for all PHP-based application containers in the project. Using variables, you can use the same files for all your environments and override values on any given environment if needed. You can set the PHP memory limit to 256 MB on a specific environment by running the following [CLI command](https://docs.upsun.com../../administration/cli/_index.md): ```bash upsun variable:create --level environment --prefix php --name memory_limit --value 256M --environment ``` To use variables across environments, set them in your [app configuration](https://docs.upsun.com../../create-apps.md). For example, to change the PHP memory limit for all environments, use the following configuration: ```yaml {location=".upsun/config.yaml"} applications: : variables: php: memory_limit: "256M" ``` ##### Framework-specific variables For specific frameworks, you can implement logic to override global configurations with [environment-specific variables](https://docs.upsun.com/development/variables/set-variables.md#create-environment-specific-variables). So you can use the same codebase and settings for all your environments, but still adapt the behavior to each environment. ##### Service environment variables For each service defined via a relationship to your application, Upsun automatically generates corresponding environment variables within your application container, in the `$_` format. All the non-alphanumerical or `_` characters (`[^0-9A-Z_]`) are transformed into an `_` , such as `MY_DATABASE_PASSWORD` for a `my-database` relationship name. **Example:** For a relationship named ``database`` to a service named `postgresl`, the following environment variables are automatically generated in your `myapp` container: ```bash DATABASE_URL=pgsql://main:main@postgresql.internal:5432/main DATABASE_INSTANCE_IPS=['123.456.78.901'] DATABASE_SERVICE=database DATABASE_QUERY={'is_master': True} DATABASE_CLUSTER=oiaenewa6sfiq-test-services-afdwftq DATABASE_HOST_MAPPED=false DATABASE_NAME=main DATABASE_FRAGMENT= DATABASE_PATH=main DATABASE_SCHEME=pgsql DATABASE_EPOCH=0 DATABASE_PORT=5432 DATABASE_HOSTNAME=azertyuiop1234567890.database.service._.eu-3.platformsh.site DATABASE_TYPE=postgresql:13 DATABASE_PUBLIC=false DATABASE_PASSWORD=main DATABASE_IP=123.456.78.901 DATABASE_USERNAME=main DATABASE_HOST=postgresql.internal DATABASE_REL=postgresql ``` #### Set variables To set variables, determine which [type of variable](https://docs.upsun.com/development/variables.md#variable-types) to use. Remember to take into account the order of precedence. All of the variables can also be [overridden via script](#set-variables-via-script). ###### Set variables in your app Set variables [in code](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#variables) using the `.upsun/config.yaml` file. These values are the same across all environments and present in the Git repository, which makes them a poor fit for API keys and other such secrets. They're better fits for uses such as configuration for consistent builds across every environment, including setting [PHP configuration values](https://docs.upsun.com/development/variables.md#php-specific-variables). Application variables are available at both build time and runtime. ###### Create project variables Add secrets for all environments in project variables using [the Console](https://docs.upsun.com../../administration/web/configure-project.md#variables) or the [CLI](https://docs.upsun.com../../administration/cli.md). For example, you may need to vary API credentials between production and other environments. To do so, set the non-production credentials as a project variable and then override these credentials for the production environment by setting a [variable specific to that environment](#create-environment-specific-variables). To specify other options, use the [flags for variable options](#variable-options). To add a project variable, follow these steps: - Select the project where you want to create a variable. - Click Settings **Settings**. - Under **Project settings**, click **Variables**. - Click **+ Create variable**. - Enter a name for the variable. - Enter the variable value. - Ensure you have selected the right [other options](#variable-options). - Click **Create variable**. When naming variables, be sure to take [variable prefixes](https://docs.upsun.com/development/variables.md#variable-prefixes) into account. In particular, to expose a variable as its own environment variable, [use the prefix `env:`](https://docs.upsun.com../../development/variables.md#top-level-environment-variables). ####### Variable options Variables have several Boolean options you can set in the Console or the CLI: | Option | CLI flag | Default | Description | |-----------|---------------------|---------|--------------------------------------------------------------------------------------------------------------------------------------------------------| | JSON | `--json` | `false` | Whether the variable is a JSON-serialized value (`true`) or a string (`false`). | | Sensitive | `--sensitive` | `false` | If set to `true`, the variable's value is hidden in the Console and in CLI responses for added security. It's still readable within the app container. | | Runtime | `--visible-runtime` | `true` | Whether the variable is available at runtime. | | Build | `--visible-build` | `true` | Whether the variable is available at build time. | So if you want the `foo` variable to be visible at build time but hidden during runtime, you can set it by running the following command: ```bash upsun variable:create --level project --name foo --value bar --visible-build true --visible-runtime false ``` You can also change the variable options after you create them (except for sensitive values, which can't be set to non-sensitive). For example, to make the `foo` variable visible at runtime and hidden during the build, run the following command: ```bash upsun variable:update foo --visible-build false --visible-runtime true ``` Note that for changes to project variables to have effect, you need to [redeploy](https://docs.upsun.com../troubleshoot.md#force-a-redeploy) your environments. ###### Create environment-specific variables Set variables for specific environments using [the Console](https://docs.upsun.com../../administration/web/configure-environment.md#variables) or the CLI. Variables can be inherited or overridden from parent environments and project variables. See [more on overriding values](https://docs.upsun.com/development/variables.md#overrides). To specify the environment for the variable, use the ``-e`` flag to specify its name. To specify other options, use the [flags for variable options](#environment-variable-options). To add a project variable, follow these steps: - Select the project where you want to create a variable. - Click Settings **Settings**. - Under **Environments**, click the environment where you want to create a variable. - Click **Variables**. - Click **+ Create variable**. - Enter a name for the variable. - Enter the variable value. - Ensure you have selected the right [other options](#environment-variable-options). - Click **Create variable**. When naming variables, be sure to take [variable prefixes](https://docs.upsun.com/development/variables.md#variable-prefixes) into account. In particular, to expose a variable as its own environment variable, [use the prefix `env:`](https://docs.upsun.com../../development/variables.md#top-level-environment-variables). ####### Environment variable options Environment variables share all of the [options available for project variables](#variable-options). Environment variables have one additional option: | Option | CLI flag | Default | Description | |-------------|-----------------|---------|----------------------------------------------------------| | Inheritable | `--inheritable` | `true` | Whether the variable is inherited by child environments. | This option is useful for setting production-only values such as credentials. For example, to set a PayPal secret value for only the `main` branch and have it not be readable elsewhere, run the following command: ```bash upsun variable:create -e main --name paypal_id --inheritable false --sensitive true ``` Other environments don't inherit it and get either a project variable of the same name if it exists or no value at all. Note that changing an environment variable causes that environment to be redeployed so the new value is available. But child environments are *not* redeployed. To make the new value accessible to those environments, [trigger a redeploy](https://docs.upsun.com../troubleshoot.md#force-a-redeploy). ####### Example environment variable Environment variables are a good place to store values that apply only on Upsun and not on your local development environment. This includes API credentials for third-party services, mode settings, and which server (development vs. production) to use. One example would be to define a Node.js application's build on a production branch (`NODE_ENV=production`), but use development mode (`NODE_ENV=development`) for each of your preview environments. Assuming you have a `main` environment for production and a `staging` environment with more child environments for development, run the following commands: ```bash upsun variable:create -l environment -e main --prefix env: --name NODE_ENV --value production --visible-build true --inheritable false upsun variable:create -l environment -e staging --prefix env: --name NODE_ENV --value development --visible-build true --inheritable true ``` Now `NODE_ENV` is `production` on the default branch but `development` on `staging` and each of its child environments. Note that build visible environment variables change the application's build configuration ID: value updates trigger a rebuild of the application in the same way that a commit would. ###### Set variables via script You can also provide a `.environment` file as in [your app root](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#root-directory). This file runs as a script in dash when the container starts and on all SSH logins. It can be used to set any environment variables directly, such as the PATH variable. For example, the following `.environment` file allows any executable installed in the `vendor/bin` directory (such as executables installed using Composer) to be run regardless of the current directory: ```bash {location=".environment"} export PATH=/app/vendor/bin:$PATH ``` You can also dynamically define environment variables based on the current environment. For example, you might want to get the [defined route](https://docs.upsun.com../../define-routes.md) with the id `api` for the current environment. To define it as the `URL` environment variable, you might add something like: ```bash {location=".environment"} URL=$(echo $PLATFORM_ROUTES | base64 --decode | jq -r 'to_entries[] | select (.value.id == "api") | .key') ``` Note that the file is sourced after all other environment variables above are defined and so they're available to the script. This also means the `.environment` script has the last word on environment variable values and can override anything it wants to. ####### Testing `.environment` scripts You may find that a command that works during an SSH session provides a `bad substitution` error when placed in a `.environment` file. Remember, `.environment` is sourced using dash, not bash. When testing your `.environment` logic, be sure to first enter a `dash` session in your terminal or within the SSH session. When testing, you might print to stdout (using an `echo` or `printf` command) to check what's happening. The following example looks for a `deploy/environment.tracker.txt` file. It displays a different message if it's found or not, which helps you track what variables are being set. ```bash {location=".environment"} if [ -f "deploy/environment.tracker.txt" ]; then echo "File found." export DEPLOY='Friday' else echo "File not found." export DEPLOY='Never on a Friday' fi ``` While sanity checks like this are useful during troubleshooting, you shouldn't include such commands in your final code. Because the `.environment` file is run at the start of an SSH session, the message is printed at the start of the session. Even when your SSH command executes successfully, you might later attempt to download data from one of your mounts, such as by using the CLI command `upsun mount:download`. When you do, you see this error: ```bash protocol version mismatch -- is your shell clean? (see the rsync man page for an explanation) rsync error: protocol incompatibility (code 2) at .../rsync/compat.c(61) [receiver=2.6.9] [ProcessFailedException] The command failed with the exit code: 2 ``` This failure comes because `mount:download` and `rsync` don't expect output when the SSH connection is made. To solve the issue, remove the printed output from your `.environment` file. ###### Map variables If your app needs different names for environment variable than those set by Upsun, which is common for database connections, map the Upsun's variable names to those required by the application via a shell script. You can obtain relationship information through the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) themselves, or through the [`PLATFORM_RELATIONSHIPS` environment variable](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). For example, if your application has a relationship named ``database`` to a database service named `mariadb`: This sets environment variables with the names your app needs, and the values from [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables).It uses the ``jq`` library, which is included in all app containers for this purpose. ```bash {location=".environment"} export APP_DATABASE_HOST=$(echo $PLATFORM_RELATIONSHIPS | base64 --decode | jq -r ".database[0].host") export APP_DATABASE_USER=$(echo $PLATFORM_RELATIONSHIPS | base64 --decode | jq -r ".database[0].username") ``` This sets environment variables with names your app needs, and the values from [PLATFORM_RELATIONSHIPS](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). ###### Use `.env` files Many applications use a `.env` file in the application root for configuration. These are useful for local development to set variables without needing them to be global across the development computer. Read more about [the use cases for `.env` files](https://platform.sh/blog/2021/we-need-to-talk-about-the-env/). You shouldn't need to use a `.env` file in production. Add it to your `.gitignore` file to avoid confusion as its values can vary for each local developer. #### Use variables Get a list of all variables defined on a given environment in [the Console](https://docs.upsun.com../../administration/web/configure-environment.md#variables) or use the CLI: ```bash upsun var ``` You get output similar to the following: ```bash Variables on the project Example (abcdef123456), environment main: +------+---------+-------+---------+ | Name | Level | Value | Enabled | +------+---------+-------+---------+ | foo | project | bar | true | +------+---------+-------+---------+ ``` ###### Access variables in a shell Project and environment variables with the [prefix](https://docs.upsun.com/development/variables.md#top-level-environment-variables) `env:` are available as Unix environment variables in all caps. Access these variables and Upsun-provided variables directly like this: ```bash echo $FOO bar echo $PLATFORM_APPLICATION_NAME Sample Project ``` Other project and environment variables are listed together in the `PLATFORM_VARIABLES` variable as a base64-encoded JSON object. Access them like this: ```bash echo $PLATFORM_VARIABLES | base64 --decode {"theanswer": "42"} ``` You can also get the value for a single variable within the array, such as with this command, which uses the [`jq` processor](https://stedolan.github.io/jq/): ```bash echo $PLATFORM_VARIABLES | base64 --decode | jq '.theanswer' "42" ``` Variable availability depends on the type and configuration. Variables available during builds can be accessed in `build` hooks and those available at runtime can be accessed in `deploy` hooks. ###### Access variables in your app To access environment variables in your app, use a built-in method for the given language. * PHP: The [`getenv()` function](https://www.php.net/manual/en/function.getenv.php) * Python: The [`os.environ` object](https://docs.python.org/3/library/os.md#os.environ) * Node.js: The [`process.env` object](https://nodejs.org/api/process.md#process_process_env) * Ruby: The [`ENV` accessor](https://ruby-doc.org/current/ENV.md) * Java: The [`System.getenv()` method](https://docs.oracle.com/javase/8/docs/api/java/lang/System.md#getenv-java.lang.String-) ```python {} import os import json import base64 # A simple variable. project_id = os.getenv('PLATFORM_PROJECT') # An encoded JSON object. variables = json.loads(base64.b64decode(os.getenv('PLATFORM_VARIABLES')).decode('utf-8')) ``` ```js {} const { env } = process; // Utility to assist in decoding a packed JSON variable. function read_base64_json(varName) { try { return JSON.parse(Buffer.from(env[varName], "base64").toString()); } catch (err) { throw new Error(`no ${varName} environment variable`); } }; // A simple variable. const projectId = env.PLATFORM_PROJECT; // An encoded JSON object. const variables = read_base64_json('PLATFORM_VARIABLES'); ``` ```ruby {} # A simple variable. project_id = ENV["PLATFORM_PROJECT"] || nil # An encoded JSON object. variables = JSON.parse(Base64.decode64(ENV["PLATFORM_VARIABLES"])) ``` ```java {} import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.util.Base64; import java.util.Map; import static java.lang.System.getenv; import static java.util.Base64.getDecoder; public class App { public static void main(String[] args) throws IOException { // A simple variable. final String project = getenv("PLATFORM_PROJECT"); // An encoded JSON object. ObjectMapper mapper = new ObjectMapper(); final Map variables = mapper.readValue( String.valueOf(getDecoder().decode(getenv("PLATFORM_VARIABLES"))), Map.class); } } ``` ####### Access complex values Variables can have nested structures. The following example shows nested structures in an [app configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#variables): ```yaml {location=".upsun/config.yaml"} applications: : variables: env: BASIC: "a string" INGREDIENTS: - 'peanut butter' - 'jelly' QUANTITIES: "milk": "1 liter" "cookies": "1 kg" stuff: STEPS: ['one', 'two', 'three'] COLORS: red: '#FF0000' green: '#00FF00' blue: '#0000FF' ``` You can access these nested variables as follows: ```php {} string(2) "one" [1]=> string(4) "two" [2]=> string(5) "three" } */ print_r($variables['stuff:COLORS']); /* array(3) { ["red"]=> string(7) "#FF0000" ["green"]=> string(7) "#00FF00" ["blue"]=> string(7) "#0000FF" } */ ``` ```python {} import os import json import base64 print os.getenv('BASIC') # a string print os.getenv('INGREDIENTS') # ["peanut butter", "jelly"] print os.getenv('QUANTITIES') # {"milk": "1 liter", "cookies": "1 kg"} variables = json.loads(base64.b64decode(os.getenv('PLATFORM_VARIABLES')).decode('utf-8')) print variables['stuff:STEPS'] # [u'one', u'two', u'three'] print variables['stuff:COLORS'] # {u'blue': u'#0000FF', u'green': u'#00FF00', u'red': u'#FF0000'} ``` ```java {} scriptconst { BASIC, INGREDIENTS, QUANTITIES, PLATFORM_VARIABLES } = process.env; const { "stuff:STEPS": stuffSteps, "stuff:COLORS": stuffColors } = JSON.parse( Buffer.from(PLATFORM_VARIABLES, "base64").toString() ); console.log(BASIC); // "a string" console.log(INGREDIENTS); // ["peanut butter", "jelly"] console.log(QUANTITIES); // {"cookies": "1 kg", "milk": "1 liter"} console.log(stuffSteps); // [ 'one', 'two', 'three' ] console.log(stuffColors); // { blue: '#0000FF', green: '#00FF00', red: '#FF0000' } ``` ###### Use provided variables Upsun also provides a series of variables to inform your app about its runtime configuration. They're mostly prefixed with `PLATFORM_` to differentiate them from user-provided values. You can't set or update them directly. The following table presents all available variables and whether they're available at build time (during [build hooks](https://docs.upsun.com../../administration/../create-apps/hooks/hooks-comparison.md#build-hook)) and at runtime. | Variable name | Build | Runtime | Description | | --------------------------- | ----- | ------- | ----------- | | `PLATFORM_APP_DIR` | Yes | Yes | The absolute path to the app directory. | | `PLATFORM_APPLICATION` | Yes | Yes | A base64-encoded JSON object that describes the app. It maps certain attributes from your [app configuration](https://docs.upsun.com../../create-apps.md), some with more structure. See [notes](#platform_application). | | `PLATFORM_APPLICATION_NAME` | Yes | Yes | The app name as set in your [app configuration](https://docs.upsun.com../../create-apps.md). | | `PLATFORM_BRANCH` | No | Yes | The name of the Git branch. | | `PLATFORM_CACHE_DIR` | Yes | No | The directory where files are cached from one build to the next. The directory is shared among all branches, so the same cache is used for all environments. | | `PLATFORM_DOCUMENT_ROOT` | No | Yes | The absolute path to the web document root, if applicable. | | `PLATFORM_ENVIRONMENT` | No | Yes | The name of the Upsun environment. | | `PLATFORM_ENVIRONMENT_TYPE` | No | Yes | The environment type of the Upsun environment (`development`, `staging`, or `production`). | | `PLATFORM_OUTPUT_DIR` | Yes | No | The output directory for compiled languages at build time. Equivalent to `PLATFORM_APP_DIR` in most cases. | | `PLATFORM_PROJECT` | Yes | Yes | The project ID. | | `PLATFORM_PROJECT_ENTROPY` | Yes | Yes | A random, 56-character value created at project creation and then stable throughout the project's life. Can be used for Drupal hash salts, Symfony secrets, and other similar values. | | `PLATFORM_RELATIONSHIPS` | No | Yes | The `PLATFORM_RELATIONSHIPS` variable is automatically broken down into [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables), so your app can seamlessly connect to databases and other services defined in `.upsun/config.yaml`. For some advanced use cases, you may need to use the `PLATFORM_RELATIONSHIPS` variable itself. It is a base64-encoded JSON object of relationships, with keys that indicate the relationship names, and values that are arrays of relationship endpoint definitions. The exact format is defined differently for each [service](https://docs.upsun.com../../add-services.md). You may need to gather `PLATFORM_RELATIONSHIPS` information in a ``.environment`` file. See how to [use ``.env`` files](https://docs.upsun.com/development/variables/set-variables.md#use-env-files), and refer to [dedicated service pages](https://docs.upsun.com/add-services.md) for examples. | | `PLATFORM_ROUTES` | No | Yes | A base64-encoded JSON object that describes the routes for the environment. It maps the content of your [routes configuration](https://docs.upsun.com../../define-routes.md). Note that this information is also available in your `/run/config.json` file. | | `PLATFORM_SMTP_HOST` | No | Yes | The SMTP host to send email messages through. Is empty when mail is disabled for the current environment. | | `PLATFORM_SOURCE_DIR` | Yes | No | The path to the root directory of your code repository in the context of a running [source operation](https://docs.upsun.com../../create-apps/source-operations.md). The directory contains a writable copy of your repository that you can commit to during the operation. | | `PLATFORM_TREE_ID` | Yes | Yes | The ID of the tree the application was built from, essentially the SHA hash of the tree in Git. Use when you need a unique ID for each build. | | `PLATFORM_VARIABLES` | Some | Some | A base64-encoded JSON object with all user-defined project and environment variables that don't use a [prefix](https://docs.upsun.com/development/variables.md#variable-prefixes). The keys are the variable names and the values are the variable values. Availability during builds and at runtime depends on the settings for each variable. See how to [access individual variables](#access-variables-in-a-shell). | | `PLATFORM_VENDOR` | Yes | No | Allows you to change the behavior of the build according to the vendor (Upsun or Platform.sh). | | `PORT` | No | Yes | A `string` representing the port to which requests are sent if the [`web.upstream.socket_family` property](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#upstream) is unset or set to `tcp`. | | `SOCKET` | No | Yes | A `string` representing the path to the Unix socket file to use if the [`web.upstream.socket_family` property](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#upstream) is set to `unix`. | ####### `PLATFORM_APPLICATION` The `PLATFORM_APPLICATION` variable is available both at build time and in the runtime environment. But the specific attributes it contains differ in each case. Each environment's build is associated with a configuration ID that identifies it uniquely so builds can be reused. The ID is a product of your app code and some of its [configuration for Upsun](https://docs.upsun.com../../create-apps.md). Not every attribute your app configuration is relevant to the build. Only those attributes that are relevant to builds are accessible at build time from `PLATFORM_APPLICATION`. Attributes that are **not** available in `PLATFORM_APPLICATION` during builds: - Everything under `access` - Everything under `relationship` - Everything under `firewall` - `hooks.deploy` and `hooks.post_deploy` - Everything under `crons` - Everything under `web`, except `web.mounts` - Everything under `workers`, except `workers.mounts` These attributes aren't visible during build because they aren't included as a part of the configuration component of the build slug. So modifying these values in your [app configuration](https://docs.upsun.com../../create-apps.md) doesn't trigger an app rebuild, only a redeploy. For more information, read about [how builds work](https://docs.upsun.com/learn/overview/build-deploy.md#the-build). ###### Use variables in static files Some apps require configuration values to be specified in a static, non-executable file (such as a `.ini`, `.xml`, or `.yaml` file) and don't support reading from environment variables. To populate these files with variables you set yourself, make sure the variables are set to be [visible at build time](https://docs.upsun.com/development/variables/set-variables.md#variable-options). The files can't be populated with Upsun-provided variables not available at build time (such as `PLATFORM_RELATIONSHIPS` or [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables)). You also can't write to them in a `deploy` hook as the file system is read only. One workaround is to create a symbolic link to a writable location and then write to it in a [`deploy` hook](https://docs.upsun.com../../create-apps/hooks/hooks-comparison.md#deploy-hook). The following example shows the process, though you have to modify it to fit your needs. 1. Create a mount that isn't accessible to the web in your [app configuration](https://docs.upsun.com../../create-apps/_index.md): ```yaml {location=".upsun/config.yaml"} applications: mounts: /config: source: storage source_path: config ``` 2. Create a symbolic link from the config file the application wants to a location in that mount: ```bash # From the application root... ln -s config/db.yaml db.yaml ``` This example assumes the app wants a `db.yaml` file in its root for configuration. 3. Commit the symbolic link and an empty `config` directory to Git. 4. Configure a script to read from environment variables and write to `config/db.yaml` through the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) themselves, or through the [`PLATFORM_RELATIONSHIPS` environment variable](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables).
Create a file with a shell script similar to this: ```bash {location="export-config.sh"} #!/bin/bash # Ensure the file is empty. cat '' > config/db.yaml # Map the database information from the PLATFORM_RELATIONSHIPS variable into the YAML file. # Use this process to use whatever variable names your app needs. # For more information, please visit https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables. printf "host: %s\n" $(echo $PLATFORM_RELATIONSHIPS | base64 --decode | jq -r ".database[0].host") >> config/db.yaml printf "user: %s\n" $(echo $PLATFORM_RELATIONSHIPS | base64 --decode | jq -r ".database[0].username") >> config/db.yaml ``` 5. Call the script from the `deploy` hook your [app configuration](https://docs.upsun.com../../create-apps/_index.md): ```yaml {location=".upsun/config.yaml"} applications: hooks: deploy: | bash export-config.sh ``` Now, when your app starts and attempts to parse `db.yaml`, the symbolic link redirects it to `config/db.yaml`. Your script writes to that file on each deploy with updated information. Your app reads the exported values and proceeds as expected. ### Access your site Once you have an environment running, you can view it in a web browser. To find which URLs you can use to access your site, follow these steps: - Run the following command: ```bash {} upsun url ``` - Select the URL to open in a browser. For more information about URLs in your project and how you can control access to your web applications, see how to [define routes](https://docs.upsun.com../define-routes/). ### Transfer files to and from your app After your app is built, its file system is read-only. This means that the only way you can edit your app's code is through Git. However, you can transfer files to and from your built app without using Git. To do so, you need to configure mounts or use an SSH client. [Mounts](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#mounts) let you set up directories that remain writable after the build is complete. You can then transfer files directly to and from mounts inside your app with a single command via the [Upsun CLI](https://docs.upsun.com../administration/cli.md). Alternatively, you can transfer files to and from your built app using an SSH client such as `scp` or `rsync`. ##### Transfer files using the CLI ###### View the mounts inside your app Before you start transferring files, you may want to view a list of all the mounts inside your app. To do so, run the following command: ```bash upsun mounts ``` The output is similar to the following: ```bash Mounts on abcdefgh1234567-main-abcd123--app@ssh.eu.upsun.com: +-------------------------+----------------------+ | Mount path | Definition | +-------------------------+----------------------+ | web/sites/default/files | source: storage | | | source_path: files | | private | source: storage | | | source_path: private | | tmp | source: tmp | | | source_path: temp | +-------------------------+----------------------+ ``` ###### Transfer a file to a mount To transfer a file to a mount using the CLI, you can use the `mount:upload` command. For example, to upload the files contained in the local `private` directory to the `private` mount, run the following command: ```bash upsun mount:upload --mount private --source ./private ``` You get the following output: ```bash Uploading files from ./private to the remote mount private Are you sure you want to continue? [Y/n] sending incremental file list example.sh sent 2.35K bytes received 20 bytes 1.58K bytes/sec total size is 1.77M speedup is 745.09 ``` ###### Transfer a file from a mount To transfer a file from a mount using the CLI, you can use the `mount:download` command. For example, to download a file from the `private` mount to your local `private` directory, run the following command: ```bash upsun mount:download --mount private --target ./private ``` You get the following output: ```bash Downloading files from the remote mount private to ./private Are you sure you want to continue? [Y/n] receiving incremental file list example.sh sent 2.35K bytes received 20 bytes 1.58K bytes/sec total size is 1.77M speedup is 745.09 ``` ##### Transfer files using an SSH client Another way to transfer files to and from your built app is to use an SSH client such as [`scp`](file-transfer.md#scp), [`rsync`](file-transfer.md#rsync), or [`sftp`](file-transfer.md#sftp). ###### scp You can use `scp` to copy files to and from a remote environment. For example, to download a `diagram.png` file from the `web/uploads` directory (relative to the [app root](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#root-directory)), run the following command: ```bash scp "$(upsun ssh --pipe)":web/uploads/diagram.png . ``` The `diagram.png` file is copied to the current local directory. To copy files from your local directory to the Upsun environment, reverse the order of the parameters: ```bash scp diagram.png "$(upsun ssh --pipe)":web/uploads ``` For other options, see the [`scp` documentation](https://www.man7.org/linux/man-pages/man1/scp.1.md). ###### rsync You can use `rsync` to copy files to and from a remote environment. For example, to copy all the files in the `web/uploads` directory on the remote environment to the local `uploads` directory, run the following command: ```bash rsync -azP "$(upsun ssh --pipe)":web/uploads/ ./uploads/ ``` To copy files from your local directory to the Upsun environment, reverse the order of the parameters: ```bash rsync -azP uploads/ "$(upsun ssh --pipe)":web/uploads/ ``` Note that `rsync` is very sensitive about trailing `/` characters. If you're using UTF-8 encoded files on macOS, add the `--iconv=utf-8-mac,utf-8` flag to your `rsync` call. For more options, consult the [rsync documentation](https://man7.org/linux/man-pages/man1/rsync.1.md). ###### sftp You can use `sftp` to copy files to and from a remote environment. **Note**: Upsun supports ``sftp``, but the following limitations apply: - You can only create ``sftp`` accounts with an existing Upsun user and an SSH key. Custom users and passwords aren’t supported. - ``sftp`` access cannot be limited to a specific directory. Instead, access is given to **the whole application directory** and its mounts. ####### Open an `sftp` connection Run the following command: ```bash sftp "$(upsun ssh --pipe)" ``` When prompted, select the project and environment you want to connect to. The `sftp` connection is open once the `sftp>` prompt is displayed in your terminal. ####### Download a file Say you want to download a `diagram.png` file from the `web/uploads` directory (relative to the [app root](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#root-directory)). To do so, run the following command: ``` sftp> get web/uploads/diagram.png ``` The `diagram.png` file is copied to the current local directory. ####### Upload a file Say you want to upload a `diagram.png` file to the `web/uploads` directory (relative to the [app root](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#root-directory)). To do so, run the following command: ```bash sftp> put diagram.png web/uploads ``` For other options, see the [`sftp` documentation](https://man7.org/linux/man-pages/man1/sftp.1.md). ### HTTP Headers Upsun adds a number of HTTP headers to both inbound and outbound messages. We don’t modify or block existing headers on either request or response. ##### Request headers Upsun adds the following HTTP headers in the router to give the application information about the connection. These are stable and may be examined by the application as necessary. * `X-Forwarded-Proto`: The protocol forwarded to the application, for example: `http`, `https`. * `X-Client-IP`: The remote IP address of the request. * `X-Client-SSL`: Set "on" only if the client is using SSL connection, otherwise the header isn't added. * `X-Original-Route`: The route in `.upsun/config.yaml` which is used currently, for example: `https://{default}/`. ##### Response headers Upsun adds a number of response headers automatically to assist in debugging connections. These headers should be treated as a semi-private API. Do not code against them, but they may be inspected to help determine how Upsun handled the request to aid in debugging. - `X-Platform-Cache`: Either `HIT` or `MISS` to indicate if the router in your cluster served the response from its own cache or if the request was passed through to the application. - `X-Platform-Cluster`: The ID of the cluster that received the request. The cluster name is formed from the project ID and environment ID. - `X-Platform-Processor`: The ID of the container that generated the response. The container ID is the cluster ID plus the container name. - `X-Platform-Router`: The ID of the router that served the request. The router ID is the processor ID of the router container, specifically. - `X-Debug-Info`: This is a header added by the edge layer. It doesn't contain any sensitive information or anything that could be misused. It has no relation to the PHP debugging tool [Xdebug](https://xdebug.org). ##### Classification data headers Upsun sends classification data to your backend system through the following HTTP headers. | HTTP header | Type | Description | | -------------------- | ------- | --------------------------------------------------------------------------------------------------------- | | `Client-Cdn` | string | When a CDN that is supported by Upsun is used, this header displays its name (Fastly, Cloudflare, or Cloudfront). | | `Client-Country` | string | The two-character ISO 3166-1 country code of the end-client IP (after CDN handling for the CDNs that Upsun supports). The geolocation data sent through this header is provided by [MaxMind GeoLite2](https://dev.maxmind.com/geoip/geolite2-free-geolocation-data).| | `Client-Abuse-Score` | integer | The abuse score of the end-client IP. A score >= 100 indicates a near certainty that the request comes from an abusive IP. The abuse data sent through this header is provided by [AbuseIPDB](https://www.abuseipdb.com/). | | `Client-Asn` | integer | The Autonomous System number of the end-client IP. The geolocation data sent through this header is provided by [MaxMind GeoLite2](https://dev.maxmind.com/geoip/geolite2-free-geolocation-data).| ##### Custom headers Apart from those listed above, your application is responsible for setting its own response headers. You can also [add headers to static files](https://docs.upsun.com../create-apps/web/custom-headers.md). ### Send email You can configure your Upsun environments to send emails via an SMTP proxy. Emails aren't guaranteed to be deliverable and you can't white-label them. The SMTP proxy is intended as a zero-configuration, best-effort service. **Note**: All preview environments are limited to 12,000 email credits per calendar month. ##### 1. Turn on outgoing email You can turn on outgoing email for each environment. By default, email is turned on for your Production environment and blocked for other environments. To turn it on for a specific environment, follow these steps: To turn on outgoing email, run the following command: ```bash {} upsun environment:info --environment enable_smtp true ``` To turn off outgoing email, replace ``true`` with ``false``. Changing the setting rebuilds the environment. ##### 2. Recommended: Improve deliverability Improve deliverability of your email with [Sender Policy Framework (SPF)](https://docs.sendgrid.com/ui/account-and-settings/spf-records). If you don't have an SPF record, add the following `TXT` record to your domain's DNS records: ```txt v=spf1 include:sendgrid.net -all ``` Having several, conflicting `TXT` records isn't supported due to [rfc4408 section 3.1.2](https://datatracker.ietf.org/doc/html/rfc4408#section-3.1.2). If you already have an SPF record, please add SendGrid into your existing record. ##### 3. (Optional) Validate your email You can request for DomainKeys Identified Mail (DKIM) to be enabled on your domain. DKIM improves your delivery rate as an email sender. Learn more about [how DKIM works](https://docs.sendgrid.com/glossary/dkim). To have DKIM enabled for your domain: 1. Open a [support ticket](https://docs.upsun.com/learn/overview/get-support.md) with the domain where you want DKIM. 2. Update your DNS configuration with the `CNAME` and `TXT` records that you get in the ticket. Checks for the expected DNS records run every 15 minutes before validation. The `TXT` record looks similar to the following: ```txt v=spf1 include:u17504801.wl.sendgrid.net -all ``` ##### 4. Test the email service To test the email service, use the [CLI](https://docs.upsun.com../administration/cli.md) to connect to your app by running `upsun ssh`. Run the following command: ```bash printf "From: \nSubject: Test \nThis is a test message" | /usr/sbin/sendmail ``` Replace the variables with actual email addresses as in the following example: ```bash printf "From: someone@example.com\nSubject: Test \nThis is a test message" | /usr/sbin/sendmail someone@example.net ``` In a little while, the test message should arrive at the recipient address. Be careful to test with real email addresses. If you send emails to fake domains (such as `example.com`), they fail and hurt your sending reputation. Make sure your test emails are deliverable. ##### 5. Send email from your app You can use `/usr/sbin/sendmail` on your app container to send emails as with the example in the previous step. Or use the `PLATFORM_SMTP_HOST` environment variable in your SMTP configuration. When outgoing emails are on, `PLATFORM_SMTP_HOST` is the address of the SMTP host that should be used. When outgoing emails are off, the variable is empty. When using `PLATFORM_SMTP_HOST`, send email through port 25 (often the default). Your emails are proxied through the Upsun SMTP host and encrypted over port 465 before being sent to the outside world. The precise way to send email depends on the language and framework you use. See some examples for given languages. JavaMail is a Java API used to send and receive email via SMTP, POP3, and IMAP. JavaMail is built into the [Jakarta EE](https://jakarta.ee/) platform, but also provides an optional package for use in Java SE. [Jakarta Mail](https://projects.eclipse.org/projects/ee4j.mail) defines a platform-independent and protocol-independent framework to build mail and messaging applications. The following example sends email using Jakarta Mail: ```java {} import sh.platform.config.Config; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; public class JavaEmailSender { private static final Logger LOGGER = Logger.getLogger(JavaEmailSender.class.getName()); public void send() { Config config = new Config(); String to = "";//change accordingly String from = "";//change accordingly String host = config.getSmtpHost(); //or IP address //Get the session object Properties properties = System.getProperties(); properties.setProperty("mail.smtp.host", host); Session session = Session.getDefaultInstance(properties); //compose the message try { MimeMessage message = new MimeMessage(session); message.setFrom(new InternetAddress(from)); message.addRecipient(Message.RecipientType.TO, new InternetAddress(to)); message.setSubject("Ping"); message.setText("Hello, this is example of sending email "); // Send message Transport.send(message); System.out.println("message sent successfully...."); } catch (MessagingException exp) { exp.printStackTrace(); LOGGER.log(Level.SEVERE, "there is an error to send an message", exp); } } } ``` Guides on using JavaMail: - [Send email with HTML formatting and attachments](https://mkyong.com/java/java-how-to-send-email/) - [JavaMail API](https://javaee.github.io/javamail/) ##### Alternative: Use a different email server If you need more options, use your own SMTP server or email delivery service provider. Bear in mind that TCP port 25 is blocked for security reasons. Use port 465 or 587 instead to send email to your own external email server. ### Pull code from a private Git repository To complete its build, your Upsun project may need to access pieces of code stored in private Git repositories. Examples include themes, libraries, and modules. Configure these repositories to grant access to your project. To grant access to a private Git repository, add the project's public SSH key to your Git repository's deploy keys. ##### 1. Get your project's public key 1. In the Console, open the project you want. 2. Click **Settings Settings**. 3. Under **Project settings**, click **Deploy key**. 4. Click ** Copy**. ![Deploy Key](https://docs.upsun.com/images/management-console/settings-deploy-key.png "0.5") ##### 2. Add the key to your repository in your Git provider * [GitHub deploy key](https://docs.github.com/en/developers/overview/managing-deploy-keys#deploy-keys) * [GitLab deploy key](https://docs.gitlab.com/ee/user/project/deploy_keys/#grant-project-access-to-a-public-deploy-key) * [Bitbucket access key](https://support.atlassian.com/bitbucket-cloud/docs/configure-repository-settings/) If you're only pulling code, the key doesn't need write permissions. Now your Upsun project can access your private repository via SSH, including to add dependencies. This means you can access the private repository through links like: ``git@:/.git``. For example, you can clone a repository in your [`build` hook](https://docs.upsun.com../create-apps/hooks/_index.md): ```yaml {location=".upsun/config.yaml"} applications: : hooks: build: | set -e git clone git@bitbucket.org:username/module.git ``` You can also use [private repositories as submodules](https://docs.upsun.com/development/submodules.md#use-private-git-repositories). ##### Using multiple private GitHub repositories GitHub requires a separate deploy key for each repository. To grant your project access to multiple repositories, create an automated user account, known as a machine user, with its own SSH key. You can then add the machine account as collaborator to specific repositories or to a team with access to the repositories. See more information about [machine users on GitHub](https://docs.github.com/en/developers/overview/managing-deploy-keys#machine-users). ### Use Git submodules ##### Clone submodules during deployment Upsun allows you to use submodules in your Git repository. They're usually listed in a `.gitmodules` file at the root of your Git repository. When you push via Git, Upsun tries to clone them automatically. Say you have a multi-app project that includes the following submodules: - A BigFoot app - An API Platform v3, Admin component - A Gatsby frontend - A Mercure Rocks server To import all the submodules, run the following commands from your multiple application project's root folder: ```bash touch .gitmodules git submodule add --name admin https://github.com/platformsh-templates/bigfoot-multiapp-admin.git admin git submodule add --name api https://github.com/platformsh-templates/bigfoot-multiapp-api.git api git submodule add --name gatsby https://github.com/platformsh-templates/bigfoot-multiapp-gatsby.git gatsby git submodule add --name mercure https://github.com/platformsh-templates/bigfoot-multiapp-mercure.git mercure git add . git commit -m "Adding submodules for Bigfoot App, API Platform Admin, Gatsby frontend and Mercure Rocks server" git push ``` Here is an example of a `.gitmodules` file: ```ini [submodule "admin"] path = admin url = https://github.com/platformsh-templates/bigfoot-multiapp-admin.git [submodule "api"] path = api url = https://github.com/platformsh-templates/bigfoot-multiapp-api.git [submodule "gatsby"] path = gatsby url = https://github.com/platformsh-templates/bigfoot-multiapp-gatsby.git [submodule "mercure"] path = mercure url = https://github.com/platformsh-templates/bigfoot-multiapp-mercure.git ``` When you run `git push`, you can see the output of the logs: ```bash Validating submodules Updating submodule ttps://github.com/platformsh-templates/bigfoot-multiapp-admin.git Updated submodule https://github.com/platformsh-templates/bigfoot-multiapp-admin.git: 549 references updated. Updating submodule ttps://github.com/platformsh-templates/bigfoot-multiapp-api.git Updated submodule https://github.com/platformsh-templates/bigfoot-multiapp-api.git: 898 references updated. Updating submodule https://github.com/platformsh-templates/bigfoot-multiapp-gatsby.git Updated submodule https://github.com/platformsh-templates/bigfoot-multiapp-gatsby.git: 257 references updated. Updating submodule https://github.com/platformsh-templates/bigfoot-multiapp-mercure.git Updated submodule https://github.com/platformsh-templates/bigfoot-multiapp-mercure.git: 124 references updated. ... ``` **Note**: If your submodule contains an independent app, see [how to configure it properly](https://docs.upsun.com/create-apps/multi-app/project-structure.md#split-your-code-source-into-multiple-git-submodule-repositories). ##### Update submodules **Note**: To specify which submodule needs to be updated, replace ``[submodule]`` with your submodule path. **Note**: Deploy keys only grant access to a single repository, which can cause issues when attempting to pull several repositories to the same server. If your server needs access to multiple repositories, follow these steps: - [Create a machine user](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/managing-deploy-keys#machine-users) with access rights to each of the private repositories. - Attach the deploy key to your machine user. ##### Removing submodules These steps aren't specific to Upsun, but kept as a reference for Git so that submodules are effectively removed before entering the build process. 1. In your `.gitmodules` and `.git/config` files, delete the information related to the submodule you want to remove. ```bash git submodule deinit -f path_to_submodule ``` 2. Stage changes to `.gitmodules`: ```bash git add .gitmodules ``` 3. Remove the submodule from the repository (without trailing slash): ```bash git rm --cached path_to_submodule ``` 4. Remove the submodule files in `.git` from the repository (without trailing slash): ```bash rm -rf .git/modules/path_to_submodule ``` 5. Commit the changes: ```bash git commit -m "Removed submodule." ``` 6. Remove the submodule code locally, now no longer tracked: ```bash rm -rf path_to_submodule ``` ### Connect securely with SSH When you interact with a deployed environment, you need to guard your connection against unauthorized access. Use Secure Shell (SSH) to provide a secure channel. You can securely log in to your deployed app to troubleshoot and read logs. And create a tunnel to export data through. And interact with your project through the CLI. All secured through SSH. ##### Connect to apps To connect to an app securely with SSH, follow two steps. ###### 1. Authenticate with the CLI To authenticate with the CLI: 1. Install the [Upsun CLI](https://docs.upsun.com/administration/cli.md). 2. Run `upsun login`. 3. In the open browser window, log in with your Upsun account credentials. (This webpage is encrypted with [HTTPS](https://docs.upsun.com/define-routes/https.md), making it secure.) 4. Authorize the CLI to use your account. A certificate gets stored in your local SSH configuration. The certificate is automatically cycled every hour for a new certificate as long as your session is active. If you are inactive for an extended period, your certificate expires and you are asked to login again the next time you use a command that requires authentication. You are now ready to run CLI commands and connect to an environment. ###### 2. Connect to an app with SSH To access an app in a given environment via the CLI, run the following command: ```bash upsun ssh --project --environment --app ``` Replace each of ````, ````, and ```` with the values you want to access. To find these values in the Console, navigate to the environment you want to access and click **SSH** in the top right-hand corner. Alternatively, just run `upsun ssh` and select the values from each list presented to you. Once you've connected, you get a welcome message detailing which environment you're connected to. Now you can interact with the environment as you want. Note that your app's file system is read-only, except for any [mounts you've defined](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#mounts). ##### Connect to services To connect to a service, you need the [service credentials](https://docs.upsun.com../../add-services.md#connect-to-a-service). Then you can connect either with a [direct tunnel](#use-a-direct-tunnel) or a [tunnel in your app](#use-an-app-tunnel). ###### Use a direct tunnel To open SSH tunnels for all of your services, run the following command: ```bash upsun tunnel:open ``` You get output similar to the following: ```bash SSH tunnel opened to database at: http://127.0.0.1:30000 Logs are written to: ~/.upsun/tunnels.log List tunnels with: upsun tunnels View tunnel details with: upsun tunnel:info Close tunnels with: upsun tunnel:close Save encoded tunnel details to the PLATFORM_RELATIONSHIPS variable using: export PLATFORM_RELATIONSHIPS="$(platform tunnel:info --encode)" ``` Use the returned host (in this case `http://127.0.0.1:30000`) for your connection and fill in the details with the rest of your [service credentials](https://docs.upsun.com../../add-services.md#connect-to-a-service). The `tunnel:open` command connects all relationships defined in your [app configuration](https://docs.upsun.com../../create-apps.md). To open only one connection when you have multiple relationships defined, run `tunnel:single`. By default, this opens a tunnel at `http://127.0.0.1:30000`. You can specify the port for the connection using the `--port` flag. ###### Use an app tunnel Many database applications (such as MySQL Workbench) support establishing their own SSH tunnel. You need to use [SSH keys](https://docs.upsun.com/development/ssh/ssh-keys.md) for authentication. Consult the documentation for your application for how to enter SSH credentials. ####### Get SSH connection details To get the host and username for connections, follow these steps: You get output similar to the following: ```bash {} jyu7waly36ncj-main-7rqtwti--app@ssh.us.upsun.com ``` - Navigate to the environment you want to connect to. - Click **SSH** in the top right-hand corner. - You get output similar to the following: ``jyu7waly36ncj-main-7rqtwti--app@ssh.us.upsun.com`` The host is everything after the `@` and the username is what's before it. In this case, the host is `ssh.us.upsun.com` and the username is `jyu7waly36ncj-main-7rqtwti--app`. The host is the same for the entire project, while the username varies by environment. To connect to a service, fill in the details with the rest of your [service credentials](https://docs.upsun.com../../add-services.md#connect-to-a-service). ##### Alternative authentication methods There are three basic ways to authenticate with Upsun: * [Through the CLI](#1-authenticate-with-the-cli) * The fastest and easiest method. * Supports multifactor authentication. * Automatically generates new certificates to keep your connection safe. * Necessary when using the CLI and when your organization has multifactor authentication set up. * [Using SSH keys](https://docs.upsun.com/development/ssh/ssh-keys.md) * Requires more setup on your part. * Represents only a single authentication method. * Requires you to regularly change the keys to maintain security. * Useful for checking out code as part of an automated process. * [Using API tokens](https://docs.upsun.com../../administration/cli/api-tokens.md) * Good for letting automation tools use the CLI. * Requires you to regularly change the tokens to maintain security. ##### SSH into an MFA-protected environment For enhanced security, as an organization owner or admin user, you can [enforce Multi-Factor Authentication (MFA) within your organization](https://docs.upsun.com/administration/mfa.md#enforce-mfa-within-your-organization). As a project contributor, if you haven't enabled MFA on your user account and SSH into an environment that is protected by MFA, you get an error message. See how you can [troubleshoot that error message](https://docs.upsun.com/development/ssh/troubleshoot-ssh.md#mfa-related-error-message). #### Authenticate with SSH keys To connect to your app using SSH keys, you need two keys: * A **private key** you must keep _secret_ * A **public key** stored in your Upsun account A given SSH key pair can only be linked to a single user account. A key pair is valid for as long as you have access to the private key on the system from which you are connecting. If you have a key pair available, you aren't prompted to login. To keep connection secure, you need to regularly update the keys you use. A well-encrypted key is no substitute for regular key rotation. If you used GitHub to sign up for your Upsun account your public keys from GitHub are automatically synced to your Upsun account. So you can use them already with the CLI or to [connect to your app](https://docs.upsun.com/development/ssh.md#2-connect-to-an-app-with-ssh). ###### Add SSH keys If you don't have keys already added, you might be able to [find existing keys](#1a-find-your-keys) or else you need to [generate new keys](#1b-generate-new-keys). ####### 1A. Find your keys If you haven't used SSH keys before or it's been a while since you created the key, skip right to [generating new keys](#1b-generate-new-keys). If you have generated SSH keys before and want to find them on your system, follow these instructions. A public key file has a name ending in `.pub`. It contains seemingly random lines of characters, like this example of a public [RSA key](https://en.wikipedia.org/wiki/RSA_%28cryptosystem%29) (note the email address at the end, which wouldn't be present in a private key): ```text ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC2nDRLgPANWParTiaGIgySG+thTtnqFGI1tMWyqDdfvH+5hL91w2tK9PzaP+NJ5hA/cOyh30YRFb52Y64toU16Ko5K1mLqNFJajjWEI5Y4VukG6betrWfqdQ7XBr/s7nBuDOFQ5+eKbvug4rRSCSo8CsEI1eI0VNQkC9HJWYK28k7KurMdTN7X/Z/4vknM4/Rm2bnMk2idoORQgomeZS1p3GkG8dQs/c0j/b4H7azxnqdcCaR4ahbytX3d49BN0WwE84C+ItsnkCt1g5tVADPrab+Ywsm/FTnGY3cJKKdOAHt7Ls5lfpyyug2hNAFeiZF0MoCekjDZ2GH2xdFc7AX/ your_email_address@example.com ``` To find your public key file: 1. Open a terminal. 2. Run the following commands: ```bash cd ~/.ssh ls -a ``` If you find a file ending in `.pub`, copy the location and [add it to your Upsun account](#2-add-an-ssh-key-to-your-account). If you don't find an existing key, [generate new keys](#1b-generate-new-keys). ####### 1B. Generate new keys If you're logged in using the [Upsun CLI](https://docs.upsun.com/development/ssh.md#1-authenticate-with-the-cli), generate a key and have it added to your Upsun account automatically. 1. In a terminal, run `upsun ssh-key:add`. 1. If necessary, log in to a browser. 1. Press `Y` and `enter` to create a new SSH key. 1. Copy the location of the generated key. 1. Run the following commands (replacing `` with the location you copied): ```bash eval $(ssh-agent) ssh-add '' ``` To generate a key otherwise, GitHub has a good [walk-through for creating SSH key pairs](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent) on various operating systems. Then you need to [add it to your Upsun account](#2-add-an-ssh-key-to-your-account). ####### 2. Add an SSH key to your account Once you have the location of your public key, add it to your Upsun account. If you're logged in using the [Upsun CLI](https://docs.upsun.com/development/ssh.md#1-authenticate-with-the-cli), in a terminal run the following command (replacing `` with the location of your public key): ```bash upsun ssh-key:add '' ``` You can also add it in the Console. Now you are ready to use the key to [connect to an environment](https://docs.upsun.com/development/ssh.md#2-connect-to-an-app-with-ssh). ####### 3. Connect to your server with SSH keys To connect to a server using SSH keys, find the details in the Console: 1. Open the [Upsun Console](https://console.platform.sh/). 1. Select a project. 1. In the **Environment** dropdown, select the environment you want to access. 1. Click the **SSH** dropdown. 1. Copy the ssh command for where you want access. (Example: `ssh abcdefghi5k-main-7rqtwti--app@ssh.us-2.upsun.com`) 1. Enter the command into a terminal. Note that if you have just added your SSH key, you need to [redeploy your environment](https://docs.upsun.com/development/ssh/troubleshoot-ssh.md#redeploy-your-environment) before you can access it using SSH keys. ###### Forwarding keys by default It may be helpful to set your SSH client to always forward keys to Upsun servers, which can simplify other SSH or rsync commands. To do so, include a block in your local `~/.ssh/config` file like so: ```text Host *.us.upsun.com ForwardAgent yes Host *.eu.upsun.com ForwardAgent yes ``` Include one `Host` entry for each Upsun region you want to connect to, such as `us-2` or `eu-4`. (You can include other configuration as desired.) #### Troubleshoot SSH While trying to use SSH, you may get a response indicating permission is denied. Or if you get an error with a code of 255, it means there's a problem with your SSH connection. ```txt The command failed with the exit code: 255 ``` There are several places to check to try to solve such issues. ###### Check your environment If your environment is [inactive](https://docs.upsun.com/glossary.md#inactive-environment) or the deployment has failed, you can't log in to it. To make sure the environment is active and the deployment has succeeded, check it using `upsun environment:list` or in the [Console](https://console.platform.sh/) . ###### Redeploy your environment If you have just added your SSH key or made changes to [access rules](https://docs.upsun.com/administration/users.md), you need to redeploy your environment before you can access it using SSH keys. You can do this in the [Console](https://console.platform.sh/), by running `upsun redeploy`, or by pushing an empty git commit: ```bash git commit --allow-empty -m 'chore: force redeploy' git push origin main ``` ###### Check your public key Make sure your public key has been uploaded to your user account. Check it in the [Upsun Console](https://console.platform.sh/). ###### SSH key can not be duplicated A given SSH key pair can only be linked to a single user account. If you add an already used SSH key to another account, you see the error: `SSH key can not be duplicated`. [Generate a new pair of SSH keys](https://docs.upsun.com/development/ssh/ssh-keys.md#add-ssh-keys) for the second user account you want to add. ###### Check your SSH agent Check that your key is properly added to your SSH agent. This is an authentication agent that manages your private key. 1. Run `ssh-add -l` in your terminal: ```bash ssh-add -l ``` You get output similar to the following: ```bash 2048 12:b0:13:83:7f:56:18:9b:78:ca:54:90:a7:ff:12:69 /Users/your_username/.ssh/id_rsa (RSA) ``` 1. Check that the file exists and that the file name or comment matches your private key file. 1. If you don't see your private key file, add your private key: ```bash ssh-add path-to-your-key ``` ###### Specify your identity file If your identity (SSH key) associated with Upsun isn't in a default file name (as may be explained in your SSH software manual, for example), you may have to append a specification like the one below so that the SSH software finds the correct key. ```bash Host platform.sh IdentityFile ~/.ssh/id_upsun ``` Be aware that, above, `upsun` stands for a hostname. Each different hostname you connect to Upsun at may have to be specified in the host line, separated by spaces. ###### Check your Git integrations If your project is integrated with another Git provider (such as GitHub), that provider controls Git operations. Make sure you have added your public SSH key to your provider and that your user there has access. ###### Generate SSH debug information If your private key and public key both look OK but you don't have any luck logging in, print debugging information. These lines often give clues about what's going wrong. Run the SSH command with the `-v` option, like so: ```bash ssh -v [SSH-URL] ``` You get output similar to the following: ```bash OpenSSH_6.7.8, OpenSSL 1.2.3 1 Sep 2014 debug1: Connecting to ssh.eu.upsun.com [54.32.10.98] port 22. debug1: Connection established. debug1: identity file /Users/your_username/.ssh/id_rsa type 1 ...(many more lines of this light reading)... debug1: Offering RSA public key: /Users/your_username/.ssh/id_rsa debug1: Authentications that can continue: publickey debug1: No more authentication methods to try. Permission denied (publickey). ``` Alternatively, you can run the following command: ```bash GIT_SSH_COMMAND="ssh -v" git clone ``` You can use this information to make one last check of the private key file. ###### MFA-related error message If you haven't enabled MFA on your user account and try to SSH into an environment that is protected by MFA, you get the following error message: ```bash Error: Access denied Service: abcdefg123456-main-bvxea6i--app User: () Parameters: {"amr":["mfa"]} Detail: Additional authentication is required: - Multi-factor authentication (MFA) ``` To solve this, [enable MFA on your user account](https://docs.upsun.com../../administration/mfa.md#enable-mfa-on-your-user-account). Alternatively, open the Console and select the desired organization. Follow the instructions so you can effectively access its contents. Similarly for bot users and CLI tokens, you may see the message: ```bash [RequestException] Multi-factor authentication (MFA) is required. The API token may need to be re-created after enabling MFA. ``` In this case, as described, it will be necessary to: 1. Enable MFA on the (bot) user account associated with the token. 2. Generate a new access token, and then replace its value in your workflow that requires the token (such as updating a GitHub workflow secret variable). ###### Something still wrong? For more general information, see how to [troubleshoot development](https://docs.upsun.com/development/troubleshoot.md). If you're still stuck, open a [support ticket](https://docs.upsun.com/learn/overview/get-support.md) and provide the full SSH debug information. ### Regions Upsun offers several regions for hosting project data. You can choose a region based on criteria such as its closeness to your users and its environmental impact. **Upcoming changes!**: On **17 March 2025**, outbound IPs on **all GCP and Azure regions** will change. These upcoming changes will affect **outbound IPs** for all GCP and Azure regions, and will require your intervention if your are using public IP addresses explicitly. Please see [the documentation](#upcoming-changes) below for details and relevant deadlines. ##### Environmental impact At Upsun, we are committed to reducing our environmental impact. Whenever you create a project with us, we provide information about the electricity grid provider for that region. You can view the average carbon intensity of the energy grid in grams of CO2 equivalent per kilowatt-hour. These data are sourced from an annual average, which we update as new information becomes available. If you want to see real-time emissions generated by each power grid, we recommend checking out [Electricity Maps](https://app.electricitymap.org/map). You can also access a public GitHub page of Electricity Maps [data sources](https://github.com/electricitymap/electricitymap-contrib/blob/master/DATA_SOURCES.md). Summary of data being used in Upsun’s Region Picker when creating a new Project: | Source | Last update of this page | Previous versions of this page | |--------|--------------------------|--------------------------------| | Electricity Maps 2022 annual averages (previous to May 2023, we had used annual averages from the IEA).
See our [blog post](https://platform.sh/blog/platformsh-is-now-using-annual-carbon-intensities-from-electricity-maps/) for more information.| 11 May 2023 | Available [here](https://github.com/platformsh/platformsh-docs/commits/main/docs/src/development/regions.md) | Information on carbon intensity is also available in the Upsun API. For example, to get a list of the regions and their carbon intensities, run the following command: ```bash upsun api:curl regions | jq -r '.regions[] | select(.available != false) | "\(.label): \(.environmental_impact.carbon_intensity)"' ``` See all available information in the [API documentation](https://api.platform.sh/docs/#tag/Regions). ###### Greener Region Discount You can get a 3% discount on your resource usage if you host your project in one of Upsun's eco-friendly regions: - Quebec, Canada (`ca-central-1`), - Stockholm, Sweden (`eu-north-1`), - Paris, France (`francecentral`), - OVH (`gra7`), - Quincy, Washington (`westus2`), - Zurich, Switzerland (`europe-west6`). The 3% discount covers application CPU, application memory, service CPU, service memory, and build resources. It **doesn’t** apply to the project fee or other billing aspects. It can be combined with other offers or discounts. See [more information on the greener region discount](https://platform.sh/company/press/a-first-for-cloud-industry-platformsh-greener-region-discount/). ##### Region availability The regions listed here may be different from those available to you when you create a new project. Each organization can have its own rules for what regions to allow. When adding a new project, you only see regions allowed by your organization. ##### Region location To find out where a given region is hosted, use the following command: ``` bash upsun api:curl regions | jq '.regions[] | select(.available != false) | .id + ": " + .provider.name + " - " + .zone + " - " + .timezone' | sort ``` The returned list contains, for each available region, its name, provider, geographic zone and its timezone. ##### Public IP addresses The public IP addresses for regions are stable, but not guaranteed to never change. Before any change, you are notified well in advance regarding affected projects. Planned and upcoming changes to IPs will be documented in the [**Upcoming changes**](#upcoming-changes) section below. They're useful for cases such as when you have a corporate firewall that blocks outgoing SSH connections. In such cases, add the inbound IP addresses for your region to your allow list. ##### Regions ###### Europe Region | Provider | Available to new orgs | Outbound IPs | Inbound IPs | Region ####### [Switzerland (ch-1)](#switzerland-ch-1-ch-1) ch-1.platform.sh Provider Google Cloud Platform Available to new orgs ✅ Outbound ips - 34.65.236.213 - 34.65.152.61 - 34.65.244.185 Inbound ips ``gw.ch-1.platformsh.site`` - 34.65.236.213 - 34.65.152.61 - 34.65.244.185 Region ####### [Germany (de-2)](#germany-de-2-de-2) de-2.platform.sh Provider Google Cloud Platform Available to new orgs ✅ Outbound ips - 35.246.248.138 - 35.246.184.45 - 35.242.229.239 Inbound ips ``gw.de-2.platformsh.site`` - 35.246.248.138 - 35.246.184.45 - 35.242.229.239 Region ####### [Ireland (eu)](#ireland-eu-eu) eu.platform.sh Provider AWS Available to new orgs ✅ Outbound ips - 54.72.94.105 - 54.76.137.67 - 54.76.137.94 Inbound ips ``gw.eu.platformsh.site`` - 54.76.137.79 - 54.76.136.188 - 54.76.137.151 Region ####### [Sweden (eu-5)](#sweden-eu-5-eu-5) eu-5.platform.sh Provider AWS Available to new orgs ✅ Outbound ips - 13.48.116.14 - 13.51.46.87 - 13.48.202.56 Inbound ips ``gw.eu-5.platformsh.site`` - 13.51.62.86 Region ####### [France (fr-3)](#france-fr-3-fr-3) fr-3.platform.sh Provider OVHcloud Available to new orgs ✅ Outbound ips - 135.125.91.125 - 135.125.89.47 - 135.125.90.255 Inbound ips ``gw.fr-3.platformsh.site`` - 94.23.123.122 Region ####### [France (fr-4)](#france-fr-4-fr-4) fr-4.platform.sh Provider Azure Available to new orgs ✅ Outbound ips - 20.74.41.190 - 20.74.41.218 - 20.74.42.30 Inbound ips ``gw.fr-4.platformsh.site`` - 20.74.41.190 - 20.74.41.218 - 20.74.42.30 Region ####### [United Kingdom (uk-1)](#united-kingdom-uk-1-uk-1) uk-1.platform.sh Provider Google Cloud Platform Available to new orgs ✅ Outbound ips - 35.242.142.110 - 35.189.126.202 - 35.242.183.249 Inbound ips ``gw.uk-1.platformsh.site`` - 35.242.142.110 - 35.189.126.202 - 35.242.183.249 Region ####### [Ireland (eu-2)](#ireland-eu-2-eu-2) eu-2.platform.sh Provider AWS Available to new orgs Outbound ips - 52.208.123.9 - 52.214.63.84 - 52.30.200.164 Inbound ips ``gw.eu-2.platformsh.site`` - 34.248.104.12 - 34.241.191.143 - 52.210.208.94 Region ####### [Ireland (eu-4)](#ireland-eu-4-eu-4) eu-4.platform.sh Provider AWS Available to new orgs Outbound ips - 18.200.158.188 - 18.200.157.200 - 18.200.184.206 Inbound ips ``gw.eu-4.platformsh.site`` - 52.215.88.119 - 52.208.179.40 - 18.200.179.139 Region ####### [France (fr-1)](#france-fr-1-fr-1) fr-1.platform.sh Provider Orange Available to new orgs Outbound ips - 90.84.46.222 - 90.84.47.148 - 90.84.46.40 Inbound ips ``gw.fr-1.platformsh.site`` - 90.84.46.40 - 90.84.47.148 - 90.84.46.222 ###### United States Region | Provider | Available to new orgs | Outbound IPs | Inbound IPs | Region ####### [East (us)](#east-us-us) us.platform.sh Provider AWS Available to new orgs ✅ Outbound ips - 54.88.149.31 - 54.209.114.37 - 54.210.53.51 Inbound ips ``gw.us.platformsh.site`` - 54.210.49.244 - 54.88.225.116 - 54.210.55.162 Region ####### [East (us-2)](#east-us-2-us-2) us-2.platform.sh Provider AWS Available to new orgs ✅ Outbound ips - 34.238.64.193 - 52.4.246.137 - 54.157.66.30 Inbound ips ``gw.us-2.platformsh.site`` - 34.226.46.235 - 34.238.11.122 - 54.89.106.200 Region ####### [West (us-3)](#west-us-3-us-3) us-3.platform.sh Provider Azure Available to new orgs ✅ Outbound ips - 52.137.90.183 - 52.156.93.30 - 51.143.107.76 Inbound ips ``gw.us-3.platformsh.site`` - 52.137.90.183 - 52.156.93.30 - 51.143.107.76 Region ####### [East (us-4)](#east-us-4-us-4) us-4.platform.sh Provider Google Cloud Platform Available to new orgs ✅ Outbound ips - 34.73.189.215 - 34.74.8.155 - 34.75.104.115 Inbound ips ``gw.us-4.platformsh.site`` - 34.73.189.215 - 34.74.8.155 - 34.75.104.115 ###### Canada Region | Provider | Available to new orgs | Outbound IPs | Inbound IPs | Region ####### [Canada (ca-1)](#canada-ca-1-ca-1) ca-1.platform.sh Provider AWS Available to new orgs ✅ Outbound ips - 35.182.24.224 - 52.60.213.255 - 35.182.220.113 Inbound ips ``gw.ca-1.platformsh.site`` - 35.182.174.169 - 35.182.59.77 - 52.60.219.22 ###### Australia Region | Provider | Available to new orgs | Outbound IPs | Inbound IPs | Region ####### [Australia (au)](#australia-au-au) au.platform.sh Provider AWS Available to new orgs ✅ Outbound ips - 13.55.135.0 - 13.54.121.225 - 13.55.215.151 Inbound ips ``gw.au.platformsh.site`` - 13.54.88.239 - 13.55.140.143 - 13.54.222.56 Region ####### [Australia (au-2)](#australia-au-2-au-2) au-2.platform.sh Provider Azure Available to new orgs ✅ Outbound ips - 20.92.240.74 - 20.191.224.199 - 20.92.240.236 Inbound ips ``gw.au-2.platformsh.site`` - 20.92.240.74 - 20.191.224.199 - 20.92.240.236 ##### Upcoming changes ###### GCP and Azure regions outbound IPs On the 17th of March 2025, outbound IPs on **all GCP and Azure regions** will change. Customer projects that refer to outbound IPs explicitly in their code and/or configuration must intervene and update to the **New outbound IPs** as soon as is possible. Before the 17th of March, no traffic go through the **New outbound IPs**. After the 17th of March, the **Old outbound IPs** will no longer be available. Allowing both new and old IP addresses in any configuration during the transition period is recommended. Region | Old outbound IPs | New outbound IPs | Region ####### United Kingdom (uk-1) uk-1.platform.sh Outbound ips - 35.242.142.110 - 35.189.126.202 - 35.242.183.249 Outbound ips - 35.246.36.142 - 34.147.217.161 - 34.89.33.176 Region ####### Germany (de-2) de-2.platform.sh Outbound ips - 35.246.248.138 - 35.246.184.45 - 35.242.229.239 Outbound ips - 34.159.207.210 - 34.159.181.149 - 34.107.79.7 Region ####### Switzerland (ch-1) ch-1.platform.sh Outbound ips - 34.65.236.213 - 34.65.152.61 - 34.65.244.185 Outbound ips - 34.65.197.163 - 34.65.144.16 - 34.65.72.28 Region ####### East (us-4) us-4.platform.sh Outbound ips - 34.73.189.215 - 34.74.8.155 - 34.75.104.115 Outbound ips - 104.196.203.234 - 34.148.171.57 - 35.243.131.172 Region ####### France (fr-4) fr-4.platform.sh Outbound ips - 20.74.41.190 - 20.74.41.218 - 20.74.42.30 Outbound ips - 20.188.46.156 - 20.188.46.158 - 20.188.46.165 Region ####### West (us-3) us-3.platform.sh Outbound ips - 52.137.90.183 - 52.156.93.30 - 51.143.107.76 Outbound ips - 52.148.128.255 - 52.250.13.106 - 40.91.69.215 Region ####### Australia (au-2) au-2.platform.sh Outbound ips - 20.92.240.74 - 20.191.224.199 - 20.92.240.236 Outbound ips - 104.210.116.116 - 40.126.245.226 - 104.210.117.92 ####### How to audit the potential impact on an organization You can determine which of your project are potentially impacted by this change via the CLI or the Console. Where is one of the impacted regions: - ``ch-1.platform.sh`` - ``uk-1.platform.sh`` - ``de-2.platform.sh`` - ``us-4.platform.sh`` - ``fr-4.platform.sh`` - ``us-3.platform.sh`` - ``au-2.platform.sh`` There is a community-maintained [Region auditing snippet](https://github.com/platformsh/snippets/blob/main/src/region-audit.sh) you can use for this case: ```bash {} curl -s https://raw.githubusercontent.com/platformsh/snippets/region-audit/src/region-audit.sh | bash -s -- ch-1,uk-1,de-2,us-4,fr-4,us-3,au-2 upsun ``` - Navigate to the organization () you’d like to audit at ``https://console.upsun.com/ORG_NAME``. This view shows all of your projects within the organization (assuming you have at least [projects:list](https://docs.upsun.com/administration/users.md#organization-permissions) permissions on the organization). - On the left hand side, under the **Filter** heading, expand the **Region** option. - Under Region, select the following region filters: - Germany (de-2) - Switzerland (ch-1) - United Kingdom (uk-1) - United States - East (us-4) - France (fr-4) - United States - West (us-3) - Australia - East (au-2) ![Console filter GCP IP changes](https://docs.upsun.com/images/gcpaffected.png) Not every project listed in this audit will necessarily be impacted by the change, only those that are explicitly using the outbound IPs in some way. ### Troubleshoot development ##### Common tasks ###### Force a redeploy There are times where you might want to trigger a redeployment of your application, such as to add custom TLS certificates. A redeploy reuses your built app and services. To trigger a redeploy, follow these steps: Run the following command: ```sh {} upsun redeploy ``` The redeploy takes place after any scheduled activities (either *Running* or *Pending*). **Note**: Despite the name, redeployment doesn’t rerun the ``deploy`` hook, only the ``post_deploy`` hook. Both your ``build`` and ``deploy`` hooks are tied to individual commits in code. They’re reused until another commit is pushed to the environment. See [more about hooks](https://docs.upsun.com/create-apps/hooks.md) and their reuse. To rerun the ``build`` and ``deploy`` hooks, [manually trigger a build](#manually-trigger-builds). **Is there a way to redeploy the production environment without knowing its name?**: It’s often desirable that the production environment, like many other values, is not hardcoded into your external workflows and management scripts. You can use the CLI, along with the [environment type distinction](https://docs.upsun.com/glossary.md#environment-type) to identify a production environment (assuming there is only one) and redeploy it in a single line. To do so, run the following command: ```bash {} upsun redeploy -e $(upsun environment:list --type production --pipe) ``` ###### Manually trigger builds To increase performance and keep applications the same across environments, Upsun reuses built applications if its code and build time configuration (variables and such) remain the same. There may be times where you want to force your application to be built again without changing its code, for example to test an issue in a build hook or when external dependencies change. To force a rebuild without changing the code, use an [environment variable](https://docs.upsun.com/development/variables/set-variables.md#create-environment-specific-variables). Assuming you want to do this for your `main` environment, first create a `REBUILD_DATE` environment variable: ```bash upsun variable:create --environment main --level environment --prefix env --name REBUILD_DATE --value "$(date)" --visible-build true ``` This triggers a build right away to propagate the variable. To force a rebuild at any time, update the variable with a new value: ```bash upsun variable:update --environment main --value "$(date)" "env:REBUILD_DATE" ``` This forces your application to be built even if no code has changed. ###### Clear the build cache You may find that you need to clear the build cache, such as when it's grown too big or, in rare circumstances, when it's corrupted. It may get corrupted when code is downloaded from a third-party language service like Packagist or npm while that service is experiencing issues. To clear the build cache, run the following command: ```sh upsun project:clear-build-cache ``` The next build for each environment is likely to take longer as the cache rebuilds. ##### Access denied or permission denied In most cases, issues accessing a project are caused by missing permissions for a given user. For more information see how to [manage user permissions](https://docs.upsun.com../administration/users.md). If you are using the CLI, make sure that [you are authenticated](https://docs.upsun.com../administration/cli.md#2-authenticate). If you are using SSH, see how to [troubleshoot SSH access](https://docs.upsun.com../development/ssh/troubleshoot-ssh.md). ##### HTTP responses 502 Bad Gateway or 503 Service Unavailable If you see these errors when accessing your application, it indicates your application is crashing or unavailable. Typical causes and potential solutions include: - Your app is listening at the wrong place. - Check your app's [upstream properties](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#upstream). - If your app listening at a port, make sure it's using the [`PORT` environment variable](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). - Your `.upsun/config.yaml` configuration has an error and a process isn't starting or requests can't be forwarded to it correctly. - Check your `web.commands.start` entry or your `passthru` configuration. - The amount of traffic coming to your site exceeds the processing power of your application. - You may want to [check if bots are overwhelming your site](https://support.platform.sh/hc/en-us/community/posts/16439634723858). - Certain code paths in your application are too slow and timing out. - Check your code is running smoothly. - Consider using the [observability solution](https://docs.upsun.com../increase-observability/application-metrics.md) included in your project to get a better view of your application. - A PHP process is crashing because of a segmentation fault. - See [how to deal with crashed processes](https://docs.upsun.com../languages/php/troubleshoot.md#troubleshoot-a-crashed-php-process). - A PHP process is killed by the kernel out-of-memory killer. - See [how to deal with killed processes](https://docs.upsun.com../languages/php/troubleshoot.md#troubleshoot-a-killed-php-process). ##### Site outage If you can't access some part of your project, whether it's the live site, development environment, or Console, check the [Upsun status page](https://status.platform.sh/). There you can see planned maintenance and subscribe to updates for any potential outages. If the status is operational, [contact support](https://docs.upsun.com/learn/overview/get-support.md). ##### Command not found When you've added a command line tool (such as [Drush](https://docs.upsun.com/glossary.md#drush)), you might encounter an error like the following: ```bash -bash: drush: command not found ``` If you see this, add the command you want to run to your path with a [`.environment` file script](https://docs.upsun.com/development/variables/set-variables.md#set-variables-via-script). As a Linux or Unix-like operating system user (MacOS included), to be able to run your scripts directly and quickly get past this error you may need to run the `chmod +x ` command. However, regardless of which operating system you're using, it's best if you **don't rely on scripts having execute permissions**. Instead, call the app/shell/runtime directly passing your script file to that executable. ##### Missing commits If you push code to Upsun without the full Git history, sometimes commits are missing. This can happen if you're pushing code from an external CI/CD pipeline, such as a GitHub action. Such pipelines often do only shallow clones by default. In such cases, your build might fail with an internal error. Or you might see an error like `unexpected disconnect while reading sideband packet`. To avoid the error, make sure you do a full clone of the repository before pushing code. For example, for the [Checkout GitHub action](https://github.com/actions/checkout), set `fetch-depth: 0` to clone the full history. For GitLab, set clones to have a limit of `0` either in [repository settings](https://docs.gitlab.com/ee/ci/pipelines/settings.md#limit-the-number-of-changes-fetched-during-clone) or using the [`GIT_DEPTH` variable](https://docs.gitlab.com/ee/user/project/repository/monorepos/index.md#shallow-cloning). ##### Large JSON file upload failing When trying to upload a large JSON file to your API, you might see a 400 response code (`Malformed request`). Upsun enforces a 10 MB limit on files with the `application/json` `Content-Type` header. To send large files, use the `multipart/form-data` header instead: ```bash curl -XPOST 'https://example.com/graphql' --header 'Content-Type: multipart/form-data' --form file=large_file.json ``` ##### Databases For MySQL specific errors, see how to [troubleshoot MySQL](https://docs.upsun.com../add-services/mysql/troubleshoot.md). ###### Permission error creating a database If you try to use a user to create a database, you get an error saying `permission denied to create database`. The database is created for you and can be found in the `"SERVICE_NAME"_"PATH"` [service environment variable](https://docs.upsun.com/development/variables.md#service-environment-variables), or in the `path` key of the `PLATFORM_RELATIONSHIPS` [environment variable](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). ##### Storage If you're having trouble with storage, see how to [troubleshoot mounts](https://docs.upsun.com../create-apps/troubleshoot-mounts.md) and [disks](https://docs.upsun.com../create-apps/troubleshoot-disks.md). ###### Can't write to file system If you attempt to write to disk outside a `build` hook, you may encounter a `read-only file system` error. Except where you define it, the file system is all read-only, with code changes necessary through git. This gives you benefits like repeatable deployments, consistent backups, and traceability. To generate anything you need later, [write to disk during a `build` hook](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#writable-directories-during-build). Or [declare mounts](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#mounts), which are writable even during and after deploy. They can be used for your data: file uploads, logs, and temporary files. ###### Upsun push fails due to lack of disk space You might see the following message when attempting to run `upsun push`: `There isn't enough free space to complete the push` This usually indicates that large files are present in the repository (where they shouldn't be). Make sure that the paths for files like media files, dependencies, and databases are set to be ignored in your `.gitignore` file. If large files are already in the repository, the open-source tool [bfg-repo-cleaner](https://rtyley.github.io/bfg-repo-cleaner/) can help in cleaning up the repository by purging older commits, removing unnecessary files, and more. If none of these suggestions work, open a [support ticket](https://docs.upsun.com/learn/overview/get-support.md). ##### Stuck build or deployment If you see a build or deployment running longer than expected, it may be one of the following cases: - The build is blocked by a process in your `build` hook. - The deployment is blocked by a long-running process in your `deploy` hook. - The deployment is blocked by a long-running cron job in the environment. - The deployment is blocked by a long-running cron job in the parent environment. To determine if your environment is being stuck in the build or the deployment, check your [activity log](https://docs.upsun.com../increase-observability/logs/access-logs.md#activity-logs). If the activity has the result `success`, the build has completed successfully and the system is trying to deploy. If the result is still `running`, the build is stuck. In most regions, stuck builds terminate after one hour. When a deployment is blocked, you should try the following: 1. Connect to your environment using [SSH](https://docs.upsun.com/development/ssh.md). 2. Find any long-running cron jobs or deploy hooks on the environment by running `ps afx`. 3. Kill any long-running processes with `kill `. Replace `` with the process ID shown by `ps afx`. If a `sync` of `activate` process is stuck, try the above on the parent environment. Note that, for PHP apps, you can [restart processes that get stuck during a build or deployment](https://docs.upsun.com../languages/php/troubleshoot.md#restart-php-processes-stuck-during-a-build-or-deployment) from your app container. ##### Slow or failing build or deployment Builds can take long time or fail. Most of the time, it's related to an application issue. Here are a few tips that can help you find the exact cause. ###### Check for errors in the logs Invisible errors during the build and deploy phase can cause increased wait times, failed builds, and other problems. Investigate [each log](https://docs.upsun.com../increase-observability/logs/access-logs.md#container-logs) and fix any errors you find. ###### Build and deploy hooks [`build` and `deploy` hooks](https://docs.upsun.com../create-apps/hooks.md) can cause long build times. If they run into issues, they can cause the build to fail or hang indefinitely. `build` hooks can be tested in your local environment. `deploy` hooks can be tested either locally or by logging into the application over [SSH](https://docs.upsun.com/development/ssh.md) and running them there. Be careful not to test the scripts on production environments. You can also test your hooks with these Linux commands to help debug issues: ```text time # Print execution time strace -T # Print a system call report ``` ###### Cron jobs Containers can't be shutdown while long-running [cron jobs and scheduled tasks](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#crons) are active. That means long-running cron jobs block a container from being shut down to make way for a new deploy. Make sure your custom cron jobs run quickly and properly. Cron jobs may invoke other services in unexpected ways, which can increase execution time. ##### Cache configuration A common source of performance issues is a misconfigured cache. The most common issue isn't allowing the right cookies as part of the router cache. Some cookies, such as session cookies, need to be allowed. Others, such as marketing and analytics cookies, usually shouldn't be part of the cache key. See more about [router cache](https://docs.upsun.com../define-routes/cache.md) and [cookie entry](https://docs.upsun.com../define-routes/cache.md#cookies). Because the router cache follows cache headers from your app, your app needs to send the correct `cache-control` header. For static assets, set cache headers using the `expires` key in your [app configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#locations). ##### Language-specific troubleshooting For language-specific troubleshooting for your apps: - [PHP](https://docs.upsun.com../languages/php/troubleshoot.md) - [Node JS](https://docs.upsun.com../languages/nodejs/debug.md) ### Sanitize databases When working on a new feature on your website, you want to use a new branch. Using a new branch makes sure that you don't risk breaking your live, production website. Creating a branch on Upsun copies both the code and the database to that new development branch. These code and database changes need to be tested before being merged into production. Depending on your processes, internal or external teams may interact with the preview environment branch. Databases of live websites often contain personally identifiable information (PII) such as full names, mailing addresses, and phone numbers. To ensure people reviewing code changes can't access information they shouldn't, sanitize your databases of any PII that they may contain. ##### Examples #### Sanitizing databases: MariaDB and Drupal Databases of live websites often contain personally identifiable information (PII) such as full names, mailing addresses, and phone numbers. To ensure people reviewing code changes can't access information they shouldn't, sanitize your databases of any PII that they may contain. This example goes through the process for a MySQL database using Drupal. ###### Before you begin You need: - A project with a [MySQL database](https://docs.upsun.com../../add-services/mysql.md). - A command interface installed: - If doing it manually, the [Upsun CLI](https://docs.upsun.com../../administration/cli.md). - Otherwise, make sure [Drush](https://www.drush.org/latest/install/) is installed in your environment. This guide is about sanitizing MySQL databases. This guide doesn't address: - Sanitizing NoSQL Databases (such as [MongoDB](https://docs.upsun.com../../add-services/mongodb.md)) - Input validation and input sanitization, which both help prevent security vulnerabilities ###### Sanitize the database Make sure that you only sanitize preview environments and **never** the production environment. Otherwise you may lose most or even all of the relevant data stored in your database. First, take a [database dump](https://docs.upsun.com../../add-services/mysql.md#exporting-data) of your preview environment. This is just a safety precaution. Production data isn't altered. To get a database dump, run the following command: ``upsun db:dump -e ``. You see output like the following: ```sql {} +----+------------+---------------+---------------------------+---------------+ | ID | first_name | last_name | user_email | display_name | +----+------------+---------------+---------------------------+---------------+ | 1 | admin | admin | admin@yourcompany.com | admin | | 2 | john | doe | john.doe@gmail.com | john | | 3 | jane | doe | janedoe@ymail.com | jane | +----+------------+---------------+---------------------------+---------------+ ``` - Change the fields where PII is contained with the [UPDATE](https://mariadb.com/kb/en/update/). For example, to change the display name of users with an email address not in your company’s domain to a random value, run the following query: ```sql {} UPDATE users SET display_name==substring(md5(display_name||'$PLATFORM_PROJECT_ENTROPY') for 8); WHERE email NOT LIKE '%@yourcompany%' ``` Adapt and run that query for all fields that you need to sanitize. If you modify fields that you shouldn’t alter, [you can restore them](https://docs.upsun.com/environments/restore.md) from the dump you took in step 1. You can create a script to automate the sanitization process to be run automatically on each new deployment. Once you have a working script, add your script to sanitize the database to [a ](https://docs.upsun.com/create-apps/hooks/hooks-comparison.md#deploy-hook): ```yaml {location=".upsun/config.yaml"} applications: myapp: # ... hooks: deploy: | # ... cd /app/public if [ "$PLATFORM_ENVIRONMENT_TYPE" = production ]; then # Do whatever you want on the production site. else # The sanitization of the database should happen here (since it's non-production) sanitize_the_database.sh fi ``` To sanitize your database and get rid of sensitive, live information, use the ``drush sql:sanitize`` command. Add your script to sanitize the database to [a ](https://docs.upsun.com/create-apps/hooks/hooks-comparison.md#deploy-hook) for preview environments: ```yaml {location=".upsun/config.yaml"} applications: myapp: hooks: deploy: | # ... cd /app/public if [ "$PLATFORM_ENVIRONMENT_TYPE" = production ]; then # Do whatever you want on the production site. else drush -y sql:sanitize fi drush -y updatedb ``` More options are available. These are described in the [Drush documentation](https://www.drush.org/latest/commands/sql_sanitize/). To sanitize only on the initial deploy and not all future deploys, use [Drush state](https://www.drush.org/latest/commands/state_set/) as in the following example: ```yaml {location=".upsun/config.yaml"} applications: myapp: hooks: deploy: | # ... cd /app/public if [ "$PLATFORM_ENVIRONMENT_TYPE" = production ] || [ "$(drush state:get --format=string mymodule.sanitized)" != yes ]; then # Do whatever you want on the production site. else drush -y sql:sanitize drush state:set --input-format=string mymodule.sanitized yes fi ``` ###### What's next You learned how to remove sensitive data from a database. To replace sensitive data that with other meaningful data, you can add a `faker` to the process. A `faker` is a program that generates fake data that looks real. Having meaningful PII-free data allows you to keep your current Q&A, external reviews, and other processes. To add a faker, adapt your sanitizing queries to replace each value that contains PII with a new value generated by the faker. You might also want to make sure that you [implement input validation](https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.md#goals-of-input-validation). If your database contains a lot of data, consider using the [`OPTIMIZE TABLE` statement](https://mariadb.com/kb/en/optimize-table/) to reduce its size and help improve performance. #### Sanitizing databases: PostgreSQL and Django Databases of live websites often contain personally identifiable information (PII) such as full names, mailing addresses, and phone numbers. To ensure people reviewing code changes can't access information they shouldn't, sanitize your databases of any PII that they may contain. This example goes through the process for a PostgreSQL database using Django. ###### Before you begin You need: - A project with a [PostgreSQL database](https://docs.upsun.com../../add-services/postgresql.md). - A command interface installed: - If doing it manually, the [Upsun CLI](https://docs.upsun.com../../administration/cli.md). - Otherwise, make sure ``pqsl`` is installed in your environment. This guide is about sanitizing PostgreSQL databases. This guide doesn't address: - Sanitizing NoSQL Databases (such as [MongoDB](https://docs.upsun.com../../add-services/mongodb.md)) - Input validation and input sanitization, which both help prevent security vulnerabilities ###### Sanitize the database Make sure that you only sanitize preview environments and **never** the production environment. Otherwise you may lose most or even all of the relevant data stored in your database. First, take a [database dump](https://docs.upsun.com../../add-services/postgresql.md#exporting-data) of your preview environment. This is just a safety precaution. Production data isn't altered. To get a database dump, run the following command: ``upsun db:dump -e ``. You see output like the following: ```sql {} id | user_email | display_name -----+-----------------------------------------+----------------------- 3501 | daniel02@yourcompany.com | Jason Brown 3502 | ismith@kim.com | Sandra Griffin 3503 | olee@coleman-rodriguez.com | Miss Christine Morgan ``` - Change the fields where PII is contained with the [UPDATE](https://mariadb.com/kb/en/update/). For example, to change the display name of users with an email address not in your company’s domain to a random value, run the following query: ```sql {} UPDATE users SET display_name==substring(md5(display_name||'$PLATFORM_PROJECT_ENTROPY') for 8); WHERE email NOT LIKE '%@yourcompany%' ``` Adapt and run that query for all fields that you need to sanitize. If you modify fields that you shouldn’t alter, [you can restore them](https://docs.upsun.com/environments/restore.md) from the dump you took in step 1. You can create a script to automate the sanitization process to be run automatically on each new deployment. Once you have a working script, add your script to sanitize the database to [a ](https://docs.upsun.com/create-apps/hooks/hooks-comparison.md#deploy-hook): ```yaml {location=".upsun/config.yaml"} applications: myapp: # ... hooks: deploy: | # ... cd /app/public if [ "$PLATFORM_ENVIRONMENT_TYPE" = production ]; then # Do whatever you want on the production site. else # The sanitization of the database should happen here (since it's non-production) sanitize_the_database.sh fi ``` Assumptions: - ``users`` is the table where all of your PII is stored in the ``staging`` development database. - ``database`` is the relationship name for the PostgreSQL service. Set up a script by following these steps: - Retrieve service credentials from the [service environment variables](https://docs.upsun.com/development/variables.md#service-environment-variables) to use the ``psql`` command interface. Export these values to a [.environment](https://docs.upsun.com/development/variables/set-variables.md#set-variables-via-script) or include them directly in the sanitization script. ```bash {location=".environment"} # Pull credentials from the service environment variables. DB_USER=${DATABASE_USERNAME} DB_HOST=${DATABASE_HOST} DB_PORT=${DATABASE_PORT} DB_PASS=${DATABASE_PASSWORD} ``` - Create an executable sanitizing script by running the following command: ```bash {} touch sanitize.sh && chmod +x sanitize.sh ``` - Make the script sanitize environments with an [environment type](https://docs.upsun.com/administration/users.md#environment-type-roles) other than ``production``. The following example runs only in preview environments and sanitizes the ``display_name`` and ``email`` columns of the ``users`` table. Adjust the details to fit your data. ```bash {location="sanitize.sh"} #!/usr/bin/env bash if [ "$PLATFORM_ENVIRONMENT_TYPE" != production ]; then # Sanitize data PGPASSWORD=$DB_PASS psql -c "UPDATE users SET display_name=substring(md5(display_name||'$PLATFORM_PROJECT_ENTROPY') for 8);" -U $DB_USER -h $DB_HOST -p $DB_PORT PGPASSWORD=$DB_PASS psql -c "UPDATE users SET email=substring(md5(email||'$PLATFORM_PROJECT_ENTROPY') for 8);" -U $DB_USER -h $DB_HOST -p $DB_PORT fi ``` To sanitize only on the initial deploy and not all future deploys, on sanitization create a file on a [mount](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#mounts). Then add a check for the file as in the following example: ```bash {location="sanitize.sh"} #!/usr/bin/env bash if [ "$PLATFORM_ENVIRONMENT_TYPE" != production ] && [ ! -f /is_sanitized ]; then # Sanitize data touch /is_sanitized fi ``` - Update the deploy hook to run your script on each deploy. ```yaml {location=".upsun/config.yaml"} applications: myapp: hooks: build: ... deploy: | python manage.py migrate bash sanitize.sh ``` - Commit your changes by running the following command: ```bash {} git add .environment sanitize.sh .upsun/config.yaml&& git commit -m "Add sanitization." ``` Push the changes to ``staging`` and verify that environment’s database was sanitized. Once merged to production, all data from future preview environments are sanitized on environment creation. ###### What's next You learned how to remove sensitive data from a database. To replace sensitive data that with other meaningful data, you can add a `faker` to the process. A `faker` is a program that generates fake data that looks real. Having meaningful PII-free data allows you to keep your current Q&A, external reviews, and other processes. To add a faker, adapt your sanitizing queries to replace each value that contains PII with a new value generated by the faker. You might also want to make sure that you [implement input validation](https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.md#goals-of-input-validation). If your database contains a lot of data, consider using the [`REINDEX` statement](https://www.postgresql.org/docs/current/sql-reindex.md) to help improve performance. #### Sanitizing databases: PostgreSQL and Symfony Databases of live websites often contain personally identifiable information (PII) such as full names, mailing addresses, and phone numbers. To ensure people reviewing code changes can't access information they shouldn't, sanitize your databases of any PII that they may contain. This example goes through the process for a PostgreSQL database using Symfony. ###### Before you begin You need: - A project with a [PostgreSQL database](https://docs.upsun.com../../add-services/postgresql.md). - A command interface installed: - If doing it manually, the [Symfony CLI](https://symfony.com/download). - Otherwise, make sure ``pqsl`` is installed in your environment. This guide is about sanitizing PostgreSQL databases. This guide doesn't address: - Sanitizing NoSQL Databases (such as [MongoDB](https://docs.upsun.com../../add-services/mongodb.md)) - Input validation and input sanitization, which both help prevent security vulnerabilities ###### Sanitize the database Make sure that you only sanitize preview environments and **never** the production environment. Otherwise you may lose most or even all of the relevant data stored in your database. First, take a [database dump](https://docs.upsun.com../../add-services/postgresql.md#exporting-data) of your preview environment. This is just a safety precaution. Production data isn't altered. To get a database dump, run the following command: ``symfony db:dump -e ``. You see output like the following: ```sql {} id | user_email | display_name -----+-----------------------------------------+----------------------- 3501 | daniel02@yourcompany.com | Jason Brown 3502 | ismith@kim.com | Sandra Griffin 3503 | olee@coleman-rodriguez.com | Miss Christine Morgan ``` - Change the fields where PII is contained with the [UPDATE](https://mariadb.com/kb/en/update/). For example, to change the display name of users with an email address not in your company’s domain to a random value, run the following query: ```sql {} UPDATE users SET display_name==substring(md5(display_name||'$PLATFORM_PROJECT_ENTROPY') for 8); WHERE email NOT LIKE '%@yourcompany%' ``` Adapt and run that query for all fields that you need to sanitize. If you modify fields that you shouldn’t alter, [you can restore them](https://docs.upsun.com/environments/restore.md) from the dump you took in step 1. You can create a script to automate the sanitization process to be run automatically on each new deployment. Once you have a working script, add your script to sanitize the database to [a ](https://docs.upsun.com/create-apps/hooks/hooks-comparison.md#deploy-hook): ```yaml {location=".upsun/config.yaml"} applications: myapp: # ... hooks: deploy: | # ... cd /app/public if [ "$PLATFORM_ENVIRONMENT_TYPE" = production ]; then # Do whatever you want on the production site. else # The sanitization of the database should happen here (since it's non-production) sanitize_the_database.sh fi ``` Assumptions: - An Entity User exist and contains all of your PII (Personally Identifiable Information) - [fakerphp/faker](https://fakerphp.github.io/) has been installed as a dependency on your Symfony application Set up a script by following these steps: - Create a Symfony command to sanitize data ```php {location="src/Command/SanitizeDataCommand.php"} setDescription('This command allows you to sanitize user data (username and email).'); } protected function execute(InputInterface $input, OutputInterface $output) { $io = new SymfonyStyle($input, $output); $users = $this->userRepository->findAll(); $io->progressStart(count($users)); /** @var User $user */ foreach ($users as $user) { $io->progressAdvance(); // initialize faker $faker = Faker\Factory::create(); // sanitize user info $user->setUsername(uniqid($faker->userName())); $user->setEmail($faker->email()); // adapt to your needs $this->entityManager->flush(); } $io->progressFinish(); return static::SUCCESS; } } ``` - Update the deploy hook to run your Symfony Command on each deploy. ```yaml {location=".upsun/config.yaml"} applications: myapp: hooks: build: ... deploy: | if [ "$PLATFORM_ENVIRONMENT_TYPE" != production ]; then # The sanitization of the database should happen here (since it's non-production) php bin/console app:sanitize-data fi ``` To sanitize only on the initial deploy and not all future deploys, on sanitization create a file on a mount. Then add a check for the file as in the following example: ```yaml {location=".upsun/config.yaml"} applications: myapp: hooks: build: ... deploy: | if [ "$PLATFORM_ENVIRONMENT_TYPE" != production ] && [ ! -f MOUNT_PATH/is_sanitized ]; then # The sanitization of the database should happen here (since it's non-production) php bin/console app:sanitize-data touch MOUNT_PATH/is_sanitized fi ``` - Commit your changes by running the following command: ```bash {} git add src/Command/SanitizeDataCommand.php .upsun/config.yaml && git commit -m "Add sanitization." ``` Push the changes to ``staging`` and verify that environment’s database was sanitized. Once merged to production, all data from future preview environments are sanitized on environment creation. This example show you how to sanitize data on multiple projects inside an organization, except for production environments. Assumptions: - Symfony Command from previous tab ``Using a Symfony Command`` has already been pushed to all of your environments. Set up a script by following these steps: - Create an executable sanitizing script by running the following command: ```bash {} touch sanitize_fleet.sh && chmod +x sanitize_fleet.sh ``` - Make the script sanitize environments with an [environment type](https://docs.upsun.com/administration/users.md#environment-type-roles) other than ``production``. The following example runs only in preview environments and sanitizes data using the Symfony Command from previous tab, already pushed to all of your environments. ```bash {location="sanitize_fleet.sh"} if [ -n "$ZSH_VERSION" ]; then emulate -L ksh; fi ###################################################### # fleet sanitization demo script, using the Symfony CLI. # # Enables the following workflow on a project: # . # └── main # ├── staging # | └── new-feature # └── auto-updates # # Usage # 1. source this script: `. sanitize_fleet.sh` or `source sanitize_fleet.sh` depending of your local machine # 2. define ORGANIZATION var: ORGANIZATION= # 3. run `sanitize_organization_data $ORGANIZATION` ###################################################### # Utility functions. # list_org_projects: Print list of projects operation will be applied to before starting. # $1: Organization, as it appears in console.upsun.com. list_org_projects () { symfony project:list -o $1 --columns="ID, Title" } # get_org_projects: Retrieve an array of project IDs for a given organization. # Note: Makes array variable PROJECTS available to subsequent scripts. # $1: Organization, as it appears in console.upsun.com. get_org_projects () { PROJECTS_LIST=$(symfony project:list -o $1 --pipe) PROJECTS=($PROJECTS_LIST) } # get_project_envs: Retrieve an array of envs IDs for a project. # Note: Makes array variable ENVS available to subsequent scripts. # $1: ProjectId, as it appears in console.upsun.com. get_project_envs () { ENV_LIST=$(symfony environment:list -p $1 --pipe) ENVS=($ENV_LIST) } # list_project_envs: Print list of envs operation will be applied to before starting. # $1: ProjectId, as it appears in console.upsun.com. list_project_envs () { symfony environment:list -p $1 } # add_env_var: Add environment level environment variable. # $1: Variable name. # $2: Variable value. # $3: Target project ID. # $4: Target environment ID. add_env_var () { VAR_STATUS=$(symfony project:curl -p $3 /environments/$4/variables/env:$1 | jq '.status') if [ "$VAR_STATUS" != "null" ]; then symfony variable:create \ --name $1 \ --value "$2" \ --prefix env: \ --project $3 \ --environment $4 \ --level environment \ --json false \ --sensitive false \ --visible-build true \ --visible-runtime true \ --enabled true \ --inheritable true \ -q else printf "\nVariable $1 already exists. Skipping." fi } # Main functions. sanitize_organization_data () { list_org_projects $1 get_org_projects $1 for PROJECT in "${PROJECTS[@]}" do printf "\n### Project $PROJECT." # get environments list list_project_envs $PROJECT get_project_envs $PROJECT for ENVIRONMENT in "${ENVS[@]}" do unset -f ENV_CHECK ENV_CHECK=$(symfony project:curl -p $PROJECT /environments/$ENVIRONMENT | jq -r '.status') unset -f ENV_TYPE ENV_TYPE=$(symfony project:curl -p $PROJECT /environments/$ENVIRONMENT | jq -r '.type') if [ "$ENV_CHECK" = active -a "$ENV_TYPE" != production ]; then unset -f DATA_SANITIZED DATA_SANITIZED=$(symfony variable:get -p $PROJECT -e $ENVIRONMENT env:DATA_SANITIZED --property=value) if [ "$DATA_SANITIZED" != true ]; then printf "\nEnvironment $ENVIRONMENT exists and isn't sanitized yet. Sanitizing data." printf "\n" # do sanitization here symfony ssh -p $PROJECT -e $ENVIRONMENT -- php bin/console app:sanitize-data printf "\nSanitizing data is finished, redeploying" add_env_var DATA_SANITIZED true $PROJECT $ENVIRONMENT else printf "\nEnvironment $ENVIRONMENT exists and doesn't need to be sanitized. skipping." fi elif [ "$ENV_TYPE" == production ]; then printf "\nEnvironment $ENVIRONMENT is production one, skipping." else printf "\nEnvironment $ENVIRONMENT isn't active $ENV_CHECK, skipping." fi done done } ``` - use this shell script Depending on the machine you want to run this script on, adapt this to your needs. ```bash {} . sanitize_fleet.sh # or source sanitize_fleet.sh ORGANIZATION= sanitize_organization_data $ORGANIZATION ``` **Note**: You can find the organization identifier for a specific project, within the Upsun console, by clicking on your name, and then on “Settings”, in the top right corner. - [Option] Commit your changes by running the following command: ```bash {} git add sanitize_fleet.sh && git commit -m "Add sanitization." ``` Push the changes to ``staging`` and verify that environment’s database was sanitized. Once merged to production, all data from future preview environments are sanitized on environment creation. ###### What's next You learned how to remove sensitive data from a database. To replace sensitive data that with other meaningful data, you can add a `faker` to the process. A `faker` is a program that generates fake data that looks real. Having meaningful PII-free data allows you to keep your current Q&A, external reviews, and other processes. To add a faker, adapt your sanitizing queries to replace each value that contains PII with a new value generated by the faker. You might also want to make sure that you [implement input validation](https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.md#goals-of-input-validation). If your database contains a lot of data, consider using the [`REINDEX` statement](https://www.postgresql.org/docs/current/sql-reindex.md) to help improve performance. ### External Integrations Upsun can be integrated with external services. Upsun supports native integrations with multiple services, first and foremost Git hosting services such as GitHub, GitLab, or Bitbucket. You can continue to use those tools for your development workflow, and have Upsun environments created automatically for your pull requests and branches. ##### List active integrations With the CLI, you can list all your active integrations using the following command: ```bash upsun integrations ``` You get output similar to the following: ```bash +---------------+-------------+-------------------------------------------------------------------------------------+ | ID | Type | Summary | +---------------+-------------+-------------------------------------------------------------------------------------+ | abcdefghijklm | github | Repository: platformsh/platformsh-docs | | | | Hook URL: | | | | https://eu-3.platform.sh/api/projects/123abcdefgh3i/integrations/abcdefghijklm/hook | +---------------+-------------+-------------------------------------------------------------------------------------+ ``` ##### Validate integrations Once your integration has been configured, you can check that it's working as expected. To do so, follow these steps: 1. Run the `upsun integration:validate` command. 2. When prompted, select the integration you want to validate: ```bash Enter a number to choose an integration: [0] 5aut2djgt6kdd (health.slack) [1] a6535j9qp4sl8 (github) > 1 ``` You get output similar to: ```bash Validating the integration a6535j9qp4sl8 (type: github)... The integration is valid. ``` ##### Debug integrations When integrations run, they trigger "activities." Activities are actions that happen on Upsun, and they get logged. Usually these are triggered nearly instantaneously on the webhook endpoint. These activities may be delayed due to the external services having latency. Those logs are available via the CLI. In most cases they aren't necessary but may be useful for debugging an integration if it is misbehaving for some reason. There are a handful of CLI commands available, all under the `integrations` section. ###### List all activities To list all the updates triggered by [activities](https://docs.upsun.com../integrations/activity/reference.md) on a given project and integration, follow these steps: 1. Run the `upsun integration:activities` command. 2. When prompted, select an integration. ```bash Enter a number to choose an integration: [0] dxr45hfldrkoe (webhook) [1] n2ukd4p7qofg4 (health.email) [2] c4opi5tjv3yfd (github) > 2 ``` You get output similar to the following: ```bash Activities on the project Upsun | Docs (6b2eocegfkwwg), integration c4opi5tjv3yfd (github): +---------------+---------------------------+-------------------------------------------------------------+----------+---------+ | ID | Created | Description | State | Result | +---------------+---------------------------+-------------------------------------------------------------+----------+---------+ | 6456zmdtoykxa | 2020-04-14T16:38:09-05:00 | Fetching from https://github.com/platformsh/platformsh-docs | complete | success | | wcwp34yjvydgk | 2020-04-14T16:35:22-05:00 | Fetching from https://github.com/platformsh/platformsh-docs | complete | success | | w2bp3oa5xbfoe | 2020-04-14T16:33:13-05:00 | Fetching from https://github.com/platformsh/platformsh-docs | complete | success | | uqqvdyxmcdmsa | 2020-04-14T16:31:45-05:00 | Fetching from https://github.com/platformsh/platformsh-docs | complete | success | | 7x3wefhh4fwqc | 2020-04-14T16:30:36-05:00 | Fetching from https://github.com/platformsh/platformsh-docs | complete | success | | a46aah3ga65gc | 2020-04-14T16:29:46-05:00 | Fetching from https://github.com/platformsh/platformsh-docs | complete | success | | r7erid2jlixgi | 2020-04-14T16:24:50-05:00 | Fetching from https://github.com/platformsh/platformsh-docs | complete | success | | ieufk3vvde5oc | 2020-04-14T16:24:49-05:00 | Fetching from https://github.com/platformsh/platformsh-docs | complete | success | | bc7ghg36ty4ea | 2020-04-14T15:30:17-05:00 | Fetching from https://github.com/platformsh/platformsh-docs | complete | success | | 4qojtv7a6rk2w | 2020-04-14T15:27:26-05:00 | Fetching from https://github.com/platformsh/platformsh-docs | complete | success | +---------------+---------------------------+-------------------------------------------------------------+----------+---------+ ``` You may also specify an integration to display in the command line directly: `upsun integration:activities c4opi5tjv3yfd`. The ID is an internal identifier for the activity event. The Description field is an arbitrary string of text produced by the integration code. The State and Result fields indicate if the activity completed successfully, failed for some reason, or is currently in progress. See the `--help` output of the command for more options. ###### Show detailed information on an activity To show detailed information on a specific activity, run the following command: ```bash upsun integration:activity:log -t ``` The `-t` option specifies that timestamps must be included in the display of the results. You get output similar to the following: ```bash Integration ID: ceopz5tgj3yfc Activity ID: 6456zmdtoykxa Type: integration.github.fetch Description: Fetching from https://github.com/platformsh/platformsh-docs Created: 2020-04-15T08:44:07-05:00 State: complete Log: [2020-04-15T13:44:17-05:00] Waiting for other activities to complete [2020-04-15T13:46:07-05:00] Fetching from GitHub repository platformsh/platformsh-docs [2020-04-15T13:46:09-05:00] No changes since last fetch [2020-04-15T13:46:09-05:00] [2020-04-15T13:46:09-05:00] Synchronizing branches [2020-04-15T13:46:09-05:00] [2020-04-15T13:46:09-05:00] Synchronizing pull requests [2020-04-15T13:46:59-05:00] [2020-04-15T13:46:59-05:00] W: No changes found, scheduling a retry.. ``` That shows the full output of the activity, including timestamps. That can be especially helpful if trying to determine why an integration isn't behaving as expected. See the `--help` output of the command for more options. If you omit the activity ID (the second random-seeming string), the command will default to the most recent activity recorded. ### Activity scripts Upsun supports custom scripts that can fire in response to any activity. These scripts allow you to take arbitrary actions in response to actions in your project, such as when it deploys, when a new branch is created, etc. ##### Installing Activity scripts are configured as integrations. That means they're at the *project level*, not at the level of an individual environment. While you can store the scripts in your Git repository for access, they have no effect there. To install a new activity script, use [`integration:add` command](https://docs.upsun.com/administration/cli/reference.md#integrationadd) from the [Upsun CLI](https://docs.upsun.com/administration/cli.md). ```bash upsun integration:add --type script --file ./my_script.js ``` That installs and enables the `my_script.js` file as an activity script on the current project. Don't run the `integration:add` command a second time, or it installs a second integration with the same code. ##### Updating To update an existing activity script, follow these steps: 1. Get the activity script's ID by running the following command: ```bash upsun integrations ``` This returns something like the following: ```bash +---------------+--------------+--------------+ | ID | Type | Summary | +---------------+--------------+--------------+ | nadbowmhd67do | script | ... | | rcqf6b69jdcx6 | health.email | From: | | | | To: #admins | +---------------+--------------+--------------+ ``` 2. Update the integration by running the following command: ```bash upsun integration:update --file ./my_script.js ``` This [`integration:update` command](https://docs.upsun.com/administration/cli/reference.md#integrationupdate) updates the integration in place, permanently overwriting the previous version. 3. Test the activity script update by [triggering a redeployment](https://docs.upsun.com/administration/cli/reference.md#environmentredeploy) with the following command: ```bash upsun redeploy ``` ##### Removing To disable an activity script, follow these steps: 1. Get the activity script's ID by running the following command: ```bash upsun integrations ``` This returns something like the following: ```bash +---------------+--------------+--------------+ | ID | Type | Summary | +---------------+--------------+--------------+ | nadbowmhd67do | script | ... | | rcqf6b69jdcx6 | health.email | From: | | | | To: #admins | +---------------+--------------+--------------+ ``` 2. [Delete the integration](https://docs.upsun.com/administration/cli/reference.md#integrationdelete) by running the following command: ```bash upsun integration:delete ``` ##### Debugging Get activity logs by running the following command: ```bash upsun integration:activities ``` Every time your activity script runs it generates a new log entry, including the output from the script. Any output produced by `console.log` is available in the activity log, which is the recommended way to debug scripts. See the [activity log](https://docs.upsun.com../overview.md#debug-integrations) documentation for further details. To get a more readable output of a variable you're trying to debug, you can make `JSON.stringify` use human-friendly formatting. ```javascript console.log(JSON.stringify(project, null, 2)); ``` ##### Configuring scripts There are many types of activity to which a script could respond. By default, it will activate only after a successful `git push` operation. That trigger is configurable via command line switches when adding or updating a script. For example, to have a script trigger any time an environment is activated or deactivated, run: ```bash upsun integration:update --events='environment.activate,environment.deactivate' ``` A complete list of possible events is available in the [Activity script type documentation](https://docs.upsun.com/integrations/activity/reference.md#type). Any of those Activity Script types can be added to the `--events=event1,event2,...` option. Scripts can also trigger only when an action reaches a [given state](https://docs.upsun.com/integrations/activity/reference.md#state), such as `pending`, `in_progress`, `complete`, `cancelled`, or `scheduled`. The default is only when they reach `complete`. To have a script execute when a synchronize action first starts, for example, you would run: ```bash upsun integration:update --events=environment.synchronize --states=in_progress ``` It's also possible to restrict scripts to certain environments by name. Most commonly, that's used to have them execute only for your production environment or for all other environments. The following example executes only for backup actions on the `production` environment: ```bash upsun integration:update --events=environment.backup --environments=production ``` As a general rule, it's better to have an activity script only execute on the specific events and branches you're interested in rather than firing on all activities and then filtering out undesired use cases in the script itself. ##### Activity script variables Some activities don't have access to [project and environment variables](https://docs.upsun.com/development/variables.md#variable-types). In this case, to avoid hardcoding sensitive variables (such as API tokens) and therefore prevent security breaches, add a variable to your activity script. You can add activity script variables through the Upsun CLI. Activity script variables are only visible in the activity script itself, inside the `variables` variable. ###### Add an activity script variable To add a variable to your activity script at the integration level, use the following `POST` request: ```bash POST /api/projects//integrations//variables ``` You get a payload similar to the following: ```json { "name": "string", "attributes": { "property1": "string", "property2": "string" }, "value": "string", "is_json": true, "is_sensitive": true } ``` ###### Delete or patch an activity script variable To delete an activity script variable, use the following `DELETE` request: ``` DELETE /api/projects//integrations//variables ``` You can also patch your activity script variable. To do so, send the same request using the `PATCH` method instead of the `DELETE` one. ###### List an activity script variable To list all your activity script variables at the integration level, use the following `GET` request: ``` GET /api/projects//integrations//variables ``` ##### Available APIs Activity scripts can be written in ES2021 and don't support installing additional packages. There are a series of [utility functions you can reuse](https://docs.upsun.com/integrations/activity/utility.md) as well as the following libraries, APIs, and global variables to facilitate building out custom functionality. ###### `underscore.js` [`Underscore.js`](https://github.com/jashkenas/underscore) is available out-of-the-box to make writing Activity scripts more pleasant. See [Underscore's documentation](https://underscorejs.org/) for available functions and utilities. ###### `activity` Every activity script has a global variable `activity` that contains detailed information about the activity, including embedded, JSON-ified versions of the routes configuration and relevant `.upsun/config.yaml` files. The `activity` variable is the same as the [webhook payload](https://docs.upsun.com/integrations/activity/webhooks.md). See the documentation there for details and a complete example. Several of the utility functions below work by pulling out common portions of the `activity` object. ###### `project` The `project` global variable includes information about the project subscription itself. That includes its ID and name, how many users are associated with the project, its SSH public key, and various other values. An example of this object is below: ```json { "attributes": {}, "created_at": "2024-03-15T19:50:09.514267+00:00", "default_domain": null, "description": "", "id": "azertyuiopqsdfghjklm", "owner": "...", "region": "eu-1.upsun.com", "repository": { "client_ssh_key": "ssh-rsa ...", "url": "azertyuiopqsdfghjklm@git.eu-1.upsun.com:kqyhl5f5nuzky.git" }, "status": { "code": "provisioned", "message": "ok" }, "subscription": { "environments": 3, "included_users": 1, "license_uri": "...", "plan": "development", "restricted": false, "storage": 5120, "subscription_management_uri": "...", "suspended": false, "user_licenses": 1 }, "timezone": "Europe/Dublin", "title": "Activity script examples", "updated_at": "2020-04-21T17:15:35.526498+00:00" } ``` ###### Storage API Activity scripts have access to a limited key/value storage API to persist values from one execution to another. The API is similar to the JavaScript `LocalStorage` API. ```javascript // Access the storage API. // It isn't pre-required. var storage = require("storage"); // Retrieve a stored value. If the value isn't set it will return null. var counter = storage.get('counter') || 0; if (counter) { // Generate debug output. console.log("Counter is: " + counter); } // Write a value into the storage. Only string-safe values are supported. // To save an object or array, run JSON.stringify() on it first. storage.set('counter', counter + 1); // Remove a value completely. storage.remove('counter'); // Remove all values in storage, unconditionally. storage.clear(); ``` ###### Fetch API Activity scripts support a modified version of the browser "Fetch API" for issuing HTTP requests. Unlike the typical browser version, however, they only support synchronous requests. That means the return value of `fetch()` is a `Response`, not a `Promise` for one. The returned `Response` is also a bit different: only the `ok`, `status` and `statusText` properties as well as the `text` and `json` methods are available. Note that because of the synchronous nature of our `fetch` implementation, the `Response.text` and `Response.json` methods are also synchronous, so they directly return a `string` and an `object`, respectively. The API is otherwise essentially the same as that [in the MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch). For instance, this example sends a GET request every time it executes: ```javascript var resp = fetch("http://example.com/site-deployed"); // The fetch call above being synchronous, we can directly access resp properties. // resp.ok is true if the response was a 2xx, false otherwise. if (!resp.ok) { console.log("Well that didn't work."); } ``` While this example sends a POST request with a JSON string as the body: ```javascript var body = JSON.stringify({ "some": "value", }); var resp = fetch("http://example.com/", { method: "POST", headers: { 'Content-Type': 'application/json', }, body: body, } ) if (!resp.ok) { console.log("Couldn't POST."); } else { // resp.json() is synchronous so this will log an object, not `Promise { }` console.log(resp.json()); } ``` For more `fetch()` options, see the [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch). ###### Cryptographic API A minimalist cryptographic API is also available to activity scripts. Its main use is for signing requests to 3rd party APIs. The `crypto.createHmac()` function allows you to create a secure HMAC hash and digest. ```javascript var h = crypto.createHmac("sha256", "foo"); h.update("bar"); h.digest("hex") ``` * The available hashing functions are `'sha256'`, `'sha1'` and `'md5'` as hashing functions. * The available digest formats are `'base64'`, `'hex'` or `''` (empty). An empty digest will yield a byte string. For example, if you wanted to call an AWS API, you would calculate the signature like so: ```Javascript function HMAC(key, value) { var h = crypto.createHmac("sha256", key); h.update(value); return h.digest(); } var kSecret = "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY"; HMAC(HMAC(HMAC(HMAC("AWS4" + kSecret,"20150830"),"us-east-1"),"iam"),"aws4_request"); ``` > Example taken from the [AWS documentation for signing API requests](https://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.md). #### Activity reference Activities log changes to your project, including when you deploy your app, when you [push code](#push), and when a [cron job is run](#cron). To automate your workflows, you can parse and react to the activity's JSON object through [activity scripts](https://docs.upsun.com../activity.md). ###### Activity schema Every activity has a corresponding JSON object containing all information for that activity, including timestamps, configuration, and sometimes logs. In practice, you can ignore much of the JSON object's content. The most commonly used values are documented in this reference. The response differs depending on the activity and doesn't always include all fields. ####### Example response The following is a shortened example of a response for an [environment sync activity](https://docs.upsun.com/glossary.md#sync). You can also see [complete examples of responses](#examples). ``` json { "id": "abcdefg123456", ... "created_at": "2022-12-16T14:28:17.890467+00:00", "updated_at": null, "type": "environment.synchronize", "parameters": { ... }, "project": "abcdefgh1234567", "environments": [ "feature" ], "state": "complete", "result": "success", "started_at": "2022-12-16T14:28:18.188888+00:00", "completed_at": "2022-12-16T14:31:48.809068+00:00", "completion_percent": 100, "cancelled_at": null, "timings": { "wait": 0, "build": 0.349, "deploy": 209.986, "execute": 210.508 }, "log": "Building application 'app' (runtime type: php:8.2, tree: 9851a01)\n Reusing existing build for this tree ID\n\n...\nRedeploying environment test, as a clone of main\n ...\n Closing all services\n Opening application app and its relationships\n Executing deploy hook for application app\n ... Environment configuration\n app (type: php:8.0, size: S, disk: 2048)\n\n ...", "payload": { ... }, "description": "Cloé Weber synchronized test's **data** from Main", "text": "Cloé Weber synchronized test's **data** from Main", "expires_at": "2023-12-16T14:28:17.890467+00:00" } ``` ####### `id` A unique `id` value to identify the activity itself. ####### `*_at` `created_at`, `started_at`, `updated_at`, `cancelled_at`, `completed_at`, and `expires_at` are all timestamps in UTC. For when a given activity occurred, use `completed_at`. You can use these properties to calculate the duration of the activity. To calculate the timing for steps in the activity, see the [`timings` property](#timings). ####### `parameters` The `parameters` property includes detailed information about what triggered the activity, such as the user, the impacted environment, the git commits, or the cron commands. The response changes based on the activity. ####### `project` The ID of the project in which the activity took place. Use this value to distinguish multiple projects sent the same URL. Different from [`project` activities](#type). ####### `type` The type of the activity in one of the following categories: - [Project](#project-activity-types) - [Environment](#environment-activity-types) - [Integration](#integration-activity-types) - [Maintenance](#maintenance-activity-types) ######## `project` activity types Activities that happened on a given project. The following table presents the possible activity types: | Name | Description | |-----------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `project.clear_build_cache` | The build cache is cleared. | | `project.create` | A new project is created. | | `project.metrics.enable` | A metric from the [continuous profiling](https://docs.upsun.com/increase-observability.md) has been enabled. | | `project.metrics.update` | A metric from the [continuous profiling](https://docs.upsun.com/increase-observability.md) has been updated. | | `project.metrics.disable` | A metric from the [continuous profiling](https://docs.upsun.com/increase-observability.md) has been disabled. | | `project.modify.title` | The project title has changed. | | `project.variable.create` | A new [project variable](https://docs.upsun.com/administration/web/configure-project.md#variables) has been created. The value is visible only if the variable is not [set as sensitive](https://docs.upsun.com../../development/variables/set-variables.md#variable-options). | | `project.variable.delete` | A [project variable](https://docs.upsun.com/administration/web/configure-project.md#variables) has been deleted. | | `project.variable.update` | A [project variable](https://docs.upsun.com/administration/web/configure-project.md#variables) has been modified. | ######## `environment` activity types Activities that happened on an environment. The following table presents the possible activity types: | Name | Description | |--------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `environment.activate` | The environment has been made [active](https://docs.upsun.com/glossary.md#active-environment). | | `environment.backup` | A user triggered a [backup](https://docs.upsun.com/environments/backup.md). | | `environment.backup.delete` | A user deleted a [backup](https://docs.upsun.com/environments/backup.md). | | `environment.branch` | A [new branch](https://docs.upsun.com/environments.md#create-environments) has been created via the CLI, Console, or API. A branch created via Git shows up as `environment.push`. | | `environment.certificate.renewal` | An environment's SSL certificate has been [renewed](https://docs.upsun.com/define-routes/https.md#certificate-renewals). | | `environment.cron` | A [cron job](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#crons) has completed. | | `environment.deactivate` | An environment has been made [inactive](https://docs.upsun.com/glossary.md#inactive-environment). | | `environment.delete` | An environment's code was deleted through Git. | | `environment.domain.create` | A new [domain](administration/web/configure-project.md#domains) has been associated with the environment. | | `environment.domain.delete` | A [domain](administration/web/configure-project.md#domains) associated with the environment has been removed. | | `environment.domain.update` | A [domain](administration/web/configure-project.md#domains) associated with the environment has been updated, such as having its SSL certificate modified. | | `environment.initialize` | The [default branch](https://docs.upsun.com/environments.md#default-environment) of the project has just been initialized with its first commit. | | `environment.merge` | An environment was [merged](https://docs.upsun.com/glossary.md#merge) through the CLI, Console, or API. A basic Git merge doesn't trigger this activity. | | `environment.merge-pr` | A Pull Request/Merge Request was merged through the CLI, Console, or API. A basic Git merge doesn't trigger this activity. | | `environment.operation` | A [source operation](https://docs.upsun.com/create-apps/runtime-operations.md) has been triggered | | `environment.pause` | An environment has been [paused](https://docs.upsun.com/environments.md#pause-an-environment). | | `environment.push` | A user [pushed](https://docs.upsun.com/administration/cli/reference.md#environmentpush) code to a branch, either existing or new. | | `environment.redeploy` | An environment was [redeployed](https://docs.upsun.com/administration/cli/reference.md#environmentredeploy). | | `environment.restore` | A user restored a [backup](https://docs.upsun.com/environments/backup.md). | | `environment.resume` | An inactive environment was [resumed](https://docs.upsun.com/environments.md#resume-a-paused-environment) | | `environment.resources.update` | The resources allocated to the environment [have been updated](https://docs.upsun.com/manage-resources/adjust-resources.md). | | `environment.route.create` | A new [route](https://docs.upsun.com/administration/web/configure-environment.md#routes) has been created through the API. Edits made using Git to the `.upsun/config.yaml` file don't trigger this activity. | | `environment.route.delete` | A [route](https://docs.upsun.com/administration/web/configure-environment.md#routes) has been deleted through the API. Edits made using Git to the `.upsun/config.yaml` file don't trigger this activity. | | `environment.route.update` | A [route](https://docs.upsun.com/administration/web/configure-environment.md#routes) has been modified through the API. Edits made using Git to the `.upsun/config.yaml` file don't trigger this activity. | | `environment.source-operation` | A [source operation](https://docs.upsun.com/create-apps/source-operations.md) has been triggered. | | `environment.synchronize` | An environment has had its data and/or code replaced with the data and/or code from its parent environment. | | `environment.update.http_access` | [HTTP access rules](https://docs.upsun.com/administration/web/configure-environment.md#http-access-control) for an environment have been modified. | | `environment.update.restrict_robots` | The option to [hide from search engines](https://docs.upsun.com../../environments/search-engine-visibility.md) has been enabled or disabled for an environment. | | `environment.update.smtp` | Email sending has been enabled or disabled for an environment. | | `environment.variable.create` | A [new variable](https://docs.upsun.com/development/variables/set-variables.md#variable-options) has been created. The value is visible only if the variable is not [set as sensitive](https://docs.upsun.com../../development/variables/set-variables.md#variable-options). | | `environment.variable.delete` | A [variable](https://docs.upsun.com/development/variables/set-variables.md#variable-options) has been deleted. | | `environment.variable.update` | A [variable](https://docs.upsun.com/development/variables/set-variables.md#variable-options) has been modified. | | `environment_type.access.create` | A [new access](https://docs.upsun.com/administration/users.md#manage-project-access) has been added to the environment | | `environment_type.access.delete` | An [existing access](https://docs.upsun.com/administration/users.md#manage-project-access) to the environment has been deleted | | `environment_type.access.update` | An [existing access](https://docs.upsun.com/administration/users.md#manage-project-access) to the environment has been updated | ######## `integration` activity types Activities that relate to an integration. The following table presents the possible activity types: | Name | Description | |-----------------------------------------------|-----------------------------------------------------------------------------------------------------------------------| | `integration.bitbucket.fetch` | A fetch has been triggered on your [Bitbucket Cloud](https://docs.upsun.com/integrations/source/bitbucket.md#bitbucket-cloud) repository. | | `integration.bitbucket.register_hooks` | An integration hook has been registered with [Bitbucket Cloud](https://docs.upsun.com/integrations/source/bitbucket.md#bitbucket-cloud). | | `integration.bitbucket_server.fetch` | A fetch has been triggered on your [Bitbucket Server](https://docs.upsun.com/integrations/source/bitbucket.md#bitbucket-server) repository. | | `integration.bitbucket_server.register_hooks` | An integration hook has been registered with [Bitbucket Server](https://docs.upsun.com/integrations/source/bitbucket.md#bitbucket-server). | | `integration.github.fetch` | A fetch has been triggered on your [GitHub](https://docs.upsun.com/integrations/source/github.md) repository. | | `integration.gitlab.fetch` | A fetch has been triggered on your [GitLab](https://docs.upsun.com/integrations/source/gitlab.md) repository. | | `integration.health.email` | A [health notification](https://docs.upsun.com../notifications.md) was sent by email. | | `integration.health.pagerduty` | A [health notification](https://docs.upsun.com../notifications.md) was sent to PagerDuty. | | `integration.health.slack` | A [health notification](https://docs.upsun.com../notifications.md) was sent to Slack. | | `integration.health.webhook` | A [health notification](https://docs.upsun.com../notifications.md) was sent to a webhook. | | `integration.script` | An [activity script](https://docs.upsun.com/integrations/activity.md) has been triggered. | | `integration.webhook` | A [webhook](https://docs.upsun.com/integrations/activity/webhooks.md) was triggered. | ######## `maintenance` activity types Activities that relate to a maintenance. The following table presents the possible types: | Name | Description | |-----------------------|-----------------------------------------------------------| | `maintenance.upgrade` | An upgrade is triggered for API Server and Metrics Server | ####### `environments` An array listing the environments that were involved in the activity. It's usually only a single value representing one environment. ####### `state` The current state of the activity. Its value can be `pending`, `in_progress`, `complete`, `cancelled`, or `scheduled`. ####### `completion_percent` What percentage of the activity is complete. ####### `result` Whether or not the activity completed successfully. If it did, the value is `success`. Note that certain activities, such as deploy hooks, can be marked as successful activities even if some commands failed. ####### `timings` The amount of time required by the activity. It can include the following properties: | Name | Description | |-----------|--------------------------------------------------------------| | `wait` | The delay if a command is set to wait before being executed. | | `build` | The execution time for the build hook. | | `deploy` | The execution time for the deploy hook. | | `execute` | The execution time for your script or cron job. | ####### `log` A human-friendly record of what happened in the activity. The log shouldn't be parsed for data as its structure isn't guaranteed. ####### `description` A short machine-readable description of the activity. ####### `text` A short human-readable description of the activity. ####### `payload` Contains settings and details related to the completed activity. Its content varies based on the activity type. | Name | Description | |-------------------------|---------------------------------------------------------------------------------------------------------------------------------| | `payload.user` | The user that triggered the activity. For details on its properties, see the [`user` payload](#user-payload). | | `payload.environment` | The environment affected by the activity. For details on its properties, see the [`environment` payload](#environment-payload). | | `payload.commits` | A list of changes with their Git metadata. | | `payload.commits_count` | The number of Git commits. | | `payload.deployment` | Information about the deployed environment. For details on its properties, see the [`deployment` payload](#deployment-payload). | | `payload.project` | Information about the project. For details on its properties, see the [`project` payload](#project-payload). | ######## `user` payload Contains information about the Upsun user that triggered the activity. | Name | Description | |-----------------------------|---------------------------------------------| | `payload.user.created_at` | The date the user was created. | | `payload.user.display_name` | The user's name in a human-friendly format. | | `payload.user.id` | The user's ID. | | `payload.user.updated_at` | The date the user was last updated. | ######## `environment` payload Contains information about the environment associated with the activity, including its settings, state, and deployment. The following table presents the most notable properties of the environment: | Name | Description | |-------------------------------------|---------------------------------------------------------------------------------------------| | `payload.environment.name` | The environment name. | | `payload.environment.type` | The [environment type](https://docs.upsun.com../../administration/users.md#environment-type-roles). | | `payload.environment.head_commit` | The ID of the environment's latest Git commit. | | `payload.environment.edge_hostname` | The URL you should target when setting up a [custom domain](https://docs.upsun.com../../domains/steps.md). | Different from [`environment` activities](#type). ######## `project` payload Contains information about the project associated with the activity, including plan details, timezone, and region. The following table presents the most notable properties of the project: | Name | Description | |--------------------------------|-----------------------------------------------------------------------------------------| | `payload.project.timezone` | Your project's [timezone](https://docs.upsun.com../../projects/change-project-timezone.md). | | `payload.project.region` | Your project's [region](https://docs.upsun.com../../development/regions.md#regions). | | `payload.project.title` | Your project's name. | | `payload.project.subscription` | All of the details about your project's [plan](https://docs.upsun.com../../administration/pricing.md). | Different from [`project` activities](#type). ######## `deployment` payload Contains information about the deployed environment, if one is associated with the activity. The following table presents the most notable properties of the deployment: | Name | Description | |--------------------------------|----------------------------------------------------------------------------------------------------------------------------------------| | `payload.deployment.routes` | All the URLs connected to the environment. The list includes redirects. To exclude redirects, find objects whose `type` is `upstream`. | | `payload.deployment.services` | All the services on your environment. | | `payload.deployment.variables` | All the [variables for the environment](https://docs.upsun.com../../development/variables.md). | The `payload.deployment` property includes the configuration extracted from the following sources: - Your [app configuration](https://docs.upsun.com../../create-apps.md) - Your [routes](https://docs.upsun.com../../define-routes.md) - Your [services](https://docs.upsun.com../../add-services.md) ###### Maximum activities and parallelism Project activities are distributed across separate queues, which enables *two* simultaneous activities to occur in parallel across your environments. For a given environment, only one activity can run at a time. Those queues include the following types of activities: | Name | Description | |----------------|------------------------------------------------------------------------------------------------------| | `default` | The most common activities on repositories (pushes, merges) and environments (syncs, redeployments). | | `integrations` | Source and webhook integration activities. | | `backup` | Backup activities. | | `cron` | Cron activities. | Production activities are prioritized across all queues. When an activity for the production environment is triggered, it's placed at the top of the queue. This makes it unlikely that activities on preview environments block activities for the production environment for long, though there may be a temporary wait. ###### Examples The response is often usually long, so the following examples are shortened using ellipses. Remember that the response differs depending on the activity and not all fields are always available. To test responses, [set up a webhook](https://docs.upsun.com/integrations/activity/webhooks.md#setup). ####### Cron When a cron job is triggered, the activity contains all the [job's information](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#crons). The following example response was triggered by a setting where the cron is scheduled to run every five minutes (`5 * * * *`) with the command `sleep 60 && echo sleep-60-finished && date` and times out after 86,400 seconds. To get details about the configured cron job, see the `parameters` property: ``` json ... "parameters": { "user": "admin", "cluster": "abcdefgh1234567-main-abcd123", "environment": "main", "application": "app", "cron": "saybye", "spec": { "spec": "5 * * * *", "commands": { "start": "sleep 60 && echo sleep-60-finished && date", "stop": null }, "shutdown_timeout": null, "timeout": 86400 } ... ``` The following example shows the full activity response to a cron job: ``` json { "id": "ypalrypnezbye", "_links": { "self": { "href": "https://eu-3.upsun.com/api/projects/abcdefgh1234567/activities/ypalrypnezbye" }, "log": { "href": "/api/projects/abcdefgh1234567/activities/ypalrypnezbye/log" } }, "created_at": "2022-12-13T16:06:08.081312+00:00", "updated_at": null, "type": "environment.cron", "parameters": { "user": "admin", "cluster": "abcdefgh1234567-main-abcd123", "environment": "main", "application": "app", "cron": "saybye", "spec": { "spec": "5 * * * *", "commands": { "start": "sleep 60 && echo sleep-60-finished && date", "stop": null }, "shutdown_timeout": null, "timeout": 86400 } }, "project": "abcdefgh1234567", "environments": [ "main" ], "state": "complete", "result": "success", "started_at": "2022-12-13T16:06:08.258090+00:00", "completed_at": "2022-12-13T16:07:09.658339+00:00", "completion_percent": 100, "cancelled_at": null, "timings": { "wait": 0, "execute": 61.244 }, "log": "hello world\nTue Dec 13 16:07:09 UTC 2022", "payload": { "user": { "id": "admin", "created_at": "2022-12-13T16:06:08.066085+00:00", "updated_at": null, "display_name": "Upsun Bot" }, "project": { "id": "abcdefgh1234567", "created_at": "2022-03-22T15:47:28.739099+00:00", "updated_at": "2022-12-01T09:42:19.860188+00:00", "attributes": {}, "title": "php-test", "description": "", "owner": "c9926428-44dc-4b10-be03-a26dd43b44c1", "namespace": "upsun", "organization": "01FF4NBNVMMDWP1NVK0G4EGJW0", "default_branch": "main", "status": { "code": "provisioned", "message": "ok" }, "timezone": "Europe/Dublin", "region": "eu-3.upsun.com", "repository": { "url": "abcdefgh1234567@git.eu-3.upsun.com:abcdefgh1234567.git", "client_ssh_key": "ssh-rsa aaaaaaabbbbbbbcccccccddddddd abcdefgh1234567@upsun" }, "default_domain": null, "subscription": { "license_uri": "https://accounts.upsun.com/api/v1/licenses/2291467", "plan": "development", "environments": 3, "storage": 5120, "included_users": 1, "subscription_management_uri": "https://console.upsun.com-/users/abcd12345/billing/plan/12345678", "restricted": false, "suspended": false, "user_licenses": 1 } }, "environment": { "id": "main", "created_at": "2022-03-22T15:47:43.750880+00:00", "updated_at": "2022-11-29T16:16:37.085719+00:00", "name": "main", "machine_name": "main-abcd123", "title": "Main", "attributes": {}, "type": "production", "parent": null, "default_domain": null, "clone_parent_on_create": true, "deployment_target": "local", "is_pr": false, "status": "active", "enable_smtp": true, "restrict_robots": true, "edge_hostname": "main-abcd123-abcdefgh1234567.eu-3.platformsh.site", "deployment_state": { "last_deployment_successful": true, "last_deployment_at": "2022-11-29T16:16:37.085609+00:00", "crons": { "enabled": true, "status": "running" } }, "resources_overrides": {}, "last_active_at": "2022-12-13T15:07:10.862854+00:00", "last_backup_at": null, "project": "abcdefgh1234567", "is_main": true, "is_dirty": false, "has_code": true, "head_commit": "6aac318907b50252976c47e4e62ed95d438af0ea", "merge_info": { "commits_ahead": 0, "commits_behind": 0, "parent_ref": null }, "has_deployment": true }, "cron": "saybye" }, "description": "Upsun Bot ran cron **saybye**", "text": "Upsun Bot ran cron **saybye**", "expires_at": "2023-01-12T16:06:08.081293+00:00" } ``` ####### Push A push activity contains several properties. The `commits` property contains everything related to the Git push that triggered the activity: ``` json ... "commits": [ { "sha": "2bab04e050279ac078d5d34016f5dd9c466e948d", "author": { "email": "cloeweber@example.com", "name": "Cloé Weber", "date": 1671032461 }, "parents": [ "6aac318907b50252976c47e4e62ed95d438af0ea" ], "message": "Add cron" } ], ... ``` The `environment` property contains the settings for the environment that was pushed to: ``` json ... "environment": { "id": "main", "created_at": "2022-03-22T15:47:43.750880+00:00", "updated_at": "2022-11-29T16:16:37.085719+00:00", "name": "main", "machine_name": "main-abcd123", "title": "Main", "attributes": {}, "type": "production", "parent": null, "default_domain": null, "clone_parent_on_create": true, "deployment_target": "local", "is_pr": false, "status": "active", "enable_smtp": true, "restrict_robots": true, "edge_hostname": "main-abcd123-abcdefgh1234567.eu-3.platformsh.site", "deployment_state": { "last_deployment_successful": true, "last_deployment_at": "2022-11-29T16:16:37.085609+00:00", "crons": { "enabled": true, "status": "sleeping" } }, "resources_overrides": {}, "last_active_at": "2022-12-13T16:07:09.788910+00:00", "last_backup_at": null, "project": "abcdefgh1234567", "is_main": true, "is_dirty": false, "has_code": true, "head_commit": "6aac318907b50252976c47e4e62ed95d438af0ea", "merge_info": { "commits_ahead": 0, "commits_behind": 0, "parent_ref": null }, "has_deployment": true }, ... ``` The `deployment` property contains the settings for the deployment, including the [image type](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#types) and [resource allocation](https://docs.upsun.com/manage-resources/adjust-resources.md). The following example shows a shortened excerpt of the `deployment` property: ``` json ... "deployment": { "id": "current", "created_at": "2022-03-22T15:48:05.396979+00:00", "updated_at": "2022-12-14T15:41:57.264813+00:00", "cluster_name": "abcdefgh1234567-main-abcd123", "project_info": { "deployment": { "id": "current", "created_at": "2022-03-22T15:48:05.396979+00:00", "updated_at": "2022-12-14T15:41:57.264813+00:00", "cluster_name": "abcdefgh1234567-main-abcd123", "project_info": { "name": "abcdefgh1234567", "settings": { "initialize": { "values": { "initialize": true, "start": false, "base": { "files": [], "profile": "PHP", "config": null, "repository": "https://github.com/platformsh-templates/php.git@master", "title": "PHP" } } }, ... "application_config_file": ".upsun/config.yaml", "project_config_dir": ".upsun", ... "development_service_size": "S", "development_application_size": "S", "enable_certificate_provisioning": true, "certificate_style": "ecdsa", "certificate_renewal_activity": true, ... "cron_minimum_interval": 5, "cron_maximum_jitter": 20, "concurrency_limits": { "internal": null, "integration": 4, "backup": 2, "cron": 10, "default": 2 }, ... "build_resources": { "cpu": 1, "memory": 2048 }, ... "max_allowed_routes": 50000, "max_allowed_redirects_paths": 50000, "enable_incremental_backups": true, ... } }, ... ``` The following example shows the full activity response to a Git push: ``` json { "id": "a1kz6ffxui7em", "_links": { "self": { "href": "https://eu-3.upsun.com/api/projects/abcdefgh1234567/activities/a1kz6ffxui7em" }, "log": { "href": "/api/projects/abcdefgh1234567/activities/a1kz6ffxui7em/log" } }, "created_at": "2022-12-14T15:41:05.821145+00:00", "updated_at": null, "type": "environment.push", "parameters": { "user": "c9926428-44dc-4b10-be03-a26dd43b44c1", "environment": "main", "old_commit": "6aac318907b50252976c47e4e62ed95d438af0ea", "new_commit": "2bab04e050279ac078d5d34016f5dd9c466e948d" }, "project": "abcdefgh1234567", "environments": [ "main" ], "state": "complete", "result": "success", "started_at": "2022-12-14T15:41:05.969872+00:00", "completed_at": "2022-12-14T15:41:57.635442+00:00", "completion_percent": 100, "cancelled_at": null, "timings": { "wait": 0, "parse_commits": 0.63, "build": 0.506, "deploy": 49.954, "execute": 51.516 }, "log": "Found 1 new commit\n\nBuilding application 'myapp' (runtime type: php:8.0, tree: 9851a01)\n Reusing existing build for this tree ID\n\nProvisioning certificates\n Certificates\n - certificate 5093946: expiring on 2023-02-23 11:09:20+00:00, covering {,www}.main-abcd123-abcdefgh1234567.eu-3.platformsh.site\n\n\nRedeploying environment main\n Preparing deployment\n Closing service myapp\n Opening application myapp and its relationships\n Executing deploy hook for application myapp\n hello world\n\n Opening environment\n Environment configuration\n myapp (type: php:8.0, size: S, disk: 2048)\n\n Environment routes\n http://main-abcd123-abcdefgh1234567.eu-3.platformsh.site/ redirects to https://main-abcd123-abcdefgh1234567.eu-3.platformsh.site/\n http://www.main-abcd123-abcdefgh1234567.eu-3.platformsh.site/ redirects to https://www.main-abcd123-abcdefgh1234567.eu-3.platformsh.site/\n https://main-abcd123-abcdefgh1234567.eu-3.platformsh.site/ is served by application `myapp`\n https://www.main-abcd123-abcdefgh1234567.eu-3.platformsh.site/ redirects to https://main-abcd123-abcdefgh1234567.eu-3.platformsh.site/\n", "payload": { "user": { "id": "c9926428-44dc-4b10-be03-a26dd43b44c1", "created_at": "2022-12-14T15:40:16.891889+00:00", "updated_at": null, "display_name": "Cloé Weber" }, "environment": { "id": "main", "created_at": "2022-03-22T15:47:43.750880+00:00", "updated_at": "2022-11-29T16:16:37.085719+00:00", "name": "main", "machine_name": "main-abcd123", "title": "Main", "attributes": {}, "type": "production", "parent": null, "default_domain": null, "clone_parent_on_create": true, "deployment_target": "local", "is_pr": false, "status": "active", "enable_smtp": true, "restrict_robots": true, "edge_hostname": "main-abcd123-abcdefgh1234567.eu-3.platformsh.site", "deployment_state": { "last_deployment_successful": true, "last_deployment_at": "2022-11-29T16:16:37.085609+00:00", "crons": { "enabled": true, "status": "sleeping" } }, "resources_overrides": {}, "last_active_at": "2022-12-13T16:07:09.788910+00:00", "last_backup_at": null, "project": "abcdefgh1234567", "is_main": true, "is_dirty": false, "has_code": true, "head_commit": "6aac318907b50252976c47e4e62ed95d438af0ea", "merge_info": { "commits_ahead": 0, "commits_behind": 0, "parent_ref": null }, "has_deployment": true }, "commits": [ { "sha": "2bab04e050279ac078d5d34016f5dd9c466e948d", "author": { "email": "cloeweber@example.com", "name": "Cloé Weber", "date": 1671032461 }, "parents": [ "6aac318907b50252976c47e4e62ed95d438af0ea" ], "message": "Add cron" } ], "commits_count": 1, "deployment": { "id": "current", "created_at": "2022-03-22T15:48:05.396979+00:00", "updated_at": "2022-12-14T15:41:57.264813+00:00", "cluster_name": "abcdefgh1234567-main-abcd123", "project_info": { "name": "abcdefgh1234567", "settings": { "initialize": { "values": { "initialize": true, "start": false, "base": { "files": [], "profile": "PHP", "config": null, "repository": "https://github.com/platformsh-templates/php.git@master", "title": "PHP" } } }, "product_name": "Upsun", "product_code": "upsun", "variables_prefix": "PLATFORM_", "bot_email": "bot@upsun.com", "application_config_file": ".upsun/config.yaml", "project_config_dir": ".upsun", "use_drupal_defaults": false, "use_legacy_subdomains": false, "development_service_size": "S", "development_application_size": "S", "enable_certificate_provisioning": true, "certificate_style": "ecdsa", "certificate_renewal_activity": true, "development_domain_template": null, "enable_state_api_deployments": true, "temporary_disk_size": null, "cron_minimum_interval": 5, "cron_maximum_jitter": 20, "concurrency_limits": { "internal": null, "integration": 4, "backup": 2, "cron": 10, "default": 2 }, "flexible_build_cache": false, "strict_configuration": true, "has_sleepy_crons": true, "crons_in_git": true, "custom_error_template": null, "app_error_page_template": null, "environment_name_strategy": "name-and-hash", "data_retention": null, "enable_codesource_integration_push": true, "enforce_mfa": false, "systemd": true, "router_gen2": false, "chorus": { "enabled": true, "exposed": true }, "build_resources": { "cpu": 1, "memory": 2048 }, "outbound_restrictions_default_policy": "allow", "self_upgrade": true, "additional_hosts": {}, "max_allowed_routes": 50000, "max_allowed_redirects_paths": 50000, "enable_incremental_backups": true, "sizing_api_enabled": false, "enable_cache_grace_period": true, "enable_zero_downtime_deployments": false, "enable_admin_agent": true, "certifier_url": "https://proxy.upsun.com/", "centralized_permissions": false, "glue_server_max_request_size": 10 } }, "environment_info": { "name": "main", "is_main": true, "is_production": false, "reference": "refs/heads/main", "machine_name": "main-abcd123", "environment_type": "production" }, "deployment_target": "local", "vpn": null, "http_access": { "is_enabled": true, "addresses": [], "basic_auth": {} }, "enable_smtp": true, "restrict_robots": true, "variables": [ { "name": "php:memory_limit", "value": "512M", "is_sensitive": false } ], "access": [ { "entity_id": "c9926428-44dc-4b10-be03-a26dd43b44c1", "role": "admin" } ], "subscription": { "license_uri": "https://accounts.upsun.com/api/v1/licenses/12345678", "plan": "development", "environments": 3, "storage": 5120, "included_users": 1, "subscription_management_uri": "https://console.upsun.com//-/users/abcd12345/billing/plan/12345678", "restricted": false, "suspended": false, "user_licenses": 1 }, "services": {}, "routes": { "https://main-abcd123-abcdefgh1234567.eu-3.platformsh.site/": { "primary": true, "id": null, "production_url": "https://main-abcd123-abcdefgh1234567.eu-3.platformsh.site/", "attributes": {}, "type": "upstream", "tls": { "strict_transport_security": { "enabled": null, "include_subdomains": null, "preload": null }, "min_version": null, "client_authentication": null, "client_certificate_authorities": [] }, "original_url": "https://{default}/", "restrict_robots": true, "cache": { "enabled": true, "default_ttl": 0, "cookies": [ "*" ], "headers": [ "Accept", "Accept-Language" ] }, "ssi": { "enabled": false }, "upstream": "myapp:http", "redirects": { "expires": "-1s", "paths": {} } }, "https://www.main-abcd123-abcdefgh1234567.eu-3.platformsh.site/": { "primary": false, "id": null, "production_url": "https://www.main-abcd123-abcdefgh1234567.eu-3.platformsh.site/", "attributes": {}, "type": "redirect", "tls": { "strict_transport_security": { "enabled": null, "include_subdomains": null, "preload": null }, "min_version": null, "client_authentication": null, "client_certificate_authorities": [] }, "original_url": "https://www.{default}/", "restrict_robots": true, "to": "https://main-abcd123-abcdefgh1234567.eu-3.platformsh.site/", "redirects": { "expires": "-1s", "paths": {} } }, "http://main-abcd123-abcdefgh1234567.eu-3.platformsh.site/": { "primary": false, "id": null, "production_url": "http://main-abcd123-abcdefgh1234567.eu-3.platformsh.site/", "attributes": {}, "type": "redirect", "tls": { "strict_transport_security": { "enabled": null, "include_subdomains": null, "preload": null }, "min_version": null, "client_authentication": null, "client_certificate_authorities": [] }, "original_url": "http://{default}/", "restrict_robots": true, "to": "https://main-abcd123-abcdefgh1234567.eu-3.platformsh.site/", "redirects": { "expires": "-1s", "paths": {} } }, "http://www.main-abcd123-abcdefgh1234567.eu-3.platformsh.site/": { "primary": false, "id": null, "production_url": "http://www.main-abcd123-abcdefgh1234567.eu-3.platformsh.site/", "attributes": {}, "type": "redirect", "tls": { "strict_transport_security": { "enabled": null, "include_subdomains": null, "preload": null }, "min_version": null, "client_authentication": null, "client_certificate_authorities": [] }, "original_url": "http://www.{default}/", "restrict_robots": true, "to": "https://www.main-abcd123-abcdefgh1234567.eu-3.platformsh.site/", "redirects": { "expires": "-1s", "paths": {} } } }, "webapps": { "app": { "resources": null, "size": "AUTO", "disk": 2048, "access": { "ssh": "contributor" }, "relationships": {}, "additional_hosts": {}, "mounts": { "/web/uploads": { "source": "local", "source_path": "uploads" }, "/private": { "source": "local", "source_path": "private" } }, "timezone": null, "variables": {}, "firewall": null, "initial_size": null, "container_profile": null, "instance_count": null, "name": "app", "type": "php:8.0", "runtime": {}, "preflight": { "enabled": true, "ignored_rules": [] }, "tree_id": "9851a01081f3c2f943f75f62c38b67f8bc0ec15c", "slug_id": "abcdefgh1234567-app-9851a01081f3c2f943f75f62c38b67f8bc0ec15c-73985064e66fd2299f4b83931cff46891249a964", "app_dir": "/app", "web": { "locations": { "/": { "root": "web", "expires": "-1s", "passthru": "/index.php", "scripts": true, "allow": true, "headers": {}, "rules": {} } }, "move_to_root": false }, "hooks": { "build": "set -e\n", "deploy": "set -e\n", "post_deploy": null }, "crons": { "saybye": { "spec": "5 * * * *", "commands": { "start": "sleep 60 && echo sleep-60-finished && date", "stop": null }, "shutdown_timeout": null, "timeout": 86400 } } } }, "workers": {}, } } }, "description": "Cloé Weber pushed to Main", "text": "Cloé Weber pushed to Main", "expires_at": "2023-12-14T15:41:05.821145+00:00" } ``` #### Utility routines The following utility routines can help simplify common tasks in your activity scripts. They’re free to copy, modify, bend, fold, spindle, and mutilate as needed for your own scripts. They also demonstrate some common patterns for working with the ``activity`` and ``project`` data structures. ###### Route access ```javascript /** * Returns just those routes that point to a valid upstream. * * This method is similar to routes(), but filters out redirect routes that are rarely * useful for app configuration. If desired it can also filter to just those routes * whose upstream is a given application name. To retrieve routes that point to the * current application where the code is being run, use: * * routes = getUpstreamRoutes(applicationName); * * @param {string} [appName] * The name of the upstream app on which to filter, if any. * @return {object} * An object map of route definitions. The generated URLs of the routes are added as a "url" key. */ function getUpstreamRoutes(appName) { return Object.entries(activity.payload.deployment.routes).reduce( (upstreams, [url, route]) => route.type === "upstream" && (!appName || appName === route.upstream.split(":")[0]) ? { ...upstreams, [url]: { ...route, url, }, } : upstreams, {} ); } ``` ```javascript /** * Returns the primary route. * * The primary route is the one marked primary in `.upsun/config.yaml`, or else * the first non-redirect route in that file if none are marked. * * @return {object} * The route definition. The generated URL of the route is added as a "url" key. */ function getPrimaryRoute() { return Object.entries(activity.payload.deployment.routes).reduce( (primary, [url, route]) => route.primary ? { ...route, url, } : primary, {} ); } ``` ```javascript /** * Returns the route definition that has the specified id. * * Note: If no route ID was specified in .upsun/config.yaml then it will not be possible * to look up a route by ID. * * @param {string} id * The ID of the route to load. * @return {object} * The route definition. The generated URL of the route is added as a "url" key. * @throws {Error} * If there is no route by that ID, an exception is thrown. */ function getRoute(id) { const found = Object.entries(activity.payload.deployment.routes).reduce( (foundRoute, [url, route]) => route.id === id ? { ...route, url, } : foundRoute, null ); if (found === null) { throw new Error(`No such route id found: ${id}`); } return found; } ``` #### Example: Discord The following example activity script posts a message to a Discord channel every time it's triggered. To use it, follow these steps: 1. In your Discord administrative interface, [create a new Discord webhook](https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks). Give it a name and specify the channel where it should post messages. Copy the URL for the webhook. 2. Replace `DISCORD_URL` in the following script with your webhook URL. 3. Paste the code into a `.js` file. 4. Add it as a new [script integration](https://docs.upsun.com/integrations/activity.md#installing). Specify which events should trigger it using the `--events` flag. Optionally specify environments with the `--environments` flag. Now, any activities that meet the events/environment criteria you specified are reported to Discord. Once you have it working, you're free to modify the code below as desired. For more on the message format, see the [Discord webhook API reference](https://discord.com/developers/docs/resources/webhook#execute-webhook). ```javascript /** * Sends a message to Discord. * * To control what events trigger it, use the --events switch in * the Upsun CLI. * * @param {string} title * The title of the message block to send. * @param {string} message * The message body to send. */ function sendDiscordMessage(title, message) { const url = DISCORD_URL; const messageTitle = title + (new Date().getDay() === 5) ? " (On a Friday! :calendar:)" : ""; const body = { content: messageTitle, embeds: [ { description: message, }, ], }; const resp = fetch(url, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(body), }); if (!resp.ok) { console.log("Sending Discord message failed: " + resp.body.text()); } } sendDiscordMessage(activity.text, activity.log); ``` Common properties you may want to send to Discord (in the last line of the script) include: - `activity.text`: A brief, one-line statement of what happened. - `activity.log`: The complete build and deploy log output, as it would be seen in the Console log screen. For more properties, see the [activity reference](https://docs.upsun.com/integrations/activity/reference.md). #### Example: Slack The following example activity script posts a message to a Slack channel every time it's triggered. To use it, follow these steps: 1. In your Slack administrative interface, [create a new Slack webhook](https://api.slack.com/messaging/webhooks). You get a URL starting with `https://hooks.slack.com/`. 2. Replace `SLACK_URL` in the following script with your webhook URL. 3. Paste the code into a `.js` file. 4. Add it as a new [script integration](https://docs.upsun.com/integrations/activity.md#installing). Specify which events should trigger it using the `--events` flag. Optionally specify environments with the `--environments` flag. Now, any activities that meet the events/environment criteria you specified are reported to Slack. Once you have it working, you're free to modify the code below as desired. For formatting more complex messages, see the [Slack messaging documentation](https://api.slack.com/messaging/composing/layouts). ```javascript /** * Sends a color-coded formatted message to Slack. * * To control what events trigger it, use the --events switch in * the Upsun CLI. * * @param {string} title * The title of the message block to send. * @param {string} message * The message body to send. */ function sendSlackMessage(title, message) { const url = SLACK_URL; const messageTitle = title + (new Date().getDay() === 5) ? " (On a Friday! :calendar:)" : ""; const color = activity.result === "success" ? "#66c000" : "#ff0000"; const body = { attachments: [ { title: messageTitle, text: message, color: color, }, ], }; const resp = fetch(url, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(body), }); if (!resp.ok) { console.log("Sending slack message failed: " + resp.body.text()); } } sendSlackMessage(activity.text, activity.log); ``` Common properties you may want to send to Slack (in the last line of the script) include: - `activity.text`: A brief, one-line statement of what happened. - `activity.log`: The complete build and deploy log output, as it would be seen in the Console log screen. For more properties, see the [activity reference](https://docs.upsun.com/integrations/activity/reference.md). #### Webhooks Webhooks allow you to host a script yourself externally that receives the same payload as an activity script and responds to the same events, but can be hosted on your own server in your own language. ###### Setup ```bash upsun integration:add --type=webhook --url= ``` The webhook URL receives a POST message for every activity that's triggered. The message contains complete information about the entire state of the project at that time. It's possible to set the integration to only send certain activity types, or only activities on certain branches. The CLI prompts you to specify which to include or exclude. Leave at the default values to get all events on all environments in a project. For testing purposes, you can generate a URL from a service such as [webhook.site](https://webhook.site/) and use the generated URL as ``. ###### Webhook schema See the [activity script](https://docs.upsun.com/integrations/activity/reference.md) reference for a description of the webhook payload. ###### Validate the integration To verify your integration is functioning properly, run the following [CLI command](https://docs.upsun.com/integrations/overview.md#validate-integrations): ```bash upsun integration:validate ``` ### Source integrations You might want to keep your code in a third-party repository that's linked to your Upsun project. This means you keep all your workflows where you want and use Upsun for deploying. Your Upsun project becomes a mirror of your code repository elsewhere. This means you shouldn't push code directly to Upsun. Any changes you push directly get overwritten by the integration when changes happen in the third-party repository. #### Integrate with Bitbucket If you have code in a Bitbucket repository, you might want to connect it to a Upsun project. This means you can keep your Bitbucket workflows and treat the Bitbucket repository as the source of truth for your code. Your Upsun project becomes a mirror of your Bitbucket repository. This means you shouldn't push code directly to Upsun. Any changes you push directly get overwritten by the integration when changes happen in the Bitbucket repository. When you set up an integration with Bitbucket, it automates the following processes for you: - Creating a new environment when a branch is created or a pull request is opened. - Rebuilding the environment when new code is pushed to Bitbucket. - Deleting the environment when a pull request is merged. You can set up an integration with either Bitbucket Cloud or a self-hosted [Bitbucket Server](https://confluence.atlassian.com/bitbucketserver/). ###### Before you begin To manage source integrations, you need to be a [project admin](https://docs.upsun.com../../administration/users.md). You also need a Bitbucket Cloud or Bitbucket Server repository with working code. ###### Bitbucket Cloud ####### 1. Create an OAuth consumer To integrate your Upsun project with an existing Bitbucket Cloud repository, [create an OAuth consumer](https://support.atlassian.com/bitbucket-cloud/docs/use-oauth-on-bitbucket-cloud/): ![A screenshot of how to setup the Bitbucket OAuth consumer](https://docs.upsun.com/images/integrations/bitbucket/bitbucket-oauth-consumer.svg "0.35") **Note**: Be sure to define the above as a private consumer by checking the **This is a private consumer** box. The **Callback URL** isn't important in this case. You can set it to `http://localhost`. Copy the **Key** and **Secret** for your consumer. ####### 2. Enable the Cloud integration To enable the integration, use either the [CLI](https://docs.upsun.com/administration/cli.md) or the [Console](https://docs.upsun.com/administration/web.md). - ``PROJECT_ID`` is the ID of your Upsun project. - ``OWNER/REPOSITORY`` is the name of your repository in Bitbucket. - ``CONSUMER_KEY`` is the key of the [OAuth consumer you created](#1-create-an-oauth-consumer). - ``CONSUMER_SECRET`` is the secret of the [OAuth consumer you created](#1-create-an-oauth-consumer). For example, if your repository is located at ``https://bitbucket.org/platformsh/platformsh-docs``, the command is similar to the following: ```bash {} upsun integration:add \ --project abcdefgh1234567 \ --type bitbucket \ --repository platformsh/platformsh-docs \ --key abc123 \ --secret abcd1234 \ ``` - Select the project where you want to enable the integration. - Click **Settings Settings**. - Under **Project settings**, click **Integrations**. - Click **+ Add integration**. - Under **Bitbucket**, click **+ Add**. - Complete the form with: - The repository in the form ``owner/repository`` - The [key and secret you generated](#1-create-an-oauth-consumer) - Check that the other options match what you want. - Click **Add integration**. In both the CLI and Console, you can choose from the following options: | CLI flag | Default | Description | | ---------------- | ------- | ------------------------------------------------------------------------- | | `fetch-branches` | `true` | Whether to mirror and update branches on Upsun and create inactive environments from them. When enabled, merging on a Upsun isn't possible. That is, merging environments must be done on the source repository rather than on the Upsun project. See note below for details related to this flag and synchronizing code from a parent environment. | | `prune-branches` | `true` | Whether to delete branches from Upsun that don’t exist in the Bitbucket repository. When enabled, branching (creating environments) must be done on the source repository rather than on the Upsun project. Branches created on Upsun that are not on the source repository will not persist and will be quickly pruned. Automatically disabled when fetching branches is disabled. | | `build-pull-requests` | `true` | Whether to track all pull requests and create active environments from them, which builds the pull request. | | `resync-pull-requests` | `false` | Whether to sync data from the parent environment on every push to a pull request. | | `resources-init` | `false` | To [specify a resource initialization strategy](https://docs.upsun.com/manage-resources/resource-init.md#first-deployment) for new containers. Once set, the strategy applies to **all** the deployments you launch through your source integration. See more information on [available resource initialization strategies](https://docs.upsun.com/manage-resources/resource-init.md#specify-a-resource-initialization-strategy). | **Note**: To [keep your repository clean](https://docs.upsun.com/learn/bestpractices/clean-repository.md) and avoid performance issues, make sure you enable both the ``fetch-branches`` and ``prune-branches`` options. ####### 3. Validate the integration Verify that your integration is functioning properly [using the CLI](https://docs.upsun.com../overview.md#validate-integrations): ```bash upsun integration:validate ``` ######## Add the webhook manually If the integration was added with the correct permissions, the necessary webhook is added automatically. If you see a message that the webhook wasn't added, add one manually. To configure a webhook on a Bitbucket repository, you need to have Admin [user permissions](https://support.atlassian.com/bitbucket-cloud/docs/manage-webhooks/). 1. Get the webhook URL by running this command: `upsun integration:get --property hook_url`. 1. Copy the returned URL. 1. Follow the [Bitbucket instructions to create a webhook](https://support.atlassian.com/bitbucket-cloud/docs/manage-webhooks/#Create-webhooks) using the URL you copied. Make sure to update the triggers to include all pull request events except comments and approval. You can now start pushing code, creating new branches, and opening pull requests directly in your Bitbucket repository. Your Upsun environments are automatically created and updated. ###### Bitbucket Server ####### 1. Generate a token To integrate your Upsun project with a repository on a Bitbucket Server instance, you first need to create an access token associated with your account. [Generate a token](https://confluence.atlassian.com/display/BitbucketServer/HTTP+access+tokens). and give it at least read access to projects and admin access to repositories. Copy the token. ####### 2. Enable the Server integration To enable the integration, use either the [CLI](https://docs.upsun.com/administration/cli.md) or the [Console](https://docs.upsun.com/administration/web.md). - ``PROJECT_ID`` is the ID of your Upsun project. - ``OWNER/REPOSITORY`` is the name of the repository in Bitbucket server. - ``BITBUCKET_SERVER_ACCESS_TOKEN`` is the [token you generated](#1-generate-a-token). - ``BITBUCKET_SERVER_URL`` is the base URL for your Bitbucket server. For example, if your repository is located at ``https://example.com/upsun/upsun-docs``, the command is similar to the following: ```bash {} upsun integration:add \ --project abcdefgh1234567 \ --type bitbucket_server \ --repository upsun/upsun-docs \ --username user@example.com \ --token abc123 ``` - Select the project where you want to enable the integration. - Click Settings **Settings**. - Under **Project settings**, click **Integrations**. - Click **+ Add integration**. - Under **Bitbucket server**, click **+ Add**. - Complete the form with: - Your server URL - Your Bitbucket username - The [token you generated](#1-generate-a-token) - The Bitbucket server project name - The repository in the form ``owner/repository`` - Check that the other options match what you want. - Click **Add integration**. In both the CLI and Console, you can choose from the following options: | CLI flag | Default | Description | | ``fetch-branches`` | ``true`` | Whether to mirror and update branches on Upsun and create inactive environments from them. | | ``prune-branches`` | ``true`` | Whether to delete branches from Upsun that don’t exist in the Bitbucket server repository. Automatically disabled when fetching branches is disabled. | | ``build-pull-requests`` | ``true`` | Whether to track all pull requests and create active environments from them, which builds the pull request. | | ``pull-requests-clone-parent-data`` | ``true`` | Whether to clone data from the parent environment when creating a pull request environment. | To [keep your repository clean ](https://docs.upsun.com/learn/bestpractices/clean-repository.md) and avoid performance issues, make sure you enable both the ``fetch-branches`` and ``prune-branches`` options. ####### 3. Validate the integration Verify that your integration is functioning properly [using the CLI](https://docs.upsun.com../overview.md#validate-integrations): ```bash upsun integration:validate ``` ######## Add the webhook manually If the integration was added with the correct permissions, the necessary webhook is added automatically. If you see a message that the webhook wasn't added, add one manually. To configure a webhook on a Bitbucket repository, you need to have Admin [user permissions](https://support.atlassian.com/bitbucket-cloud/docs/manage-webhooks/). 1. Get the webhook URL by running this command: `upsun integration:get --property hook_url`. 1. Copy the returned URL. 1. Follow the [Bitbucket instructions to create a webhook](https://confluence.atlassian.com/bitbucketserver076/managing-webhooks-in-bitbucket-server-1026535073.md#ManagingwebhooksinBitbucketServer-creatingwebhooksCreatingwebhooks) using the URL you copied. Send all events except comments and approval. You can now start pushing code, creating new branches, and opening pull requests directly in your Bitbucket repository. Your Upsun environments are automatically created and updated. ###### Environment parent and status When a **branch** is created in Bitbucket, an environment is created in Upsun with the default branch as its parent. It starts as an [inactive environment](https://docs.upsun.com/glossary.md#inactive-environment) with no data or services. When a **pull request** is opened in Bitbucket, an environment is created in Upsun with the pull request's target branch as its parent. It starts as an [active environment](https://docs.upsun.com/glossary.md#active-environment) with a copy of its parent's data. ###### Source of truth When you add an integration, your Bitbucket repository is considered to be the source of truth for the project. Your Upsun project is only a mirror of that repository and you can only push commits to Bitbucket. To clone your code, follow these steps: - In the Console, open the project you want to clone. - Click **Code**. - Click **Git**. - Run the command you find using Git. When you do this, you're cloning from your integrated Bitbucket repository, if you have the [appropriate access to do so](https://docs.upsun.com/integrations/source/troubleshoot.md). ####### Sync, fetch, and prune An integration from Bitbucket to Upsun establishes that: - Bitbucket is the source of truth, where Git operations occur - Upsun is a mirror of that repository - provisioning infrastructure according to configuration, and orchestrating environments according to the branch structure of the Bitbucket repository Actions that take place on Upsun don't affect commits on Bitbucket. Because of this, the Bitbucket integration enables both `fetch-branches` (track branches on Bitbucket) and `prune-branches` (delete branches that don't exist on Bitbucket) by default. You can change these settings but it is recommend to keep them. When enabled by default, you are limited by design as to what actions can be performed within the context of a Upsun project with a Bitbucket integration: | Action | Observation | Recommendation | | :---------------- | :---------------- | :------- | | Branch from parent | Running [`environment:branch`](https://docs.upsun.com/administration/cli/reference#environmentbranch) with the CLI, or selecting **Branch** in Console produces a new child environment, but it's deleted shortly after automatically. | Contribute to the Bitbucket repository itself by creating a branch and pull request. When the PR has been opened, a new environment will be provisioned for it. | | Merge in parent | Running [`environment:merge`](https://docs.upsun.com/administration/cli/reference#environmentmerge) with the CLI fails locally, and the **Merge** option in Console is not clickable. | Review and merge pull requests and/or branches on the Bitbucket repository. | | Merge into child (sync code) | Running [`environment:synchronize`](https://docs.upsun.com/administration/cli/reference#environmentsynchronize) with the CLI fails locally, and the **Sync** option in Console won't allow me to include `code` in that sync. | Perform the merge locally from a matching branch on Bitbucket. For example, clone the most recent parent (`git pull origin parent-branch`), switch to the pull request branch (`git checkout ga-staging`), and then merge the parent into the current branch (`git merge main`). | ###### Pull request URLs When a pull request is deployed, the integration reports the primary URL for the deployed environment. So you get a link to the deployed environment right in the pull request. If you have multiple routes, ensure the correct one is reported by [specifying the primary route](https://docs.upsun.com/define-routes.md#route-configuration-reference). #### Integrate with GitHub If you have code in a GitHub repository, you might want to connect it to a Upsun project. This means you can keep your GitHub workflows and treat the GitHub repository as the source of truth for your code. Your Upsun project becomes a mirror of your GitHub repository. This means you shouldn't push code directly to Upsun. Any changes you push directly get overwritten by the integration when changes happen in the GitHub repository. When you set up an integration with GitHub, it automates the following processes for you: - Creating a new environment when a branch is created or a pull request is opened. - Rebuilding the environment when new code is pushed to GitHub. - Deleting the environment when a pull request is merged. ###### Before you begin To manage source integrations, you need to be a [project admin](https://docs.upsun.com../../administration/users.md). You also need a GitHub repository with working code. ###### 1. Generate a token To integrate your Upsun project with an existing GitHub repository, you need to [generate a new token](https://github.com/settings/tokens/new). You can generate a classic personal access token, or a [fine-grained personal access token](https://github.blog/changelog/2022-10-18-introducing-fine-grained-personal-access-tokens/) for even greater control over the permissions you grant. For the integration to work, your GitHub user needs to have permission to push code to the repository. When you set up or update an integration, it also needs permission to manage its webhooks. This means your user needs to be a repository admin to create the integration. You can remove this permission after setup. Make sure you give your token a description. If you're generating a classic personal access token, ensure the token has the appropriate scopes based on what you want to do: | Scope | Purpose | | --------------------- | ---------------------------------------------------------------------- | | `admin:repo_hook` | To create webhooks for events in repositories. Always needed. | | `public_repo` | To integrate with public repositories. | | `repo` | To integrate with your private repositories. | | `repo` and `read:org` | To integrate with private repositories in organizations you belong to. | If you're generating a fine-grained personal access token, ensure the token has the right [repository permissions](https://docs.github.com/en/rest/overview/permissions-required-for-fine-grained-personal-access-tokens?apiVersion=2022-11-28) for the integration to work: | Permission | Access level | | ------------------| ----------------| | `Commit statuses` | Read and write | | `Contents` | Read and write | | `Metadata` | Read-only | | `Pull request` | Read and write | | `Webhooks` | Read and write | After you've set the needed scopes or permissions, generate and copy your token. ###### 2. Enable the integration To enable the integration, use either the [CLI](https://docs.upsun.com/administration/cli.md) or the [Console](https://docs.upsun.com/administration/web.md). - ``PROJECT_ID`` is the ID of your Upsun project. - ``OWNER/REPOSITORY`` is the name of your repository in GitHub. - ``GITHUB_ACCESS_TOKEN`` is the [token you generated](#1-generate-a-token). - ``GITHUB_URL`` is the base URL for your GitHub server if you self-host. If you use the public ``https://github.com``, omit the ``--base-url`` flag when running the command. For example, if your repository is located at ``https://github.com/platformsh/platformsh-docs``, the command is similar to the following: ```bash {} upsun integration:add \ --project abcdefgh1234567 \ --type github \ --repository platformsh/platformsh-docs \ --token abc123 ``` - Select the project where you want to enable the integration. - Click **Settings Settings**. - Under **Project settings**, click **Integrations**. - Click **+ Add integration**. - Under **GitHub**, click **+ Add**. - Add the [token you generated](#1-generate-a-token). - Optional: If your GitHub project isn’t hosted at ``github.com``, enter your GitHub custom domain. - Click **Continue**. - Choose the repository to use for the project. - Check that the other options match what you want. - Click **Add integration**. In both the CLI and Console, you can choose from the following options: | CLI flag | Default | Description | | ---------------- | ------- | ------------------------------------------------------------------------- | | `fetch-branches` | `true` | Whether to mirror and update branches on Upsun and create inactive environments from them. When enabled, merging on a Upsun isn't possible. That is, merging environments must be done on the source repository rather than on the Upsun project. See note below for details related to this flag and synchronizing code from a parent environment. | | `prune-branches` | `true` | Whether to delete branches from Upsun that don’t exist in the GitHub repository. When enabled, branching (creating environments) must be done on the source repository rather than on the Upsun project. Branches created on Upsun that are not on the source repository will not persist and will be quickly pruned. Automatically disabled when fetching branches is disabled. | | `build-pull-requests` | `true` | Whether to track all pull requests and create active environments from them, which builds the pull request. | | `build-draft-pull-requests` | `true` | Whether to also track and build draft pull requests. Automatically disabled when pull requests aren’t built. | | `pull-requests-clone-parent-data` | `true` | Whether to clone data from the parent environment when creating a pull request environment. | | `build-pull-requests-post-merge`| `false` | Whether to build what would be the result of merging each pull request. Turning it on forces rebuilds any time something is merged to the target branch. | | `resources-init` | `false` | To [specify a resource initialization strategy](https://docs.upsun.com/manage-resources/resource-init.md#first-deployment) for new containers. Once set, the strategy applies to **all** the deployments you launch through your source integration. See more information on [available resource initialization strategies](https://docs.upsun.com/manage-resources/resource-init.md#specify-a-resource-initialization-strategy). | To [keep your repository clean](https://docs.upsun.com/learn/bestpractices/clean-repository.md) and avoid performance issues, make sure you enable both the `fetch-branches` and `prune-branches` options. ###### 3. Validate the integration Verify that your integration is functioning properly [using the CLI](https://docs.upsun.com../overview.md#validate-integrations): ```bash upsun integration:validate ``` ####### Add the webhook manually If the integration was added with the correct permissions, the necessary webhook is added automatically. If you see a message that the webhook wasn't added, add one manually. To configure a webhook on a GitHub repository, you need to have Admin [user permissions](https://docs.github.com/en/organizations/managing-user-access-to-your-organizations-repositories/repository-roles-for-an-organization#permissions-for-each-role). 1. Get the webhook URL by running this command: `upsun integration:get --property hook_url`. 1. Copy the returned URL. 1. In your GitHub repository, click **Settings** > **Webhooks** > **Add webhook**. 1. In the **Payload URL** field, paste the URL you copied. 1. For the content type, select **application/json**. 1. Select **Send me everything**. 1. Click **Add webhook**. You can now start pushing code, creating new branches, and opening pull requests directly in your GitHub repository. Your Upsun environments are automatically created and updated. ###### Environment parent and status When a **branch** is created in GitHub, an environment is created in Upsun with the default branch as its parent. It starts as an [inactive environment](https://docs.upsun.com/glossary.md#inactive-environment) with no data or services. When a **pull request** is opened in GitHub, an environment is created in Upsun with the pull request's target branch as its parent. It starts as an [active environment](https://docs.upsun.com/glossary.md#active-environment) with a copy of its parent's data. ###### Source of truth When you add an integration, your GitHub repository is considered to be the source of truth for the project. Your Upsun project is only a mirror of that repository and you can only push commits to GitHub. To clone your code, follow these steps: - In the Console, open the project you want to clone. - Click **Code**. - Click **Git**. - Run the command you find using Git. When you do this, you're cloning from your integrated GitHub repository, if you have the [appropriate access to do so](https://docs.upsun.com/integrations/source/troubleshoot.md). ####### Sync, fetch, and prune An integration from GitHub to Upsun establishes that: - GitHub is the source of truth, where Git operations occur - Upsun is a mirror of that repository - provisioning infrastructure according to configuration, and orchestrating environments according to the branch structure of the GitHub repository Actions that take place on Upsun don't affect commits on GitHub. Because of this, the GitHub integration enables both `fetch-branches` (track branches on GitHub) and `prune-branches` (delete branches that don't exist on GitHub) by default. You can change these settings but it is recommend to keep them. When enabled by default, you are limited by design as to what actions can be performed within the context of a Upsun project with a GitHub integration: | Action | Observation | Recommendation | | :---------------- | :---------------- | :------- | | Branch from parent | Running [`environment:branch`](https://docs.upsun.com/administration/cli/reference#environmentbranch) with the CLI, or selecting **Branch** in Console produces a new child environment, but it's deleted shortly after automatically. | Contribute to the GitHub repository itself by creating a branch and pull request. When the PR has been opened, a new environment will be provisioned for it. | | Merge in parent | Running [`environment:merge`](https://docs.upsun.com/administration/cli/reference#environmentmerge) with the CLI fails locally, and the **Merge** option in Console is not clickable. | Review and merge pull requests and/or branches on the GitHub repository. | | Merge into child (sync code) | Running [`environment:synchronize`](https://docs.upsun.com/administration/cli/reference#environmentsynchronize) with the CLI fails locally, and the **Sync** option in Console won't allow me to include `code` in that sync. | Perform the merge locally from a matching branch on GitHub. For example, clone the most recent parent (`git pull origin parent-branch`), switch to the pull request branch (`git checkout ga-staging`), and then merge the parent into the current branch (`git merge main`). | ###### Pull request URLs When a pull request is deployed, the integration reports the primary URL for the deployed environment. So you get a link to the deployed environment right in the pull request. If you have multiple routes, ensure the correct one is reported by [specifying the primary route](https://docs.upsun.com/define-routes.md#route-configuration-reference). #### Integrate with GitLab If you have code in a GitLab repository, you might want to connect it to a Upsun project. This means you can keep your GitLab workflows and treat the GitLab repository as the source of truth for your code. Your Upsun project becomes a mirror of your GitLab repository. This means you shouldn't push code directly to Upsun. Any changes you push directly get overwritten by the integration when changes happen in the GitLab repository. When you set up an integration with GitLab, it automates the following processes for you: - Creating a new environment when a branch is created or a merge request is opened. - Rebuilding the environment when new code is pushed to GitLab. - Deleting the environment when a merge request is merged. ###### Before you begin To manage source integrations, you need to be a [project admin](https://docs.upsun.com../../administration/users.md). You also need a GitLab repository with working code. ###### 1. Generate a token To integrate your Upsun project with an existing GitLab repository, generate a [project access token](https://docs.gitlab.com/ee/user/project/settings/project_access_tokens.md#create-a-project-access-token). Ensure the token has the following scopes: - `api` to access your API - `read_repository` to read the repository For the integration to work, your GitLab user needs push access to the repository and to configure a webhook on a GitLab repository, you need to have Maintainer or Owner user permissions. Copy the token. **Note**: To create a project access token, you need to have a [sufficient GitLab license tier](https://docs.gitlab.com/ee/user/project/settings/project_access_tokens.md). If you don’t see **Access Tokens** under **Settings**, upgrade your GitLab tier. Alternatively, you can create a [personal access token](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.md), but that’s attached to a specific user rather than the project as a whole and grants more permissions. ###### 2. Enable the integration To enable the integration, use either the [CLI](https://docs.upsun.com/administration/cli.md) or the [Console](https://docs.upsun.com/administration/web.md). - ``PROJECT_ID`` is the ID of your Upsun project. - ``PROJECT/SUBPROJECT`` is the name of your repository in GitLab. - ``GITLAB_ACCESS_TOKEN`` is the [token you generated](#1-generate-a-token). - ``GITLAB_URL`` is the base URL for your GitLab server if you self-host. If you use the public ``https://gitlab.com``, omit the ``--base-url`` flag when running the command. For example, if your repository is located at ``https://gitlab.com/platformsh/platformsh-docs``, the command is similar to the following: ```bash {} upsun integration:add \ --project abcdefgh1234567 \ --type gitlab \ --server-project platformsh/platformsh-docs \ --token abc123 ``` - Select the project where you want to enable the integration. - Click **Settings Settings**. - Under **Project settings**, click **Integrations**. - Click **+ Add integration**. - Under **GitLab**, click **+ Add**. - Add the [token you generated](#1-generate-a-token). - Optional: If your GitLab project isn’t hosted at ``gitlab.com``, enter your GitLab custom domain. - Click **Continue**. - Choose the repository to use for the project. - Check that the other options match what you want. - Click **Add integration**. In both the CLI and Console, you can choose from the following options: | CLI flag | Default | Description | | ---------------- | ------- | ------------------------------------------------------------------------- | | `fetch-branches` | `true` | Whether to mirror and update branches on Upsun and create inactive environments from them. When enabled, merging on a Upsun isn't possible. That is, merging environments must be done on the source repository rather than on the Upsun project. See note below for details related to this flag and synchronizing code from a parent environment. | | `prune-branches` | `true` | Whether to delete branches from Upsun that don’t exist in the GitLab repository. When enabled, branching (creating environments) must be done on the source repository rather than on the Upsun project. Branches created on Upsun that are not on the source repository will not persist and will be quickly pruned. Automatically disabled when fetching branches is disabled. | | `build-merge-requests` | `true` | Whether to track all merge requests and create active environments from them, which builds the merge request. | | `build-wip-merge-requests` | `true` | Whether to also track and build draft merge requests. Automatically disabled when merge requests aren’t built. | | `merge-requests-clone-parent-data` | `true` | Whether to clone data from the parent environment when creating a merge request environment. | | `resources-init` | `false` | To [specify a resource initialization strategy](https://docs.upsun.com/manage-resources/resource-init.md#first-deployment) for new containers. Once set, the strategy applies to **all** the deployments you launch through your source integration. See more information on [available resource initialization strategies](https://docs.upsun.com/manage-resources/resource-init.md#specify-a-resource-initialization-strategy). To [keep your repository clean](https://docs.upsun.com/learn/bestpractices/clean-repository.md) and avoid performance issues, make sure you enable both the `fetch-branches` and `prune-branches` options. ###### 3. Validate the integration Verify that your integration is functioning properly [using the CLI](https://docs.upsun.com../overview.md#validate-integrations): ```bash upsun integration:validate ``` ####### Add the webhook manually If the integration was added with the correct permissions, the necessary webhook is added automatically. If you see a message that the webhook wasn't added, add one manually. To configure a webhook on a GitLab repository, you need to have Maintainer or Owner [user permissions](https://docs.gitlab.com/ee/user/permissions.md). 1. Get the webhook URL by running this command: `upsun integration:get --property hook_url`. 1. Copy the returned URL. 1. In your GitLab repository, click **Settings** > **Webhooks**. 1. In the **URL** field, paste the URL you copied. 1. Under **Trigger**, select **Push events** and **Merge request events**. 1. Click **Add webhook**. You can now start pushing code, creating new branches, and opening merge requests directly in your GitLab repository. Your Upsun environments are automatically created and updated. ###### Environment parent and status When a **branch** is created in GitLab, an environment is created in Upsun with the default branch as its parent. It starts as an [inactive environment](https://docs.upsun.com/glossary.md#inactive-environment) with no data or services. When a **merge request** is opened in GitLab, an environment is created in Upsun with the merge request's target branch as its parent. It starts as an [active environment](https://docs.upsun.com/glossary.md#active-environment) with a copy of its parent's data. ###### Source of truth When you add an integration, your GitLab repository is considered to be the source of truth for the project. Your Upsun project is only a mirror of that repository and you can only push commits to GitLab. To clone your code, follow these steps: - In the Console, open the project you want to clone. - Click **Code**. - Click **Git**. - Run the command you find using Git. When you do this, you're cloning from your integrated GitLab repository, if you have the [appropriate access to do so](https://docs.upsun.com/integrations/source/troubleshoot.md). ####### Sync, fetch, and prune An integration from GitLab to Upsun establishes that: - GitLab is the source of truth, where Git operations occur - Upsun is a mirror of that repository - provisioning infrastructure according to configuration, and orchestrating environments according to the branch structure of the GitLab repository Actions that take place on Upsun don't affect commits on GitLab. Because of this, the GitLab integration enables both `fetch-branches` (track branches on GitLab) and `prune-branches` (delete branches that don't exist on GitLab) by default. You can change these settings but it is recommend to keep them. When enabled by default, you are limited by design as to what actions can be performed within the context of a Upsun project with a GitLab integration: | Action | Observation | Recommendation | | :---------------- | :---------------- | :------- | | Branch from parent | Running [`environment:branch`](https://docs.upsun.com/administration/cli/reference#environmentbranch) with the CLI, or selecting **Branch** in Console produces a new child environment, but it's deleted shortly after automatically. | Contribute to the GitLab repository itself by creating a branch and pull request. When the PR has been opened, a new environment will be provisioned for it. | | Merge in parent | Running [`environment:merge`](https://docs.upsun.com/administration/cli/reference#environmentmerge) with the CLI fails locally, and the **Merge** option in Console is not clickable. | Review and merge pull requests and/or branches on the GitLab repository. | | Merge into child (sync code) | Running [`environment:synchronize`](https://docs.upsun.com/administration/cli/reference#environmentsynchronize) with the CLI fails locally, and the **Sync** option in Console won't allow me to include `code` in that sync. | Perform the merge locally from a matching branch on GitLab. For example, clone the most recent parent (`git pull origin parent-branch`), switch to the pull request branch (`git checkout ga-staging`), and then merge the parent into the current branch (`git merge main`). | ###### Merge request URLs When a merge request is deployed, the integration reports the primary URL for the deployed environment. So you get a link to the deployed environment right in the merge request. If you have multiple routes, ensure the correct one is reported by [specifying the primary route](https://docs.upsun.com/define-routes.md#route-configuration-reference). #### Resolve access issues with source integrations If you [add a user](https://docs.upsun.com/administration/users.md#add-a-user-to-a-project) to a Upsun project, but you haven’t added them to the remote repository on GitHub, GitLab, or Bitbucket, they can't clone the project locally. That user might try to clone the repository using the CLI with the following command: ```bash upsun get ``` In this case, the user gets an error similar to the following: ```txt Failed to connect to the Git repository: git@github.com:organization/repository.git Please make sure you have the correct access rights and the repository exists. ``` ###### Solution: Check external repository access rights To enable the user to clone the repository, grant them the correct access rights for the integrated repository. ### Health notifications Upsun can notify you when various events happen on your project, in any environment. At this time the only notification provided is a low disk space warning, but others may be added in the future. To add or modify an integration for a project, you need to be a [project admin](https://docs.upsun.com../administration/users.md#project-roles). ##### Default low-disk email notifications When you create a new project, Upsun creates a default [low-disk email notification](#low-disk-warning) for all [project admins](https://docs.upsun.com../administration/users.md#project-roles). ##### Available notifications ###### Low-disk warning Upsun monitors disk space usage on all applications and services in your cluster. * When available disk space drops below 20% or 4 GB, whichever is smaller, a warning notification is generated. * When available disk space drops below 10% or 2 GB, whichever is smaller, a critical notification is generated. * When available disk space returns above 20% or 4 GB, whichever is smaller, an all-clear notification is generated. Notifications are generated every 5 minutes, so there may be a brief delay between when the threshold is crossed and when the notification is triggered. ##### Configuring notifications Health notifications can be set up via the [Upsun CLI](https://docs.upsun.com/administration/cli.md), through a number of different channels. ###### Email notifications A notification can trigger an email to be sent, from an address of your choosing to one or more addresses of your choosing. You can view an email notification by running `upsun integration:get`. ```bash upsun integration:get +--------------+---------------+ | Property | Value | +--------------+---------------+ | id | abcdefghijklm | | type | health.email | | role | | | from_address | | | recipients | - '#admins' | +--------------+---------------+ ``` To edit the `recipients` that receive the default email notification, use the `integration:update` command. ```bash upsun integration:update abcdefghijklm --recipients you@example.com ``` The `recipients` field may be any valid email address, or one of the following special values. * `#admins` maps to all project admins and up. * `#viewers` maps to everyone with access to the project. To add a new email notification, register a `health.email` integration as follows: ```bash upsun integration:add --type health.email --recipients them@example.com --recipients others@example.com ``` You must specify one or more `recipients`, each as its own switch. The default `from-address` points to the "Upsun Bot". You can also configure a custom `--from-address`. The `--from-address` is whatever address you want the email to appear to be from. It is completely fine to use the same email address for both `from-address` and `recipients`. Note that depending on the configuration of the recipient mail server (including SPF and DKIM DNS entries) when using a custom `from-address`, the email can be marked as spam or lost. ###### Slack notifications A notification can trigger a message to be posted to a Slack channel via a [Slack app](https://api.slack.com/apps). ####### 1. Optional: Create a Slack app **Note**: If you are already have a Slack app, you can jump to [enabling notifications](#2-enable-notifications). 1. Open the [Slack API website](https://api.slack.com/) and go to **Your apps**. 2. Click **Create an App**. 3. Choose if you want to build your app from scratch, or via [an app manifest](https://api.slack.com/concepts/manifests). 4. Give your app a name. 5. Select a workspace to install your app in. **Note**: If you are not an admin of the selected workspace, request approval to install your app there. 6. Click **Create App**. ####### 2. Enable notifications 1. Open the [Slack API website](https://api.slack.com/) and go to **Your apps**. 2. Go to **Features** > **OAuth & Permissions** in the sidebar. 3. Scroll down to the **Scopes** area and select **User Token Scopes**. 4. Click **Add an OAuth Scope** to add the `chat:write` scope. ![Slack app scopes](https://docs.upsun.com/images/slack/slack-app-scopes.png "0.30") 5. Go to **Settings** > **Install app** in the sidebar. **Note**: If you are not an admin of the workspace, you need to provide a link to install the app into the workspace and onto a channel. Once the app is approved and installed, a **User OAuth Token** is provided in your app settings. Copy the token, and use it in the next step. 6. Using the **User OAuth Token**, run the following command: ```bash upsun integration:add --type health.slack --token --channel --project ``` For example, if you want your Slack app to post messages in the `project-notifications` channel, write the channel name in the command as you would reference it within Slack: ```bash upsun integration:add --type health.slack ... --channel '#project-notifications' ... ``` 6. When the integration is successfully configured, Upsun then sends an initial message to the channel. **Bot users v. Slack apps**: Previously, Upsun allowed for the configuration of health notifications sent to Slack via bot users and their associated API tokens. As of June 2024, Slack has deprecated bot users, and integrations must be configured using Slack apps as described above. If you already have defined an integration using a bot user API token, it will continue to work properly, though you should consider upgrading your processes to the above settings to avoid any future retirement. ###### PagerDuty notifications A notification can trigger a message to be sent via PagerDuty, if you are using that service. First, create a new PagerDuty "[integration](https://support.pagerduty.com/docs/services-and-integrations)" that uses the Events API v2. Copy the "Integration Key" as known as the "routing key" for the integration. Now register a `health.pagerduty` integration as follows: ```bash upsun integration:add --type health.pagerduty --routing-key YOUR_ROUTING_KEY ``` Any notification will now trigger an alert in PagerDuty. ##### Validate the integration You can then verify that your integration is functioning properly [using the CLI](https://docs.upsun.com/integrations/overview.md#validate-integrations) command ```bash upsun integration:validate ``` ### Infrastructure metrics Upsun projects are accompanied by live infrastructure metrics that provide an overview of resource usage for environments. Within the Console, metrics can be found for an environment under **Resources**. The information under **Resources** shows usage metrics for: Upsun environments: your service, app, and worker containers. These metrics are available for all of your environments. ##### Default thresholds All of the graphs show color-coded lines for the following thresholds: - Usage up to _100%_ results. - Usage that crosses _80%_ results. - Usage that crosses _90%_ results. - Usage that crosses _50%_ results. ###### Recommendations The default thresholds aim to give you an idea of when your hosts or containers are close to running out of resources. The impact differs based on your specific apps and service. If the resources are hovering close to the 100% threshold, you might want to consider: * [Optimizing your code](https://docs.upsun.com../application-metrics.md) (if possible) * [Changing your app size or service size](https://docs.upsun.com/manage-resources.md) ##### Time intervals Measurements are taken for each metric every 1 minute. You can select a time frame over which to see these measurements for the entire **Resources** view. In the primary three views, averages are shown over larger intervals. | View | Time between measurements | Example | | :-------------------------------------------------------------------- | :-------------------------------------------- | :--------------------------- | | The last 15 minutes (*15m*) | 1 minute | 10:00, 10:01, 10:02 | | The last hour (*1hr*) | 1 minute | 10:00, 10:01, 10:02 | | The last 8 hours (*8hr*) | 10 minutes | 10:00, 10:10, 10:20, 11:00 | To zoom in on smaller intervals, select specific ranges in a graph. The interval between measurements then changes based on the range you choose. | View | Time between measurements | | :----------- | :------------------------ | | < 2 hours | 1 minute | | 2 to 5 hours | 5 minutes | | 5+ hours | 20 minutes | ###### Longer time intervals You can access historical data for up to 30 days. These data should help you understand trends over time and whether a given measurement is normal, something that occurs occasionally, or a true anomaly. To see data over a given time frame, use the date picker to select the range to display. ##### Deployments Sometimes deployment activities (pushes, merges, syncs) can influence the underlying infrastructure. You don't want to confuse a spike caused by a successful deploy with an issue that needs your attention. To see how deployment activity influences the infrastructure, turn on **Deployments** on your metrics. Each deployment activity appears as a line on each graph corresponding to the time the activity finished. - To see information about the deployment activity, hover over the line. - To see the build log for a specific deployment activity, click the line. #### HTTP metrics The HTTP metrics dashboard provides Upsun users with network-related metrics. Those insights are designed to help them better understand the state of their applications. Those metrics can be accessed by clicking the **HTTP metrics** tab on the environment page within the console. The HTTP metrics dashboard can help you: - Verify if there were any recent spikes in error responses - Check bandwidth consumption to determine if there were any service interruptions - Identify specific URLs causing site-wide issues - Prioritize performance optimization (see [application metrics](https://docs.upsun.com../application-metrics.md)) ###### HTTP requests status graph The **HTTP requests** graph provides an aggregated view of the health of HTTP requests made to the application. It reflects the status responses (e.g. 1XX, 2XX, 3XX, 4XX, 5XX) of HTTP requests across a defined time frame. This graph helps identify surge of error responses or periods of elevated request activity. ###### Bandwidth usage graph The **Bandwidth** graph displays the data transfer volume. It represents incoming (data the app receives) and outgoing (data the app sends) bandwidth usage over time. This graph helps identify bandwidth bottlenecks, optimize resource allocation, and track bandwidth usage. ###### Top 10 most impactful URLs The **Top 10 URL Impact** graph and list pinpoint high-traffic or resource-intensive URLs for targeted optimization or investigation. It showcases the evolution over time of the top-10 most impactful URLs during a given time frame. This graph helps identify potential trouble spots, understand user behavior, and prioritize areas for optimization. #### Understand Platform.sh metrics Upsun environments consist of: * App containers: one or more [app containers](https://docs.upsun.com/create-apps.md) * Service containers: zero or more [service containers](https://docs.upsun.com../../add-services.md) * Worker containers: zero or more [worker instances](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#workers). Infrastructure metrics report CPU, RAM, and disk space for app, service, and worker containers. These metrics are available for all of your environments. App containers are shown first, with the app name and an image corresponding to the app type. Service containers follow next with the same pattern, and worker containers are shown last. You can collapse the graphs by clicking the 3-dot menu on the right-hand side, then **Hide resources**. The graphs switch to an overview of the average resource utilization for the selected container. ![How service container metrics look when minimized](https://docs.upsun.com/images/observability/metrics/service-container-minimized.png "0.65") The same menu provides a convenient **Configure resource** CTA, allowing you to swiftly adjust resources allocation for that container based on the observability metrics. ###### Example of how to read metrics This example should give you an idea of how the metrics appear. Environment metrics show resource usage for each app, service, and worker container. This reference project has a single app, two services (MySQL and Redis), and two workers. The appropriate resources have been [manually allocated](https://docs.upsun.com/manage-resources.md) for each container. The graphs show the current average usage in relation to the resources allocated to each container. By default, the graphs include all instances and an average over the instances. To select metrics for specific instances, click **Filter**. ![Clicking Filter reveals a list of instances you can filter](https://docs.upsun.com/images/observability/filtering-upsun.png "0.4") ####### App container Metrics graphs for the app container show CPU, RAM, and disk allocation and usage. The persistent disk has been configured in the [project resources](https://docs.upsun.com/manage-resources.md). ![All of the metrics for the app container](https://docs.upsun.com/images/metrics/application-metrics.png) ####### Service containers Metrics graphs for the service containers show CPU, RAM, and disk allocation and usage. ######## MySQL Metrics graphs for the MySQL service container show CPU, RAM, and disk allocation and usage. The persistent disk has been configured in the [project resources](https://docs.upsun.com/manage-resources.md). ![All of the metrics for the MySQL container](https://docs.upsun.com/images/observability/metrics/mysql-metrics-1.png) ######## Redis Metrics graphs for the Redis service container show CPU, RAM, disk allocation and usage. No persistent disk has been configured for Redis. ![All of the metrics for the Redis container](https://docs.upsun.com/images/observability/metrics/redis-metrics.png) ####### Worker containers Metrics graphs for the App-Horizon worker container show CPU, RAM, and disk allocation and usage. The persistent disk has been configured in the [project resources](https://docs.upsun.com/manage-resources.md). ![All of the metrics for the App-Horizon worker container](https://docs.upsun.com/images/metrics/workers-metrics-1.png) Metrics graphs for the App-Schedule worker container show CPU, RAM, and disk allocation and usage. The persistent disk has been configured in the [project resources](https://docs.upsun.com/manage-resources.md). ![All of the metrics for the App-Horizon worker container](https://docs.upsun.com/images/metrics/php-metrics.png) ### Application metrics #### Understanding application observablity Multiple application observability features are available for your Upsun projects. A full access to [Blackfire](https://www.blackfire.io/) is bundled with all your PHP and Python projects. The continuous profiling of your NodeJS, Go, Ruby and Rust applications is available directly from the Console under the `Profiling` tab of your environments. ###### Blackfire: Deterministic observability for PHP and Python Blackfire has a **deterministic** approach for PHP and Python, meaning it collects an extensive range of metrics for every instrumented request or script. The quantity of data and metrics collected differ for every layer of data Blackfire collects. The way scripts or requests are chosen to be instrumented also depends on the data layer. [Profiles](https://blackfire.io/docs/profiling-cookbooks/index) are manually triggered by a Blackfire user, or automatically triggered by [Blackfire builds](https://blackfire.io/docs/builds-cookbooks/index), the synthetic monitoring feature that evaluates the performance of critical user journeys. Meanwhile, monitoring traces and extended traces are based on the sample rate, which is the percentage of requests that are monitored. In that matter, [Blackfire monitoring](https://blackfire.io/docs/monitoring-cookbooks/index) offers a mix of two approaches: - a probabilistic one on how requests are selected to be instrumented - a deterministic one on how they are monitored, with the instrumentation starting at the very beginning of the request and ending with it A [blog post](https://blog.blackfire.io/understanding-monitoring-traces-extended-traces-and-profiles.md) provides all the details on the differences and complementarity between Blackfire's monitoring traces, extended traces, and profiles. ###### Continuous Profiling: Probabilistic observability Probabilistic profiling involves capturing data intermittently. It collects information at defined intervals, logging functions or services activated by any ongoing request or script. This approach provides a more comprehensive view of your application’s performance over time, but certain event nuances may be overlooked due to the frequency of sampling. Comparing deterministic to probabilistic profiling is akin to contrasting medical imaging devices. Asserting that an fMRI is unequivocally better than a PET scan or ultrasound is a misplaced judgment; each tool has its specific diagnostic purpose. You might not know all the details about a specific script. But you will have a good overview of everything happening at a specific time. Information on shorter spans starting and ending between two consecutive ticks won’t be collected. ###### Pros and cons Both approaches have their strengths and weaknesses. One is not better than the other. It all depends on the instrumented languages and your understanding of the data. - Deterministic profiling: Its strength lies in precision and facilitating meticulous script analysis. But it’s resource-intensive, leading to considerable overhead and potential data overload, making analysis potentially tedious. - Probabilistic profiling: Lightweight and scalable, tailored for holistic application oversight. However, its periodic snapshots might miss rapid function calls, yielding a not-so-perfect application map. Deterministic and probabilistic profiling each hold value within the development process. The former delivers a thorough and detailed view, while the latter offers a wider, more adaptable perspective. Developers may choose one or even combine both approaches based on the project’s specifics and the issues faced.#### Blackfire for PHP and Python Full access to [Blackfire](https://www.blackfire.io/) is bundled with all your PHP and Python Upsun projects. Blackfire is the **official Upsun observability service** that helps you improve the performance of your apps at each stage of their lifecycle. With Blackfire's unique Application Performance Monitoring (APM), Profiling, Alerting, and Testing features, you can achieve the following goals: - Avoid performance bottlenecks by proactively identifying issues in your code - Promptly solve identified issues by taking advantage of actionable recommendations - Create performance budgets for critical parts of your app and get alerted of any problem before a change hits your production Blackfire is installed natively on Upsun and [works integrally with the Upsun workflow](https://www.youtube.com/watch?v=Bq-LFjgD6L0). This results in an effortless setup process and smooth user experience. ###### Get started with Blackfire You can only access your Blackfire environments after you've been granted access to the related Upsun project. Therefore, to access your Blackfire environments, make sure you log in using your Upsun account. To access a Blackfire environment, each project user needs a Blackfire account. When a project user doesn't already have a Blackfire account, a new one is automatically created using the user's Upsun credentials. **Note**: If you’re using a [Content Delivery Network (CDN)](https://docs.upsun.com/domains/cdn.md), make sure you [configure it](https://blackfire.io/docs/integrations/proxies/index) to let Blackfire profile the code running on your servers. ####### Automated integration The Blackfire automated integration is enabled on your environments by default. When you create a new environment, it automatically triggers the creation of a Blackfire environment with the same settings. On this Blackfire environment, you have access to [all the features provided by Blackfire](https://www.blackfire.io/features/). This includes monitoring, profiling, alerting, and build-related features. Note that Blackfire monitoring is enabled by default on your production environment. On other environment types, you need to [enable it](#blackfire-monitoring). User access settings are replicated from the Upsun Console to Blackfire -- this includes all [access levels](https://blackfire.io/docs/up-and-running/access-management). You might have Blackfire variables already set on your project. In this case, the existing variables override the settings of the automated integration. **Note**: To trigger the synchronization of changes to users and their access levels, you need to redeploy the environment. ####### Blackfire monitoring Blackfire monitoring is enabled by default on your production environment. To enable Blackfire monitoring on your development or staging environments, follow these steps: 1. Go to your [organizations list](https://blackfire.io/my/organizations) and select the organization where you want to enable Blackfire monitoring. 2. Click **Organization Monitoring Usage**. ![A screenshot of where to find Organization Monitoring Usage](https://docs.upsun.com/images/integrations/blackfire/blackfire-organization-monitoring.png "0.40") 3. In the **Monitoring Activation** section, enable monitoring on the environments of your choice. ![A screenshot of what's seen in Monitoring Activation](https://docs.upsun.com/images/integrations/blackfire/blackfire-monitoring-activation.png "0.40") For more information on Blackfire monitoring features, see the [Blackfire documentation](https://blackfire.io/docs/monitoring-cookbooks/index). ###### Blackfire Profiling While your code is running, the Blackfire profiler collects deep performance metrics and provides full details and context of your code's behavior. This helps you find the root cause of performance bottlenecks. Blackfire lets you profile your application anywhere it's deployed, including on your local development machines. Using a browser extension or CLI command, you can profile HTTP requests, CLI scripts, Consumers, and Daemons. While HTTP requests can be profiled out-of-the-box, CLI profiling requires a [specific configuration](https://blackfire.io/docs/integrations/paas/upsun#cli-profiling). For more information on Blackfire profiling features, see the [Blackfire documentation](https://blackfire.io/docs/profiling-cookbooks/index). ###### Test the performance of each new deployment Blackfire's native integration with Upsun enables you to test your app's performance every time you deploy a branch in production, staging, or development. Follow these steps: 1. Set up the [Blackfire Builds integration](https://blackfire.io/docs/integrations/paas/upsun#builds). 2. Optional: set up an [integration with your Git provider](https://blackfire.io/docs/integrations/git/index) and get commit status updates from build reports. 3. Recommended: test business-critical use cases, with Blackfire [synthetic monitoring](https://blackfire.io/docs/builds-cookbooks/scenarios). ###### Troubleshooting ####### Bypass your reverse proxy, load balancer or CDN To use [Blackfire profiling](#blackfire-profiling), you need to bypass any reverse proxy, load balancer or [CDN](https://docs.upsun.com../../domains/cdn.md) that sits in front of your app. See [how to configure a bypass](https://blackfire.io/docs/reference-guide/reverse-proxies#documentation). ####### Configure your HTTP cache To take advantage of Blackfire features while using the HTTP cache with cookies, allow the `__blackfire` cookie to go through the cache. To do so, add [a configuration](https://docs.upsun.com../../define-routes/cache.md#allowing-only-specific-cookies) similar to the following: ```yaml {location=".upsun/config.yaml"} routes: "https://{default}/": cache: enabled: true cookies: ["/SESS.*/", "__blackfire"] ``` ###### Get support If you're experiencing issues with Blackfire and [troubleshooting](#troubleshooting) information doesn't help, follow these steps: 1. Retrieve [startup errors](#1-retrieve-startup-errors). 2. Retrieve your [Blackfire logs](#2-retrieve-your-blackfire-logs). 3. Send this data to [Blackfire Support](https://support.blackfire.io). ####### 1. Retrieve startup errors To retrieve startup errors, run the following command: ```bash upsun ssh -- php -d display_startup_errors=on --ri blackfire ``` ####### 2. Retrieve your Blackfire logs To retrieve your Blackfire logs, follow these steps: 1. On the environment where you're facing issues, create the following [variable](https://docs.upsun.com../../development/variables/set-variables.md): ```bash upsun variable:create php:blackfire.log_file --value /tmp/blackfire.log ``` 2. To set the verbosity of the logs to level 4 (debug level), create the following variable: ```bash upsun variable:create php:blackfire.log_level --value 4 ``` 3. Start a profile or build. 4. To display the logs, run the following command: ```bash upsun ssh -- cat /tmp/blackfire.log > blackfire.log ``` After you've retrieved the logs, you can disable them. To do so, run the following commands: ```bash upsun variable:delete php:blackfire.log_file upsun variable:delete php:blackfire.log_level ``` #### Comparing Continuous Profiling Timeframes **Feature Availability** By default, Upsun offers 15 minutes of continuous profiling per project and for free. To get 30 days of continuous profiling per project and for a fixed fee, [upgrade to the Continuous Profiling add-on](https://docs.upsun.com/administration/billing/add-on-subscription.md#continuous-profiling-add-on). Upsun Continuous Profiler dashboard allows comparing two timeframes to better understand application dynamics in various contexts. You could compare two versions of the application, before and after a deployment, or rush hours with quiet times for instance. ###### Enabling comparison mode A toggle on the top right corner of the continuous profiling dashboard enables the comparison mode. ![Routes](https://docs.upsun.com/images/observability/cont-prof-comparison-console.png "0.5") With comparisons enabled, you can select two timeframes referred to as ``A`` and ``B``. Those times can overlap. ###### Understanding continuous profiling visual comparison The flamegraph provides a visual representation of how timeframe ``B`` compares to ``A`` for the selected dimension using shades of colors. The stronger the color, the higher resource variation. ![Routes](https://docs.upsun.com/images/observability/cont-prof-comparison-flamegraph.png "0.5") Shades of green indicates timeframe ``B`` is consuming less resources than ``A`` for the selected dimension. Shades of red indicate the opposite. A scale and contextual information are displayed when hovering a span. This ensures accessibility for all users and allow colorblind users to benefit from this feature. ![Routes](https://docs.upsun.com/images/observability/cont-prof-comparison-scale.png "0.5")#### Continuous Profiling dashboard **Feature Availability** By default, Upsun offers 15 minutes of continuous profiling per project and for free. To get 30 days of continuous profiling per project and for a fixed fee, [upgrade to the Continuous Profiling add-on](https://docs.upsun.com/administration/billing/add-on-subscription.md#continuous-profiling-add-on). Continuous profiling is a multi-dimensional performance optimization technique where web applications are monitored and profiled in real-time. Lightweight and scalable, it's tailored for holistic application oversight. Continuous profiling collects performance data continuously, enabling developers to gain deep insights into their application's behavior, identify bottlenecks, and optimize code for better performance and resource utilization. This proactive approach allows for quicker identification and resolution of performance issues, ensuring the smooth running of software in live environments. ###### Continuous profiling on Upsun Upsun Continuous Profiling is powered by [Blackfire](https://docs.upsun.com../../../increase-observability/application-metrics/blackfire.md). It is available directly from the Console under the `Profiling` tab of your environments. The Continuous Profiling dashboard lets you visualize the profiling data of a specific application. It is composed of several views: flame graph, table view, and a split view combining the flame graph and table views. Each view helps make sense of the profiling data for the selected dimension and time frame. The available dimensions vary with the runtime profiled. ###### Color-coded node dimensions Upsun continuous profiling dashboard employs a color-coded system to represent each dimension, ensuring consistency across different runtimes. The intensity of a node's background color is directly proportional to the resources it consumes. As resource consumption increases, so does the vibrancy of the background color. This visual representation pinpoints application areas that may require optimization. ![Routes](https://docs.upsun.com/images/observability/cont-prof-color-code.png "0.5") The contrast between the dimension color and the grayscale of regular nodes has been designed to ensure accessibility for all users and allow colorblind users to benefit from this feature. ###### Flame graph The flame graph is a hierarchical visualization of the contribution of the different function calls to the selected dimensions. Flame graphs are effective in identifying performance issues and understanding the behavior of software during execution. ![Routes](https://docs.upsun.com/images/observability/flame-graph.png "0.5") Rectangles in a flame graph are called frames. Each frame represents a function, arranged vertically (y-axis) to show the sequence of method calls. The width of a frame relates to its resource usage. It helps pinpoint the most resource-intensive function calls. Their colors are not performance-related. They are meant to differentiate between functions. Horizontally (x-axis), methods are sorted by name, not the order in which they run. Hovering a frame displays in-depth information on it. ![Routes](https://docs.upsun.com/images/observability/flame-graph-hover.png "0.3") Clicking on a frame narrows down the flame graph to the callers and callee nodes of that frame. ![Routes](https://docs.upsun.com/images/observability/flame-graph-clicked.png "0.5") ###### Table view The table view displays a list of all the frames sorted by their resource consumption, for the selected dimension and time frame. By default, the table is sorted by `exclusive` resource consumption, which is the total value of the frame, minus the combined total values of its direct children. ![Routes](https://docs.upsun.com/images/observability/table-view.png "0.5") #### Continuous profiling for Go **Feature Availability** By default, Upsun offers 15 minutes of continuous profiling per project and for free. To get 30 days of continuous profiling per project and for a fixed fee, [upgrade to the Continuous Profiling add-on](https://docs.upsun.com/administration/billing/add-on-subscription.md#continuous-profiling-add-on). ###### Continuous profiling on Upsun Upsun [Continuous Profiler](https://docs.upsun.com/increase-observability/application-metrics/cont-prof.md) is powered by [Blackfire](https://docs.upsun.com../../../increase-observability/application-metrics/blackfire.md). It is available directly from the Console under the `Profiling` tab of your environments. The GO continuous profiling is currently made across 6 dimensions: - **Allocations**: Number of objects allocated - **Allocated Memory**: Number of bytes allocated - **CPU**: Time spent running on the CPU - **Goroutines**: Number of goroutines (both on-CPU and off-CPU) - **Heap Live Objects**: Number of objects allocated that are not yet garbage collected - **Heap Live Size**: Number of bytes allocated that are not yet garbage collected The default sampling frequency is 100 Hz. This means the Go continuous profiler is collecting information 100 times per second. ###### Prerequisites Upsun Continuous Profiler requires [`Go >=1.18`](https://docs.upsun.com/languages/go.md). ###### Installation Get the [Blackfire Continuous Profiler Go library](https://github.com/blackfireio/go-continuous-profiling): ```bash go get github.com/blackfireio/go-continuous-profiling ``` ###### Go continuous profiler API The Go continuous profiler API has two functions: ```go func Start(opts ...Option) error {} func Stop() {} ``` ####### `func Start(opts ...Option) error` `Start` starts the continuous profiler probe. It collects profiling information and uploads it to the Blackfire Agent periodically. ```go profiler.Start( profiler.WithCPUDuration(3 * time.Second), profiler.WithCPUProfileRate(1000), profiler.WithProfileTypes(profiler.CPUProfile, profiler.HeapProfile, profiler.GoroutineProfile), profiler.WithLabels({ "key1": "value1", "key2": "value2", }), profiler.WithUploadTimeout(5 * time.Second), ) defer profiler.Stop() ``` The `Start` function accepts the following options: - `WithCPUDuration`: specifies the length at which to collect CPU profiles. The default is 45 seconds. Can also be set via the environment variable `BLACKFIRE_CONPROF_CPU_DURATION`. - `WithCPUProfileRate`: sets the CPU profiling rate in Hz (number of samples per second). The default is defined by the Go runtime as 100 Hz. Can also be set via the environment variable `BLACKFIRE_CONPROF_CPU_PROFILERATE`. - `WithProfileTypes`: sets the profiler types. Multiple profile types can be set (`profiler.CPUProfile`, `profiler.HeapProfile`, `profiler.GoroutineProfile`). The default is `Profiler.CPUProfile`. - `WithLabels`: sets custom labels specific to the profile payload that is sent. - `WithUploadTimeout`: sets the upload timeout of the message that is sent to the Blackfire Agent. The default is 10 seconds. Can also be set via the environment variable `BLACKFIRE_CONPROF_UPLOAD_TIMEOUT`. **Note:**: If the same parameter is set by both an environment variable and a ``Start`` call, the explicit parameter in the ``Start`` call takes precedence. There is also some additional configuration that can be done using environment variables: - `BLACKFIRE_LOG_FILE`: Sets the log file. The default is logging to `stderr`. - `BLACKFIRE_LOG_LEVEL`: Sets the log level. The default is logging only errors. ####### `func Stop()` Stops the continuous profiling probe. ###### An example application 1. Get the Blackfire Continuous Profiler Go library ```bash go get github.com/blackfireio/go-continuous-profiling ``` 2. Save the following code as `main.go` and run as follows: ```bash go run main.go ``` ```go package main import ( "crypto/md5" "encoding/hex" "io" "time" profiler "github.com/blackfireio/go-continuous-profiling" ) func doSomethingCpuIntensive() { md5Hash := func(s string) string { h := md5.New() io.WriteString(h, s) return hex.EncodeToString(h.Sum(nil)) } for i := 0; i < 1_000_000; i++ { md5Hash("UpsunIsCoolAndSoAreYou") } } func main() { err := profiler.Start( profiler.WithAppName("my-app"), ) if err != nil { panic("Error while starting Profiler") } defer profiler.Stop() for i := 0; i < 15; i++ { doSomethingCpuIntensive() time.Sleep(1 * time.Second) } } ``` #### Continuous profiling for Java Upsun [Continuous Profiler](https://docs.upsun.com/increase-observability/application-metrics/cont-prof.md) is powered by [Blackfire](https://docs.upsun.com../../../increase-observability/application-metrics/blackfire.md). It is available directly the [Console](https://docs.upsun.com/administration/web.md), under the **Profiling** tab of your environments. The Java continuous profiling is currently made across 3 dimensions: - **CPU Time**: Time spent running on the CPU - **Allocations**: Time spent running on the CPU - **Allocated Memory**: Number of bytes allocated The default sampling frequency is 100 Hz. This means the Java continuous profiler is collecting information 100 times per second. ###### Prerequisites Upsun Continuous Profiler requires [`Java >= 17`](https://docs.upsun.com/languages/java.md). ###### Configuration The Java continuous profiler is enabled by default without configuration. #### Continuous profiling for Node.js **Feature Availability** By default, Upsun offers 15 minutes of continuous profiling per project and for free. To get 30 days of continuous profiling per project and for a fixed fee, [upgrade to the Continuous Profiling add-on](https://docs.upsun.com/administration/billing/add-on-subscription.md#continuous-profiling-add-on). ###### Continuous profiling on Upsun Upsun Continuous Profiling is powered by [Blackfire](https://docs.upsun.com../../../increase-observability/application-metrics/blackfire.md). It is available directly from the Console under the `Profiling` tab of your environments. The Node.js continuous profiling is currently made across 3 dimensions: - **CPU Time**: Time spent running on the CPU - **Wall-time**: Elapsed time per function call - **Heap**: Memory allocation and reserved space over time The default sampling frequency is 100 Hz. This means the Node.js continuous profiler is collecting information 100 times per second. ###### Prerequisites Upsun Continuous Profiler requires [`Node.js >= 16.0.0`](https://docs.upsun.com/languages/nodejs.md). ###### Installation Get the [Blackfire Continuous Profiler NodeJS library](https://github.com/blackfireio/node-continuous-profiling/): ```shell npm install @blackfireio/node-tracing ``` ```js const Blackfire = require('@blackfireio/node-tracing'); ``` ###### NodeJS continuous profiler API The NodeJS continuous profiler API has two functions: ```js function start(config) {} function stop() {} ``` ####### `function start(config) {}` The `start` function starts the continuous profiler probe. It collects profiling information in the background and periodically uploads it to the Blackfire Agent until the `stop` function is called. ```js const Blackfire = require('@blackfireio/node-tracing'); Blackfire.start({ appName: 'my-app' }); // your application... // If needed, you can stop profiling before cpuDuration // Blackfire.stop(); ``` The `start` function accepts an object as a parameter with the following keys: - `appName`: name of the application - `durationMillis`: time in milliseconds for which to collect profile (default: 45_000) - `cpuProfileRate`: average sampling frequency in Hz. (default: 100) - `labels`: Labels to add to the profile. (default: {}) - `uploadTimeoutMillis`: Timeout in milliseconds for the upload request (default: 10000) ####### `function stop() {}` Stops the continuous profiling probe. ###### An example application 1. Get the Continuous Profiler NodeJS library ```shell npm install express @blackfireio/node-tracing ``` 2. Create `index.js` with the following code ```js const Blackfire = require('@blackfireio/node-tracing'); const express = require('express') const crypto = require("crypto"); const app = express() const port = 3000 app.get('/', (req, res) => { const salt = crypto.randomBytes(128).toString("base64"); const hash = crypto.pbkdf2Sync("this is my password", salt, 10000, 512, "sha512"); res.send('Hello World!'); }) app.listen(port, () => { console.log(`Example app listening on port ${port}`) Blackfire.start({appName: 'blackfire-example'}); }) ``` 3. Run the Node.js server ```bash node index.js#### Continuous profiling for PHP **Feature Availability** By default, Upsun offers 15 minutes of continuous profiling per project and for free. To get 30 days of continuous profiling per project and for a fixed fee, [upgrade to the Continuous Profiling add-on](https://docs.upsun.com/administration/billing/add-on-subscription.md#continuous-profiling-add-on). Upsun [Continuous Profiler](https://docs.upsun.com/increase-observability/application-metrics/cont-prof.md) is powered by [Blackfire](https://docs.upsun.com../../../increase-observability/application-metrics/blackfire.md). It is available directly the [Console](https://docs.upsun.com/administration/web.md), under the **Profiling** tab of your environments. The PHP continuous profiling is currently made across 4 dimensions: - **CPU Time**: Time spent running on the CPU - **Wall-time**: Elapsed time per function call - **Allocated Memory**: Number of bytes allocated in memory - **Allocations**: Time spent running on the CPU The default sampling frequency is 100 Hz. This means the PHP continuous profiler is collecting information 100 times per second. ###### Prerequisites Upsun Continuous Profiler requires [`PHP >=8.2`](https://docs.upsun.com/languages/php.md). ###### Installation The Blackfire Continuous Profiler PHP library is included by default in all PHP images matching its requirements. There is no installation required. ###### Configuration The PHP continuous profiler is enabled by default without configuration. Optionally, you can override the following environment variables: - `DD_PROFILING_ENABLED=true`: forces the PHP continuous profiler activation/deactivation - `DD_PROFILING_LOG_LEVEL=off`: controls the PHP continuous profiler log level #### Continuous profiling for Python **Feature Availability** By default, Upsun offers 15 minutes of continuous profiling per project and for free. To get 30 days of continuous profiling per project and for a fixed fee, [upgrade to the Continuous Profiling add-on](https://docs.upsun.com/administration/billing/add-on-subscription.md#continuous-profiling-add-on). Upsun [Continuous Profiler](https://docs.upsun.com/increase-observability/application-metrics/cont-prof.md) is powered by [Blackfire](https://docs.upsun.com../../../increase-observability/application-metrics/blackfire.md). It is available directly from the [Console](https://docs.upsun.com/administration/web.md), under the **Profiling** tab of your environments. The PHP continuous profiling is currently made across 4 dimensions: - **CPU Time**: Time spent running on the CPU - **Wall-time**: Elapsed time per function call - **Heap Live Size**: Number of bytes allocated that are not yet garbage collected - **Allocated Memory**: Number of bytes allocated in memory - **Allocations**: Time spent running on the CPU The default sampling frequency is 100 Hz. This means the Python continuous profiler is collecting information 100 times per second. ###### Prerequisites Upsun Continuous Profiler requires [`Python >=3.7.0`](https://docs.upsun.com/languages/python.md). ###### Installation The [Blackfire Continuous Profiler Python library](https://github.com/blackfireio/python-continuous-profiling) is included by default in all Python images matching its requirements. There is no installation required. ###### Python continuous profiler API The Python profiler API (`profiler`) can be initiated with the following options: - `application_name`: the application name. - `period`: specifies the length at which to collect CPU profiles. The default is 45 seconds. - `upload_timeout`: observability data upload timeout. The default is 10 seconds. - `labels`: a dict containing the custom labels specific to the profile payload that is sent. The Python continuous profiler API has two functions: ``` python def start(): def stop(): ``` | Function | Description | | ---------------------- | ----------- | | `def start():` | The `start` function starts the continuous profiler probe. It collects profiling information in the background and periodically uploads it to the Blackfire Agent until the ``stop`` function is called. | | `def stop():` |Stops the continuous profiling probe. | ###### Example Here is an example of how you can initiate the Python `profiler` on a basic app: 1. Create `example.py` with the following code: ``` python def foo(): import time time.sleep(1.0) profiler = Profiler(application_name="my-python-app", labels={'my-extra-label': 'data'}) profiler.start() foo() profiler.stop() ``` 2. Run the app: ``` bash python example.py ``` #### Continuous profiling for Ruby Upsun [Continuous Profiler](https://docs.upsun.com/increase-observability/application-metrics/cont-prof.md) is powered by [Blackfire](https://docs.upsun.com../../../increase-observability/application-metrics/blackfire.md). It is available directly the [Console](https://docs.upsun.com/administration/web.md), under the **Profiling** tab of your environments. The Ruby continuous profiling is currently made across 3 dimensions: - **CPU Time**: Time spent running on the CPU - **Wall-time**: elapsed time per function call - **Allocations**: Time spent running on the CPU The default sampling frequency is 100 Hz. This means the Ruby continuous profiler is collecting information 100 times per second. ###### Prerequisites Upsun Continuous Profiler requires [`Ruby >= 2.5`](https://docs.upsun.com/languages/ruby.md). ###### Installation 1. Add the `datadog` gem to your `Gemfile` or `gems.rb` file: ``` bash gem 'datadog', '~> 2.0' ``` 2. Install the gems running the `bundle install` command. 3. Add the ``ddprofrb exec`` command to your Ruby application start command: ``` bash bundle exec ddprofrb exec ruby myrubyapp.rb ``` Rails example: ``` bash bundle exec ddprofrb exec bin/rails s ``` Alternatively, start the profiler by adding the following code in your application's entry point if you can't start it using `ddprofrb exec`: ``` bash require 'datadog/profiling/preload' ``` #### Continuous profiling for Rust Upsun [Continuous Profiler](https://docs.upsun.com/increase-observability/application-metrics/cont-prof.md) is powered by [Blackfire](https://docs.upsun.com../../../increase-observability/application-metrics/blackfire.md). It is available directly the [Console](https://docs.upsun.com/administration/web.md), under the **Profiling** tab of your environments. The Rust continuous profiling is currently made across 3 dimensions: - **CPU Time**: Time spent running on the CPU - **Allocated Memory**: Number of bytes allocated in memory - **Allocations**: Time spent running on the CPU The default sampling frequency is 100 Hz. This means the Rust continuous profiler is collecting information 100 times per second. The allocated memory sampling frequency is 524288 Hz. ###### Installation The Blackfire Continuous Profiler Rust library is included by default in all Rust images. There is no installation required nor minimal Rust version needed. ###### Configuration The Rust continuous profiler is enabled by default without configuration. It is recommended to build your Rust application in [debug mode](https://doc.rust-lang.org/book/ch14-01-release-profiles.md) to benefit from comprehensive stacktrace and information that could be obfuscated and collapsed otherwise. ```shell $ cargo build ``` ### Consume logs #### Access your logs ###### Activity logs Changes to your environments, such as deployments, cron jobs, and code or variable updates, are each logged as activities. You can access the logs either in the Console or using the [CLI](https://docs.upsun.com../../administration/cli/_index.md): - Get a list of activities by running ```bash {} upsun activity:list -e ``` Pass the ``--start`` flag to get activities from a specific date in the past. - To see details about the activity’s state and timing, run ```bash {} upsun activity:get ``` Where comes from the list in step 1. - Get a log of any given activity by running ```bash {} upsun activity:log ``` If a running activity is stuck, you can [cancel the activity](https://docs.upsun.com../../environments/cancel-activity.md). ####### Sharing activity logs When trying to identify and resolve failures, it can often help to have another person's perspective. Troubleshoot collaboratively by sharing the logs of specific activities. To share a log, open the log and click Share **Copy URL**. Share specific lines in the log on clicking the line number. To select multiple lines, hold Shift. After selecting multiple lines, hovering on the next unselected line gives you the amount of time that passed between the selected lines. ![An activity log with multiple lines selected showing the duration of part of the activity](https://docs.upsun.com/images/management-console/activity-lines.png "0.5") ###### Container logs Events that occur within an app container are logged within that container. The logs can be written to, but you should do so only with standard logging mechanisms. If your app has its own logging mechanism, use it to write to a dedicated logs [mount](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#mounts). To access the logs of various types of events: To get other logs, just replace ``access`` with the [type of log](#types-of-container-logs). To view more lines, use the ``--lines`` flag. - Access the container by running ```bash {} upsun ssh -e ``` - Change to the right directory by running ``cd /var/log``. - Read the desired log, such as by running ``tail access.log``. All log files are trimmed to 100 MB automatically. If you need larger logs, set up a [cron job](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#crons) to upload them to third-party storage. See an example of [uploading logs to Amazon S3](https://gitlab.com/contextualcode/platformsh-store-logs-at-s3) from Contextual Code. ####### Types of container logs | Type | Always present | Description | | ------------- | -------------- | ----------- | | `access` | Yes | The raw access log for the nginx instance running on the container. It doesn't include requests that are redirected or cached by the [router](https://docs.upsun.com../../define-routes.md). | | `app` | Yes | All log messages generated by the app including language errors and exceptions. | | `cron` | No | The output of cron jobs. Only exists after a cron job has run. | | `deploy` | No | The output of the [`deploy` hook](https://docs.upsun.com../../create-apps/hooks/hooks-comparison.md#deploy-hook). Only exists after a `deploy` hook has run. | | `dns` | Yes | All DNS queries made by processes in the container (such as the app and cron jobs). | | `error` | Yes | nginx-level errors that occur once nginx has fully started such as HTTP errors for missing directories and excluded file types. | | `nginx/error` | No | All nginx startup log messages. Only useful when debugging possible nginx configuration errors. Not currently available using the `upsun log` command. | | `php.access` | No | A record of all requests to the PHP service. See [PHP access record format](#php-access-record-format). | | `post-deploy` | No | The output of the [`post_deploy` hook](https://docs.upsun.com../../create-apps/hooks/hooks-comparison.md#post-deploy-hook). Only exists after a `post_deploy` hook has run. | ######## PHP access record format The formatting of `php.access.log` is determined by the PHP settings. To determine the format, run the following: ```bash upsun ssh cat -n /etc/php/-zts/fpm/php-fpm.conf | grep "access.format" ``` You get a response such as the following: ```bash Connection to ssh.eu.platform.sh closed. access.format = "%{%FT%TZ}t %m %s %{mili}d ms %{kilo}M kB %C%% %{REQUEST_URI}e" ``` See what [each value in this string means](https://www.php.net/manual/en/install.fpm.configuration.php#access-format). ###### Timezones UTC is the default timezone for all logs. #### Forward Platform.sh and Blackfire logs You might use a service to analyze logs from various parts of your fleet. You might want to consolidate all your logs in one place that everyone has access to without needing to grant them access to each project individually. In such cases, forward your logs from Upsun and Blackfire to a third-party service. You can use a [service with an integration](#use-a-log-forwarding-integration) or any service that supports a [syslog endpoint](#forward-to-a-syslog-endpoint) or [HTTP endpoint](#forward-to-an-http-endpoint). Logs to `stdout` and `stderr` are forwarded. Logs in files can't be forwarded. To enable log forwarding in a project, you need to be a [project admin](https://docs.upsun.com../../administration/users.md). You also need your project to have the capability for log forwarding. To get a price quote, [contact Sales](https://platform.sh/contact/). ###### Use a log forwarding integration Certain services have a specific integration for forwarding logs. If your third-party service isn't supported, you can forward to a [syslog endpoint](#forward-to-a-syslog-endpoint). ####### Integrated third-party services Integrations exist for the following third-party services to enable log forwarding: - [New Relic](https://newrelic.com/) - [Splunk](https://www.splunk.com/) - [Sumo Logic](https://www.sumologic.com/) ####### Enable a log forwarding integration ######## Using the CLI To enable log forwarding for a specific project using the [Upsun CLI](https://docs.upsun.com../../administration/cli.md), follow the steps for your selected service. View your logs in the **Logs** dashboard. - In Splunk, get an Event Collector token on [Splunk Platform](https://docs.splunk.com/Documentation/Splunk/latest/Data/UsetheHTTPEventCollector#Create_an_Event_Collector_token_on_Splunk_Cloud_Platform) or [Splunk Enterprise](https://docs.splunk.com/Documentation/Splunk/latest/Data/UsetheHTTPEventCollector#Create_an_Event_Collector_token_on_Splunk_Enterprise). - Determine your host, which is the Splunk instance that’s collecting data. - Choose an index name. - Create the integration with the following command: ```bash {} upsun integration:add --type splunk --url https://http-inputs..splunkcloud.com/services/collector/event --index --token ``` View your logs in the **Apps->Search & Reporting** dashboard. Filter by the index name to find the relevant events. - In Sumo Logic, [configure an HTTP source](https://help-opensource.sumologic.com/docs/send-data/hosted-collectors/http-source/logs-metrics/#configure-an-httplogs-and-metrics-source). Make sure to copy the Source Category and collector URL. - Create the integration with the following command: ```bash {} upsun integration:add --type sumologic --url --category ``` View your logs in the **Log Search** tab. To start forwarding logs, [trigger a redeploy](https://docs.upsun.com../../development/troubleshoot.md#force-a-redeploy). ######## In the Console To enable log forwarding for a specific project from the Console, follow these steps: 1. Navigate to your project. 2. Click Settings **Settings**. 3. Click **Integrations**. 4. Click **Add Integration**. 5. Select the integration you want to enable. 6. In the **Configure your integration** window, specify your configuration options. 7. Click **Add Integration**. The new integration overview is displayed, and you can view your logs in the **Activity** section. ###### Forward to a syslog endpoint Syslog is a standard protocol for transferring log messages. Many third-party services offer endpoints for ingesting syslog events. You can forward your Upsun and Blackfire logs to any of those endpoints. ``type``, ``syslog-host``, and ``syslog-port`` are the only properties required for all endpoints. The following table shows the other available properties: | Property | Type | Default | Description | | ``auth-token`` | ``string`` | | The token to authenticate with the given service. | | ``auth-mode`` | ``string`` | ``prefix`` | The mode for authentication with the given service. Can be ``prefix`` or ``structured_data``. Defaults to ``prefix``. | | ``facility`` | ``string`` | ``1`` (user) | A [syslog facility code](https://en.wikipedia.org/wiki/Syslog#Facility) to attach with each log to identify the source. Can be a number from 0 to 23. | | ``message-format`` | ``string`` | ``rfc5424`` | The standard to use for the message format. Can be ``rfc5424`` or ``rfc3164``. | | ``protocol`` | ``string`` | ``tls`` | The network protocol to use in the connection. Can be one of ``tls``, ``tcp``, or ``udp``. Defaults to ``tls``. | | ``verify-tls`` | ``boolean`` | ``true`` | Whether to verify Transport Layer Security (TLS) certification when using the TLS protocol. | To include a property, add it as a flag, for example ``--protocol tcp``. This should let you connect to any service that has syslog endpoints. To start forwarding logs, once you’ve added the service [trigger a redeploy](https://docs.upsun.com/development/troubleshoot.md#force-a-redeploy). To enable log forwarding to a syslog endpoint for a specific project using the [Upsun CLI](https://docs.upsun.com/administration/cli.md), follow these steps: - Navigate to your project. - Click Settings **Settings**. - Click **Integrations**. - Click **Add Integration**. - Select the syslog integration. - In the **Configure your integration** window, specify your configuration options. - Click **Add Integration**. The new integration overview is displayed, and you can view your logs in the **Activity** section. ###### Forward to an HTTP endpoint Some third-party services, such as [Elasticsearch](https://docs.upsun.com../../add-services/elasticsearch.md) and [OpenSearch](https://docs.upsun.com../../add-services/opensearch.md), support ingesting log messages through an HTTP endpoint. You can use HTTP forwarding to forward Upsun and Blackfire logs to such third-party services. HTTP forwarding makes a `POST` HTTP request with an `application/json` body while forwarding the log messages to the endpoint. As an example, to forward logs to Elasticsearch using HTTP log forwarding, run the following command: ``` upsun integration:add --type httplog --url "https:////_doc" --header "Authorization: Basic " --header "Content-Type: application/json" ``` `type` and `url` are the only properties required for all endpoints. Optionally, you can use the `headers` property to pass additional headers in the HTTP requests. Note that if your endpoint URL includes a `PORT`, that can also be included in the `--url` flag: ``` upsun integration:add --type httplog --url "https://://_doc" --header "Authorization: Basic " --header "Content-Type: application/json" ``` Once you've [added the service](https://docs.upsun.com../../add-services.md), to start forwarding logs [trigger a redeploy](https://docs.upsun.com../../development/troubleshoot.md#force-a-redeploy). ###### Log levels Your app may output logs with distinct severity levels. But as Plaform.sh only reads logs from `stdout`, this distinction is lost and everything gets logged at `INFO` level. To preserve the original log level, use a language-specific syslog module/package for logging. The following example code snippets show how logs can be written to Syslog: Using the logging module: ```python {} import logging import logging.handlers logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) handler = logging.handlers.SysLogHandler(address="/dev/log") logger.addHandler(handler) logger.info("Operation started") logger.error("Operation failed") ``` Using the Syslog module: ```python {} import syslog syslog.openlog(logoption=syslog.LOG_PID, facility=syslog.LOG_LOCAL0) syslog.syslog(syslog.LOG_INFO, "Operation started") syslog.syslog(syslog.LOG_ERR, "Operation failed") syslog.closelog() ``` Using the log package: ```go {} package main import ( "log" "log/syslog" ) func main() { logger, err := syslog.NewLogger(syslog.LOG_LOCAL0|syslog.LOG_INFO, log.LstdFlags) if err != nil { panic(err) } logger.Println("Operation started...") logger.Fatalln("Operation failed") } ``` Using the Syslog package: ```go {} package main import ( "fmt" "log" "log/syslog" ) func main() { syslogWriter, err := syslog.Dial("", "", syslog.LOG_LOCAL0|syslog.LOG_INFO, "") if err != nil { log.Fatal(err) } defer syslogWriter.Close() fmt.Fprintf(syslogWriter, "Operation has started") syslogWriter.Err("Operation failed") } ``` ### Back up an environment When you're making changes to your apps, you want to be sure those changes only improve things and don't make you lose any data. You also want to have a disaster recovery plan in place. Backups help you protect yourself against potential data loss. You might want to create backups of your live environment before merging a different environment into it or each time you increase the storage space of your services. You also have regularly scheduled automated backups of your production environments to cover most cases. Note that you can only create backups and restore active environments. To work with an [inactive environment](https://docs.upsun.com/glossary.md#inactive-environment), first activate it. ##### How backup and restore works 1. As an [admin user](https://docs.upsun.com../administration/users.md), you can do a backup of your environment. This backup includes the complete data and code of the environment. All persistent data from all running [services](https://docs.upsun.com../add-services.md) and any files stored on [mounts](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#mounts) are included. The backup is stored internally on Upsun. That is, the backup can be applied to environments on Upsun, but it can't be downloaded. If you need to download backups, instead [export your mount and service data](https://docs.upsun.com/learn/tutorials/exporting.md)). 2. You restore your environment using the backup. At this point, the data and code from the backup are restored to ensure a consistent state. The latest code in your repository may have been modified such that it no longer works correctly with the old, restored data. **Warning**: Upsun does not modify your Git repository. Any further changes you make use the latest code in your repository. 3. Depending on your needs, you can do the following: a) To use the code from the time of the backup as a baseline for future changes, make sure you restore it yourself in your Git repository. To do so, use Git commands such as `revert`. b) To use your latest code instead, just redeploy your environment or push a new change. **Note**: You may not want the code from the backup to be restored at step 2. For instance, if you have deleted containers since the backup, you may not want them to be restored with the backup. In this case, you can opt out of restoring the code. To do so, when you restore your backup, use the ``--no-code`` flag. Also, see [how resource allocation works](https://docs.upsun.com/manage-resources/resource-init.md#backup-restoration) when you restore a backup. ##### Backups and downtime By default, creating a manual backup causes a momentary pause in site availability so that all requests can complete. This means the environment is backed up in a known consistent state. The total interruption is usually only 15 to 30 seconds. Any requests during that time are held temporarily, not dropped. To avoid this downtime, use [live backups](#live-backups). For consistent backups, create the backups during non-peak hours for your site. ##### Data retention ###### Manual backups [Manual backups](https://docs.upsun.com../environments/backup.md#create-a-manual-backup) are retained until you delete them or replace them with another backup. You can configure the maximum number of manual backups. Once that number is reached, any new manual backup automatically replaces the oldest backup. ###### Automated backups Automated backups are retained for 2 days when you use the [default backup policy](#default-backup-policy) (meaning, 2 days worth of backups are retained at any given point). When you [configure your own automated backup policy](#configure-a-backup-policy), the retention time varies based on that configuration. Automated backups are always [live](#live-backups). ##### Backup policy ###### Default backup policy By default, Upsun provides 1 automated backup a day for your production environment, with a [2-day retention](https://docs.upsun.com/security/data-retention.md) (2 days worth of backups are retained at any given point). You can [configure your own backup policy](#configure-a-backup-policy). The default backup policy is equivalent to a custom backup policy using a `1d` interval and a count of `2` (see below). ###### Configure a backup policy Upsun allows you to fully configure your own backup policy. You can setup a different automated backup schedule per environment type (production, staging, and development environments). On a given environment type, you can configure: - The total number of backups (manual and automated) - The total number of manual backups specifically - Multiple schedules for automated backups An automated backup schedule is composed of an interval and a count. The interval defines the frequency of the backups. An interval can be a couple of hours, days, weeks, months, or years. To configure an interval, use the following values: - ``h`` for hour - ``d`` for day - ``w`` for week - ``M`` for month - ``y`` for year The count defines the number of backups to retain. ###### Configuration examples To take a backup every day and keep up to 7 backups, run the following command: ```bash {location="Terminal"} upsun project:curl settings -X PATCH \ -d '{ "data_retention": { "production": { "default_config": { "schedule": [ {"interval": "1d", "count": 7}, ] } } } }' ``` ####### Configure multiple automated backup schedules You can use multiple schedules to implement you own backup policy. For instance, you may want to keep multiple recent backups and fewer older backups, using a command similar to the following: ```bash {location="Terminal"} upsun project:curl settings -X PATCH \ -d '{ "data_retention": { "production": { "default_config": { "schedule": [ {"interval": "1d", "count": 7}, {"interval": "1w", "count": 4}, {"interval": "1M", "count": 12} ] } } } }' ``` The command results in: - A backup every day for 7 days - A backup every week for 4 weeks - A backup every month for 12 months ####### Set a limit for backups To configure the maximum number of backups (automated and manual backups alike) on your production environment, run a command similar to the following: ```bash {location="Terminal"} upsun project:curl /settings -X PATCH -d '{"data_retention": {"production": {"max_backups": 10}}}' ``` To configure the maximum number of manual backups on the production environment, run a command similar to the following: ```bash {location="Terminal"} upsun project:curl /settings -X PATCH -d '{"data_retention": {"production": {"default_config": {"manual_count": 1}}}}' ``` ##### Live backups You can create backups without any downtime. This means your environment is running and open to connections during the backup. Because the connections may come in during backup creation, live backups may have data inconsistencies among containers. They may make restorations less reliable. To avoid such issues, schedule [manual backups](#create-a-manual-backup) during non-peak hours, when the short amount of downtime is least noticed. You can create a manual live backup on a Grid project: When [creating the backup](#create-a-manual-backup), select **Run live backup** in the last step. ##### Create a manual backup You can create a manual backup using the [CLI](https://docs.upsun.com../administration/cli.md) or in the [Console](https://docs.upsun.com../administration/web.md). - Navigate to the environment you want to back up. - Click **Backups**. - Click **Backup**. - Click **Backup**. See more information on [backup policies](#backup-policy) and [data retention](#data-retention). ###### Automate manual backups You can also automate the process of creating manual backups through [cron jobs](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#crons). The cron job uses the CLI command to back up the environment. It requires you to [set up the CLI on the environment with an API token](https://docs.upsun.com../administration/cli/api-tokens.md#authenticate-in-an-environment). Although this process is automated, backups created in this way count as [manual backups](#manual-backups). They don't affect the automated backups taken as part of [a schedule](#configure-a-backup-policy). ##### Physical storage location Backups are stored as binary large objects separate from your environments. This storage is replicated over multiple data centers in different locations [within the region your project is hosted in](https://platform.sh/trust-center/security/data-security/). This means that in the rare event a data center becomes unavailable, your backups are still available. ### Restore an environment from a backup Once you have [backups of your environment](https://docs.upsun.com/environments/backup.md), you can restore data from a previous point. To restore an environment, you need an [Admin role for that environment type](https://docs.upsun.com../administration/users.md). ##### 1. List available backups To restore an environment, first select one of the available backups: You get a response similar to the following: ```bash {} Backups on the project My Project (1234567abcdef), environment main (type: production): +---------------------------+----------------------------+------------+ | Created | Backup ID | Restorable | +---------------------------+----------------------------+------------+ | 2022-08-15T09:48:58+01:00 | 5ouvtgo4v75axijww7sqnftste | true | | 2022-07-09T14:17:17+01:00 | 7jks7dru5xpx5p5id5wtypur2y | true | | 2022-06-22T18:33:29+01:00 | f3jbyxlhtmalco67fmfoxs7n4m | true | +---------------------------+----------------------------+------------+ ``` Select one of the backups marked as **Restorable** and copy its **Backup ID**. - Navigate to the environment where you want to see backups. - Click **Backups**. Select one of the backups marked as having completed successfully . ##### 2. Restore from a backup To restore the backup you've selected, follow these steps: - Press ``enter`` to agree with the consequences and continue. - Next to the backup you’ve selected, click **More** More. - Click **Restore**. - Read through the consequences and click **Yes, Restore**. The data is restored and your backed-up environment is deployed. This deployment uses the built app, including variables, from when the backup was taken. **Warning**: The code is also initially restored, but Upsun doesn’t modify your Git repository. So any future (re)deployments use the current Git repository to build the environment. To restore your code to its previous state when the backup was taken, use Git commands such as [revert](https://git-scm.com/docs/git-revert). Note that you can also opt out of restoring the code entirely by using the ``--no-code`` flag. For more information, see [how backup and restore works on Upsun](https://docs.upsun.com/environments/backup.md#how-backup-and-restore-works). Also, see [how resource allocation works](https://docs.upsun.com/manage-resources/resource-init.md#backup-restoration) when you restore a backup. ##### Restore to a different environment You can restore backups to a different environment than they were created on using the CLI: 1. Switch to the branch where the backup was created. 2. To restore your backup to an existing environment, run the following command: ```bash upsun backup:restore --target= ``` If your target environment doesn't exist yet, you can create it by [branching an existing environment](https://docs.upsun.com/glossary.md#branch). The new target environment will be an exact copy of the existing (parent) environment. To do so, use the `--branch-from` option to specify the parent of your new target environment: ```bash upsun backup:restore --target= --branch-from= ``` ### Cancel an activity If you have a stuck activity or you pushed a change you know doesn't work, you can cancel a running or pending activity on an environment. This works for activities such as builds, cron jobs, and source operations. You can cancel activities using the [CLI](https://docs.upsun.com../administration/cli.md) or in the [Console](https://docs.upsun.com../administration/web.md). If you have more than one running or pending activity, choose which activity to cancel. You can also cancel a specific activity by specifying its ID: ```bash {} upsun activity:cancel ``` Get the ID from the [activity log](https://docs.upsun.com/increase-observability/logs/access-logs.md#activity-logs). - Open the environment where you want to cancel an activity. - In the [activity log](https://docs.upsun.com/increase-observability/logs/access-logs.md#activity-logs), click More **More** next to the activity you want to cancel. - Click **Cancel**. ##### Non-cancellable activities An activity can finish in between when you load the Console and when you click **Cancel**. For example, when the activity is a [source operation](https://docs.upsun.com../create-apps/source-operations.md) and the related build hook has already completed. In such cases, you get a message that the activity can't be cancelled. ### Change an environment's parent All environments default to having another environment as their parent. If you [branched](https://docs.upsun.com/glossary.md#branch) the environment from another, its parent starts as the environment it was created from. If you pushed a branch through Git or a [source integration](https://docs.upsun.com../integrations/source.md), the parent defaults to the default environment. To change the environment's parent, follow these steps: Run the following command: ```bash {} upsun environment:info -e parent ``` So if you have the environment ``new-feature`` and want to change its parent to ``main``, run the following: ```bash {} upsun environment:info -e new-feature parent main ``` If you're not using a [source integration](https://docs.upsun.com/integrations/source.md), you can also set a parent for your environment when pushing changes to it. To do so, run the following command: ```bash git push -o "environment.parent=" ``` Learn more about how to [trigger actions on `push`](https://docs.upsun.com/environments.md#push-options). ### Configure HTTP access control When developing your site, you might want to hide your preview environments from outside viewers. Or you may find you have performance issues from [excessive bot access](https://support.platform.sh/hc/en-us/community/posts/16439634723858). You can control access with a username and password **or** by allowing/denying specific IP addresses or networks. This setting applies to the entire environment. The settings for a specific environment are inherited by all of its children. So if you have a `staging` environment and you [branch environments from it](https://docs.upsun.com/glossary.md#branch), all of the environments branched from it inherit the same authentication information. Changing access control triggers a new deploy of the current environment. The changes don't propagate to child environments until they're [redeployed manually](https://docs.upsun.com../development/troubleshoot.md#force-a-redeploy). ##### Use a username and password You can set up one or more combinations of a username and password. To add a username and password, follow these steps: Run the following command: ```bash {} upsun environment:http-access -e --auth : ``` For example, to add the username ``name`` with the password ``12321`` to the ``test`` environment, run: ```bash {} upsun environment:http-access -e test --auth name:12321 ``` ##### Filter IP addresses Alternatively, you can control access to environments by allowing or denying specific IP addresses or ranges of IP addresses. The addresses should be in the [CIDR format](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing). Both`4.5.6.7` and `4.5.6.0/8` are accepted formats. Note that `allow` entries should come before `deny` entries in case they both match. For example, the following configuration allows only the IP `198.51.100.0` to access your website. ```txt 198.51.100.0 allow 0.0.0.0/0 deny ``` **Pick your authentication method**: When you set up IP filtering authentication, make sure no [username and password are defined](#use-a-username-and-password) for your environment. Otherwise, your environment will remain accessible through the defined username and password combination, regardless of your IP filtering settings. To control access based on IP address, follow these steps: Run the following command: ```bash {} upsun environment:http-access -e --access allow: --access deny: ``` ### Deactivate an environment If you have environments you aren't using, you may want to deactivate them to save resources for what you need. To deactivate an environment, you need to be an admin for the project or the given environment. **Note**: Your default environment is protected. It can’t be deactivated through the Console or the CLI. To change which environment is the default, see how to [rename the default branch](https://docs.upsun.com/environments/default-environment.md). Deactivating the project results in the following: * The environment becomes [inactive](https://docs.upsun.com/glossary.md#inactive-environment). Unless it's reactivated, it's no longer deployed and isn't accessible from the web or via SSH. * All services running on this environment are deleted. * All data specific to the environment is deleted. If the environment is reactivated, it syncs data from its parent environment. ##### Deactivate an environment To deactivate an environment, follow these steps: Run the following command: ```bash {} upsun environment:deactivate ``` ##### Delete the branch Inactive environments still have branches in Git. To delete the branch entirely, run the following command: ```bash git push origin --delete ``` ##### Reactivate an environment Reactivating an environment [syncs](https://docs.upsun.com/glossary.md#sync) data from its parent environment. To reactivate an inactive environment, follow these steps: Run the following command: ```bash {} upsun environment:activate ``` If you're not using a [source integration](https://docs.upsun.com/integrations/source.md), you can also activate an environment when pushing changes to it. To do so, run the following command: ```bash git push -o "environment.status=active" ``` Learn more about how to [trigger actions on `push`](https://docs.upsun.com/environments.md#push-options). ### Rename the default environment You can set the name of your default/production environment when creating a project. To change it after project creation, follow the steps below. For consistency, the steps are all given using the [CLI](https://docs.upsun.com../administration/cli.md). The examples below are based off of changing the default environment from `old` to `main`. Replace these names with what suits your situation. If your site is already live, remember that deactivating an environment is a destructive operation that can result in data loss. To minimize potential issues, take the following steps: - Switch the default environment during non-peak hours. - Keep your data by taking a [backup of the `old` environment](https://docs.upsun.com../environments/backup.md) - Reduce your DNS time-to-live (TTL) to a minimum. ##### Requirements If you have a domain set for your default environment, remove it before changing the default branch. Otherwise you get an error that `default domain must be a valid project domain`. To change the default branch, you need to be an [admin for the project](https://docs.upsun.com../administration/users.md) ##### Note on source integrations The following steps depend of whether your project has a [source integration](https://docs.upsun.com../integrations/source.md). If it doesn't, Upsun is your primary remote repository for the project. If it does, GitHub, GitLab, or BitBucket hosts your primary remote repository for the project. ##### 1. Create a `main` environment Without a source integration With a source integration In your local copy of your repository, create a new environment from ``old`` called ``main``: ```bash {} upsun environment:branch main old ``` In your local copy of the external repository, make sure your default branch is up to date: ```bash {} git checkout old && git pull origin old ``` Then create the ``main`` branch off of your default branch and push it to the remote repository: ```bash {} git checkout -b main git push origin main ``` Source integrations include all branches, but don’t activate the corresponding environments in Upsun. Activate the ``main`` environment by running the following command: ```bash {} upsun environment:activate main ``` ##### 2. Copy settings If you have variables or other settings specific to your default environment, add those to the `main` environment. For example, you may have variables for your production environment set to not be inheritable (such as if you set them with `--inheritable=false` through the CLI). These variables aren't added automatically to child environments and so you need to add them to the `main` environment manually. If you want the `main` environment to send emails, [turn on outgoing email](https://docs.upsun.com../development/email.md). ##### 3. Make `main` a top-level branch To have `main` be your default, it needs to not be a child of `old`. Use the following command to remove its parent and make it a top-level branch: ```bash upsun environment:info -e main parent - ``` ##### 4. Make `main` the parent for other environments Without a source integration With a source integration You probably have other environments that are children of ``old``. For each environment, update its parent to ``main``: ```bash {} upsun environment:info -e parent main ``` To preserve your data on Upsun, it’s best to switch your work in progress to be based off of ``main``. Close any open pull/merge requests and resubmit them against ``main``. If you want to continue working on branches after switching the default branch, rebase them by running ``git rebase --onto main ``. Once you resubmit a request, it appears under the ``main`` environment on Upsun. ##### 5. Deactivate the `old` branch To change your default branch, you first need to deactivate the existing default branch to remove protections. Deactivate the `old` environment without deleting it by running the following CLI command: ```bash upsun environment:delete --no-delete-branch old ``` ##### 6. Set `main` as the default branch Without a source integration With a source integration Once ``old`` has been deactivated, set the project’s default branch to ``main``: ```bash {} upsun project:info default_branch main ``` Set the project’s default branch in Upsun to ``main``: ```bash {} upsun project:info default_branch main ``` Follow the instructions to change the default branch to ``main`` for your provider: - [GitHub](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-branches-in-your-repository/changing-the-default-branch) - [GitLab](https://docs.gitlab.com/ee/user/project/repository/branches/default.md#change-the-default-branch-name-for-a-project) - [BitBucket](https://community.atlassian.com/t5/Bitbucket-questions/How-to-change-MAIN-branch-in-BitBucket/qaq-p/977418) ##### 7. Update DNS records Whether or not you're using a CDN, if your site is live you have probably added a Upsun address somewhere when configuring a [custom domain](https://docs.upsun.com../domains/steps.md). If you have a CDN, it's with the CDN provider. If you don't have a CDN, it's probably a `CNAME` record. In either case, the setting probably has the old environment name as part of it. Update the setting to use the new environment name. Verify that the new URL is correct by comparing it to the result from this command: ```bash upsun environment:info edge_hostname ``` ##### 8. Optional: Delete the `old` environment If you no longer want the `old` environment, such as to stop accidental use, delete it completely: ```bash upsun environment:delete --delete-branch old ``` ### Set an environment's visibility to search engines When you have preview environments, you don't want search engines indexing them and diluting the SEO of your production site. Search engine indexers are told to ignore all preview environments. When you're ready to go live, give your production environment a [custom domain](https://docs.upsun.com../domains/steps.md) and then set it to be visible to search engines. To change your production environment's visibility to search engines, follow these steps: - Select the project where you want to change visibility. - From the **Environment** menu, select your production environment. - Click Settings **Settings**. - In the row with **Hide from search engines**, click **Edit **. - Select or clear the **Hide from search engines** checkbox. Upsun can't guarantee that indexers follow the instructions. If you're concerned about access, set up [HTTP access control](https://docs.upsun.com/environments/http-access-control.md). ##### How it's done When the **Hide from search engines** is activated, search engines are turned away from environments by including a `X-Robots-Tag` header: ```txt X-Robots-Tag: noindex, nofollow ``` That tells search engine indexers to not index these sites and not traverse links from these sites. This helps keep non-Production sites out of search engine indexes. It's automatically on for all `upsun.site` domains, and it's automatically off for production environments with a custom domain. ##### Alternative method You can also send instructions to search engine indexers using a `robots.txt` file. Your app can serve this as a static file from its disk or as a dynamic response from its `passthru`. Control either with the [`location` section of your app configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#locations). If your `robots.txt` file includes instructions to ignore a page, search engine indexers may ignore it even if you have configured Upsun to not send the header. ### Change a project's region To host your project data, Upsun offers several [regions](https://docs.upsun.com../development/regions.md). You specify a region when you create a project. You can also change the project's region after it's created. ##### Why migrate between regions - Different data centers are located in different geographic areas. You may want your site close to your users for improved performance. - You may want to move to a region with a lower [environmental impact](https://docs.upsun.com../development/regions.md#environmental-impact). ##### 1. Plan the migration Before starting the migration process, you need to plan for it: - Plan a time frame in which to handle the migration. Your code shouldn't change during this time to ensure all changes are copied to the new project. Prepare for a brief site outage when you migrate, just as with a relaunch of a site. - Set your DNS Time-to-Live as low as possible. This ensures the switch to the new site propagates as quickly as possible. ##### 2. Create a new project In the target region, [create a new project from scratch]( https://console.upsun.com/org/create-project/info?_utm_campaign=cta_deploy_marketplace_template&utm_source=public_documentation&_utm_medium=organic ). If you plan to test for long, start with the least amount of resources on the project and then upsize it before switching the DNS. ##### 3. Add code and environments Select your newly created blank project. - Push the code for your production branch: ```bash {} upsun push --target ``` - (Optional) Checkout other branches and then push their code: ```bash {} upsun push --activate --target --parent ``` For a [source integration](https://docs.upsun.com/integrations/source.md) with GitHub, BitBucket, or GitLab, add the integration to your new project. Your new project then mirrors the configured repository automatically. ##### 4. Copy files If you have files in a mount, first download them: ```bash upsun mount:download ``` Then upload them to your new project: ```bash upsun mount:upload ``` See more options on [how to export files](https://docs.upsun.com/learn/tutorials/exporting.md) and [how to import files](https://docs.upsun.com/learn/tutorials/migrating/from-psh.md#6-import-data). ##### 5. Copy data from services For services with generated data such as Solr and Redis, you don't need to copy data directly. Just rebuild the data in the new project. To download data from persistent services such as databases, see how to export and then import data for each service: - [InfluxDB](https://docs.upsun.com../add-services/influxdb.md#export-data) - [MongoDB](https://docs.upsun.com../add-services/mongodb.md#exporting-data) - [MariaDB/MySQL](https://docs.upsun.com../add-services/mysql.md#exporting-data) - [PostgreSQL](https://docs.upsun.com../add-services/postgresql.md#exporting-data) ##### 6. Migrate variables and project settings Make sure anything else connected to your old project is moved to your new project: - If you have project or environment variables defined on your old project, add them to your new project. Get a list of all variables set outside of code by running `upsun variables`. - Add any users to your new project that you want to continue to have access. - Add any existing [integrations](https://docs.upsun.com../integrations.md). ##### 7. Test the site Verify that the new site is working as desired before continuing. You can leave the two projects running for as long as you need. After you have finished all your testing, sync all your data (code, files, database) for the last time. ##### 8. Switch to the new site Now that you know the new project works, switch public traffic to that site: 1. Make sure your new project has the right plan size. 2. If possible, put your site into read-only mode or maintenance mode. 3. Add your domain names to your new project and remove them from the old project. 4. (Optional) Add any custom SSL certificates you have. 5. Update your DNS provider's records to point to the new site. See more on [setting custom domains](https://docs.upsun.com../domains/steps.md). It may take some time for the DNS change and SSL change to propagate. Until it does, some browsers may not see the new site or may get an SSL mismatch error. In most cases that resolves itself in 1--3 hours. ##### 9. Remove the old project Once the new project is running and the DNS has fully propagated, delete the old project. ##### Alternative process Although not directly supported by Upsun, an agency named [Contextual Code](https://www.contextualcode.com/) has built a bash migration script. This script automates most common configurations. If your site is a typical single app with a single SQL database, the script should take care of most of the process for you. See more at the [Upsun Project Migration repository](https://gitlab.com/contextualcode/platformsh-migration). ### Change the project timezone The project timezone affects [automated backups](https://docs.upsun.com../environments/backup.md). The project timezone doesn't affect: - [App runtime](https://docs.upsun.com/create-apps/timezone.md). - [Cron jobs](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#crons). - [System logs](https://docs.upsun.com/increase-observability/logs.md). UTC is the default timezone for all logs. To change the timezone for a project, follow these steps: 1. Open the project where you want to change the timezone. 2. Click Settings **Settings**. 3. Select the timezone from the list. 4. Click **Save**. ### Delete a project To delete a project, you must be an organization owner or have the [manage plans permission](https://docs.upsun.com../administration/users.md#organization-permissions). To delete a Upsun project, including all data, code, and active environments: - Run the following command: ```bash {} upsun project:delete --project ``` - Read the consequences to deletion and enter ``y``. - Enter the project title to confirm. You are billed only for the portion of a month when the project was active. When you remove all your projects from your user account, you stop being charged. ### Set up a custom domain Once your project is ready for production, replace the automatically generated domain with your own custom domain. Note that adding a domain disables the automatically generated URL for your Production environment only. You can also [customize the URLs for your preview environments](https://docs.upsun.com/domains/steps/custom-domains-preview-environments.md). ##### Before you begin You need: - A project that's ready to go live - A domain with access to its settings with the registrar - A registrar that allows `CNAME` records or [one of the alternatives](https://docs.upsun.com/domains/steps/dns.md) on [apex domains](https://docs.upsun.com/glossary.md#apex-domain) - Optional: The [CLI](https://docs.upsun.com../../administration/cli.md) installed locally If you are planning to use several subdomains of the same domain on different projects, see how to [manage multiple subdomains](https://docs.upsun.com/domains/steps/subdomains.md) *before* you add your domain to Upsun. ##### 1. Get the target for your project You want to point your DNS record to the automatically generated URL. Your domain needs to point to that target for your site to go live. - Navigate to your production environment and click **Settings Settings**. - Select the **Domains** tab. - In the **Configure your domain** section, copy the content of the **CNAME record** field. ##### 2. Configure your DNS provider Your DNS provider (usually your registrar) is where you manage your domain. Most registrars offer similar functionalities regarding DNS configuration but use different terminology or configuration. For example, some registrars require you to use an `@` to create custom records on the apex domain, while others don't. Check your registrar's documentation. Note that depending on your registrar and the time to live (TTL) you set, it can take anywhere from 15 minutes to 72 hours for DNS changes to be taken into account. To configure your CDN and your domain name to point to your project: - Open your CDN’s management system. - Point the CDN at your [target](#1-get-the-target-for-your-project). - Open your registrar’s domain management system. - Open your registrar’s domain management system and configure your DNS zone settings to point at your CDN. The address or ``CNAME`` record to use varies by CDN provider. Refer to the official documentation of your DNS provider and CDN provider. - Check that redirects and subdomains are set correctly for the [TLS certificate ownership verification](https://docs.upsun.com/domains/troubleshoot.md#ownership-verification). - [Disable the router cache](https://docs.upsun.com/domains/cdn.md#disable-the-router-cache). - Optional: For increased security and to prevent the CDN from being bypassed, you can force all traffic to [go through the CDN](https://docs.upsun.com/domains/cdn.md#prevent-direct-access-to-your-server). - Optional: If you have multiple domains you want to be served by the same app, add a ``CNAME`` record for each of them. That includes the ``www`` subdomain if you are using it in your [routes configuration](https://docs.upsun.com/define-routes.md). Adding a custom domain sets your site as [visible to search engines](https://docs.upsun.com/environments/search-engine-visibility.md#how-its-done). See how you can further [configure your CDN](https://docs.upsun.com/domains/cdn.md). ##### 3. Set your domain Add a single domain to your project: - Select the project where you want to add a domain. - Click Settings **Settings**. - Click **Domains**. - In the **Domain** field, enter your domain. - Click **Add domain**. ##### What's next * [Use a content delivery network](https://docs.upsun.com../cdn.md) * [Use subdomains across multiple projects](https://docs.upsun.com/domains/steps/subdomains.md) * [Use a custom TLS certificate](https://docs.upsun.com/domains/steps/tls.md) #### DNS management and apex domains Using `CNAME` records helps [prevent downtime](#cname-records) during maintenance operations. But `CNAME` records can't point to apex domains, so you need to [set up a workaround](#workarounds-for-apex-domains). Available workarounds depend on your DNS provider. ###### `CNAME` records Each site on Upsun is made up of a set of containers. To map incoming requests to the appropriate container, Upsun runs routers in [each region](https://docs.upsun.com../../development/regions.md). A router's IP address can change in two cases: - During an upgrade or maintenance operation, routers can be taken offline while changes are applied. - During a region upscale or downscale, routers can be added or removed. In such situations, using `A` records can cause downtime. `A` records map a domain to an IP address. When a router's IP address changes, you need to manually update your `A` records. Your site remains offline until you do, or until the router is back from maintenance. To prevent downtime, create `CNAME` records through your DNS provider. `CNAME` records map a domain to another. Set up your `CNAME` records to point at your project's [target URL](https://docs.upsun.com../../domains/steps.md#1-get-the-target-for-your-project). The DNS record for this target URL automatically resolves to the IP addresses of the routers in your project's region. When a router's IP address changes, the DNS record is automatically and immediately updated. This prevents downtime without intervention from you. Note that `CNAME` records can't point to [apex domains](https://docs.upsun.com/glossary.md#apex-domain). Check with your DNS provider if they offer [workarounds](#workarounds-for-apex-domains). ###### Workarounds for apex domains Although `CNAME` records can't point to apex domains, most DNS providers offer workarounds. Contact your DNS provider and choose the option that works for you. If you use a CDN, you likely already have a workaround in place, such as with [Fastly](https://docs.upsun.com../cdn/fastly.md#3-handle-apex-domains) and [Cloudflare](https://docs.upsun.com../cdn/cloudflare.md#3-handle-apex-domains). ####### Custom records Some DNS providers offer custom records such as `ANAME`, `ALIAS` or `HTTPS` records, which you can manage like `CNAME` records. But unlike `CNAME` records, these custom records can point to apex domains. To use custom records, follow the instructions on [how to set up a custom domain](https://docs.upsun.com/domains/steps.md). When you come to configuring your DNS provider, instead of a `CNAME` record, add a custom record pointing from your domain to [your project's target URL](https://docs.platform.sh/domains/steps.md#2-get-the-target-for-your-project). ####### Domain forwarding If your DNS provider doesn't support custom records, consider using domain forwarding. If your domain is `example.com`, domain forwarding redirects all requests from `example.com` to `www.example.com`. To use domain forwarding, follow these steps: 1. Make the `www.` version of your site the default (canonical) version and configure your app and routes to [use the `www` subdomain as `upstream`](https://docs.upsun.com../../define-routes.md). 2. Follow the instructions on [how to set up a custom domain](https://docs.upsun.com/domains/steps.md). When you come to configuring your DNS provider, instead of a `CNAME` record, add a record forwarding requests from `` to `www.`. ####### Redirection service If your DNS provider doesn't support custom records or domain forwarding, consider using a redirection service. If your domain is `example.com`, a redirection service uses an `A` record to redirect all requests from `example.com` to `www.example.com`. To use a redirection service, follow these steps: 1. Make the `www.` version of your site the default (canonical) version and configure your app and routes to [use the `www` subdomain as `upstream`](https://docs.upsun.com../../define-routes.md). 2. Follow the instructions on [how to set up a custom domain](https://docs.upsun.com/domains/steps.md). When you come to configuring your DNS provider, instead of a `CNAME` record, add an `A` record pointing from your domain to the redirection service. ####### `A` records If your DNS provider doesn't support any other workaround, consider using `A` records, but only as a last resort. When you use `A` records, [if a router's IP address changes](#cname-records), you need to update your `A` records manually. Until you do, your site can appear offline because requests are lost. To use `A` records, follow these steps: 1. [Get the IP addresses](https://docs.upsun.com/development/regions.md#public-ip-addresses) of your project's production environment. 2. Follow the instructions on [how to set up a custom domain](https://docs.upsun.com/domains/steps.md). When you come to configuring your DNS provider, instead of a `CNAME` record, add `A` records pointing from your domain to each of the IP addresses from step 1. When a request comes in, one of those IP addresses is used at random. #### Configure a third-party TLS certificate Upsun automatically provides standard Transport Layer Security (TLS) certificates for all sites and environments. These certificates are issued at no charge by [Let's Encrypt](https://letsencrypt.org/) and cover most needs. To use them, you need to [specify HTTPS routes](https://docs.upsun.com../../define-routes/https.md#enable-https). Note that some [limitations](https://docs.upsun.com../../define-routes/https.md#lets-encrypt-limitations) apply. Upsun allows you to use third-party TLS certificates free of charge. You can use many kinds of custom certificates, including domain-validated, extended validation, high-assurance, or wildcard certificates. Consult your TLS issuer for pricing and instructions on how to generate a TLS certificate. Seven days before a third-party custom certificate is due to expire, Upsun replaces it with a new default Let’s Encrypt certificate. This helps prevent downtime. To avoid switching to a default certificate, make sure you replace your custom certificate with an updated one more than seven days before its expiration date. Note that custom certificates aren't necessary for preview environments. Wildcard certificates that cover all `*.platform.sh` domains, including preview environments, are automatically provided. ####### Add a custom certificate You can add a custom certificate using the [CLI](https://docs.upsun.com../../administration/cli.md) or in the [Console](https://docs.upsun.com../../administration/web.md). Your certificate has to be in PKCS #1 format and start with `-----BEGIN RSA PRIVATE KEY-----`. If it doesn't start that way, [change the format](#change-the-private-key-format). To add your custom certificate, follow these steps: For example: ```bash {} upsun domain:add secure.example.com --cert /etc/TLS/private/secure-example-com.crt --key /etc/TLS/private/secure-example-com.key ``` You can optionally include intermediate SSL certificates by adding ``‐‐chain `` for each one. - Redeploy your production environment with the following command: ```bash {} upsun environment:redeploy ``` - Open the project where you want to add a certificate. - Click Settings **Settings**. - Click **Certificates**. - Click **+ Add**. - Fill in your private key, public key certificate, and (optionally) intermediate SSL certificates. - Click **Add Certificate**. - Access your production environment. - Click More **More**. - Click **Redeploy**. ####### Change the private key format The expected format for your certificate’s private key is PKCS #1. Private keys in PKCS #1 format start with `-----BEGIN RSA PRIVATE KEY-----`. If your private key starts with `-----BEGIN PRIVATE KEY-----`, it’s in PKCS #8 format, which isn’t appropriate. To convert your private key (`private.key`) from PKCS #8 to PKCS #1 format (`private.rsa.key`), run the following command: ```bash openTLS rsa -in private.key -out private.rsa.key ``` #### Handle subdomains across different projects You can host multiple subdomains, such as `foo.example.com` and `bar.example.com`, within a single project using [routes](https://docs.upsun.com../../define-routes.md). If you try to use a subdomain that's used in another project, you get an error like the following: ```text This domain is already claimed by another service ``` You need to add a DNS record to make it clear you explicitly allow multiple projects to use the domain. ###### Enable subdomains across multiple projects To ensure multiple projects can use subdomains of the same apex domain, add a specific `TXT` DNS record for your apex domain. The `TXT` record should look like the following: ```text _public-suffix-root. TXT "public-suffix-root=" ``` This adds your domain to the [Upsun implementation of the Public Suffix List](#why-this-is-necessary). After you add your subdomains, remove the `TXT` record to reinstate [subdomain hijacking protection](#subdomain-hijacking-protection). This ensures no other users can possibly add a subdomain of your domain to their project. Even if you don’t remove the record, your DNS records should prevent others from using a subdomain as long as you don’t use wildcards records pointing at Upsun. However, if you don't remove the `TXT` record, restrictions apply on the apex domain. For example, you can't add the apex domain to another project until you remove the `TXT` record. ###### Bypass locked domains In certain cases (such as if your domain was added manually by Upsun support), your domain may be reserved for the project you added it to. Then you can't set up a second project with the bare domain (`example.com`) or a subdomain (`foo.example.com`). If that happens, [contact support](https://docs.upsun.com/learn/overview/get-support.md). Include the project ID of the project that already has the domain. ###### Why this is necessary ####### The Public Suffix List Domain names are segmented into different hierarchical levels, separated by a `.`. The right-most portion of the domain, such as `.com`, `.edu`, and `.fr`, is known as the top-level domain (TLD). Most applications, including web browsers, handle TLDs specially, such as by restricting certain actions. For example, a webpage at `foo.bar.baz.example.com` can usually set a cookie that's keyed to any of the following: - `foo.bar.baz.example.com` - `bar.baz.example.com` - `baz.example.com` - `example.com` So a single site can be segmented across different subdomains but use a single account login cookie. But this webpage *can't* set cookies keyed to all `.com` domains, which would be a security risk. Other restrictions apply to TLDs, but cookies are the most basic example. Aside from true TLDs, browser makers have a list of domain suffixes that should get the same special handling called the [Public Suffix List (PSL)](https://publicsuffix.org/). If you add the `example.com` domain to the PSL, browsers refuse to set a cookie on `example.com` from a page at `foo.example.com`. They still accept cookies from a page at `example.com`. ####### Subdomain hijacking protection By default, a given domain can be used by only one project at a time. This security measure prevents malicious actions such as registering a project with the `evil.example.com` subdomain and using that to set cookies on your `example.com` website. When you add a domain to a project, the first level of the domain not in the [PSL](#the-public-suffix-list) is reserved. So if you add `foo.bar.baz.example.com` to a project, that project has `example.com` reserved within Upsun and no other project can have a domain anywhere in `*.example.com`. You can add multiple subdomains within that one project. Subdomain hijacking protection ensures that no other users can add a subdomain to their project as long as you don't use wildcard DNS records pointing at Upsun. In most cases, that's a desirable added layer of security. But you may run into a problem when you want multiple subdomains from the same organization as separate projects. One option would be to add `example.com` to the PSL, but you might not want or be able to do that. To limit what domains get protected, Upsun supports a small extension to the PSL. When you add a `TXT` record for your domain, Upsun treats that domain as part of the PSL. So when you add a `TXT` record for `example.com`, Upsun treats `example.com` as a top-level domain. That means it isn't reserved and is open for other projects. Then when you add a domain, the next level down from `example.com` is reserved. So if you add `foo.bar.baz.example.com` to a project, `*.baz.example.com` is reserved for that project. You can add `beep.example.com` to a different project without any issues. You can do the same for any level of subdomain. So if you set a `TXT` record for `baz.example.com` and add `foo.bar.baz.example.com` to a project, `*.bar.baz.example.com` is reserved for that project. Nothing at a higher level is reserved. #### Set up a custom domain on a preview environment [Preview environments](https://docs.upsun.com/glossary.md#preview-environment) in your project can't use the custom domain [set up on your production environment](https://docs.upsun.com../steps.md). By default and for each preview environment, Upsun automatically replaces the custom production domain with an automatically generated URL. If you don't want to use these default URLs, you can add a custom domain to each of your preview environments (`staging` or `development` [environment types](https://docs.upsun.com/glossary.md#environment-type)). To do so, no need to modify your [routes configuration](https://docs.upsun.com../../define-routes.md). When you add a new custom domain for a preview environment, just attach it to the custom production domain it replaces. If you have multiple custom production domains, you need to select which one you're replacing. **Example**: You have two environments, a production environment and a staging environment. You’ve added the ``example.com`` custom domain to your production environment. You want to add the ``staging.example.com`` custom domain to your staging environment. To do so, you need to attach the new ``staging.example.com`` custom domain to its corresponding custom production domain ``example.com``. You can then access your staging environment through ``staging.example.com``, and still access your production environment through ``example.com``. If you have multiple custom domains on your production environment, when you set up a custom domain on a preview environment, you don't need to update your [routes configuration](https://docs.upsun.com../../define-routes.md) either. Upsun automatically figures out the routing of your preview environment based on the following elements: - The custom production domains in your existing [routes configuration](https://docs.upsun.com../../define-routes.md) - The custom domains for preview environments attached to each of those custom production domains ###### Before you start You need: - A production environment with at least one custom domain already set up - At least one preview (staging or development) environment - Optional: The [Upsun CLI](https://docs.upsun.com../../administration/cli.md) (v4.8.0+) To prevent abuse, by default you can add custom domains to up to 5 preview environments per project only. This limit doesn't include the production environment, and you can increase it without charge. To do so, [contact Support](https://docs.upsun.com/learn/overview/get-support.md). **Note**: If you delete a custom production domain, all of the attached custom domains for preview environments are deleted too. You need to rebuild the affected preview environments for the deletion to be complete. ###### Add a custom domain to a preview environment To add a custom domain to a preview environment, follow these steps: - [Configure your DNS provider](https://docs.upsun.com/domains/steps.md#2-configure-your-dns-provider). In particular, make sure your DNS record points to the target of your preview environment. **Note**: Using the target of your production environment to configure your DNS provider is technically possible, but Upsun recommends using the target of your preview environment as a best practice. - Run a command similar to the following: ```bash {} upsun domain:add staging.example.com --environment --attach ``` - Get the target for your preview environment. To do so, navigate to your preview environment and click **Settings Settings**. Select the **Domains** tab. In the **Configure your domain** section, copy the content of the **CNAME record** field. Save it for later use at step 7. - Click **Add domain**. - Name the custom domain for your preview environment. - Attach the custom domain for your preview environment to the desired production custom domain. - Click **Add**. - Click **Okay**. - [Configure your DNS provider](https://docs.upsun.com/domains/steps.md#2-configure-your-dns-provider). In particular, make sure your DNS record points to the target of your preview environment. **Note**: Using the target of your production environment to configure your DNS provider is technically possible, but Upsun recommends using the target of your preview environment as a best practice. **Note**: You can’t update a custom domain when it’s used on a preview environment. You can only delete it and create a new one as a replacement. ####### Example You've added the `mysite.com` custom domain to your production environment. You now want to add the `mydev.com` custom domain to a preview environment called `Dev`. To do so, follow these steps: - Get the target for ``Dev``. To do so, navigate to ``Dev`` and click **Settings Settings**. Select the **Domains** tab. In the **Configure your domain** section, copy the content of the **CNAME record** field. Save it for later use at step 7. - Click **Add domain**. - Enter ``mydev.com`` as a name for the custom domain you want to add to ``Dev``. - Select ``mysite.com`` as the production custom domain you want to attach ``mydev.com`` to. - Click **Add**. - Click **Okay**. - [Configure your DNS provider](https://docs.upsun.com/domains/steps.md#2-configure-your-dns-provider). In particular, make sure your DNS record points to ``Dev``’s target. In the above example, the `Dev` environment needs to exist for you to add the `mydev.com` custom domain successfully. If the `Dev` environment is later removed, the `mydev.com` custom domain is removed too. ###### List the custom domains of a preview environment - Navigate to your preview environment and click **Settings Settings**. - Select the **Domains** tab. All the custom domains for your preview environment are displayed. ###### Get a specific custom domain used on a preview environment - Navigate to your preview environment and click **Settings Settings**. - Select the **Domains** tab. All the custom domains for the selected environment are displayed. - To see which actions you can perform on a displayed custom domain, click **More More** next to it. ###### Remove a custom domain from a preview environment - Navigate to your preview environment and click **Settings Settings**. - Select the **Domains** tab. All the custom domains for the selected environment are displayed. - Click **More More** on the custom domain you want to delete. - Click **Delete**. - Click **Yes, delete**. ### Content delivery networks (CDNs) Using a CDN speeds up the delivery of your site's content to its users. The CDN deploys edge servers at many locations around the world. These edge servers behave like local caches to nearby users. Bringing content closer to users helps enhance your site's perceived performance and so can improve user engagement and retention. Fastly is the recommended CDN for Upsun projects. Self-service projects don't include a CDN by default, but you can set up one at any time, such as [Fastly](https://docs.upsun.com/domains/cdn/fastly.md) or [Cloudflare](https://docs.upsun.com/domains/cdn/cloudflare.md). ##### DNS records To start routing client traffic through your CDN, [set up a custom domain](https://docs.upsun.com../steps.md). If you use `CNAME` records for your custom domain, these records [can't point to apex domains](https://docs.upsun.com../steps/dns.md). But most CDN providers offer workarounds. For example, Fastly offers [Anycast options](https://docs.upsun.com/domains/cdn/fastly.md#3-handle-apex-domains) and Cloudflare offers [`CNAME` flattening](https://docs.upsun.com/domains/cdn/cloudflare.md#3-handle-apex-domains). ##### Host header forwarding When an HTTP request is made to a website, the client adds a `Host` header to the request. The value of this header is the domain name the request is made to. When a server hosts multiple websites, like what a CDN does, it can use the `Host` header to identify which domain to access to handle the request. When a request is made from a client to fetch a resource on a CDN edge server, the `Host` header value is rewritten to point to the CDN. If the requested resource isn't cached on the edge server, the edge server makes a request to the Upsun server to pull and cache the resource. For this process to be successful, set an `X-Forwarded-Host` header to forward the original `Host` header value to the Upsun server. Use your root domain as the value of your `X-Forwarded-Host` header, for example: `example.com`. To ensure your app handles the `X-Forwarded-Host` header, you might need to adjust your app configuration. For more information on how to set up an `X-Forwarded-Host` HTTP header, see your CDN provider's official documentation. ##### Disable the router cache When you use a CDN, the Upsun router [HTTP caching](https://docs.upsun.com../../define-routes/cache.md) becomes redundant. To disable it, change your cache configuration for the routes behind a CDN to the following: ```yaml {location=".upsun/config.yaml"} routes: "https://{default}/": type: upstream upstream: "myapp:http" cache: # Disable the HTTP cache on this route. It's handled by the CDN instead. enabled: false ``` ##### Prevent direct access to your server When you use a CDN, you might want to prevent direct access to your Upsun server for security purposes. ###### IP filtering and HTTP auth While using password or IP based authentication might be possible, it is insecure, and unreliable. There are many scenarios in which the implementation can fail, and the security features circumvented. Furthermore, IP based filtering will usually be impossible due to the fact that most CDNs use the `x-forwarded` HTTP header, which your project origin will use as the visitor IP address. Both methods are highly insecure, and we highly recommend against them. ###### Enable mTLS If your CDN provider supports it, you can secure your site through [mTLS](https://docs.upsun.com../../define-routes/https.md#enable-mtls). To enable mTLS, follow these steps: 1. Obtain an Origin Certificate Authority (CA) certificate from your CDN provider. 2. Check that the CA certificate is a `.crt` file. If the file is a `.pem` file, rename it to `cdn.crt`. 3. Add the `cdn.crt` file to your Git repository. 4. Change your routing configuration for the routes behind a CDN to the following: ```yaml {location=".upsun/config.yaml"} routes: "https://{default}": tls: client_authentication: "require" client_certificate_authorities: - !include type: string path: cdn.crt ``` The procedure can vary depending on your CDN. Contact your CDN provider for specific assistance. Note that mTLS is a mutual authentication process. It allows your CDN to check that it's communicating with your Upsun server and vice versa. So in addition to the CA certificate supplied by your CDN provider, you need to [create your own TLS certificate](https://docs.upsun.com../../define-routes/https.md). #### Set up your Fastly CDN You can [use a CDN](https://docs.upsun.com/domains/cdn.md) to deliver your site's content to users more quickly. To set up a Fastly CDN with your own Fastly subscription, follow the instructions on this page. ###### Before you begin You need: - An up-and-running Upsun project - A [Fastly](https://www.fastly.com/) CDN subscription ###### 1. Avoid double-caching To avoid stale content that can't be cleared, avoid using Fastly with [HTTP caching](https://docs.upsun.com/define-routes/cache.md). For routes where Fastly is used, disable HTTP caching using the following configuration: ```yaml {location=".upsun/config.yaml"} https://{default}/: type: upstream ... cache: enabled: false ``` ###### 2. Set up your Fastly CDN To properly configure your Fastly CDN, see the Fastly official documentation on [how to get started](https://docs.fastly.com/en/guides/getting-started#_basics). Then set up a [custom domain](https://docs.upsun.com../steps.md). To get the [DNS challenge to succeed](https://docs.upsun.com../troubleshoot.md#ownership-verification), have your CDN point to your [project's target URL](https://docs.upsun.com../../domains/steps.md#1-get-the-target-for-your-project). ###### 3. Handle apex domains To start routing client traffic through Fastly, [create `CNAME` records for your domain names](https://docs.upsun.com../../domains/steps/dns.md) through your DNS provider. `CNAME` records can't point to apex domains. As a workaround, Fastly offers [Anycast options](https://docs.fastly.com/en/guides/using-fastly-with-apex-domains). ###### 4. Optional: Protect your site from on-path attacks An on-path attack occurs when a hacker intercepts or modifies the communication between a client and a server. This can lead to sensitive data leaks. To prevent such attacks, make sure all communication with your site is encrypted through HTTPS and can't be downgraded to HTTP. To do so, enable HTTP strict transport security (HSTS). HSTS forces clients to always communicate with your site over HTTPS. You can [enable HSTS](https://docs.fastly.com/en/guides/enabling-hsts-through-fastly#forcing-tls-and-enabling-hsts) in your Fastly account. All HTTP requests are then automatically redirected to HTTPS. #### Set up your Cloudflare CDN You can [use a CDN](https://docs.upsun.com/domains/cdn.md) to deliver your site's content to users more quickly. ###### Before you begin You need: - An up-and-running Upsun project - A [Cloudflare](https://www.cloudflare.com/) CDN subscription ###### 1. Avoid double-caching To avoid stale content that can't be cleared, avoid using Cloudflare with [HTTP caching](https://docs.upsun.com/define-routes/cache.md). For routes where Cloudflare is used, disable HTTP caching using the following configuration: ```yaml {location=".upsun/config.yaml"} https://{default}/: type: upstream ... cache: enabled: false ``` ###### 2. Set up your Cloudflare CDN To properly configure your Cloudflare CDN, see the Cloudflare official documentation on [how to get started](https://developers.cloudflare.com/cache/get-started/). Then set up a [custom domain](https://docs.upsun.com../steps.md). To get the [DNS challenge to succeed](https://docs.upsun.com../troubleshoot.md#ownership-verification), have your CDN point to your [project's target URL](https://docs.upsun.com../../domains/steps.md#1-get-the-target-for-your-project). ###### 3. Handle apex domains To start routing client traffic through Cloudflare, you need to [create `CNAME` records for your domain names](https://docs.upsun.com../../domains/steps/dns.md) through your DNS provider. But `CNAME` records can't point to apex domains. As a workaround, Cloudflare offers [`HTTPS` records](https://developers.cloudflare.com/dns/manage-dns-records/reference/dns-record-types/#svcb-and-https) and [`CNAME` flattening](https://developers.cloudflare.com/dns/additional-options/cname-flattening/). ###### 4. Mitigate security risks Like all networks exposed to the internet, your origin server may become the target of security attacks. The best way to protect your site from threats like on-path attacks, spoofing attacks, or credential stuffing, is to configure mutual TLS (mTLS). [mTLS](https://www.cloudflare.com/en-gb/learning/access-management/what-is-mutual-tls/) not only has both parties in a connection authenticate each other through the TLS protocol. It also ensures that requests can't be sent directly to the origin server (Upsun). Instead, requests must transit through Cloudflare first. **Note**: mTLS is only compatible with environments where you have attached domains you own, meaning: - Your production environment - Each preview environment where you have [attached a custom domain](https://docs.upsun.com/domains/steps/custom-domains-preview-environments.md) Therefore, mTLS is **not** compatible with preview environments created by a [source code integration](https://docs.upsun.com/integrations/source.md). If you can't use mTLS, you can still take the following measures to protect your site from on-path attacks: 1. [Enable full strict SSL/TLS encryption](https://developers.cloudflare.com/ssl/origin-configuration/ssl-modes/full-strict/). Any communication between a client and Cloudflare or between Cloudflare and your Upsun server is then encrypted through HTTPS. In addition, Cloudflare checks that your Upsun server's [TLS certificate](https://docs.upsun.com/glossary.md#transport-layer-security-tls) was issued by a trusted certificate authority. This confirms the client is truly communicating with your Upsun server. 2. [Enable HTTP strict transport security (HSTS)](https://developers.cloudflare.com/ssl/edge-certificates/additional-options/http-strict-transport-security/). This ensures that your HTTPS connections can't be downgraded to HTTP. ### Going Live - Troubleshooting If your site doesn’t resolve after you’ve made DNS changes, check potential solutions to common issues. ##### Verify DNS On the command line using macOS, Linux, or the Windows Subsystem for Linux, run the following command: ```bash host www. ``` If your domain is `example.com`, the response should be something like the following: ```text www.example.com is an alias for main-abcd123.abcdefgh1234567.eu.platformsh.site main-abcd123.abcdefgh1234567.eu.platformsh.site has address 192.0.2.1 ``` If it isn't, try the following steps: - Your DNS server might not be correctly configured or the old DNS records are still cached. Try removing your local DNS cache. - Set your computer's DNS server to any Public DNS resolver (like [CloudFlare](https://developers.cloudflare.com/1.1.1.1/) or [Google](https://developers.google.com/speed/public-dns/docs/using)) to see if the issue is with the DNS server you are using. - Run `ping www.`. If the result is different from what you got from running `host www.`, you might need to remove your test settings. ##### Verify SSL/TLS encryption To find out where your domain is pointing to, you can use [the certificate checker tool](https://certcheck.pltfrm.sh/). This tool provides guidance on certificates, including when you use a [CDN](https://docs.upsun.com/domains/cdn.md). Check both the apex and the `www` domains to ensure they both point to your project. For further investigations, run the following command in a shell: ```bash curl -I -v https://www. ``` Look for error messages. Often the problem is caused by a mismatch between the certificate and the domain name or an expired [custom certificate](steps/tls.md). ###### Error provisioning certificates When a Let's Encrypt certificate fails to provision after the build hook has completed, you get output similar to the following: ```bash Provisioning certificates Validating 2 new domains E: Error validating domains: urn:ietf:params:acme:error:rejectedIdentifier :: The server will not issue certificates for the identifier :: NewOrder request did not include a SAN short enough to fit in CN Unable to validate domains domain a-new-and-really-awesome-feature-abc1234-defghijk56789.eu3.platformsh.site, www.domain a-new-and-really-awesome-feature-abc1234-defghijk56789.eu3.platformsh.site, will retry in the background. (Next refresh will be at 2023-04-28 02:22:50.639301+00:00.) E: Error: TLS Certificate provisioning failed ``` The renewal may fail because of the 64-character limit Let's Encrypt places on URLs. If you have a branch with a long name, the environment URL is over this limit and the certificate is rejected. To solve this, shorten your branch name so it doesn't exceed 20 characters. Generated URLs for environments have the following pattern: ```bash -..platformsh.site ``` If you have a [default domain](https://docs.upsun.com../define-routes.md#default) set up, the generated URL has the following pattern: ```bash .-..platformsh.site ``` The generated URLs consist of: - `` = the amount of characters your domain has - `` = `` + 7 character hash - `` = 13 characters - `` = 2 to 4 characters, depending on the region - `platformsh.site` = 15 characters - extra characters like `.` and `-` = 4 to 5 characters, depending on if you have a default domain This leaves you with 21 to 23 characters for your branch name (``) without exceeding the 64-character limit, depending on the region. To ensure your renewals succeed, keep your branch names under 20 characters. ###### Ownership verification To provide a valid TLS-certificate, the certificate issuer checks that the requester is entitled to receive the requested certificate. This check is known as the _Challenge_ step. The certificate request is generated based on your [routes definition](https://docs.upsun.com../define-routes.md). If you want your site to be available with `example.com` and its `www.example.com` subdomain, make sure both are defined in your routes. To pass this verification, there are requirements you need to meet. When you use a CDN, to ensure the challenge succeeds, check that: - Your domains and subdomains point to your CDN - The [_acme-challenge.](https://www.rfc-editor.org/rfc/rfc8555#section-8.4), as in ``_acme-challenge.example.com``, points to your CDN - The [/.well-known/](https://www.rfc-editor.org/rfc/rfc8555#section-8.3), as in ``https://www.example.com/.well-known/``, is accessible with no redirects If you don’t follow those requirements, you get an error message similar to: ```text {} W: Failed to verify the challenge at the gateway for the domain 'www.example.com' E: Error validating domain www.example.com: Couldn't complete challenge [HTTP01: The client lacks sufficient authorization] ``` For more information, see how to [setup your CDN](https://docs.upsun.com/domains/cdn.md). For more details regarding the challenge step, consult your certificate issuer’s documentation. A common issuer is [Let’s Encrypt](https://letsencrypt.org/docs/challenge-types/). Make sure that the [apex domain](https://docs.upsun.com/glossary.md#apex-domain) and its `www` subdomain are both pointing where needed. Note that it can take up to 72 hours for DNS changes to be effective. For more information, see how to [set up a custom domain](https://docs.upsun.com../domains/steps.md). If the changes take longer than expected, [redeploy](https://docs.upsun.com../development/troubleshoot.md#force-a-redeploy) the impacted environment. Also make sure that no conflicting DNS records exist for your domain. For example, a conflicting AAAA (IPv6) DNS record can result in a `[HTTP01: The client lacks sufficient authorization]` error. If the certificate generation issue persists, check if an outage is ongoing with your certificate issuer (the most common one is [Let's Encrypt](https://letsencrypt.status.io/)) and with your CDN provider if you have one. If not, [contact Support](https://docs.upsun.com/learn/overview/get-support.md). ###### Check your routes configuration Certificates are generated based on your [routes configuration](https://docs.upsun.com../define-routes.md). When a certificate is renewed, the renewal bot checks that all of the defined routes can be accessed. If at least one of the routes defined in your `.upsun/config.yaml` file can't be accessed, the renewal fails and the following error is displayed: ``` Provisioning certificates Validating 2 new domains W: Failed to verify the challenge at the gateway for the domain 'www.example.com' E: Error validating domain www.example.com: Couldn't complete challenge [HTTP01: There was a problem with a DNS query during identifier validation] Unable to validate domains www.example.com, will retry in the background. (Next refresh will be at 2023-07-04 17:43:10.259891+00:00.) Certificates - certificate 61bc4c8: expiring on 2023-09-02 01:11:12+00:00, covering sdgs.un.org E: Error: TLS Certificate provisioning failed ``` For example, if you add `example.com` and `www.example.com` to your routes configuration but the `www` subdomain doesn't point to your project through [a `CNAME` record](https://docs.upsun.com/domains/steps/dns.md#cname-records), the certificate renewal fails. For the renewal to succeed, add the missing `CNAME` record to your DNS or remove `www.example.com` (and any other `www` route) from your `.upsun/config.yaml` file. ##### Verify your application Check your app's logs and look for anomalies. On the command line type `upsun logs app` and `upsun logs error`. ##### Use ASCII for the domain Upsun expects an ASCII representation of your domain. To use an internationalized domain name (IDN), convert it to ASCII. Use a tool such as the [conversion tool provided by Verisign](https://www.verisign.com/en_US/channel-resources/domain-registry-products/idn/idn-conversion-tool/index.xhtml). ##### Something still wrong? For more general information, see how to [troubleshoot development](https://docs.upsun.com/development/troubleshoot.md). If your website is still not working as expected, [contact support](https://docs.upsun.com/learn/overview/get-support.md). ### Command line interface (CLI) See how to use and manage your Upsun projects directly from your terminal. Anything you can do within the Console can be done with the CLI. The CLI uses the git interface and the [Upsun REST API](https://api.platform.sh/docs/) to accomplish tasks. Its source code is hosted on [GitHub](https://github.com/platformsh/cli). ##### 1. Install To install the CLI, use a [Bash installation script](https://github.com/platformsh/cli#user-content-bash-installer). You can also install with [Homebrew](https://brew.sh/) (on Linux, macOS, or the Windows Subsystem for Linux) or [Scoop](https://scoop.sh/) (on Windows). ```bash {} brew install platformsh/tap/upsun-cli ``` ```bash {} scoop bucket add platformsh https://github.com/platformsh/homebrew-tap.git scoop install upsun ``` ##### 2. Authenticate To list and manage your projects, authenticate by running the following command: ```bash upsun ``` This process opens a browser tab for you to log in. It also creates certificates on your computer for [SSH](https://docs.upsun.com../../development/ssh.md). Once you are logged in, a list of your projects appears, along with some tips for getting started. If you experience authentication issues or want to force a login, run the command `upsun login`. ##### 3. Use Now you can run actions on your projects such as branching and merging. You can also simulate a local build of your codebase as if you were pushing a change to Upsun, including your services and data. Get a list of all available commands with: ```bash upsun list ``` To get more information on a specific command, preface it with `help`: ```bash upsun help get ``` You get output similar to the following: ```bash Command: project:get Aliases: get Description: Clone a project locally Usage: upsun get [-e|--environment ENVIRONMENT] [--depth DEPTH] [--build] [-p|--project PROJECT] [--host HOST] [-i|--identity-file IDENTITY-FILE] [--] [] [] Arguments: project The project ID directory The directory to clone to. Defaults to the project title Options: -e, --environment=ENVIRONMENT The environment ID to clone. Defaults to the project default, or the first available environment --depth=DEPTH Create a shallow clone: limit the number of commits in the history --build Build the project after cloning -p, --project=PROJECT The project ID or URL --host=HOST The project's API hostname -i, --identity-file=IDENTITY-FILE An SSH identity (private key) to use -h, --help Display this help message -q, --quiet Do not output any message -V, --version Display this application version -y, --yes Answer "yes" to any yes/no questions; disable interaction -n, --no Answer "no" to any yes/no questions; disable interaction -v|vv|vvv, --verbose Increase the verbosity of messages Examples: Clone the project "abc123" into the directory "my-project": upsun get abc123 my-project ``` ###### Select the right project and environment When you are in an empty directory or a directory not associated with a specific Upsun project, if you run a command that requires a specific project and environment, you are prompted to select them. For example, if you run the following command: ```bash upsun environment:info ``` You get the following output: ```bash Enter a number to choose a project: [0] My project (xb3pfo734qxbeg) [1] A great project (3p5fmol45kxp6) [2] An even better project (rjify4y564xaa) > ``` If your working directory is inside a local checkout of your project repository, your project and environment are detected automatically. You can always specify the project and environment in two ways: * As arguments for the command: ```bash upsun environment:info --project=my-project --environment=staging ``` * With environment variables: ```bash export PLATFORM_PROJECT=my-project; export PLATFORM_BRANCH=staging; upsun environment:info ``` In [multi-app](https://docs.upsun.com../../create-apps/multi-app.md) projects, this applies also to selecting the right app (the environment variable would be `PLATFORM_APPLICATION_NAME`). ####### RootNotFoundException If you check out a project via Git directly and not using the `upsun get` command, the CLI may be unable to determine what project it's in. You might run a CLI command from within a project directory you've checked out and get an error like this: ```text [RootNotFoundException] Project root not found. This can only be run from inside a project directory. ``` Then the CLI hasn't been able to determine the project to use. To fix this, run: ```bash upsun project:set-remote --project ``` Replace `` with the ID of your project. You can find that in the Console or by running `upsun projects` to list all accessible projects. ###### Choose between the CLI and Git commands Some CLI commands (especially many within the `environment` namespace) have some overlap with Git commands. Generally, they offer more options than the Git commands alone. For example, `upsun push` offers options such as `--activate` (to activate an environment before pushing) and `--no-wait` (so you can continue working without waiting for the push to complete). For all of them, you don't need to configure a Git remote. It's enough to have a project ID. An example of how this affects commands is that when you run `upsun merge`, it doesn't affect your local codebase. You don't even need the code locally. The code is only merged between environments remotely. ###### Customize the CLI You can customize how the CLI operates and what it returns with a configuration file (`~/.upsun-cli/config.yaml`) or environment variables. For details, see the [customization instructions on GitHub](https://github.com/platformsh/legacy-cli#user-content-customization). ####### Automate repetitive tasks You might want to use the CLI in a script to automate repetitive tasks such as synchronizing your files locally. In such cases, you want to customize the CLI to bypass any confirmation questions. You can set the answer to every question as `yes` using the `UPSUN_CLI_NO_INTERACTION` environment variable. For instance, to locally sync every mount point for your app named `myapp`, you could use this command: ```bash export PLATFORM_PROJECT=my-project; export PLATFORM_BRANCH=main; export UPSUN_CLI_NO_INTERACTION=1; upsun mount:download --all --app app --target local-backup ``` ###### Autocomplete commands The CLI provides tab autocompletion for commands, options, and some values (your projects, valid regions). To enable autocompletion, follow this step: Add the following to your shell’s startup (``.bashrc``, ``.zshrc``, or the equivalent): ```bash {} eval $(upsun completion) ``` ###### Run commands on your container You can use the Upsun CLI to run commands on your container. You can use any command you've added in [dependencies](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#dependencies) or a [hook](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#hooks). The syntax looks like the following: ```bash upsun ssh -- ``` For example, to run a specific Python script named `my-script.py` on your current environment, run the following command: ```bash upsun ssh -- python my-script.py ``` Or to use [Drush](https://www.drush.org/latest/install/) to rebuild the cache on the `feature` environment, run this command: ```bash upsun ssh -e feature -- drush -y cache-rebuild ``` ###### Update the CLI To update to the latest version, use the same tool as for [installation](#1-install): ```bash {} $ scoop update upsun ``` ##### Upgrade from the legacy CLI To upgrade from the legacy CLI, follow the [installation instructions](#1-install). Once you've installed the latest version, the CLI guides you through removing the installed legacy CLI. #### Authenticate the CLI using an API token You need to set up an API token to authenticate the Upsun CLI for any of the following tasks: - Running automated tasks on a CI system - Running automated tasks directly on app container, for example in a cron job ###### Before you begin You might need the [Upsun CLI](https://docs.upsun.com../cli.md) to perform certain tasks. For example, you need the CLI to do the following: - [Check the validity of an API token](#optional-check-the-validity-of-your-api-token). - [Load the CLI SSH certificate for non-CLI commands](#use-the-cli-ssh-certificate-for-non-cli-commands). ###### 1. Create a machine user To safely run automated tasks, first create machine users. Each machine user has its own Upsun account associated with a unique email address. You can grant them restrictive [access permissions](https://docs.upsun.com../users.md) to handle specific automated tasks. For security purposes, create a machine user for each type of task you want to automate. To create a machine user, follow these steps: This sets your machine user as a viewer on your project and a contributor on development environments, with no access to other environment types. Note that you can further [adjust user roles](https://docs.upsun.com/administration/users.md#environment-type-roles) depending on your needs and each environment type. - In the email invitation, click **Create account**. - To create a Upsun account for the machine user, click **Sign up** and follow the instructions. - Go to your project and click Settings **Settings**. - In the **Project Settings** menu, click **Access**. - Click **Add**. - Enter your machine user’s email address. - For each [environment type](https://docs.upsun.com/administration/users.md#environment-type-roles), assign a role to your machine user and click **Save**. ###### 2. Create an API token 1. Log in to the Console as your machine user. 2. Open the user menu (your name or profile picture). 3. Click **My profile**. 4. Go to the **API tokens** tab and click **Create API token**. 5. Enter a name for your API token and click **Create API token**. 6. To copy the API token to your clipboard, click ** Copy**. Note that after you close the **API tokens** tab, you can't display the API token again. 7. Store the API token somewhere secure on your computer. ####### Optional: check the validity of your API token To check that your API token is valid, run the following command: ```bash upsun auth:api-token-login ``` When prompted, enter your API token. You get output similar to this: ```bash The API token is valid. You are logged in. ``` For security reasons, rotate your API tokens regularly. When an API token is compromised, revoke it immediately. ###### 3. Authenticate the CLI using your API token After you create your API token, you can use it to do the following: - Allow a CI system to run automated tasks using the Upsun CLI. - Run automated tasks on an app container using the Upsun CLI, for example in a cron job. Note that when running CLI commands in these cases, some operations might take time to complete. To avoid waiting for an operation to complete before moving on to the next one, use the `--no-wait` flag. ####### Authenticate in a CI system You can allow your CI system to run automated tasks using the Upsun CLI. To do so, create an environment variable named `UPSUN_CLI_TOKEN` with your API token as its value. For more information, see your CI system's official documentation. To run SSH-based commands that aren't specific to the Upsun CLI, see how to [load the proper SSH certificate](#use-the-cli-ssh-certificate-for-non-cli-commands). ####### Authenticate in an environment You can run automated tasks on an app container using the Upsun CLI. To do so, set your API token as a [top-level environment variable](https://docs.upsun.com../../development/variables.md#top-level-environment-variables). **Note**: Once you add the token as an environment variable, anyone with [SSH access](https://docs.upsun.com/development/ssh.md) can read its value. Make sure your [machine user has only the necessary permissions](#1-create-a-machine-user). - Open the environment where you want to add the variable. - Click Settings **Settings**. - Click **Variables**. - Click **+ Add variable**. - In the **Variable name** field, enter ``env:UPSUN_CLI_TOKEN``. - In the **Value** field, enter your API token. - Make sure the **Available at runtime** and **Sensitive variable** options are selected. - Click **Add variable**. Then add a build hook to your app configuration to install the CLI as part of the build process. ```yaml {location=".upsun/config.yaml"} hooks: build: | set -e echo "Installing Upsun CLI" curl -fsSL https://raw.githubusercontent.com/platformsh/cli/main/installer.sh | bash echo "Testing Upsun CLI" upsun ``` You can now call the CLI from within the shell on the app container or in a cron job. To run SSH-based commands that aren't specific to the Upsun CLI, see how to [load the proper SSH certificate](#use-the-cli-ssh-certificate-for-non-cli-commands). You can set up a cron job on a specific type of environment. For example, to run the `update` source operation on your production environment, use the following cron job: ```yaml 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 ``` ###### Use the CLI SSH certificate for non-CLI commands When you set a `UPSUN_CLI_TOKEN` environment variable, the CLI authentication isn't complete until your run a CLI command or load the CLI SSH certificate. For example, after setting a `UPSUN_CLI_TOKEN` environment variable, you might need to run `ssh`, `git`, `rsync`, or `scp` commands before you run any CLI commands. In this case, to ensure all your commands work, load the CLI SSH certificate first. To do so, run the following command: ```bash upsun ssh-cert:load --no-interaction ``` #### CLI Command reference #TableOfContents > ul > li > ul { display: none; } # Upsun CLI 5.0.15 - [Installation](https://docs.upsun.com/administration/cli.md#1-install) - [Open an issue](https://github.com/platformsh/cli/issues) ###### All commands * [`clear-cache`](#clear-cache) * [`decode`](#decode) * [`docs`](#docs) * [`help`](#help) * [`list`](#list) * [`multi`](#multi) * [`web`](#web) **activity** * [`activity:cancel`](#activitycancel) * [`activity:get`](#activityget) * [`activity:list`](#activitylist) * [`activity:log`](#activitylog) **app** * [`app:config-get`](#appconfig-get) * [`app:config-validate`](#appconfig-validate) * [`app:list`](#applist) **auth** * [`auth:api-token-login`](#authapi-token-login) * [`auth:browser-login`](#authbrowser-login) * [`auth:info`](#authinfo) * [`auth:logout`](#authlogout) * [`auth:verify-phone-number`](#authverify-phone-number) **backup** * [`backup:create`](#backupcreate) * [`backup:delete`](#backupdelete) * [`backup:get`](#backupget) * [`backup:list`](#backuplist) * [`backup:restore`](#backuprestore) **certificate** * [`certificate:add`](#certificateadd) * [`certificate:delete`](#certificatedelete) * [`certificate:get`](#certificateget) * [`certificate:list`](#certificatelist) **commit** * [`commit:get`](#commitget) * [`commit:list`](#commitlist) **db** * [`db:dump`](#dbdump) * [`db:sql`](#dbsql) **domain** * [`domain:add`](#domainadd) * [`domain:delete`](#domaindelete) * [`domain:get`](#domainget) * [`domain:list`](#domainlist) * [`domain:update`](#domainupdate) **environment** * [`environment:activate`](#environmentactivate) * [`environment:branch`](#environmentbranch) * [`environment:checkout`](#environmentcheckout) * [`environment:delete`](#environmentdelete) * [`environment:drush`](#environmentdrush) * [`environment:http-access`](#environmenthttp-access) * [`environment:info`](#environmentinfo) * [`environment:init`](#environmentinit) * [`environment:list`](#environmentlist) * [`environment:logs`](#environmentlogs) * [`environment:merge`](#environmentmerge) * [`environment:pause`](#environmentpause) * [`environment:push`](#environmentpush) * [`environment:redeploy`](#environmentredeploy) * [`environment:relationships`](#environmentrelationships) * [`environment:resume`](#environmentresume) * [`environment:scp`](#environmentscp) * [`environment:ssh`](#environmentssh) * [`environment:synchronize`](#environmentsynchronize) * [`environment:url`](#environmenturl) * [`environment:xdebug`](#environmentxdebug) **integration** * [`integration:activity:get`](#integrationactivityget) * [`integration:activity:list`](#integrationactivitylist) * [`integration:activity:log`](#integrationactivitylog) * [`integration:add`](#integrationadd) * [`integration:delete`](#integrationdelete) * [`integration:get`](#integrationget) * [`integration:list`](#integrationlist) * [`integration:update`](#integrationupdate) * [`integration:validate`](#integrationvalidate) **local** * [`local:dir`](#localdir) **metrics** * [`metrics:all`](#metricsall) * [`metrics:cpu`](#metricscpu) * [`metrics:disk-usage`](#metricsdisk-usage) * [`metrics:memory`](#metricsmemory) **mount** * [`mount:download`](#mountdownload) * [`mount:list`](#mountlist) * [`mount:upload`](#mountupload) **operation** * [`operation:list`](#operationlist) * [`operation:run`](#operationrun) **organization** * [`organization:billing:address`](#organizationbillingaddress) * [`organization:billing:profile`](#organizationbillingprofile) * [`organization:create`](#organizationcreate) * [`organization:delete`](#organizationdelete) * [`organization:info`](#organizationinfo) * [`organization:list`](#organizationlist) * [`organization:subscription:list`](#organizationsubscriptionlist) * [`organization:user:add`](#organizationuseradd) * [`organization:user:delete`](#organizationuserdelete) * [`organization:user:get`](#organizationuserget) * [`organization:user:list`](#organizationuserlist) * [`organization:user:projects`](#organizationuserprojects) * [`organization:user:update`](#organizationuserupdate) **project** * [`project:clear-build-cache`](#projectclear-build-cache) * [`project:create`](#projectcreate) * [`project:delete`](#projectdelete) * [`project:get`](#projectget) * [`project:info`](#projectinfo) * [`project:init`](#projectinit) * [`project:list`](#projectlist) * [`project:set-remote`](#projectset-remote) **repo** * [`repo:cat`](#repocat) * [`repo:ls`](#repols) * [`repo:read`](#reporead) **resources** * [`resources:build:get`](#resourcesbuildget) * [`resources:build:set`](#resourcesbuildset) * [`resources:get`](#resourcesget) * [`resources:set`](#resourcesset) * [`resources:size:list`](#resourcessizelist) **route** * [`route:get`](#routeget) * [`route:list`](#routelist) **service** * [`service:list`](#servicelist) * [`service:mongo:dump`](#servicemongodump) * [`service:mongo:export`](#servicemongoexport) * [`service:mongo:restore`](#servicemongorestore) * [`service:mongo:shell`](#servicemongoshell) * [`service:redis-cli`](#serviceredis-cli) **source-operation** * [`source-operation:list`](#source-operationlist) * [`source-operation:run`](#source-operationrun) **ssh-cert** * [`ssh-cert:load`](#ssh-certload) **ssh-key** * [`ssh-key:add`](#ssh-keyadd) * [`ssh-key:delete`](#ssh-keydelete) * [`ssh-key:list`](#ssh-keylist) **subscription** * [`subscription:info`](#subscriptioninfo) **team** * [`team:create`](#teamcreate) * [`team:delete`](#teamdelete) * [`team:get`](#teamget) * [`team:list`](#teamlist) * [`team:project:add`](#teamprojectadd) * [`team:project:delete`](#teamprojectdelete) * [`team:project:list`](#teamprojectlist) * [`team:update`](#teamupdate) * [`team:user:add`](#teamuseradd) * [`team:user:delete`](#teamuserdelete) * [`team:user:list`](#teamuserlist) **tunnel** * [`tunnel:close`](#tunnelclose) * [`tunnel:info`](#tunnelinfo) * [`tunnel:list`](#tunnellist) * [`tunnel:open`](#tunnelopen) * [`tunnel:single`](#tunnelsingle) **user** * [`user:add`](#useradd) * [`user:delete`](#userdelete) * [`user:get`](#userget) * [`user:list`](#userlist) * [`user:update`](#userupdate) **variable** * [`variable:create`](#variablecreate) * [`variable:delete`](#variabledelete) * [`variable:get`](#variableget) * [`variable:list`](#variablelist) * [`variable:update`](#variableupdate) **worker** * [`worker:list`](#workerlist) ###### `clear-cache` Clear the CLI cache Aliases: `cc` ####### Usage ``` upsun cc ``` ######## Options * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `decode` Decode an encoded string such as PLATFORM_VARIABLES ####### Usage ``` upsun decode [-P|--property PROPERTY] [--] ``` ######## Arguments * `value`(required) The variable value to decode ######## Options * `--property` (`-P`) (expects a value) The property to view within the variable * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * View "foo" in PLATFORM_VARIABLES: ``` upsun decode "$PLATFORM_VARIABLES" -P foo ``` ###### `docs` Open the online documentation ####### Usage ``` upsun docs [--browser BROWSER] [--pipe] [--] []... ``` ######## Arguments * `search`(optional; multiple values allowed) Search term(s) ######## Options * `--browser` (expects a value) The browser to use to open the URL. Set 0 for none. * `--pipe` Output the URL to stdout. * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Search for information about the CLI: ``` upsun docs CLI ``` ###### `help` Displays help for a command ####### Usage ``` upsun help [--format FORMAT] [--raw] [--] [] ``` The help command displays help for a given command: upsun help list You can also output the help in other formats by using the --format option: upsun help --format=json list To display the list of available commands, please use the list command. ######## Arguments * `command_name`(optional) The command name ######## Options * `--format` (expects a value) The output format (txt, json, or md) * `--raw` To output raw command help * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `list` Lists commands ####### Usage ``` upsun list [--raw] [--format FORMAT] [--all] [--] [] ``` The list command lists all commands: upsun list You can also display the commands for a specific namespace: upsun list project You can also output the information in other formats by using the --format option: upsun list --format=xml It's also possible to get raw list of commands (useful for embedding command runner): upsun list --raw ######## Arguments * `command`(required) The command to execute * `namespace`(optional) The namespace name ######## Options * `--raw` To output raw command list * `--format` (expects a value) The output format (txt, xml, json, or md) * `--all` Show all commands, including hidden ones * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `multi` Execute a command on multiple projects ####### Usage ``` upsun multi [-p|--projects PROJECTS] [--continue] [--sort SORT] [--reverse] [--] ()... ``` ######## Arguments * `cmd`(required; multiple values allowed) The command to execute ######## Options * `--projects` (`-p`) (expects a value) A list of project IDs, separated by commas and/or whitespace * `--continue` Continue running commands even if an exception is encountered * `--sort` (expects a value) A property by which to sort the list of project options * `--reverse` Reverse the order of project options * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * List variables on the "main" environment for multiple projects: ``` upsun multi -p l7ywemwizmmgb,o43m25zns6k2d,3nyujoslhydhx -- var -e main ``` ###### `web` Open the project in the Web Console ####### Usage ``` upsun web [--browser BROWSER] [--pipe] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] ``` ######## Options * `--browser` (expects a value) The browser to use to open the URL. Set 0 for none. * `--pipe` Output the URL to stdout. * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `activity:cancel` Cancel an activity ####### Usage ``` upsun activity:cancel [-t|--type TYPE] [-x|--exclude-type EXCLUDE-TYPE] [-a|--all] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [--] [] ``` ######## Arguments * `id`(optional) The activity ID. Defaults to the most recent cancellable activity. ######## Options * `--type` (`-t`) (expects a value) Filter by type (when selecting a default activity). Values may be split by commas (e.g. "a,b,c") and/or whitespace. The % or * characters can be used as a wildcard for the type, e.g. '%var%' to select variable-related activities. * `--exclude-type` (`-x`) (expects a value) Exclude by type (when selecting a default activity). Values may be split by commas (e.g. "a,b,c") and/or whitespace. The % or * characters can be used as a wildcard to exclude types. * `--all` (`-a`) Check recent activities on all environments (when selecting a default activity) * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `activity:get` View detailed information on a single activity ####### Usage ``` upsun activity:get [-P|--property PROPERTY] [-t|--type TYPE] [-x|--exclude-type EXCLUDE-TYPE] [--state STATE] [--result RESULT] [-i|--incomplete] [-a|--all] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] [--date-fmt DATE-FMT] [--] [] ``` ######## Arguments * `id`(optional) The activity ID. Defaults to the most recent activity. ######## Options * `--property` (`-P`) (expects a value) The property to view * `--type` (`-t`) (expects a value) Filter by type (when selecting a default activity). Values may be split by commas (e.g. "a,b,c") and/or whitespace. The % or * characters can be used as a wildcard for the type, e.g. '%var%' to select variable-related activities. * `--exclude-type` (`-x`) (expects a value) Exclude by type (when selecting a default activity). Values may be split by commas (e.g. "a,b,c") and/or whitespace. The % or * characters can be used as a wildcard to exclude types. * `--state` (expects a value) Filter by state (when selecting a default activity): in_progress, pending, complete, or cancelled. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--result` (expects a value) Filter by result (when selecting a default activity): success or failure * `--incomplete` (`-i`) Include only incomplete activities (when selecting a default activity). This is a shorthand for --state=in_progress,pending * `--all` (`-a`) Check recent activities on all environments (when selecting a default activity) * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Find the time a project was created: ``` upsun activity:get --all --type project.create -P completed_at ``` * Find the duration (in seconds) of the last activity: ``` upsun activity:get -P duration ``` ###### `activity:list` Get a list of activities for an environment or project Aliases: `activities`, `act` ####### Usage ``` upsun activities [-t|--type TYPE] [-x|--exclude-type EXCLUDE-TYPE] [--limit LIMIT] [--start START] [--state STATE] [--result RESULT] [-i|--incomplete] [-a|--all] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] [--date-fmt DATE-FMT] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] ``` ######## Options * `--type` (`-t`) (expects a value) Filter activities by type For a list of types see: https://docs.upsun.com/integrations/activity/reference.html#type Values may be split by commas (e.g. "a,b,c") and/or whitespace. The first part of the activity name can be omitted, e.g. 'cron' can select 'environment.cron' activities. The % or * characters can be used as a wildcard, e.g. '%var%' to select variable-related activities. * `--exclude-type` (`-x`) (expects a value) Exclude activities by type. Values may be split by commas (e.g. "a,b,c") and/or whitespace. The first part of the activity name can be omitted, e.g. 'cron' can exclude 'environment.cron' activities. The % or * characters can be used as a wildcard to exclude types. * `--limit` (expects a value) Limit the number of results displayed * `--start` (expects a value) Only activities created before this date will be listed * `--state` (expects a value) Filter activities by state: in_progress, pending, complete, or cancelled. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--result` (expects a value) Filter activities by result: success or failure * `--incomplete` (`-i`) Only list incomplete activities * `--all` (`-a`) List activities on all environments * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. Available columns: id*, created*, description*, progress*, state*, result*, completed, environments, time_build, time_deploy, time_execute, time_wait, type (* = default columns). The character "+" can be used as a placeholder for the default columns. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * List recent activities for the current environment: ``` upsun activity:list ``` * List all recent activities for the current project: ``` upsun activity:list --all ``` * List recent pushes: ``` upsun activity:list --type push ``` * List all recent activities excluding crons and redeploys: ``` upsun activity:list --exclude-type '*.cron,*.backup*' ``` * List pushes made before 15 March: ``` upsun activity:list --type push --start 2015-03-15 ``` * List up to 25 incomplete activities: ``` upsun activity:list --limit 25 -i ``` ###### `activity:log` Display the log for an activity ####### Usage ``` upsun activity:log [--refresh REFRESH] [-t|--timestamps] [--type TYPE] [-x|--exclude-type EXCLUDE-TYPE] [--state STATE] [--result RESULT] [-i|--incomplete] [-a|--all] [--date-fmt DATE-FMT] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [--] [] ``` ######## Arguments * `id`(optional) The activity ID. Defaults to the most recent activity. ######## Options * `--refresh` (expects a value) Activity refresh interval (seconds). Set to 0 to disable refreshing. * `--timestamps` (`-t`) Display a timestamp next to each message * `--type` (expects a value) Filter by type (when selecting a default activity). Values may be split by commas (e.g. "a,b,c") and/or whitespace. The % or * characters can be used as a wildcard for the type, e.g. '%var%' to select variable-related activities. * `--exclude-type` (`-x`) (expects a value) Exclude by type (when selecting a default activity). Values may be split by commas (e.g. "a,b,c") and/or whitespace. The % or * characters can be used as a wildcard to exclude types. * `--state` (expects a value) Filter by state (when selecting a default activity): in_progress, pending, complete, or cancelled. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--result` (expects a value) Filter by result (when selecting a default activity): success or failure * `--incomplete` (`-i`) Include only incomplete activities (when selecting a default activity). This is a shorthand for --state=in_progress,pending * `--all` (`-a`) Check recent activities on all environments (when selecting a default activity) * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Display the log for the last push on the current environment: ``` upsun activity:log --type environment.push ``` * Display the log for the last activity on the current project: ``` upsun activity:log --all ``` * Display the log for the last push, with microsecond timestamps: ``` upsun activity:log -a -t --type %push --date-fmt 'Y-m-d\TH:i:s.uP' ``` ###### `app:config-get` View the configuration of an app ####### Usage ``` upsun app:config-get [-P|--property PROPERTY] [--refresh] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-A|--app APP] [-i|--identity-file IDENTITY-FILE] ``` ######## Options * `--property` (`-P`) (expects a value) The configuration property to view * `--refresh` Whether to refresh the cache * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--app` (`-A`) (expects a value) The remote application name * `--identity-file` (`-i`) (expects a value) [Deprecated option, no longer used] * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `app:config-validate` Validate the config files of a project Aliases: `validate` ####### Usage ``` upsun app:config-validate ``` ######## Options * `--help` (`-h`) Display this help message * `--verbose` (`-v|vv|vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Validate the project configuration files in your current directory: ``` upsun app:config-validate ``` ###### `app:list` List apps in the project Aliases: `apps` ####### Usage ``` upsun apps [--refresh] [--pipe] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] ``` ######## Options * `--refresh` Whether to refresh the cache * `--pipe` Output a list of app names only * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. Available columns: name*, type*, disk, path, size (* = default columns). The character "+" can be used as a placeholder for the default columns. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `auth:api-token-login` Log in to Upsun using an API token ####### Usage ``` upsun auth:api-token-login ``` Use this command to log in to your Upsun account using an API token. You can create an account at: https://auth.upsun.com/register Alternatively, to log in to the CLI with a browser, run: upsun auth:browser-login ######## Options * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `auth:browser-login` Log in to Upsun via a browser Aliases: `login` ####### Usage ``` upsun login [-f|--force] [--method METHOD] [--max-age MAX-AGE] [--browser BROWSER] [--pipe] ``` Use this command to log in to the Upsun CLI using a web browser. It launches a temporary local website which redirects you to log in if necessary, and then captures the resulting authorization code. Your system's default browser will be used. You can override this using the --browser option. Alternatively, to log in using an API token (without a browser), run: upsun auth:api-token-login To authenticate non-interactively, configure an API token using the UPSUN_CLI_TOKEN environment variable. ######## Options * `--force` (`-f`) Log in again, even if already logged in * `--method` (expects a value) Require specific authentication method(s) * `--max-age` (expects a value) The maximum age (in seconds) of the web authentication session * `--browser` (expects a value) The browser to use to open the URL. Set 0 for none. * `--pipe` Output the URL to stdout. * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `auth:info` Display your account information ####### Usage ``` upsun auth:info [--no-auto-login] [-P|--property PROPERTY] [--refresh] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] [--] [] ``` ######## Arguments * `property`(optional) The account property to view ######## Options * `--no-auto-login` Skips auto login. Nothing will be output if not logged in, and the exit code will be 0, assuming no other errors. * `--property` (`-P`) (expects a value) The account property to view (alternate syntax) * `--refresh` Whether to refresh the cache * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Print your user ID: ``` upsun auth:info id ``` * Print your email address: ``` upsun auth:info email ``` * Print your user ID (or nothing if not logged in): ``` upsun auth:info id --no-auto-login ``` ###### `auth:logout` Log out of Upsun Aliases: `logout` ####### Usage ``` upsun logout [-a|--all] [--other] ``` ######## Options * `--all` (`-a`) Log out from all local sessions * `--other` Log out from other local sessions * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `auth:verify-phone-number` Verify your phone number interactively ####### Usage ``` upsun auth:verify-phone-number ``` ######## Options * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `backup:create` Make a backup of an environment Aliases: `backup` ####### Usage ``` upsun backup [--live] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-W|--no-wait] [--wait] [--] [] ``` ######## Arguments * `environment`(optional) The environment ######## Options * `--live` Live backup: do not stop the environment. If set, this leaves the environment running and open to connections during the backup. This reduces downtime, at the risk of backing up data in an inconsistent state. * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Make a backup of the current environment: ``` upsun backup:create ``` * Request a backup (and exit quickly): ``` upsun backup:create --no-wait ``` * Make a backup avoiding downtime (but risking inconsistency): ``` upsun backup:create --live ``` ###### `backup:delete` Delete an environment backup ####### Usage ``` upsun backup:delete [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-W|--no-wait] [--wait] [--] [] ``` ######## Arguments * `backup`(optional) The ID of the backup. Required in non-interactive mode. ######## Options * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `backup:get` View an environment backup ####### Usage ``` upsun backup:get [-P|--property PROPERTY] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [--date-fmt DATE-FMT] [--] [] ``` ######## Arguments * `backup`(optional) The ID of the backup. Defaults to the most recent one. ######## Options * `--property` (`-P`) (expects a value) The backup property to display. * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `backup:list` List available backups of an environment Aliases: `backups` ####### Usage ``` upsun backups [--format FORMAT] [-c|--columns COLUMNS] [--no-header] [--date-fmt DATE-FMT] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] ``` ######## Options * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. Available columns: created_at*, id*, restorable*, automated, commit_id, expires_at, index, live, status, updated_at (* = default columns). The character "+" can be used as a placeholder for the default columns. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Display backups including the "live" and "commit_id" columns: ``` upsun backup:list -c+live,commit_id ``` ###### `backup:restore` Restore an environment backup ####### Usage ``` upsun backup:restore [--target TARGET] [--branch-from BRANCH-FROM] [--no-code] [--resources-init RESOURCES-INIT] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-W|--no-wait] [--wait] [--] [] ``` ######## Arguments * `backup`(optional) The ID of the backup. Defaults to the most recent one ######## Options * `--target` (expects a value) The environment to restore to. Defaults to the backup's current environment * `--branch-from` (expects a value) If the --target does not yet exist, this specifies the parent of the new environment * `--no-code` Do not restore code, only data. * `--resources-init` (expects a value) Set the resources to use for new services: parent, default or minimum. If not set, "parent" will be used. * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Restore the most recent backup: ``` upsun backup:restore ``` * Restore a specific backup: ``` upsun backup:restore 92c9a4b2aa75422efb3d ``` ###### `certificate:add` Add an SSL certificate to the project ####### Usage ``` upsun certificate:add [--cert CERT] [--key KEY] [--chain CHAIN] [-p|--project PROJECT] [-W|--no-wait] [--wait] ``` ######## Options * `--cert` (expects a value) The path to the certificate file * `--key` (expects a value) The path to the certificate private key file * `--chain` (expects a value) The path to the certificate chain file * `--project` (`-p`) (expects a value) The project ID or URL * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `certificate:delete` Delete a certificate from the project ####### Usage ``` upsun certificate:delete [-p|--project PROJECT] [-W|--no-wait] [--wait] [--] ``` ######## Arguments * `id`(required) The certificate ID (or the start of it) ######## Options * `--project` (`-p`) (expects a value) The project ID or URL * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `certificate:get` View a certificate ####### Usage ``` upsun certificate:get [-P|--property PROPERTY] [--date-fmt DATE-FMT] [-p|--project PROJECT] [--] ``` ######## Arguments * `id`(required) The certificate ID (or the start of it) ######## Options * `--property` (`-P`) (expects a value) The certificate property to view * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--project` (`-p`) (expects a value) The project ID or URL * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `certificate:list` List project certificates Aliases: `certificates`, `certs` ####### Usage ``` upsun certificates [--domain DOMAIN] [--exclude-domain EXCLUDE-DOMAIN] [--issuer ISSUER] [--only-auto] [--no-auto] [--ignore-expiry] [--only-expired] [--no-expired] [--pipe-domains] [--date-fmt DATE-FMT] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] [-p|--project PROJECT] ``` ######## Options * `--domain` (expects a value) Filter by domain name (case-insensitive search) * `--exclude-domain` (expects a value) Exclude certificates, matching by domain name (case-insensitive search) * `--issuer` (expects a value) Filter by issuer * `--only-auto` Show only auto-provisioned certificates * `--no-auto` Show only manually added certificates * `--ignore-expiry` Show both expired and non-expired certificates * `--only-expired` Show only expired certificates * `--no-expired` Show only non-expired certificates (default) * `--pipe-domains` Only return a list of domain names covered by the certificates * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. Available columns: created, domains, expires, id, issuer. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--project` (`-p`) (expects a value) The project ID or URL * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Output a list of domains covered by valid certificates: ``` upsun certificate:list --pipe-domains --no-expired ``` ###### `commit:get` Show commit details ####### Usage ``` upsun commit:get [-P|--property PROPERTY] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [--date-fmt DATE-FMT] [--] [] ``` ######## Arguments * `commit`(optional) The commit SHA. This can also accept "HEAD", and caret (^) or tilde (~) suffixes for parent commits. ######## Options * `--property` (`-P`) (expects a value) The commit property to display. * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Display the current commit on the environment: ``` upsun commit:get ``` * Display the previous commit: ``` upsun commit:get HEAD~ ``` * Display the 3rd commit before the current one: ``` upsun commit:get HEAD~3 ``` * Display the email address of the last commit author: ``` upsun commit:get -P author.email ``` ###### `commit:list` List commits Aliases: `commits` ####### Usage ``` upsun commits [--limit LIMIT] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] [--date-fmt DATE-FMT] [--] [] ``` ######## Arguments * `commit`(optional) The starting Git commit SHA. This can also accept "HEAD", and caret (^) or tilde (~) suffixes for parent commits. ######## Options * `--limit` (expects a value) The number of commits to display. * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. Available columns: author, date, sha, summary. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Display commits on an environment: ``` upsun commit:list ``` * Display commits starting from two before the current one: ``` upsun commit:list HEAD~2 ``` ###### `db:dump` Create a local dump of the remote database ####### Usage ``` upsun db:dump [--schema SCHEMA] [-f|--file FILE] [-d|--directory DIRECTORY] [-z|--gzip] [-t|--timestamp] [-o|--stdout] [--table TABLE] [--exclude-table EXCLUDE-TABLE] [--schema-only] [--charset CHARSET] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-A|--app APP] [-r|--relationship RELATIONSHIP] ``` ######## Options * `--schema` (expects a value) The schema to dump. Omit to use the default schema (usually "main"). * `--file` (`-f`) (expects a value) A custom filename for the dump * `--directory` (`-d`) (expects a value) A custom directory for the dump * `--gzip` (`-z`) Compress the dump using gzip * `--timestamp` (`-t`) Add a timestamp to the dump filename * `--stdout` (`-o`) Output to STDOUT instead of a file * `--table` (expects a value) Table(s) to include * `--exclude-table` (expects a value) Table(s) to exclude * `--schema-only` Dump only schemas, no data * `--charset` (expects a value) The character set encoding for the dump * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--app` (`-A`) (expects a value) The remote application name * `--relationship` (`-r`) (expects a value) The service relationship to use * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Create an SQL dump file: ``` upsun db:dump ``` * Create a gzipped SQL dump file named "dump.sql.gz": ``` upsun db:dump --gzip -f dump.sql.gz ``` ###### `db:sql` Run SQL on the remote database Aliases: `sql` ####### Usage ``` upsun sql [--raw] [--schema SCHEMA] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-A|--app APP] [-r|--relationship RELATIONSHIP] [--] [] ``` ######## Arguments * `query`(optional) An SQL statement to execute ######## Options * `--raw` Produce raw, non-tabular output * `--schema` (expects a value) The schema to use. Omit to use the default schema (usually "main"). Pass an empty string to not use any schema. * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--app` (`-A`) (expects a value) The remote application name * `--relationship` (`-r`) (expects a value) The service relationship to use * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Open an SQL console on the remote database: ``` upsun db:sql ``` * View tables on the remote database: ``` upsun db:sql 'SHOW TABLES' ``` * Import a dump file into the remote database: ``` upsun db:sql ``` ######## Arguments * `name`(required) The domain name ######## Options * `--cert` (expects a value) The path to a custom certificate file * `--key` (expects a value) The path to the private key for the custom certificate * `--chain` (expects a value) The path to the chain file(s) for the custom certificate * `--attach` (expects a value) The production domain that this one replaces in the environment's routes. Required for non-production environment domains. * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Add the domain example.com: ``` upsun domain:add example.com ``` * Add the domain example.org with a custom SSL/TLS certificate: ``` upsun domain:add example.org --cert example-org.crt --key example-org.key ``` ###### `domain:delete` Delete a domain from the project ####### Usage ``` upsun domain:delete [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-W|--no-wait] [--wait] [--] ``` ######## Arguments * `name`(required) The domain name ######## Options * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Delete the domain example.com: ``` upsun domain:delete example.com ``` ###### `domain:get` Show detailed information for a domain ####### Usage ``` upsun domain:get [-P|--property PROPERTY] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] [--date-fmt DATE-FMT] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [--] [] ``` ######## Arguments * `name`(optional) The domain name ######## Options * `--property` (`-P`) (expects a value) The domain property to view * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `domain:list` Get a list of all domains Aliases: `domains` ####### Usage ``` upsun domains [--format FORMAT] [-c|--columns COLUMNS] [--no-header] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] ``` ######## Options * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. Available columns: name*, ssl*, created_at*, registered_name, replacement_for, type, updated_at (* = default columns). The character "+" can be used as a placeholder for the default columns. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `domain:update` Update a domain ####### Usage ``` upsun domain:update [--cert CERT] [--key KEY] [--chain CHAIN] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-W|--no-wait] [--wait] [--] ``` ######## Arguments * `name`(required) The domain name ######## Options * `--cert` (expects a value) The path to a custom certificate file * `--key` (expects a value) The path to the private key for the custom certificate * `--chain` (expects a value) The path to the chain file(s) for the custom certificate * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Update the custom certificate for the domain example.org: ``` upsun domain:update example.org --cert example-org.crt --key example-org.key ``` ###### `environment:activate` Activate an environment ####### Usage ``` upsun environment:activate [--parent PARENT] [--resources-init RESOURCES-INIT] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-W|--no-wait] [--wait] [--] []... ``` ######## Arguments * `environment`(optional; multiple values allowed) The environment(s) to activate ######## Options * `--parent` (expects a value) Set a new environment parent before activating * `--resources-init` (expects a value) Set the resources to use for new services: parent, default or minimum. If not set, "parent" will be used. * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Activate the environments "develop" and "stage": ``` upsun environment:activate develop stage ``` ###### `environment:branch` Branch an environment Aliases: `branch` ####### Usage ``` upsun branch [--title TITLE] [--type TYPE] [--no-clone-parent] [--no-checkout] [--resources-init RESOURCES-INIT] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-W|--no-wait] [--wait] [--] [] [] ``` ######## Arguments * `id`(optional) The ID (branch name) of the new environment * `parent`(optional) The parent of the new environment ######## Options * `--title` (expects a value) The title of the new environment * `--type` (expects a value) The type of the new environment * `--no-clone-parent` Do not clone the parent environment's data * `--no-checkout` Do not check out the branch locally * `--resources-init` (expects a value) Set the resources to use for new services: parent, default or minimum. If not set, "parent" will be used. * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Create a new branch "sprint-2", based on "develop": ``` upsun environment:branch sprint-2 develop ``` ###### `environment:checkout` Check out an environment Aliases: `checkout` ####### Usage ``` upsun checkout [] ``` ######## Arguments * `id`(optional) The ID of the environment to check out. For example: "sprint2" ######## Options * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Check out the environment "develop": ``` upsun environment:checkout develop ``` ###### `environment:delete` Delete one or more environments ####### Usage ``` upsun environment:delete [--delete-branch] [--no-delete-branch] [--type TYPE] [-t|--only-type ONLY-TYPE] [--exclude EXCLUDE] [--exclude-type EXCLUDE-TYPE] [--inactive] [--status STATUS] [--only-status ONLY-STATUS] [--exclude-status EXCLUDE-STATUS] [--merged] [--allow-delete-parent] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-W|--no-wait] [--wait] [--] []... ``` When a Upsun environment is deleted, it will become "inactive": it will exist only as a Git branch, containing code but no services, databases nor files. This command allows you to delete environments as well as their Git branches. ######## Arguments * `environment`(optional; multiple values allowed) The environment(s) to delete. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. ######## Options * `--delete-branch` Delete Git branch(es) for inactive environments, without confirmation * `--no-delete-branch` Do not delete any Git branch(es) (inactive environments) * `--type` (expects a value) Delete all environments of a type (adding to any others selected) Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--only-type` (`-t`) (expects a value) Only delete environments of a specific type Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--exclude` (expects a value) Environment(s) not to delete. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--exclude-type` (expects a value) Environment type(s) of which not to delete Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--inactive` Delete all inactive environments (adding to any others selected) * `--status` (expects a value) Delete all environments of a status (adding to any others selected) Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--only-status` (expects a value) Only delete environments of a specific status Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--exclude-status` (expects a value) Environment status(es) of which not to delete Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--merged` Delete all merged environments (adding to any others selected) * `--allow-delete-parent` Allow environments that have children to be deleted * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Delete the currently checked out environment: ``` upsun environment:delete ``` * Delete the environments "test" and "example-1": ``` upsun environment:delete test example-1 ``` * Delete all inactive environments: ``` upsun environment:delete --inactive ``` * Delete all environments merged with their parent: ``` upsun environment:delete --merged ``` ###### `environment:drush` Run a drush command on the remote environment Aliases: `drush` ####### Usage ``` upsun drush [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-A|--app APP] [--] []... ``` ######## Arguments * `cmd`(optional; multiple values allowed) A command to pass to Drush ######## Options * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--app` (`-A`) (expects a value) The remote application name * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Run "drush status" on the remote environment: ``` upsun environment:drush status ``` * Enable the Overlay module on the remote environment: ``` upsun environment:drush en overlay ``` * Get a one-time login link (using -- before options): ``` upsun environment:drush user-login -- --mail=name@example.com ``` * Alternative syntax (quoting the whole command): ``` upsun environment:drush 'user-login --mail=name@example.com' ``` ###### `environment:http-access` Update HTTP access settings for an environment Aliases: `httpaccess` ####### Usage ``` upsun httpaccess [--access ACCESS] [--auth AUTH] [--enabled ENABLED] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-W|--no-wait] [--wait] ``` ######## Options * `--access` (expects a value) Access restriction in the format "permission:address". Use 0 to clear all addresses. * `--auth` (expects a value) HTTP Basic auth credentials in the format "username:password". Use 0 to clear all credentials. * `--enabled` (expects a value) Whether access control should be enabled: 1 to enable, 0 to disable * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Require a username and password: ``` upsun environment:http-access --auth myname:mypassword ``` * Restrict access to only one IP address: ``` upsun environment:http-access --access allow:69.208.1.192 --access deny:any ``` * Remove the password requirement, keeping IP restrictions: ``` upsun environment:http-access --auth 0 ``` * Disable all HTTP access control: ``` upsun environment:http-access --enabled 0 ``` ###### `environment:info` Read or set properties for an environment ####### Usage ``` upsun environment:info [--refresh] [--date-fmt DATE-FMT] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-W|--no-wait] [--wait] [--] [] [] ``` ######## Arguments * `property`(optional) The name of the property * `value`(optional) Set a new value for the property ######## Options * `--refresh` Whether to refresh the cache * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Read all environment properties: ``` upsun environment:info ``` * Show the environment's status: ``` upsun environment:info status ``` * Show the date the environment was created: ``` upsun environment:info created_at ``` * Enable email sending: ``` upsun environment:info enable_smtp true ``` * Change the environment title: ``` upsun environment:info title "New feature" ``` * Change the environment's parent branch: ``` upsun environment:info parent sprint-2 ``` * Unset the environment's parent branch: ``` upsun environment:info parent - ``` ###### `environment:init` Initialize an environment from a public Git repository ####### Usage ``` upsun environment:init [--profile PROFILE] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-W|--no-wait] [--wait] [--] ``` ######## Arguments * `url`(required) A URL to a Git repository ######## Options * `--profile` (expects a value) The name of the profile * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `environment:list` Get a list of environments Aliases: `environments`, `env` ####### Usage ``` upsun environments [-I|--no-inactive] [--status STATUS] [--pipe] [--refresh REFRESH] [--sort SORT] [--reverse] [--type TYPE] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] [-p|--project PROJECT] ``` ######## Options * `--no-inactive` (`-I`) Do not show inactive environments * `--status` (expects a value) Filter environments by status (active, inactive, dirty, paused, deleting). Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--pipe` Output a simple list of environment IDs. * `--refresh` (expects a value) Whether to refresh the list. * `--sort` (expects a value) A property to sort by * `--reverse` Sort in reverse (descending) order * `--type` (expects a value) Filter the list by environment type(s). Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. Available columns: id*, title*, status*, type*, created, machine_name, updated (* = default columns). The character "+" can be used as a placeholder for the default columns. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--project` (`-p`) (expects a value) The project ID or URL * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `environment:logs` Read an environment's logs Aliases: `log` ####### Usage ``` upsun log [--lines LINES] [--tail] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-A|--app APP] [--worker WORKER] [-I|--instance INSTANCE] [--] [] ``` ######## Arguments * `type`(optional) The log type, e.g. "access" or "error" ######## Options * `--lines` (expects a value) The number of lines to show * `--tail` Continuously tail the log * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--app` (`-A`) (expects a value) The remote application name * `--worker` (expects a value) A worker name * `--instance` (`-I`) (expects a value) An instance ID * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Display a choice of logs that can be read: ``` upsun environment:logs ``` * Read the deploy log: ``` upsun environment:logs deploy ``` * Read the access log continuously: ``` upsun environment:logs access --tail ``` * Read the last 500 lines of the cron log: ``` upsun environment:logs cron --lines 500 ``` ###### `environment:merge` Merge an environment Aliases: `merge` ####### Usage ``` upsun merge [--resources-init RESOURCES-INIT] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-W|--no-wait] [--wait] [--] [] ``` This command will initiate a Git merge of the specified environment into its parent environment. ######## Arguments * `environment`(optional) The environment to merge ######## Options * `--resources-init` (expects a value) Set the resources to use for new services: child, default, minimum or manual. If not set, "child" will be used. * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Merge the environment "sprint-2" into its parent: ``` upsun environment:merge sprint-2 ``` ###### `environment:pause` Pause an environment ####### Usage ``` upsun environment:pause [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-W|--no-wait] [--wait] ``` Pausing an environment helps to reduce resource consumption and carbon emissions. The environment will be unavailable until it is resumed. No data will be lost. ######## Options * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `environment:push` Push code to an environment Aliases: `push` ####### Usage ``` upsun push [--target TARGET] [-f|--force] [--force-with-lease] [-u|--set-upstream] [--activate] [--parent PARENT] [--type TYPE] [--no-clone-parent] [--resources-init RESOURCES-INIT] [-W|--no-wait] [--wait] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [--] [] ``` ######## Arguments * `source`(optional) The Git source ref, e.g. a branch name or a commit hash. ######## Options * `--target` (expects a value) The target branch name. Defaults to the current branch. * `--force` (`-f`) Allow non-fast-forward updates * `--force-with-lease` Allow non-fast-forward updates, if the remote-tracking branch is up to date * `--set-upstream` (`-u`) Set the target environment as the upstream for the source branch. This will also set the target project as the remote for the local repository. * `--activate` Activate the environment. Paused environments will be resumed. This will ensure the environment is active even if no changes were pushed. * `--parent` (expects a value) Set the environment parent (only used with --activate) * `--type` (expects a value) Set the environment type (only used with --activate ) * `--no-clone-parent` Do not clone the parent branch's data (only used with --activate) * `--resources-init` (expects a value) Set the resources to use for new services: parent, default, minimum, or manual. Currently the default is "default" but this will change to "parent" in future. * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Push code to the current environment: ``` upsun environment:push ``` * Push code, without waiting for deployment: ``` upsun environment:push --no-wait ``` * Push code, branching or activating the environment as a child of 'develop': ``` upsun environment:push --activate --parent develop ``` ###### `environment:redeploy` Redeploy an environment Aliases: `redeploy` ####### Usage ``` upsun redeploy [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-W|--no-wait] [--wait] ``` ######## Options * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `environment:relationships` Show an environment's relationships Aliases: `relationships`, `rel` ####### Usage ``` upsun relationships [-P|--property PROPERTY] [--refresh] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-A|--app APP] [--] [] ``` ######## Arguments * `environment`(optional) The environment ######## Options * `--property` (`-P`) (expects a value) The relationship property to view * `--refresh` Whether to refresh the relationships * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--app` (`-A`) (expects a value) The remote application name * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * View all the current environment's relationships: ``` upsun environment:relationships ``` * View the 'main' environment's relationships: ``` upsun environment:relationships main ``` * View the 'main' environment's database port: ``` upsun environment:relationships main --property database.0.port ``` ###### `environment:resume` Resume a paused environment ####### Usage ``` upsun environment:resume [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-W|--no-wait] [--wait] ``` ######## Options * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `environment:scp` Copy files to and from an environment using scp Aliases: `scp` ####### Usage ``` upsun scp [-r|--recursive] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-A|--app APP] [--worker WORKER] [-I|--instance INSTANCE] [--] []... ``` ######## Arguments * `files`(optional; multiple values allowed) Files to copy. Use the remote: prefix to define remote locations. ######## Options * `--recursive` (`-r`) Recursively copy entire directories * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--app` (`-A`) (expects a value) The remote application name * `--worker` (expects a value) A worker name * `--instance` (`-I`) (expects a value) An instance ID * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Copy local files a.txt and b.txt to remote mount var/files: ``` upsun environment:scp a.txt b.txt remote:var/files ``` * Copy remote files c.txt to current directory: ``` upsun environment:scp remote:c.txt . ``` * Copy subdirectory dump/ to remote mount var/files: ``` upsun environment:scp -r dump remote:var/logs ``` * Copy files inside subdirectory dump/ to remote mount var/files: ``` upsun environment:scp -r dump/* remote:var/logs ``` ###### `environment:ssh` SSH to the current environment Aliases: `ssh` ####### Usage ``` upsun ssh [--pipe] [--all] [-o|--option OPTION] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-A|--app APP] [--worker WORKER] [-I|--instance INSTANCE] [--] []... ``` ######## Arguments * `cmd`(optional; multiple values allowed) A command to run on the environment. ######## Options * `--pipe` Output the SSH URL only. * `--all` Output all SSH URLs (for every app). * `--option` (`-o`) (expects a value) Pass an extra option to SSH * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--app` (`-A`) (expects a value) The remote application name * `--worker` (expects a value) A worker name * `--instance` (`-I`) (expects a value) An instance ID * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Open a shell over SSH: ``` upsun environment:ssh ``` * Pass an extra option to SSH: ``` upsun environment:ssh -o 'RequestTTY force' ``` * List files: ``` upsun environment:ssh ls ``` * Monitor the app log (use '--' before flags): ``` upsun environment:ssh tail /var/log/app.log -- -n50 -f ``` * Display relationships (use quotes for complex syntax): ``` upsun environment:ssh 'echo $PLATFORM_RELATIONSHIPS | base64 --decode' ``` ###### `environment:synchronize` Synchronize an environment's code, data and/or resources from its parent Aliases: `sync` ####### Usage ``` upsun sync [--rebase] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-W|--no-wait] [--wait] [--] []... ``` This command synchronizes to a child environment from its parent environment. Synchronizing "code" means there will be a Git merge from the parent to the child. Synchronizing "data" means that all files in all services (including static files, databases, logs, search indices, etc.) will be copied from the parent to the child. Synchronizing "resources" means that the parent environment's resource sizes will be used for all corresponding apps and services in the child environment. ######## Arguments * `synchronize`(optional; multiple values allowed) List what to synchronize: "code", "data", and/or "resources". ######## Options * `--rebase` Synchronize code by rebasing instead of merging * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Synchronize data from the parent environment: ``` upsun environment:synchronize data ``` * Synchronize code and data from the parent environment: ``` upsun environment:synchronize code data ``` * Synchronize code, data and resources from the parent environment: ``` upsun environment:synchronize code data resources ``` ###### `environment:url` Get the public URLs of an environment Aliases: `url` ####### Usage ``` upsun url [-1|--primary] [--browser BROWSER] [--pipe] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] ``` ######## Options * `--primary` (`-1`) Only return the URL for the primary route * `--browser` (expects a value) The browser to use to open the URL. Set 0 for none. * `--pipe` Output the URL to stdout. * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Give a choice of URLs to open (or print all URLs if there is no browser): ``` upsun environment:url ``` * Print all URLs: ``` upsun environment:url --pipe ``` * Print and/or open the primary route URL: ``` upsun environment:url --primary ``` * Print the primary route URL: ``` upsun environment:url --primary --pipe ``` ###### `environment:xdebug` Open a tunnel to Xdebug on the environment Aliases: `xdebug` ####### Usage ``` upsun xdebug [--port PORT] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-A|--app APP] [--worker WORKER] [-I|--instance INSTANCE] ``` ######## Options * `--port` (expects a value) The local port * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--app` (`-A`) (expects a value) The remote application name * `--worker` (expects a value) A worker name * `--instance` (`-I`) (expects a value) An instance ID * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Connect to Xdebug on the environment, listening locally on port 9000.: ``` upsun environment:xdebug ``` ###### `integration:activity:get` View detailed information on a single integration activity ####### Usage ``` upsun integration:activity:get [-P|--property PROPERTY] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] [--date-fmt DATE-FMT] [--] [] [] ``` ######## Arguments * `integration`(optional) An integration ID. Leave blank to choose from a list. * `activity`(optional) The activity ID. Defaults to the most recent integration activity. ######## Options * `--property` (`-P`) (expects a value) The property to view * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) [Deprecated option, not used] * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `integration:activity:list` Get a list of activities for an integration Aliases: `integration:activities` ####### Usage ``` upsun integration:activities [--type TYPE] [-x|--exclude-type EXCLUDE-TYPE] [--limit LIMIT] [--start START] [--state STATE] [--result RESULT] [-i|--incomplete] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] [--date-fmt DATE-FMT] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [--] [] ``` ######## Arguments * `id`(optional) An integration ID. Leave blank to choose from a list. ######## Options * `--type` (expects a value) Filter activities by type. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--exclude-type` (`-x`) (expects a value) Exclude activities by type. Values may be split by commas (e.g. "a,b,c") and/or whitespace. The % or * characters can be used as a wildcard to exclude types. * `--limit` (expects a value) Limit the number of results displayed * `--start` (expects a value) Only activities created before this date will be listed * `--state` (expects a value) Filter activities by state. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--result` (expects a value) Filter activities by result * `--incomplete` (`-i`) Only list incomplete activities * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. Available columns: id*, created*, description*, type*, state*, result*, completed, progress, time_build, time_deploy, time_execute, time_wait (* = default columns). The character "+" can be used as a placeholder for the default columns. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) [Deprecated option, not used] * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `integration:activity:log` Display the log for an integration activity ####### Usage ``` upsun integration:activity:log [-t|--timestamps] [--date-fmt DATE-FMT] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [--] [] [] ``` ######## Arguments * `integration`(optional) An integration ID. Leave blank to choose from a list. * `activity`(optional) The activity ID. Defaults to the most recent integration activity. ######## Options * `--timestamps` (`-t`) Display a timestamp next to each message * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) [Deprecated option, not used] * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `integration:add` Add an integration to the project ####### Usage ``` upsun integration:add [--type TYPE] [--base-url BASE-URL] [--bitbucket-url BITBUCKET-URL] [--username USERNAME] [--token TOKEN] [--key KEY] [--secret SECRET] [--license-key LICENSE-KEY] [--server-project SERVER-PROJECT] [--repository REPOSITORY] [--build-merge-requests BUILD-MERGE-REQUESTS] [--build-pull-requests BUILD-PULL-REQUESTS] [--build-draft-pull-requests BUILD-DRAFT-PULL-REQUESTS] [--build-pull-requests-post-merge BUILD-PULL-REQUESTS-POST-MERGE] [--build-wip-merge-requests BUILD-WIP-MERGE-REQUESTS] [--merge-requests-clone-parent-data MERGE-REQUESTS-CLONE-PARENT-DATA] [--pull-requests-clone-parent-data PULL-REQUESTS-CLONE-PARENT-DATA] [--resync-pull-requests RESYNC-PULL-REQUESTS] [--fetch-branches FETCH-BRANCHES] [--prune-branches PRUNE-BRANCHES] [--resources-init RESOURCES-INIT] [--url URL] [--shared-key SHARED-KEY] [--file FILE] [--events EVENTS] [--states STATES] [--environments ENVIRONMENTS] [--excluded-environments EXCLUDED-ENVIRONMENTS] [--from-address FROM-ADDRESS] [--recipients RECIPIENTS] [--channel CHANNEL] [--routing-key ROUTING-KEY] [--category CATEGORY] [--index INDEX] [--sourcetype SOURCETYPE] [--protocol PROTOCOL] [--syslog-host SYSLOG-HOST] [--syslog-port SYSLOG-PORT] [--facility FACILITY] [--message-format MESSAGE-FORMAT] [--auth-mode AUTH-MODE] [--auth-token AUTH-TOKEN] [--verify-tls VERIFY-TLS] [--header HEADER] [-p|--project PROJECT] [-W|--no-wait] [--wait] ``` ######## Options * `--type` (expects a value) The integration type ('bitbucket', 'bitbucket_server', 'github', 'gitlab', 'webhook', 'health.email', 'health.pagerduty', 'health.slack', 'health.webhook', 'httplog', 'script', 'newrelic', 'splunk', 'sumologic', 'syslog') * `--base-url` (expects a value) The base URL of the server installation * `--bitbucket-url` (expects a value) The base URL of the Bitbucket Server installation * `--username` (expects a value) The Bitbucket Server username * `--token` (expects a value) An authentication or access token for the integration * `--key` (expects a value) A Bitbucket OAuth consumer key * `--secret` (expects a value) A Bitbucket OAuth consumer secret * `--license-key` (expects a value) The New Relic Logs license key * `--server-project` (expects a value) The project (e.g. 'namespace/repo') * `--repository` (expects a value) The repository to track (e.g. 'owner/repository') * `--build-merge-requests` (expects a value) GitLab: build merge requests as environments * `--build-pull-requests` (expects a value) Build every pull request as an environment * `--build-draft-pull-requests` (expects a value) Build draft pull requests * `--build-pull-requests-post-merge` (expects a value) Build pull requests based on their post-merge state * `--build-wip-merge-requests` (expects a value) GitLab: build WIP merge requests * `--merge-requests-clone-parent-data` (expects a value) GitLab: clone data for merge requests * `--pull-requests-clone-parent-data` (expects a value) Clone the parent environment's data for pull requests * `--resync-pull-requests` (expects a value) Re-sync pull request environment data on every build * `--fetch-branches` (expects a value) Fetch all branches from the remote (as inactive environments) * `--prune-branches` (expects a value) Delete branches that do not exist on the remote * `--resources-init` (expects a value) The resources to use when initializing a new service ('minimum', 'default', 'manual', 'parent') * `--url` (expects a value) The URL or API endpoint for the integration * `--shared-key` (expects a value) Webhook: the JWS shared secret key * `--file` (expects a value) The name of a local file that contains the script to upload * `--events` (expects a value) A list of events to act on, e.g. environment.push * `--states` (expects a value) A list of states to act on, e.g. pending, in_progress, complete * `--environments` (expects a value) The environment IDs to include * `--excluded-environments` (expects a value) The environment IDs to exclude * `--from-address` (expects a value) [Optional] Custom From address for alert emails * `--recipients` (expects a value) The recipient email address(es) * `--channel` (expects a value) The Slack channel * `--routing-key` (expects a value) The PagerDuty routing key * `--category` (expects a value) The Sumo Logic category, used for filtering * `--index` (expects a value) The Splunk index * `--sourcetype` (expects a value) The Splunk event source type * `--protocol` (expects a value) Syslog transport protocol ('tcp', 'udp', 'tls') * `--syslog-host` (expects a value) Syslog relay/collector host * `--syslog-port` (expects a value) Syslog relay/collector port * `--facility` (expects a value) Syslog facility * `--message-format` (expects a value) Syslog message format ('rfc3164' or 'rfc5424') * `--auth-mode` (expects a value) Authentication mode ('prefix' or 'structured_data') * `--auth-token` (expects a value) Authentication token * `--verify-tls` (expects a value) Whether HTTPS certificate verification should be enabled (recommended) * `--header` (expects a value) HTTP header(s) to use in POST requests. Separate names and values with a colon (:). * `--project` (`-p`) (expects a value) The project ID or URL * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Add an integration with a GitHub repository: ``` upsun integration:add --type github --repository myuser/example-repo --token 9218376e14c2797e0d06e8d2f918d45f --fetch-branches 0 ``` * Add an integration with a GitLab repository: ``` upsun integration:add --type gitlab --server-project mygroup/example-repo --token 22fe4d70dfbc20e4f668568a0b5422e2 --base-url https://gitlab.example.com ``` ###### `integration:delete` Delete an integration from a project ####### Usage ``` upsun integration:delete [-p|--project PROJECT] [-W|--no-wait] [--wait] [--] [] ``` ######## Arguments * `id`(optional) The integration ID. Leave blank to choose from a list. ######## Options * `--project` (`-p`) (expects a value) The project ID or URL * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `integration:get` View details of an integration ####### Usage ``` upsun integration:get [-P|--property [PROPERTY]] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] [-p|--project PROJECT] [--] [] ``` ######## Arguments * `id`(optional) An integration ID. Leave blank to choose from a list. ######## Options * `--property` (`-P`) (expects a value) The integration property to view * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--project` (`-p`) (expects a value) The project ID or URL * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `integration:list` View a list of project integration(s) Aliases: `integrations` ####### Usage ``` upsun integrations [-t|--type TYPE] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] [-p|--project PROJECT] ``` ######## Options * `--type` (`-t`) (expects a value) Filter by type * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. Available columns: id, summary, type. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--project` (`-p`) (expects a value) The project ID or URL * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `integration:update` Update an integration ####### Usage ``` upsun integration:update [--type TYPE] [--base-url BASE-URL] [--bitbucket-url BITBUCKET-URL] [--username USERNAME] [--token TOKEN] [--key KEY] [--secret SECRET] [--license-key LICENSE-KEY] [--server-project SERVER-PROJECT] [--repository REPOSITORY] [--build-merge-requests BUILD-MERGE-REQUESTS] [--build-pull-requests BUILD-PULL-REQUESTS] [--build-draft-pull-requests BUILD-DRAFT-PULL-REQUESTS] [--build-pull-requests-post-merge BUILD-PULL-REQUESTS-POST-MERGE] [--build-wip-merge-requests BUILD-WIP-MERGE-REQUESTS] [--merge-requests-clone-parent-data MERGE-REQUESTS-CLONE-PARENT-DATA] [--pull-requests-clone-parent-data PULL-REQUESTS-CLONE-PARENT-DATA] [--resync-pull-requests RESYNC-PULL-REQUESTS] [--fetch-branches FETCH-BRANCHES] [--prune-branches PRUNE-BRANCHES] [--resources-init RESOURCES-INIT] [--url URL] [--shared-key SHARED-KEY] [--file FILE] [--events EVENTS] [--states STATES] [--environments ENVIRONMENTS] [--excluded-environments EXCLUDED-ENVIRONMENTS] [--from-address FROM-ADDRESS] [--recipients RECIPIENTS] [--channel CHANNEL] [--routing-key ROUTING-KEY] [--category CATEGORY] [--index INDEX] [--sourcetype SOURCETYPE] [--protocol PROTOCOL] [--syslog-host SYSLOG-HOST] [--syslog-port SYSLOG-PORT] [--facility FACILITY] [--message-format MESSAGE-FORMAT] [--auth-mode AUTH-MODE] [--auth-token AUTH-TOKEN] [--verify-tls VERIFY-TLS] [--header HEADER] [-p|--project PROJECT] [-W|--no-wait] [--wait] [--] [] ``` ######## Arguments * `id`(optional) The ID of the integration to update ######## Options * `--type` (expects a value) The integration type ('bitbucket', 'bitbucket_server', 'github', 'gitlab', 'webhook', 'health.email', 'health.pagerduty', 'health.slack', 'health.webhook', 'httplog', 'script', 'newrelic', 'splunk', 'sumologic', 'syslog') * `--base-url` (expects a value) The base URL of the server installation * `--bitbucket-url` (expects a value) The base URL of the Bitbucket Server installation * `--username` (expects a value) The Bitbucket Server username * `--token` (expects a value) An authentication or access token for the integration * `--key` (expects a value) A Bitbucket OAuth consumer key * `--secret` (expects a value) A Bitbucket OAuth consumer secret * `--license-key` (expects a value) The New Relic Logs license key * `--server-project` (expects a value) The project (e.g. 'namespace/repo') * `--repository` (expects a value) The repository to track (e.g. 'owner/repository') * `--build-merge-requests` (expects a value) GitLab: build merge requests as environments * `--build-pull-requests` (expects a value) Build every pull request as an environment * `--build-draft-pull-requests` (expects a value) Build draft pull requests * `--build-pull-requests-post-merge` (expects a value) Build pull requests based on their post-merge state * `--build-wip-merge-requests` (expects a value) GitLab: build WIP merge requests * `--merge-requests-clone-parent-data` (expects a value) GitLab: clone data for merge requests * `--pull-requests-clone-parent-data` (expects a value) Clone the parent environment's data for pull requests * `--resync-pull-requests` (expects a value) Re-sync pull request environment data on every build * `--fetch-branches` (expects a value) Fetch all branches from the remote (as inactive environments) * `--prune-branches` (expects a value) Delete branches that do not exist on the remote * `--resources-init` (expects a value) The resources to use when initializing a new service ('minimum', 'default', 'manual', 'parent') * `--url` (expects a value) The URL or API endpoint for the integration * `--shared-key` (expects a value) Webhook: the JWS shared secret key * `--file` (expects a value) The name of a local file that contains the script to upload * `--events` (expects a value) A list of events to act on, e.g. environment.push * `--states` (expects a value) A list of states to act on, e.g. pending, in_progress, complete * `--environments` (expects a value) The environment IDs to include * `--excluded-environments` (expects a value) The environment IDs to exclude * `--from-address` (expects a value) [Optional] Custom From address for alert emails * `--recipients` (expects a value) The recipient email address(es) * `--channel` (expects a value) The Slack channel * `--routing-key` (expects a value) The PagerDuty routing key * `--category` (expects a value) The Sumo Logic category, used for filtering * `--index` (expects a value) The Splunk index * `--sourcetype` (expects a value) The Splunk event source type * `--protocol` (expects a value) Syslog transport protocol ('tcp', 'udp', 'tls') * `--syslog-host` (expects a value) Syslog relay/collector host * `--syslog-port` (expects a value) Syslog relay/collector port * `--facility` (expects a value) Syslog facility * `--message-format` (expects a value) Syslog message format ('rfc3164' or 'rfc5424') * `--auth-mode` (expects a value) Authentication mode ('prefix' or 'structured_data') * `--auth-token` (expects a value) Authentication token * `--verify-tls` (expects a value) Whether HTTPS certificate verification should be enabled (recommended) * `--header` (expects a value) HTTP header(s) to use in POST requests. Separate names and values with a colon (:). * `--project` (`-p`) (expects a value) The project ID or URL * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Switch on the "fetch branches" option for a specific integration: ``` upsun integration:update ZXhhbXBsZSB --fetch-branches 1 ``` ###### `integration:validate` Validate an existing integration ####### Usage ``` upsun integration:validate [-p|--project PROJECT] [--] [] ``` This command allows you to check whether an integration is valid. An exit code of 0 means the integration is valid, while 4 means it is invalid. Any other exit code indicates an unexpected error. Integrations are validated automatically on creation and on update. However, because they involve external resources, it is possible for a valid integration to become invalid. For example, an access token may be revoked, or an external repository may be deleted. ######## Arguments * `id`(optional) An integration ID. Leave blank to choose from a list. ######## Options * `--project` (`-p`) (expects a value) The project ID or URL * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `local:dir` Find the local project root Aliases: `dir` ####### Usage ``` upsun dir [] ``` ######## Arguments * `subdir`(optional) The subdirectory to find ('local', 'web' or 'shared') ######## Options * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `metrics:all` Show CPU, disk and memory metrics for an environment Aliases: `metrics`, `met` ####### Usage ``` upsun metrics [-B|--bytes] [-r|--range RANGE] [-i|--interval INTERVAL] [--to TO] [-1|--latest] [-s|--service SERVICE] [--type TYPE] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] [--date-fmt DATE-FMT] ``` ######## Options * `--bytes` (`-B`) Show sizes in bytes * `--range` (`-r`) (expects a value) The time range. Metrics will be loaded for this duration until the end time (--to). You can specify units: hours (h), minutes (m), or seconds (s). Minimum 5m, maximum 8h or more (depending on the project), default 10m. * `--interval` (`-i`) (expects a value) The time interval. Defaults to a division of the range. You can specify units: hours (h), minutes (m), or seconds (s). Minimum 1m. * `--to` (expects a value) The end time. Defaults to now. * `--latest` (`-1`) Show only the latest single data point * `--service` (`-s`) (expects a value) Filter by service or application name The % or * characters may be used as a wildcard. * `--type` (expects a value) Filter by service type (if --service is not provided). The version is not required. The % or * characters may be used as a wildcard. * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. Available columns: timestamp*, service*, cpu_percent*, mem_percent*, disk_percent*, tmp_disk_percent*, cpu_limit, cpu_used, disk_limit, disk_used, inodes_limit, inodes_percent, inodes_used, mem_limit, mem_used, tmp_disk_limit, tmp_disk_used, tmp_inodes_limit, tmp_inodes_percent, tmp_inodes_used, type (* = default columns). The character "+" can be used as a placeholder for the default columns. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Show metrics for the last 10m: ``` upsun metrics:all ``` * Show metrics in five-minute intervals over the last hour: ``` upsun metrics:all -i 5m -r 1h ``` * Show metrics for all SQL services: ``` upsun metrics:all --type mariadb,%sql ``` ###### `metrics:cpu` Show CPU usage of an environment Aliases: `cpu` ####### Usage ``` upsun cpu [-r|--range RANGE] [-i|--interval INTERVAL] [--to TO] [-1|--latest] [-s|--service SERVICE] [--type TYPE] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] [--date-fmt DATE-FMT] ``` ######## Options * `--range` (`-r`) (expects a value) The time range. Metrics will be loaded for this duration until the end time (--to). You can specify units: hours (h), minutes (m), or seconds (s). Minimum 5m, maximum 8h or more (depending on the project), default 10m. * `--interval` (`-i`) (expects a value) The time interval. Defaults to a division of the range. You can specify units: hours (h), minutes (m), or seconds (s). Minimum 1m. * `--to` (expects a value) The end time. Defaults to now. * `--latest` (`-1`) Show only the latest single data point * `--service` (`-s`) (expects a value) Filter by service or application name The % or * characters may be used as a wildcard. * `--type` (expects a value) Filter by service type (if --service is not provided). The version is not required. The % or * characters may be used as a wildcard. * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. Available columns: timestamp*, service*, used*, limit*, percent*, type (* = default columns). The character "+" can be used as a placeholder for the default columns. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `metrics:disk-usage` Show disk usage of an environment Aliases: `disk` ####### Usage ``` upsun disk [-B|--bytes] [-r|--range RANGE] [-i|--interval INTERVAL] [--to TO] [-1|--latest] [-s|--service SERVICE] [--type TYPE] [--tmp] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] [--date-fmt DATE-FMT] ``` ######## Options * `--bytes` (`-B`) Show sizes in bytes * `--range` (`-r`) (expects a value) The time range. Metrics will be loaded for this duration until the end time (--to). You can specify units: hours (h), minutes (m), or seconds (s). Minimum 5m, maximum 8h or more (depending on the project), default 10m. * `--interval` (`-i`) (expects a value) The time interval. Defaults to a division of the range. You can specify units: hours (h), minutes (m), or seconds (s). Minimum 1m. * `--to` (expects a value) The end time. Defaults to now. * `--latest` (`-1`) Show only the latest single data point * `--service` (`-s`) (expects a value) Filter by service or application name The % or * characters may be used as a wildcard. * `--type` (expects a value) Filter by service type (if --service is not provided). The version is not required. The % or * characters may be used as a wildcard. * `--tmp` Report temporary disk usage (shows columns: timestamp, service, tmp_used, tmp_limit, tmp_percent, tmp_ipercent) * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. Available columns: timestamp*, service*, used*, limit*, percent*, ipercent*, tmp_percent*, ilimit, iused, tmp_ilimit, tmp_ipercent, tmp_iused, tmp_limit, tmp_used, type (* = default columns). The character "+" can be used as a placeholder for the default columns. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `metrics:memory` Show memory usage of an environment Aliases: `mem`, `memory` ####### Usage ``` upsun mem [-B|--bytes] [-r|--range RANGE] [-i|--interval INTERVAL] [--to TO] [-1|--latest] [-s|--service SERVICE] [--type TYPE] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] [--date-fmt DATE-FMT] ``` ######## Options * `--bytes` (`-B`) Show sizes in bytes * `--range` (`-r`) (expects a value) The time range. Metrics will be loaded for this duration until the end time (--to). You can specify units: hours (h), minutes (m), or seconds (s). Minimum 5m, maximum 8h or more (depending on the project), default 10m. * `--interval` (`-i`) (expects a value) The time interval. Defaults to a division of the range. You can specify units: hours (h), minutes (m), or seconds (s). Minimum 1m. * `--to` (expects a value) The end time. Defaults to now. * `--latest` (`-1`) Show only the latest single data point * `--service` (`-s`) (expects a value) Filter by service or application name The % or * characters may be used as a wildcard. * `--type` (expects a value) Filter by service type (if --service is not provided). The version is not required. The % or * characters may be used as a wildcard. * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. Available columns: timestamp*, service*, used*, limit*, percent*, type (* = default columns). The character "+" can be used as a placeholder for the default columns. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `mount:download` Download files from a mount, using rsync ####### Usage ``` upsun mount:download [-a|--all] [-m|--mount MOUNT] [--target TARGET] [--source-path] [--delete] [--exclude EXCLUDE] [--include INCLUDE] [--refresh] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-A|--app APP] [--worker WORKER] [-I|--instance INSTANCE] ``` ######## Options * `--all` (`-a`) Download from all mounts * `--mount` (`-m`) (expects a value) The mount (as an app-relative path) * `--target` (expects a value) The directory to which files will be downloaded. If --all is used, the mount path will be appended * `--source-path` Use the mount's source path (rather than the mount path) as a subdirectory of the target, when --all is used * `--delete` Whether to delete extraneous files in the target directory * `--exclude` (expects a value) File(s) to exclude from the download (pattern) * `--include` (expects a value) File(s) not to exclude (pattern) * `--refresh` Whether to refresh the cache * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--app` (`-A`) (expects a value) The remote application name * `--worker` (expects a value) A worker name * `--instance` (`-I`) (expects a value) An instance ID * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `mount:list` Get a list of mounts Aliases: `mounts` ####### Usage ``` upsun mounts [--paths] [--refresh] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-A|--app APP] [--worker WORKER] [-I|--instance INSTANCE] ``` ######## Options * `--paths` Output the mount paths only (one per line) * `--refresh` Whether to refresh the cache * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. Available columns: definition, path. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--app` (`-A`) (expects a value) The remote application name * `--worker` (expects a value) A worker name * `--instance` (`-I`) (expects a value) An instance ID * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `mount:upload` Upload files to a mount, using rsync ####### Usage ``` upsun mount:upload [--source SOURCE] [-m|--mount MOUNT] [--delete] [--exclude EXCLUDE] [--include INCLUDE] [--refresh] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-A|--app APP] [--worker WORKER] [-I|--instance INSTANCE] ``` ######## Options * `--source` (expects a value) A directory containing files to upload * `--mount` (`-m`) (expects a value) The mount (as an app-relative path) * `--delete` Whether to delete extraneous files in the mount * `--exclude` (expects a value) File(s) to exclude from the upload (pattern) * `--include` (expects a value) File(s) not to exclude (pattern) * `--refresh` Whether to refresh the cache * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--app` (`-A`) (expects a value) The remote application name * `--worker` (expects a value) A worker name * `--instance` (`-I`) (expects a value) An instance ID * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `operation:list` List runtime operations on an environment Aliases: `ops` ####### Usage ``` upsun ops [--full] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-A|--app APP] [--worker WORKER] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] ``` ######## Options * `--full` Do not limit the length of command to display. The default limit is 24 lines. * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--app` (`-A`) (expects a value) The remote application name * `--worker` (expects a value) A worker name * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. Available columns: service*, name*, start*, role, stop (* = default columns). The character "+" can be used as a placeholder for the default columns. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `operation:run` Run an operation on the environment ####### Usage ``` upsun operation:run [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-A|--app APP] [--worker WORKER] [-W|--no-wait] [--wait] [--] [] ``` ######## Arguments * `operation`(optional) The operation name ######## Options * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--app` (`-A`) (expects a value) The remote application name * `--worker` (expects a value) A worker name * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `organization:billing:address` View or change an organization's billing address ####### Usage ``` upsun organization:billing:address [-o|--org ORG] [-p|--project PROJECT] [--date-fmt DATE-FMT] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] [--] [] [] []... ``` ######## Arguments * `property`(optional) The name of a property to view or change * `value`(optional) A new value for the property * `properties`(optional; multiple values allowed) Additional property/value pairs ######## Options * `--org` (`-o`) (expects a value) The organization name (or ID) * `--project` (`-p`) (expects a value) The project ID or URL, to auto-select the organization if --org is not used * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `organization:billing:profile` View or change an organization's billing profile ####### Usage ``` upsun organization:billing:profile [-o|--org ORG] [-p|--project PROJECT] [--date-fmt DATE-FMT] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] [--] [] [] ``` ######## Arguments * `property`(optional) The name of a property to view or change * `value`(optional) A new value for the property ######## Options * `--org` (`-o`) (expects a value) The organization name (or ID) * `--project` (`-p`) (expects a value) The project ID or URL, to auto-select the organization if --org is not used * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `organization:create` Create a new organization ####### Usage ``` upsun organization:create [--label LABEL] [--name NAME] [--country COUNTRY] ``` Organizations allow you to manage your Upsun projects, users and billing. Projects are owned by organizations. You can add other users to your organization, for collaboratively managing the organization as well as its projects and billing information. Access to individual projects (API and SSH) is managed separately, for now. ######## Options * `--label` (expects a value) The full name of the organization, e.g. "ACME Inc." * `--name` (expects a value) The organization machine name, used for URL paths and similar purposes. * `--country` (expects a value) The organization country. Used as the default for the billing address. * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `organization:delete` Delete an organization ####### Usage ``` upsun organization:delete [-o|--org ORG] [-p|--project PROJECT] ``` ######## Options * `--org` (`-o`) (expects a value) The organization name (or ID) * `--project` (`-p`) (expects a value) The project ID or URL, to auto-select the organization if --org is not used * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `organization:info` View or change organization details ####### Usage ``` upsun organization:info [-o|--org ORG] [-p|--project PROJECT] [--date-fmt DATE-FMT] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] [--] [] [] ``` ######## Arguments * `property`(optional) The name of a property to view or change * `value`(optional) A new value for the property ######## Options * `--org` (`-o`) (expects a value) The organization name (or ID) * `--project` (`-p`) (expects a value) The project ID or URL, to auto-select the organization if --org is not used * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * View the organization "acme": ``` upsun organization:info --org acme ``` * Show the organization's label: ``` upsun organization:info --org acme label ``` * Change the organization label: ``` upsun organization:info --org acme label "ACME Inc." ``` ###### `organization:list` List organizations Aliases: `orgs`, `organizations` ####### Usage ``` upsun orgs [--my] [--sort SORT] [--reverse] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] ``` ######## Options * `--my` List only the organizations you own * `--sort` (expects a value) An organization property to sort by * `--reverse` Sort in reverse order * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. Available columns: name*, label*, owner_email*, created_at, id, owner_id, owner_username, updated_at (* = default columns). The character "+" can be used as a placeholder for the default columns. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `organization:subscription:list` List subscriptions within an organization Aliases: `org:subs` ####### Usage ``` upsun org:subs [--page PAGE] [-c|--count COUNT] [-o|--org ORG] [-p|--project PROJECT] [--format FORMAT] [--columns COLUMNS] [--no-header] ``` ######## Options * `--page` (expects a value) Page number. This enables pagination, despite configuration or --count. * `--count` (`-c`) (expects a value) The number of items to display per page. Use 0 to disable pagination. Ignored if --page is specified. * `--org` (`-o`) (expects a value) The organization name (or ID) * `--project` (`-p`) (expects a value) The project ID or URL, to auto-select the organization if --org is not used * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (expects a value) Columns to display. Available columns: id*, project_id*, project_title*, project_region*, created_at, updated_at (* = default columns). The character "+" can be used as a placeholder for the default columns. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `organization:user:add` Invite a user to an organization ####### Usage ``` upsun organization:user:add [-o|--org ORG] [--permission PERMISSION] [--] [] ``` ######## Arguments * `email`(optional) The email address of the user ######## Options * `--org` (`-o`) (expects a value) The organization name (or ID) * `--permission` (expects a value) Permission(s) for the user on the organization. Valid permissions are: billing, members, plans, projects:create, projects:list * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `organization:user:delete` Remove a user from an organization ####### Usage ``` upsun organization:user:delete [-o|--org ORG] [--] ``` ######## Arguments * `email`(required) The email address of the user ######## Options * `--org` (`-o`) (expects a value) The organization name (or ID) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `organization:user:get` View an organization user ####### Usage ``` upsun organization:user:get [-o|--org ORG] [-P|--property PROPERTY] [--date-fmt DATE-FMT] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] [--] [] ``` ######## Arguments * `email`(optional) The email address of the user ######## Options * `--org` (`-o`) (expects a value) The organization name (or ID) * `--property` (`-P`) (expects a value) A property to display * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `organization:user:list` List organization users Aliases: `org:users` ####### Usage ``` upsun org:users [-c|--count COUNT] [--sort SORT] [--reverse] [-o|--org ORG] [--date-fmt DATE-FMT] [--format FORMAT] [--columns COLUMNS] [--no-header] ``` ######## Options * `--count` (`-c`) (expects a value) The number of items to display per page. Use 0 to disable pagination. * `--sort` (expects a value) A property to sort by (created_at or updated_at) * `--reverse` Reverse the sort order * `--org` (`-o`) (expects a value) The organization name (or ID) * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (expects a value) Columns to display. Available columns: id*, email*, owner*, permissions*, created_at, first_name, last_name, mfa_enabled, sso_enabled, updated_at, username (* = default columns). The character "+" can be used as a placeholder for the default columns. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `organization:user:projects` List the projects a user can access Aliases: `oups` ####### Usage ``` upsun oups [-o|--org ORG] [--list-all] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] [--date-fmt DATE-FMT] [--] [] ``` ######## Arguments * `email`(optional) The email address of the user ######## Options * `--org` (`-o`) (expects a value) The organization name (or ID) * `--list-all` List access across all organizations * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. Available columns: project_id*, project_title*, roles*, updated_at*, granted_at, organization_id, organization_label, organization_name, region (* = default columns). The character "+" can be used as a placeholder for the default columns. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `organization:user:update` Update an organization user ####### Usage ``` upsun organization:user:update [-o|--org ORG] [--permission PERMISSION] [--] [] ``` ######## Arguments * `email`(optional) The email address of the user ######## Options * `--org` (`-o`) (expects a value) The organization name (or ID) * `--permission` (expects a value) Permission(s) for the user on the organization. Valid permissions are: billing, members, plans, projects:create, projects:list * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `project:clear-build-cache` Clear a project's build cache ####### Usage ``` upsun project:clear-build-cache [-p|--project PROJECT] ``` ######## Options * `--project` (`-p`) (expects a value) The project ID or URL * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `project:create` Create a new project Aliases: `create` ####### Usage ``` upsun create [-o|--org ORG] [--title TITLE] [--region REGION] [--plan PLAN] [--environments ENVIRONMENTS] [--storage STORAGE] [--default-branch DEFAULT-BRANCH] [--set-remote] [--no-set-remote] ``` Use this command to create a new project. An interactive form will be presented with the available options. If the command is run non-interactively (with --yes), the form will not be displayed, and the --region option will be required. A project subscription will be requested, and then checked periodically (every 3 seconds) until the project has been activated, or until the process times out (15 minutes by default). If known, the project ID will be output to STDOUT. All other output will be sent to STDERR. ######## Options * `--org` (`-o`) (expects a value) The organization name (or ID) * `--title` (expects a value) The initial project title * `--region` (expects a value) The region where the project will be hosted. Get a 3% discount on resources for regions with a carbon intensity of less than 100 gCO2eq/kWh. * `--plan` (expects a value) The subscription plan * `--environments` (expects a value) The number of environments * `--storage` (expects a value) The amount of storage per environment, in GiB * `--default-branch` (expects a value) The default Git branch name for the project (the production environment) * `--set-remote` Set the new project as the remote for this repository. This is the default if no remote project is already set. * `--no-set-remote` Do not set the new project as the remote for this repository * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `project:delete` Delete a project ####### Usage ``` upsun project:delete [-p|--project PROJECT] [--] [] ``` ######## Arguments * `project`(optional) The project ID ######## Options * `--project` (`-p`) (expects a value) The project ID or URL * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `project:get` Clone a project locally Aliases: `get` ####### Usage ``` upsun get [-e|--environment ENVIRONMENT] [--depth DEPTH] [-p|--project PROJECT] [--] [] [] ``` ######## Arguments * `project`(optional) The project ID * `directory`(optional) The directory to clone to. Defaults to the project title ######## Options * `--environment` (`-e`) (expects a value) The environment ID to clone. Defaults to the project default, or the first available environment * `--depth` (expects a value) Create a shallow clone: limit the number of commits in the history * `--project` (`-p`) (expects a value) The project ID or URL * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Clone the project "abc123" into the directory "my-project": ``` upsun project:get abc123 my-project ``` ###### `project:info` Read or set properties for a project ####### Usage ``` upsun project:info [--refresh] [--date-fmt DATE-FMT] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] [-p|--project PROJECT] [-W|--no-wait] [--wait] [--] [] [] ``` ######## Arguments * `property`(optional) The name of the property * `value`(optional) Set a new value for the property ######## Options * `--refresh` Whether to refresh the cache * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--project` (`-p`) (expects a value) The project ID or URL * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Read all project properties: ``` upsun project:info ``` * Show the project's Git URL: ``` upsun project:info git ``` * Change the project's title: ``` upsun project:info title "My project" ``` ###### `project:init` Initialize a project Aliases: `ify` ####### Usage ``` upsun project:init ``` ######## Options * `--help` (`-h`) Display this help message * `--verbose` (`-v|vv|vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Create the starter YAML files for your project: ``` upsun project:init ``` ###### `project:list` Get a list of all active projects Aliases: `projects`, `pro` ####### Usage ``` upsun projects [--pipe] [--region REGION] [--title TITLE] [--my] [--refresh REFRESH] [--sort SORT] [--reverse] [--page PAGE] [-c|--count COUNT] [-o|--org ORG] [--format FORMAT] [--columns COLUMNS] [--no-header] [--date-fmt DATE-FMT] ``` ######## Options * `--pipe` Output a simple list of project IDs. Disables pagination. * `--region` (expects a value) Filter by region (exact match) * `--title` (expects a value) Filter by title (case-insensitive search) * `--my` Display only the projects you own (through organizations you own) * `--refresh` (expects a value) Whether to refresh the list * `--sort` (expects a value) A property to sort by * `--reverse` Sort in reverse (descending) order * `--page` (expects a value) Page number. This enables pagination, despite configuration or --count. Ignored if --pipe is specified. * `--count` (`-c`) (expects a value) The number of projects to display per page. Use 0 to disable pagination. Ignored if --page is specified. * `--org` (`-o`) (expects a value) Filter by organization name or ID * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (expects a value) Columns to display. Available columns: id*, title*, region*, organization_name*, created_at, organization_id, organization_label, status (* = default columns). The character "+" can be used as a placeholder for the default columns. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `project:set-remote` Set the remote project for the current Git repository Aliases: `set-remote` ####### Usage ``` upsun set-remote [] ``` ######## Arguments * `project`(optional) The project ID ######## Options * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Set the remote project for this repository to "abcdef123456": ``` upsun project:set-remote abcdef123456 ``` * Unset the remote project for this repository: ``` upsun project:set-remote - ``` ###### `repo:cat` Read a file in the project repository ####### Usage ``` upsun repo:cat [-c|--commit COMMIT] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [--] ``` ######## Arguments * `path`(required) The path to the file ######## Options * `--commit` (`-c`) (expects a value) The commit SHA. This can also accept "HEAD", and caret (^) or tilde (~) suffixes for parent commits. * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Read the configuration file: ``` upsun repo:cat .upsun/config.yaml ``` ###### `repo:ls` List files in the project repository ####### Usage ``` upsun repo:ls [-d|--directories] [-f|--files] [--git-style] [-c|--commit COMMIT] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [--] [] ``` ######## Arguments * `path`(optional) The path to a subdirectory ######## Options * `--directories` (`-d`) Show directories only * `--files` (`-f`) Show files only * `--git-style` Style output similar to "git ls-tree" * `--commit` (`-c`) (expects a value) The commit SHA. This can also accept "HEAD", and caret (^) or tilde (~) suffixes for parent commits. * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `repo:read` Read a directory or file in the project repository Aliases: `read` ####### Usage ``` upsun read [-c|--commit COMMIT] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [--] [] ``` ######## Arguments * `path`(optional) The path to the directory or file ######## Options * `--commit` (`-c`) (expects a value) The commit SHA. This can also accept "HEAD", and caret (^) or tilde (~) suffixes for parent commits. * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `resources:build:get` View the build resources of a project Aliases: `build-resources:get`, `build-resources` ####### Usage ``` upsun build-resources:get [-p|--project PROJECT] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] ``` ######## Options * `--project` (`-p`) (expects a value) The project ID or URL * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. Available columns: cpu, memory. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `resources:build:set` Set the build resources of a project Aliases: `build-resources:set` ####### Usage ``` upsun build-resources:set [--cpu CPU] [--memory MEMORY] [-p|--project PROJECT] ``` ######## Options * `--cpu` (expects a value) Build CPU * `--memory` (expects a value) Build memory (in MB) * `--project` (`-p`) (expects a value) The project ID or URL * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `resources:get` View the resources of apps and services on an environment Aliases: `resources`, `res` ####### Usage ``` upsun resources [-s|--service SERVICE] [--app APP] [--worker WORKER] [--type TYPE] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] ``` ######## Options * `--service` (`-s`) (expects a value) Filter by service name. This can select any service, including apps and workers. * `--app` (expects a value) Filter by app name * `--worker` (expects a value) Filter by worker name * `--type` (expects a value) Filter by service, app or worker type, e.g. "postgresql" * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. Available columns: service*, profile_size*, cpu*, memory*, disk*, instance_count*, base_memory, memory_ratio, profile, type (* = default columns). The character "+" can be used as a placeholder for the default columns. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `resources:set` Set the resources of apps and services on an environment ####### Usage ``` upsun resources:set [-S|--size SIZE] [-C|--count COUNT] [-D|--disk DISK] [-f|--force] [--dry-run] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-W|--no-wait] [--wait] ``` Configure the resources allocated to apps, workers and services on an environment. The resources may be the profile size, the instance count, or the disk size (MB). Profile sizes are predefined CPU & memory values that can be viewed by running: upsun resources:sizes If the same service and resource is specified on the command line multiple times, only the final value will be used. ######## Options * `--size` (`-S`) (expects a value) Set the profile size (CPU and memory) of apps, workers, or services. Items are in the format name:value and may be comma-separated. The % or * characters may be used as a wildcard for the name. List available sizes with the resources:sizes command. A value of 'default' will use the default size, and 'min' or 'minimum' will use the minimum. * `--count` (`-C`) (expects a value) Set the instance count of apps or workers. Items are in the format name:value as above. * `--disk` (`-D`) (expects a value) Set the disk size (in MB) of apps or services. Items are in the format name:value as above. A value of 'default' will use the default size, and 'min' or 'minimum' will use the minimum. * `--force` (`-f`) Try to run the update, even if it might exceed your limits * `--dry-run` Show the changes that would be made, without changing anything * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Set profile sizes for two apps and a service: ``` upsun resources:set --size frontend:0.1,backend:.25,database:1 ``` * Give the "backend" app 3 instances: ``` upsun resources:set --count backend:3 ``` * Give 512 MB disk to the "backend" app and 2 GB to the "database" service: ``` upsun resources:set --disk backend:512,database:2048 ``` * Set the same profile size for the "backend" and "frontend" apps using a wildcard: ``` upsun resources:set --size '*end:0.1' ``` * Set the same instance count for all apps using a wildcard: ``` upsun resources:set --count '*:3' ``` ###### `resources:size:list` List container profile sizes Aliases: `resources:sizes` ####### Usage ``` upsun resources:sizes [-s|--service SERVICE] [--profile PROFILE] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] ``` ######## Options * `--service` (`-s`) (expects a value) A service name * `--profile` (expects a value) A profile name * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. Available columns: cpu, memory, size. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `route:get` View detailed information about a route ####### Usage ``` upsun route:get [--id ID] [-1|--primary] [-P|--property PROPERTY] [--refresh] [--date-fmt DATE-FMT] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-A|--app APP] [-i|--identity-file IDENTITY-FILE] [--] [] ``` ######## Arguments * `route`(optional) The route's original URL ######## Options * `--id` (expects a value) A route ID to select * `--primary` (`-1`) Select the primary route * `--property` (`-P`) (expects a value) The property to display * `--refresh` Bypass the cache of routes * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--app` (`-A`) (expects a value) [Deprecated option, no longer used] * `--identity-file` (`-i`) (expects a value) [Deprecated option, no longer used] * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * View the URL to the https://{default}/ route: ``` upsun route:get 'https://{default}/' -P url ``` ###### `route:list` List all routes for an environment Aliases: `routes` ####### Usage ``` upsun routes [--refresh] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [--] [] ``` ######## Arguments * `environment`(optional) The environment ID ######## Options * `--refresh` Bypass the cache of routes * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. Available columns: route*, type*, to*, url (* = default columns). The character "+" can be used as a placeholder for the default columns. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `service:list` List services in the project Aliases: `services` ####### Usage ``` upsun services [--refresh] [--pipe] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] ``` ######## Options * `--refresh` Whether to refresh the cache * `--pipe` Output a list of service names only * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. Available columns: disk, name, size, type. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `service:mongo:dump` Create a binary archive dump of data from MongoDB Aliases: `mongodump` ####### Usage ``` upsun mongodump [-c|--collection COLLECTION] [-z|--gzip] [-o|--stdout] [-r|--relationship RELATIONSHIP] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-A|--app APP] ``` ######## Options * `--collection` (`-c`) (expects a value) The collection to dump * `--gzip` (`-z`) Compress the dump using gzip * `--stdout` (`-o`) Output to STDOUT instead of a file * `--relationship` (`-r`) (expects a value) The service relationship to use * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--app` (`-A`) (expects a value) The remote application name * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `service:mongo:export` Export data from MongoDB Aliases: `mongoexport` ####### Usage ``` upsun mongoexport [-c|--collection COLLECTION] [--jsonArray] [--type TYPE] [-f|--fields FIELDS] [-r|--relationship RELATIONSHIP] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-A|--app APP] ``` ######## Options * `--collection` (`-c`) (expects a value) The collection to export * `--jsonArray` Export data as a single JSON array * `--type` (expects a value) The export type, e.g. "csv" * `--fields` (`-f`) (expects a value) The fields to export * `--relationship` (`-r`) (expects a value) The service relationship to use * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--app` (`-A`) (expects a value) The remote application name * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Export a CSV from the "users" collection: ``` upsun service:mongo:export -c users --type csv -f name,email ``` ###### `service:mongo:restore` Restore a binary archive dump of data into MongoDB Aliases: `mongorestore` ####### Usage ``` upsun mongorestore [-c|--collection COLLECTION] [-r|--relationship RELATIONSHIP] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-A|--app APP] ``` ######## Options * `--collection` (`-c`) (expects a value) The collection to restore * `--relationship` (`-r`) (expects a value) The service relationship to use * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--app` (`-A`) (expects a value) The remote application name * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `service:mongo:shell` Use the MongoDB shell Aliases: `mongo` ####### Usage ``` upsun mongo [--eval EVAL] [-r|--relationship RELATIONSHIP] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-A|--app APP] ``` ######## Options * `--eval` (expects a value) Pass a JavaScript fragment to the shell * `--relationship` (`-r`) (expects a value) The service relationship to use * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--app` (`-A`) (expects a value) The remote application name * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Display collection names: ``` upsun service:mongo:shell --eval 'printjson(db.getCollectionNames())' ``` ###### `service:redis-cli` Access the Redis CLI Aliases: `redis` ####### Usage ``` upsun redis [-r|--relationship RELATIONSHIP] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-A|--app APP] [--] [] ``` ######## Arguments * `args`(optional) Arguments to add to the Redis command ######## Options * `--relationship` (`-r`) (expects a value) The service relationship to use * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--app` (`-A`) (expects a value) The remote application name * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Open the redis-cli shell: ``` upsun service:redis-cli ``` * Ping the Redis server: ``` upsun service:redis-cli ping ``` * Show Redis status information: ``` upsun service:redis-cli info ``` * Scan keys: ``` upsun service:redis-cli -- --scan ``` * Scan keys matching a pattern: ``` upsun service:redis-cli -- "--scan --pattern '*-11*'" ``` ###### `source-operation:list` List source operations on an environment Aliases: `source-ops` ####### Usage ``` upsun source-ops [--full] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] ``` ######## Options * `--full` Do not limit the length of command to display. The default limit is 24 lines. * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. Available columns: app, command, operation. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `source-operation:run` Run a source operation ####### Usage ``` upsun source-operation:run [--variable VARIABLE] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-W|--no-wait] [--wait] [--] [] ``` ######## Arguments * `operation`(optional) The operation name ######## Options * `--variable` (expects a value) A variable to set during the operation, in the format type:name=value * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Run the "update" operation, setting environment variable FOO=bar: ``` upsun source-operation:run update --variable env:FOO=bar ``` ###### `ssh-cert:load` Generate an SSH certificate ####### Usage ``` upsun ssh-cert:load [--refresh-only] [--new] [--new-key] ``` This command checks if a valid SSH certificate is present, and generates a new one if necessary. Certificates allow you to make SSH connections without having previously uploaded a public key. They are more secure than keys and they allow for other features. Normally the certificate is loaded automatically during login, or when making an SSH connection. So this command is seldom needed. If you want to set up certificates without login and without an SSH-related command, for example if you are writing a script that uses an API token via an environment variable, then you would probably want to run this command explicitly. For unattended scripts, remember to turn off interaction via --yes or the UPSUN_CLI_NO_INTERACTION environment variable. ######## Options * `--refresh-only` Only refresh the certificate, if necessary (do not write SSH config) * `--new` Force the certificate to be refreshed * `--new-key` Force a new key pair to be generated * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `ssh-key:add` Add a new SSH key ####### Usage ``` upsun ssh-key:add [--name NAME] [--] [] ``` This command lets you add an SSH key to your account. It can generate a key using OpenSSH. Notice: SSH keys are no longer needed by default, as SSH certificates are supported. Certificates offer more security than keys. To load or check your SSH certificate, run: upsun ssh-cert:load ######## Arguments * `path`(optional) The path to an existing SSH public key ######## Options * `--name` (expects a value) A name to identify the key * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `ssh-key:delete` Delete an SSH key ####### Usage ``` upsun ssh-key:delete [] ``` This command lets you delete SSH keys from your account. Notice: SSH keys are no longer needed by default, as SSH certificates are supported. Certificates offer more security than keys. To load or check your SSH certificate, run: upsun ssh-cert:load ######## Arguments * `id`(optional) The ID of the SSH key to delete ######## Options * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Delete the key 123: ``` upsun ssh-key:delete 123 ``` ###### `ssh-key:list` Get a list of SSH keys in your account Aliases: `ssh-keys` ####### Usage ``` upsun ssh-keys [--format FORMAT] [-c|--columns COLUMNS] [--no-header] ``` This command lets you list SSH keys in your account. Notice: SSH keys are no longer needed by default, as SSH certificates are supported. Certificates offer more security than keys. To load or check your SSH certificate, run: upsun ssh-cert:load ######## Options * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. Available columns: id*, title*, path*, fingerprint (* = default columns). The character "+" can be used as a placeholder for the default columns. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `subscription:info` Read or modify subscription properties ####### Usage ``` upsun subscription:info [-s|--id ID] [--date-fmt DATE-FMT] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] [-p|--project PROJECT] [--] [] [] ``` ######## Arguments * `property`(optional) The name of the property * `value`(optional) Set a new value for the property ######## Options * `--id` (`-s`) (expects a value) The subscription ID * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--project` (`-p`) (expects a value) The project ID or URL * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * View all subscription properties: ``` upsun subscription:info ``` * View the subscription status: ``` upsun subscription:info status ``` * View the storage limit (in MiB): ``` upsun subscription:info storage ``` ###### `team:create` Create a new team ####### Usage ``` upsun team:create [--label LABEL] [--no-check-unique] [-r|--role ROLE] [--output-id] [-o|--org ORG] ``` ######## Options * `--label` (expects a value) The team label * `--no-check-unique` Do not error if another team exists with the same label in the organization * `--role` (`-r`) (expects a value) Set the team's project and environment type roles Values may be split by commas (e.g. "a,b,c") and/or whitespace. The % or * characters may be used as a wildcard. * `--output-id` Output the new team's ID to stdout (instead of displaying the team info) * `--org` (`-o`) (expects a value) The organization name (or ID) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `team:delete` Delete a team ####### Usage ``` upsun team:delete [-o|--org ORG] [-t|--team TEAM] ``` ######## Options * `--org` (`-o`) (expects a value) The organization name (or ID) * `--team` (`-t`) (expects a value) The team ID * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `team:get` View a team ####### Usage ``` upsun team:get [-o|--org ORG] [-p|--project PROJECT] [-t|--team TEAM] [-P|--property PROPERTY] [--date-fmt DATE-FMT] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] ``` ######## Options * `--org` (`-o`) (expects a value) The organization name (or ID) * `--project` (`-p`) (expects a value) The project ID or URL, to auto-select the organization if --org is not used * `--team` (`-t`) (expects a value) The team ID * `--property` (`-P`) (expects a value) The name of a property to view * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `team:list` List teams Aliases: `teams` ####### Usage ``` upsun teams [-c|--count COUNT] [--sort SORT] [--reverse] [-o|--org ORG] [-p|--project PROJECT] [--date-fmt DATE-FMT] [--format FORMAT] [--columns COLUMNS] [--no-header] ``` ######## Options * `--count` (`-c`) (expects a value) The number of items to display per page. Use 0 to disable pagination. * `--sort` (expects a value) A team property to sort by * `--reverse` Sort in reverse order * `--org` (`-o`) (expects a value) The organization name (or ID) * `--project` (`-p`) (expects a value) The project ID or URL, to auto-select the organization if --org is not used * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (expects a value) Columns to display. Available columns: id*, label*, member_count*, project_count*, project_permissions*, created_at, updated_at (* = default columns). The character "+" can be used as a placeholder for the default columns. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `team:project:add` Add project(s) to a team ####### Usage ``` upsun team:project:add [--all] [-o|--org ORG] [-t|--team TEAM] [--] []... ``` ######## Arguments * `projects`(optional; multiple values allowed) The project ID(s). Values may be split by commas (e.g. "a,b,c") and/or whitespace. ######## Options * `--all` Add all the projects that currently exist in the organization * `--org` (`-o`) (expects a value) The organization name (or ID) * `--team` (`-t`) (expects a value) The team ID * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `team:project:delete` Remove a project from a team ####### Usage ``` upsun team:project:delete [-o|--org ORG] [-t|--team TEAM] [--] [] ``` ######## Arguments * `project`(optional) The project ID ######## Options * `--org` (`-o`) (expects a value) The organization name (or ID) * `--team` (`-t`) (expects a value) The team ID * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `team:project:list` List projects in a team Aliases: `team:projects`, `team:pro` ####### Usage ``` upsun team:projects [-c|--count COUNT] [-o|--org ORG] [-t|--team TEAM] [--date-fmt DATE-FMT] [--format FORMAT] [--columns COLUMNS] [--no-header] ``` ######## Options * `--count` (`-c`) (expects a value) The number of items to display per page (max: 200). Use 0 to disable pagination * `--org` (`-o`) (expects a value) The organization name (or ID) * `--team` (`-t`) (expects a value) The team ID * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (expects a value) Columns to display. Available columns: id*, title*, granted_at*, updated_at (* = default columns). The character "+" can be used as a placeholder for the default columns. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `team:update` Update a team ####### Usage ``` upsun team:update [--label LABEL] [--no-check-unique] [-r|--role ROLE] [-t|--team TEAM] [-o|--org ORG] [-W|--no-wait] [--wait] ``` ######## Options * `--label` (expects a value) Set a new team label * `--no-check-unique` Do not error if another team exists with the same label in the organization * `--role` (`-r`) (expects a value) Set the team's project and environment type roles Values may be split by commas (e.g. "a,b,c") and/or whitespace. The % or * characters may be used as a wildcard. * `--team` (`-t`) (expects a value) The team ID * `--org` (`-o`) (expects a value) The organization name (or ID) * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `team:user:add` Add a user to a team ####### Usage ``` upsun team:user:add [-o|--org ORG] [-t|--team TEAM] [--] [] ``` ######## Arguments * `user`(optional) The user email address or ID ######## Options * `--org` (`-o`) (expects a value) The organization name (or ID) * `--team` (`-t`) (expects a value) The team ID * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `team:user:delete` Remove a user from a team ####### Usage ``` upsun team:user:delete [-o|--org ORG] [-t|--team TEAM] [--] [] ``` ######## Arguments * `user`(optional) The user email address or ID ######## Options * `--org` (`-o`) (expects a value) The organization name (or ID) * `--team` (`-t`) (expects a value) The team ID * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `team:user:list` List users in a team Aliases: `team:users` ####### Usage ``` upsun team:users [-c|--count COUNT] [-o|--org ORG] [-t|--team TEAM] [--date-fmt DATE-FMT] [--format FORMAT] [--columns COLUMNS] [--no-header] ``` ######## Options * `--count` (`-c`) (expects a value) The number of items to display per page. Use 0 to disable pagination * `--org` (`-o`) (expects a value) The organization name (or ID) * `--team` (`-t`) (expects a value) The team ID * `--date-fmt` (expects a value) The date format (as a PHP date format string) * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (expects a value) Columns to display. Available columns: id*, email*, created_at*, updated_at (* = default columns). The character "+" can be used as a placeholder for the default columns. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `tunnel:close` Close SSH tunnels ####### Usage ``` upsun tunnel:close [-a|--all] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-A|--app APP] ``` ######## Options * `--all` (`-a`) Close all tunnels * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--app` (`-A`) (expects a value) The remote application name * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `tunnel:info` View relationship info for SSH tunnels ####### Usage ``` upsun tunnel:info [-P|--property PROPERTY] [-c|--encode] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-A|--app APP] ``` ######## Options * `--property` (`-P`) (expects a value) The relationship property to view * `--encode` (`-c`) Output as base64-encoded JSON * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--app` (`-A`) (expects a value) The remote application name * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `tunnel:list` List SSH tunnels Aliases: `tunnels` ####### Usage ``` upsun tunnels [-a|--all] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-A|--app APP] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] ``` ######## Options * `--all` (`-a`) View all tunnels * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--app` (`-A`) (expects a value) The remote application name * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. Available columns: port*, project*, environment*, app*, relationship*, url (* = default columns). The character "+" can be used as a placeholder for the default columns. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `tunnel:open` Open SSH tunnels to an app's relationships ####### Usage ``` upsun tunnel:open [-g|--gateway-ports] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-A|--app APP] ``` This command opens SSH tunnels to all of the relationships of an application. Connections can then be made to the application's services as if they were local, for example a local MySQL client can be used, or the Solr web administration endpoint can be accessed through a local browser. This command requires the posix and pcntl PHP extensions (as multiple background CLI processes are created to keep the SSH tunnels open). The tunnel:single command can be used on systems without these extensions. ######## Options * `--gateway-ports` (`-g`) Allow remote hosts to connect to local forwarded ports * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--app` (`-A`) (expects a value) The remote application name * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `tunnel:single` Open a single SSH tunnel to an app relationship ####### Usage ``` upsun tunnel:single [--port PORT] [-g|--gateway-ports] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-A|--app APP] [-r|--relationship RELATIONSHIP] ``` ######## Options * `--port` (expects a value) The local port * `--gateway-ports` (`-g`) Allow remote hosts to connect to local forwarded ports * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--app` (`-A`) (expects a value) The remote application name * `--relationship` (`-r`) (expects a value) The service relationship to use * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `user:add` Add a user to the project ####### Usage ``` upsun user:add [-r|--role ROLE] [--force-invite] [-p|--project PROJECT] [-W|--no-wait] [--wait] [--] [] ``` ######## Arguments * `email`(optional) The user's email address ######## Options * `--role` (`-r`) (expects a value) The user's project role ('admin' or 'viewer') or environment type role (e.g. 'staging:contributor' or 'production:viewer'). To remove a user from an environment type, set the role as 'none'. The % or * characters can be used as a wildcard for the environment type, e.g. '%:viewer' to give the user the 'viewer' role on all types. The role can be abbreviated, e.g. 'production:v'. * `--force-invite` Send an invitation, even if one has already been sent * `--project` (`-p`) (expects a value) The project ID or URL * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Add Alice as a project admin: ``` upsun user:add alice@example.com -r admin ``` * Add Bob as a viewer on the "production" environment type, and a contributor on "development" environments: ``` upsun user:add bob@example.com -r production:v -r development:c ``` * Add Charlie as viewer on "production" and "development": ``` upsun user:add charlie@example.com -r prod%:v -r dev%:v ``` ###### `user:delete` Delete a user from the project ####### Usage ``` upsun user:delete [-p|--project PROJECT] [-W|--no-wait] [--wait] [--] ``` ######## Arguments * `email`(required) The user's email address ######## Options * `--project` (`-p`) (expects a value) The project ID or URL * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Delete Alice from the project: ``` upsun user:delete alice@example.com ``` ###### `user:get` View a user's role(s) ####### Usage ``` upsun user:get [-l|--level LEVEL] [--pipe] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-W|--no-wait] [--wait] [-r|--role ROLE] [--] [] ``` ######## Arguments * `email`(optional) The user's email address ######## Options * `--level` (`-l`) (expects a value) The role level ('project' or 'environment') * `--pipe` Output the role to stdout (after making any changes) * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--role` (`-r`) (expects a value) [Deprecated: use user:update to change a user's role(s)] * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * View Alice's role on the project: ``` upsun user:get alice@example.com ``` * View Alice's role on the current environment: ``` upsun user:get alice@example.com --level environment --pipe ``` ###### `user:list` List project users Aliases: `users` ####### Usage ``` upsun users [--format FORMAT] [-c|--columns COLUMNS] [--no-header] [-p|--project PROJECT] ``` ######## Options * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. Available columns: email*, name*, role*, id*, granted_at, permissions, updated_at (* = default columns). The character "+" can be used as a placeholder for the default columns. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--project` (`-p`) (expects a value) The project ID or URL * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `user:update` Update user role(s) on a project ####### Usage ``` upsun user:update [-r|--role ROLE] [-p|--project PROJECT] [-W|--no-wait] [--wait] [--] [] ``` ######## Arguments * `email`(optional) The user's email address ######## Options * `--role` (`-r`) (expects a value) The user's project role ('admin' or 'viewer') or environment type role (e.g. 'staging:contributor' or 'production:viewer'). To remove a user from an environment type, set the role as 'none'. The % or * characters can be used as a wildcard for the environment type, e.g. '%:viewer' to give the user the 'viewer' role on all types. The role can be abbreviated, e.g. 'production:v'. * `--project` (`-p`) (expects a value) The project ID or URL * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Make Bob an admin on the "development" and "staging" environment types: ``` upsun user:update bob@example.com -r development:a,staging:a ``` * Make Charlie a contributor on all environment types: ``` upsun user:update charlie@example.com -r %:c ``` ###### `variable:create` Create a variable ####### Usage ``` upsun variable:create [-u|--update] [-l|--level LEVEL] [--name NAME] [--value VALUE] [--json JSON] [--sensitive SENSITIVE] [--prefix PREFIX] [--enabled ENABLED] [--inheritable INHERITABLE] [--visible-build VISIBLE-BUILD] [--visible-runtime VISIBLE-RUNTIME] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-W|--no-wait] [--wait] [--] [] ``` ######## Arguments * `name`(optional) The variable name ######## Options * `--update` (`-u`) Update the variable if it already exists * `--level` (`-l`) (expects a value) The level at which to set the variable ('project' or 'environment') * `--name` (expects a value) The variable name * `--value` (expects a value) The variable's value * `--json` (expects a value) Whether the variable value is JSON-formatted * `--sensitive` (expects a value) Whether the variable value is sensitive * `--prefix` (expects a value) The variable name's prefix which can determine its type, e.g. 'env'. Only applicable if the name does not already contain a prefix. (e.g. 'none' or 'env:') * `--enabled` (expects a value) Whether the variable should be enabled on the environment * `--inheritable` (expects a value) Whether the variable is inheritable by child environments * `--visible-build` (expects a value) Whether the variable should be visible at build time * `--visible-runtime` (expects a value) Whether the variable should be visible at runtime * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `variable:delete` Delete a variable ####### Usage ``` upsun variable:delete [-l|--level LEVEL] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-W|--no-wait] [--wait] [--] ``` ######## Arguments * `name`(required) The variable name ######## Options * `--level` (`-l`) (expects a value) The variable level ('project', 'environment', 'p' or 'e') * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * Delete the variable "example": ``` upsun variable:delete example ``` ###### `variable:get` View a variable Aliases: `vget` ####### Usage ``` upsun vget [-P|--property PROPERTY] [-l|--level LEVEL] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [--pipe] [--] [] ``` ######## Arguments * `name`(optional) The name of the variable ######## Options * `--property` (`-P`) (expects a value) View a single variable property * `--level` (`-l`) (expects a value) The variable level ('project', 'environment', 'p' or 'e') * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--pipe` [Deprecated option] Output the variable value only * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ####### Examples * View the variable "example": ``` upsun variable:get example ``` ###### `variable:list` List variables Aliases: `variables`, `var` ####### Usage ``` upsun variables [-l|--level LEVEL] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] ``` ######## Options * `--level` (`-l`) (expects a value) The variable level ('project', 'environment', 'p' or 'e') * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. Available columns: is_enabled, level, name, value. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `variable:update` Update a variable ####### Usage ``` upsun variable:update [--allow-no-change] [-l|--level LEVEL] [--value VALUE] [--json JSON] [--sensitive SENSITIVE] [--enabled ENABLED] [--inheritable INHERITABLE] [--visible-build VISIBLE-BUILD] [--visible-runtime VISIBLE-RUNTIME] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [-W|--no-wait] [--wait] [--] ``` ######## Arguments * `name`(required) The variable name ######## Options * `--allow-no-change` Return success (zero exit code) if no changes were provided * `--level` (`-l`) (expects a value) The variable level ('project', 'environment', 'p' or 'e') * `--value` (expects a value) The variable's value * `--json` (expects a value) Whether the variable value is JSON-formatted * `--sensitive` (expects a value) Whether the variable value is sensitive * `--enabled` (expects a value) Whether the variable should be enabled on the environment * `--inheritable` (expects a value) Whether the variable is inheritable by child environments * `--visible-build` (expects a value) Whether the variable should be visible at build time * `--visible-runtime` (expects a value) Whether the variable should be visible at runtime * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--no-wait` (`-W`) Do not wait for the operation to complete * `--wait` Wait for the operation to complete (default) * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ###### `worker:list` Get a list of all deployed workers Aliases: `workers` ####### Usage ``` upsun workers [--refresh] [--pipe] [-p|--project PROJECT] [-e|--environment ENVIRONMENT] [--format FORMAT] [-c|--columns COLUMNS] [--no-header] ``` ######## Options * `--refresh` Whether to refresh the cache * `--pipe` Output a list of worker names only * `--project` (`-p`) (expects a value) The project ID or URL * `--environment` (`-e`) (expects a value) The environment ID. Use "." to select the project's default environment. * `--format` (expects a value) The output format: table, csv, tsv, or plain * `--columns` (`-c`) (expects a value) Columns to display. Available columns: commands, name, type. The % or * characters may be used as a wildcard. Values may be split by commas (e.g. "a,b,c") and/or whitespace. * `--no-header` Do not output the table header * `--help` (`-h`) Display this help message * `--verbose` (`-v|-vv|-vvv`) Increase the verbosity of messages * `--version` (`-V`) Display this application version * `--yes` (`-y`) Answer "yes" to confirmation questions; accept the default value for other questions; disable interaction * `--no-interaction` Do not ask any interactive questions; accept default values. Equivalent to using the environment variable: UPSUN_CLI_NO_INTERACTION=1 ### Console Upsun provides a web console so you can interact with your projects and manage your environments. ![Overview of projects in the Console](https://docs.upsun.com/images/console/upsun-console-main-view.png "0.6") This Console offers you ways to manage projects and environments other than the [command line interface (CLI))](https://docs.upsun.com../cli.md). ##### Project list Opening the [Console](https://console.upsun.com) takes you to the first organization you joined as a Upsun user. You get an overview of all your projects within that organization. You can narrow the list down by searching for specific projects, or switch to a different organization from the menu in the top left-hand corner. Once you select a project, you can [configure the project settings](https://docs.upsun.com/administration/web/configure-project.md). You can also choose individual environments within the project and [configure each environment](https://docs.upsun.com/administration/web/configure-environment.md). You can also create a new project by clicking **+ Create project**. ##### Display settings You can personalize the display settings for the Console. To do so: 1. Open the user menu (your name or profile picture). 2. Click **My Profile**. 3. Choose the mode you want. 4. Click **Save**. The Console can be displayed in three ways: * Light mode (default) * High contrast mode * Dark mode To meet our [commitment to accessibility](https://platform.sh/trust-center/legal/wcag/), all three options are compliant with level AA of the Web Content Accessibility Guidelines 2.0. #### Configure a project Each project has settings that apply to everything within that project, including all its environments. You can only see and update settings for projects where you are a [Project Admin](https://docs.upsun.com../users.md). To access the settings, click Settings **Settings** from the main project page. The settings are divided into several sections. ###### General The **General** section shows you the project's region and allows you to update the project name and [timezone](https://docs.upsun.com../../projects/change-project-timezone.md). ![configure project](https://docs.upsun.com/images/console/settings-general.png "1.0") ###### Access The **Access** section allows you to [manage user access to the project](https://docs.upsun.com../users.md). ![Project configure icon](https://docs.upsun.com/images/console/settings-access-users.png "0.7") ###### Certificates The **Certificates** section shows a list of your project's TLS certificates. To see details about a certificate or delete one, click **Edit **. See how to [add custom certificates](https://docs.upsun.com../../domains/steps/tls.md). ![A list of certificates in a project](https://docs.upsun.com/images/management-console/settings-certificates.png "0.7") ###### Domains The **Domains** section allows you to manage the domains where your project is accessible. See how to [set up your domain](https://docs.upsun.com../../domains/steps.md). ![project domain](https://docs.upsun.com/images/management-console/settings-domains.png "0.7") ###### Deploy Key The **Deploy Key** section shows you the public SSH key you can add to your private repositories. Adding it lets Upsun access the repositories during the build process. This is useful if you want to reuse some code components across multiple projects and manage those components as dependencies of your project. ![Project deploy key](https://docs.upsun.com/images/management-console/settings-deploy-key.png "0.7") ###### Integrations The **Integrations** section allows you to manage all of your [integrations](https://docs.upsun.com../../integrations.md). ![Integrations](https://docs.upsun.com/images/management-console/settings-integrations.png "0.7") ###### Variables The **Variables** section allows you to manage all project-wide [variables](https://docs.upsun.com../../development/variables.md). ![Project variables](https://docs.upsun.com/images/management-console/settings-variables-project.png "0.7") #### Configure environments From your project's main page in the Console, you can see all your environments as a list or a project tree: ![List of all environments as a tree](https://docs.upsun.com/images/management-console/environments.png "0.5") In this overview, the names of inactive environments are lighter. Selecting an environment allows you to see details about it, such as its [activity feed](#activity-feed), [services](#service-information), [metrics](https://docs.upsun.com../../increase-observability/metrics.md), and [backups](https://docs.upsun.com../../environments/backup.md). ###### Activity Feed When you access an environment in the Console, you can see its [activity feed](https://docs.upsun.com../../increase-observability/logs/access-logs.md#activity-logs). This allows you to check which activities have happened or are currently happening on the selected environment: ![Environment activity list](https://docs.upsun.com/images/management-console/activity.png "0.5") You can filter activities by type (such as merge, sync, or redeploy). ###### Actions on environments Each environment offers ways to keep environments up to date with one another: * [Branch **Branch**](https://docs.upsun.com/glossary.md#branch) to create a new child environment. * [Merge **Merge**](https://docs.upsun.com/glossary.md#merge) to copy the current environment into its parent. * [ **Sync**](https://docs.upsun.com/glossary.md#sync) to copy changes from its parent environment into the current environment. There are also additional options: * Settings **Settings** to [configure the environment](#environment-settings). * More **More** to get more options. * **URLs** to access the deployed environment from the web. * **SSH** to access your project using SSH. * **Code** * **CLI** for the command to get your project set up locally with the [Upsun CLI](https://docs.upsun.com../cli.md). * **Git** for the command to clone the codebase via Git. If you're using Upsun as your primary remote repository, the command clones from the project. If you have set up an [external integration](https://docs.upsun.com../../integrations/source.md), the command clones directly from the integrated remote repository. If the project uses an external integration to a repository that you haven't been given access to, you can't clone until your access has been updated. See how to [troubleshoot source integrations](https://docs.upsun.com../../integrations/source/troubleshoot.md). ###### Environment URL When you access an environment in the Console, you can view its URL: ![Environment URL and details](https://docs.upsun.com/images/management-console/env-url.png "0.25") While the environment is loading in the Console, a `Waiting for URL...` message is displayed instead of the URL. If this message isn't updated once your [default environment](https://docs.upsun.com../../environments/_index.md#default-environment)'s information is loaded, follow these steps: 1. Check that [you have defined routes](https://docs.upsun.com../../define-routes.md) for your default environment. 2. Verify that your [application](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md), [services](https://docs.upsun.com../../add-services.md), and [routes](https://docs.upsun.com../../define-routes.md) configurations are correct. 3. Check that your default environment is [active](https://docs.upsun.com../../environments/deactivate-environment.md#reactivate-an-environment). ###### Environment settings To access the settings of an environment, click Settings **Settings** within that environment. ![Settings for an environment](https://docs.upsun.com/images/management-console/env-settings.png "0.75") ####### Environment name Under **Environment name**, you can edit the name and type of your environment and view its parent environment: ![Environment status](https://docs.upsun.com/images/management-console/env-name.png "0.5") ####### Status Under **Status**, you can check whether or not your environment is [active](https://docs.upsun.com/glossary.md#active-environment). ![Environment status](https://docs.upsun.com/images/management-console/env-status.png "0.5") For preview environments, you can [change their status](https://docs.upsun.com../../environments/deactivate-environment.md). ####### Outgoing emails Under **Outgoing emails**, you can allow your environment to [send emails](https://docs.upsun.com../../development/email.md): ![Environment email](https://docs.upsun.com/images/management-console/env-email.png "0.75") ####### Hide from search engines Under **Hide from search engines**, you can tell [search engines to ignore the site](https://docs.upsun.com../../environments/search-engine-visibility.md): ![Environment search](https://docs.upsun.com/images/management-console/env-search.png "0.5") ####### HTTP access control Under **HTTP access control**, you can [control access to your environment using HTTP methods](https://docs.upsun.com../../environments/http-access-control.md): ![Settings control access with password and by IP](https://docs.upsun.com/images/management-console/settings-basics-access-control.png "0.5") ####### Variables Under **Variables**, you can define [environment variables](https://docs.upsun.com../../development/variables/_index.md): ![Configure Upsun environment variables](https://docs.upsun.com/images/management-console/settings-variables-environment.png "0.6") ###### Service information For each environment, you can view information about how your routes, services, and apps are currently configured. To do so, click **Services**. By default, you see configured routes. ####### Routes The **Router** section shows a list of all the [routes configured on your environment](https://docs.upsun.com../../define-routes.md). You can see each route's type and check if caching and server side includes have been enabled for it: ![Services: routes](https://docs.upsun.com/images/management-console/service-tab/routes.png "0.5") To view the configuration file where your routes are set up, click **Configuration**. ####### Applications To see detailed information about an app container, select it in the tree or list on the left-hand side: ![Services: app overview](https://docs.upsun.com/images/management-console/service-tab/app-overview.png "0.5") The **Overview** tab gives you information about your app. You can see: * The language version, the container size, the amount of persistent disk, the number of cron jobs, and the command to SSH into the container. * A summary of [metrics for the environment](https://docs.upsun.com../../increase-observability/metrics.md). * All cron jobs with their name, frequency, and command. * All workers with their name, size, amount of persistent disk, and command to SSH into the container. To view [the configuration file where your app is set up](https://docs.upsun.com../../create-apps/), click **Configuration**. ####### Services To see detailed information about a [running service](https://docs.upsun.com../../add-services.md), select it in the tree or list on the left-hand side: ![Services: service overview](https://docs.upsun.com/images/management-console/service-tab/service-overview.png "0.5") The **Overview** gives you information about the selected service. You can see the service version, the container size, and the disk size, if you've configured a persistent disk. You can also see a summary of [metrics for the environment](https://docs.upsun.com../../increase-observability/metrics.md). To view the configuration file where your services are set up, click **Configuration**. ### Organizations Organizations allow you to manage your Upsun projects, users, and billing. You can group multiple projects in one organization and manage them together. To manage users within your organization, see how to [manage organization users](https://docs.upsun.com/administration/users.md#manage-organization-users). ##### Manage your organization settings As an organization owner, you can manage the basic settings for your organization such as its name and URL. To change the name (URL) and label of the ``acme`` organization, run: ```bash {} upsun organization:info --org acme label "Acme Corp" name acme-corp ``` To verify the changes, run: ```bash {} upsun organization:info --org acme-corp ``` ##### Manage your organization billing As an organization owner or an organization user with the **Manage billing** permission, you can access and download invoices and edit billing information such as the stored credit card and billing address. ##### Create a new organization When you create a new project, if you don't already have an organization, one is created for you automatically. You can create new organizations with different payment methods and billing addresses and organize your projects as you want. To create an organization with the label ``Acme`` and the name (URL) ``acme``, run: ```bash {} upsun organization:create --label "Acme" --name acme --country "United States" ``` To verify the changes, run: ```bash {} upsun organization:info --org acme ``` **Note**: To monitor your spend, you can [set billing alerts](https://docs.upsun.com/administration/billing/monitor-billing.md#manage-billing-alerts) on your new organization. Billing alerts are based on a [current month estimate](https://docs.upsun.com/administration/billing/monitor-billing.md#current-month-estimate). Once that estimate reaches a defined threshold, you receive an email notification. ##### Delete an existing organization As an organization owner, you can delete your own organization. Note that if your organization owns projects or owes remaining invoices, you can not delete it yourself. To have it deleted, [contact support](https://docs.upsun.com/learn/overview/get-support.md). To delete the organization ``acme``, run: ```bash {} upsun organization:delete --org acme ``` ##### Transfer project ownership You can transfer your plan ownership to a different organization at anytime. You have to be an organization owner or have the [manage plan permission](https://docs.upsun.com/administration/users.md#organization-permissions). 1. Make the new organization owner a [project admin](https://docs.upsun.com/administration/users.md#) for the project you want to transfer. 2. To ask for the transfer, from your organization account open a [support ticket](https://docs.upsun.com/learn/overview/get-support.md). Once the transfer is completed, the new organization can administer all project settings and billing and receives future invoices. Ownership transfer automatically transfers subscription charges to the new organization. ##### Transfer organization ownership To transfer an organization to a different owner, first make sure that user is part of the organization. If they aren't yet, [add them](https://docs.upsun.com/administration/users.md#add-a-user-to-an-organization). Then open a [support ticket](https://docs.upsun.com/learn/overview/get-support.md) from the current organization to ask for the transfer. ### Administer teams **Feature Availability** This feature is available as part of the Standard User Management add-on. To enable it on your organization, [administer your organization’s billing](https://docs.upsun.com/administration/billing/billing-admin.md). Organizations on Upsun are made up of both [projects](https://docs.upsun.com/projects/) and [users](https://docs.upsun.com/administration/users.md). While organizations by themselves allow you to assign project and environment type permissions to individual users on individual projects, having many users and many projects calls for another method to group common access control settings. **Teams** provide a grouping that connects a subset of an organization's users to another subset of that organization's projects. That relationship enables organization owners to set default project and environment type access settings for each user and project from one place. There is no limit to the number of teams that can be defined within a single organization. ##### Create a new team As an organization owner or member with **Manage users** permissions, you can create new teams. Teams must belong to an organization, so [create one](https://docs.upsun.com/administration/organizations.md#create-a-new-organization) first. You can create new organizations with different payment methods and billing addresses and organize your projects as you want, but keep in mind that both users and teams are restricted to single organizations. - Run the following command: ```bash {} upsun team:create -o ``` - Enter a team name. - Define your team’s project role (admin or viewer). - If your team has viewer rights on the project, define its role on each type of environment. - Enter ``Y`` to confirm. **Note**: To view a list of all the existing teams in your organization, run the following command: ```bash {} upsun team:list -o ``` ##### Delete an existing team As an organization owner or member with **Manage users** permissions, you can delete existing teams. Note that deleting teams and deleting users are not equivalent. Deleting a team will remove member access permissions to projects described by the team, but it will _not_ [remove users from the organization](https://docs.upsun.com/administration/users.md#remove-a-user-from-an-organization) (or your billing). - Run the following command: ```bash {} upsun team:delete -o ``` - Select the team you want to delete. - Enter ``Y`` to confirm. ##### Manage team settings As an organization owner or member with **Manage users** permissions, you can manage the settings of existing teams such as: - [It's name](#team-name) - [The environment type permissions granted to members on individual projects](#project--environment-type-permissions) - [Team members](#team-members) - [Project access](#team-access-to-projects) ###### Team name - Run the following command: ```bash {} upsun team:update -o ``` - Select the team you want to rename. - Enter the new name. - Confirm or adjust the team permissions. - Enter ``Y`` to confirm. ###### Project & environment type permissions The primary purpose of teams is to allow organizations to quickly apply, audit, and update project and environment type permissions for groups of users. - Run the following command: ```bash {} upsun team:update -o ``` - Select the team whose permissions you want to update. - Confirm or adjust the team name. - Adjust the team permissions. - Enter ``Y`` to confirm. ###### Team members ####### Add users to a team To join a team, a user must already have been added [to the organization](https://docs.upsun.com/administration/users.md#manage-organization-access), where their [organization permissions](https://docs.upsun.com/administration/users.md#organization-permissions) are defined. - Run the following command: ```bash {} upsun team:user:add -o ``` - Select the team you want to add a user to. - Enter the user’s email address. - Enter ``Y`` to confirm. **Note**: To view a list of all the users on a team, follow these steps: - Run the following command: ```bash {} upsun team:user:list -o ``` - Select the team whose users you want to display. ####### Remove users from a team Note that deleting users from teams and deleting users from organizations are not equivalent. Deleting users from a team will remove member access permissions to projects described by the team, but it will _not_ [remove users from the organization](https://docs.upsun.com/administration/users.md#remove-a-user-from-an-organization) (or your billing). - Run the following command: ```bash {} upsun team:user:delete -o ``` - Select a team. - Select the user you want to remove from the team. - Enter ``Y`` to confirm. ###### Team access to projects ####### Adding projects to a team's access - Run the following command: ```bash {} upsun team:project:add -o ``` - Select a team. - Select the project you want the team to access. - Enter ``Y`` to confirm. **Note**: To view a list of all the projects added to a team, follow these steps: - Run the following command: ```bash {} upsun team:project:list -o ``` - Select the team whose projects you want to display. ####### Remove project from team's access - Run the following command: ```bash {} upsun team:project:delete -o ``` - Select a team. - Select the project whose access you want to revoke for the team. - Enter ``Y`` to confirm. ### Administer users Upsun offers very granular and flexible user permissions across projects and organizations. When a user is added to a project, they are automatically added to your organization. **Available add-on**: The Standard User Management add-on offers free viewer permissions, custom [organization permissions](#organization-permissions), [teams](https://docs.upsun.com/administration/teams.md), and [MFA enforcement within an organization](https://docs.upsun.com/administration/mfa.md). See how to [subscribe to this add-on](https://docs.upsun.com/administration/billing/add-on-subscription.md#standard-user-management-add-on). ##### Manage project access If you have set up an external integration to GitHub, GitLab, or Bitbucket and your users can't clone the project locally, see how to [troubleshoot source integrations](https://docs.upsun.com../integrations/source/troubleshoot.md). ###### Project roles A user can have one of the following roles to control their access at project level: | Role | View environment | Push code | Manage user access | Change settings | Execute actions on all environments | |----------------|------------------|-----------|--------------------|-----------------|-------------------------------------| | Project admin | Yes | Yes | Yes | Yes | Yes | | Project viewer | Yes | No | No | No | No | By default, organization owners have **Project admin** access on all of the projects within their organization. ###### Environment type roles An environment type (Production, Staging, and Development) groups one or more environments together so that you can manage access for all environments of that type: - A role assigned to an environment type applies to all environments of that type. - Only one environment per project can be of the type: Production. It is set automatically as the default branch and can't be overridden separately. - You can change an environment's type (except for the Production environment). - You can have multiple preview (staging and development) environments. A user can have one of the following roles on an environment type which grants them permissions on all environments of this type: | Role | View environment | Force push | Push code | Branch environment | SSH access | Change settings | Execute actions | |-------------|------------------|------------|-----------|--------------------|------------|-----------------|-----------------| | Admin | Yes | Yes | Yes | Yes | Yes | Yes | Yes | | Contributor | Yes | No | Yes | Yes | Yes | No | No | | Viewer | Yes | No | No | Yes | No | No | No | To customize which roles can use SSH, set [`access` in your app configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#access). ###### View a user's permissions across all of the projects in your organization For each user, you can view a summary of their roles and permissions across all projects in your organization. - Navigate to your organization. - Open the user menu (your name or profile picture). - Click **Users**. - For the user whose user permissions you want to view, click **More More**. - Click **Edit user**. ###### Add a user to a project To invite a user, you need to be a [project admin](#project-roles). To add a user, follow these steps: For example, if you want to add ``user1@example.com`` to the project as a project admin, run the following command: ```bash {} upsun user:add user1@example.com -r admin ``` If you want to add ``user2@example.com`` to the project as a contributor for Development environments and a viewer for Staging environments, run the following command: ```bash {} upsun user:add user2@example.com -r development:contributor -r staging:viewer ``` - Select the project where you want to add a new user. - Click Settings **Settings**. - Click **Access**. - Click **+ Add**. - Add the user’s details and choose their permissions. - Click **Save**. The user has to create an account before they can access the project. Once you add a user to a project, they receive an invitation email with instructions. To apply SSH access changes after you add a user to a project, [trigger a redeploy](https://docs.upsun.com../development/troubleshoot.md#force-a-redeploy). ###### Manage project users To manage user permissions on a project, you need to be a [project admin](#project-roles), be an organization owner, or have the [**Manage users** permission for the organization](#organization-permissions). To change user permissions, follow these steps: If you want ``user1@example.com`` to be a viewer for Production environments and a contributor for Development environments, run the following command: ```bash {} upsun user:update user1@example.com -r production:viewer,development:contributor ``` - Select the project where you want to update user access. - Click Settings **Settings**. - Click **Access**. - Click the user you want to update permissions for. - Update environment type permissions, or click **Remove user**. - Click **Accept**. To apply SSH access changes after you add a remove a user from a project or environment type, [trigger a redeploy](https://docs.upsun.com../development/troubleshoot.md#force-a-redeploy). ###### Remove a user from a project To remove a user from a project, you need to be a [project admin](#project-roles), be an organization owner, or have the [**Manage users** permission for the organization](#organization-permissions). To remove a user, follow these steps: - Navigate to your organization or a project in it. - Open the user menu (your name or profile picture). - Click **Users**. - For the user you want to remove, click **More More**. - For the project you want to remove them from, click **More More**. - Click **Remove from project**. - Click **Yes**. To apply SSH access changes after changing a user's permissions for an environment type, [trigger a redeploy](https://docs.upsun.com../development/troubleshoot.md#force-a-redeploy). ##### Manage organization access All users who are added to any project within an organization become members of that organization. By default, such users have no [organization permissions](#organization-permissions). You can also have organization users who aren't part of any projects. Users who are a part of an organization with the **List projects** permission can see all projects in that organization at the organization's URL, which takes the form `https://console.upsun.com/`. They can only access projects they've been explicitly invited to. For more information on project access control, see how to [manage project users](#manage-project-users). ###### Organization permissions **Feature Availability** This feature is available as part of the Standard User Management add-on. To enable it on your organization, [administer your organization’s billing](https://docs.upsun.com/administration/billing/billing-admin.md). As an organization owner or an organization user with the **Manage users** permission, you can invite other users to your organization and grant them the following permissions: - **Manage billing** (`billing`): Add, remove, and edit billing information. Access invoices and vouchers. Users with this permission receive monthly invoices by email. - **Manage plans** (`plans`): Access to update settings of existing projects in an organization. - **Manage users** (`members`): Add, remove, and edit organization-level users and permissions, except their own. Users with this permission can't grant other users permissions that they themselves don't have. - **Create projects** (`projects:create`): Create new projects within the organization. - **List projects** (`projects:list`): See all projects in an organization, even those the user can't access. **Note**: Users with the **Manage users** (``members``) permission can add, edit, or remove any user’s permissions except their own. Users with the **Manage billing** (``billing``) permission automatically are granted **List projects** (``projects:list``) permission. That is, they are able to see all organization projects once given billing rights. Users without any of these permissions can only access [projects where they're users](#project-roles). They can't access or manage the rest of the organization. Organization owners have all permissions within their organization. Their permission level can't be edited. Organization owners can't be removed from their organization, except through an [ownership transfer](https://docs.upsun.com../administration/organizations.md#transfer-project-ownership). ###### Add a user to an organization For example, to invite ``alice@example.com`` to the ``acme`` organization with the **Manage billing** and **Create projects** permissions, run the following command: ```bash {} upsun organization:user:add alice@example.com --org acme --permission billing,projects:create ``` - Navigate to the organization you want to manage (or a project in it). - Open the user menu (your name or profile picture). - Click **Users**. - Click **+ Invite users**. - Enter the users’ email addresses separated by commas. - Select which organization-wide permissions they should have. - Click **Invite**. All users you invite receive an invitation email with instructions. ###### Manage organization users For example, to update the permissions for ``alice@example.com`` in your ``acme`` organization so that she has only the **Manage billing** permission, run the following command: ```bash {} upsun organization:user:update alice@example.com --org acme --permission billing ``` - Navigate to the organization you want to manage (or a project in it). - Open the user menu (your name or profile picture). - Click **Users**. - Next to the user you want to manage, click **More More**. - Click **Edit user**. You see all the projects the user is a part of and their permissions in those projects. You also see their permissions across the organization. To edit their organization permissions, follow these steps: - Select or clear the checkboxes for the relevant permissions. - Click **Save**. - Click **Yes**. ###### Remove a user from an organization For example, to remove ``alice@example.com`` from your ``acme`` organization, run the following command: ```bash {} upsun organization:user:delete alice@example.com --org acme ``` - Navigate to the organization you want to manage (or a project in it). - Open the user menu (your name or profile picture). - Click **Users**. - Next to the user you want to remove, click **More More**. - Click **Remove from organization**. To delete users in bulk, select the users to remove and click **Remove users from organization**. Remove a user from an organization will remove them from all projects they were a member of. ### Pricing Upsun offers flexible, usage-based [pricing](https://upsun.com/pricing/) for organizations and projects. **Note**: This page is meant to provide some context for how the pricing model relates to technical work on Upsun. It is not meant to be your primary resource for the exact costs of certain features. The official Upsun [Pricing page](https://upsun.com/pricing/) should always be considered the primary source of pricing details. In general, there are four main dimensions that determine the cost of work on Upsun. | Pricing dimension | Details | |---|---| | Project fees | An individual project on Upsun comes with a consistent monthly cost. The cost includes all of the orchestration and provisioning characteristics that define the Upsun platform.It comes with some baseline features and feature limits, such as infrastructure metrics and a certain number of build minutes. Individual preview environments do not come with their own associated creation cost - you are charged only for the resources those preview environments use during their lifespan (see next row). | | [Project resources](https://docs.upsun.com/manage-resources.md) | Deploying on Upsun allows you fine-grained control over the amount of resources allocated for your application and service containers. CPU, memory, and disk (including backup disk) are calculated across each organization, project, and environment to determine your overall usage for a billing period. | | [User licenses](https://docs.upsun.com/administration/users.md) | Each organization user comes with a license fee. Users can be given different levels of access to singular projects within an organization, or to multiple projects, without changing that license fee. There are two exceptions which are not charged the license fee: Viewers and Viewers who Manage Billing. There are no limits to the number of users you can have in an organization.| | Feature add-ons | There are additional features that can be added to the organization that come with their own cost. Few of these are available immediately during the Beta phase, but more will be added. | A given organization's monthly billing is then made up of the sum of each of these dimensions. You can monitor your spend from the Console via a [current month estimate](https://docs.upsun.com/administration/billing/monitor-billing.md#current-month-estimate) and a [next month estimate](https://docs.upsun.com/administration/billing/monitor-billing.md#next-month-estimate). You can also [set billing alerts](https://docs.upsun.com/administration/billing/monitor-billing.md#manage-billing-alerts) to receive an email when your current month estimate reaches a defined threshold. ##### Dunning process In instances where a payment has failed, your organization will be immediately restricted. Upsun will proceed to make three separate attempts to take the outstanding balance from your account. These attempts will be made on the 4th, 6th and 11th of the month. If your payment fails after the third attempt on the 11th, your organization will be suspended the following day. If you are a new Upsun customer and your first payment has failed, your projects will be deleted on the 13th - two days after the final payment attempt. For all other customers, projects will be deleted 30 days after your organization is suspended on the 11th. You will be notified 10 days before this deletion occurs and a payment will be attempted for the last time. If unsuccessful, all projects on the billing subscription will be deleted. Be sure to visit the [Pricing page](https://upsun.com/pricing/) for exact details related to Upsun pricing. ### Billing #### Administer your billing The [Console](https://docs.upsun.com/administration/web.md) is where you can keep your billing details up to date and redeem your vouchers. ###### Manage your billing details To add or edit billing details for your organization, follow these steps: 1. Navigate to your organization. 2. Open the user menu (your name or profile picture). 3. Click **Billing**. 4. Open the **Billing details** tab. 5. Add or update your billing details and click **Save**. 6. Add or update your payment method and click **Submit**. ###### Redeem a voucher To redeem a voucher, follow these steps: 1. Navigate to your organization. 2. Open the user menu (your name or profile picture). 3. Click **Billing**. 4. Open the **Vouchers** tab. 5. Enter your voucher code. 6. Click **Redeem**.#### Monitor your billing information To help you manage costs related to your organization, Upsun provides estimates for the current month and the next. You can set billing alerts to ensure you don't overspend, and track resource usage on each of your projects. For details on costs, see the [Upsun pricing page](https://upsun.com/pricing/). ###### Access your organization billing information To access your organization billing information in the [Console](https://docs.upsun.com/administration/web/_index.md): 1. Navigate to your organization. 2. Open the user menu (your name or profile picture). 3. Click **Billing**. The **Overview** tab is displayed. You can view your current month and next month estimates. ![Organization billing information in the Overview tab](https://docs.upsun.com/images/billing/organization-billing.png "0.6") ####### Current month estimate The [**Overview** tab](#access-your-organization-billing-information) shows an estimate of how much you may be charged at the end of this month. This estimate is based on: - Your organization settings (user management settings, number of projects, potential add-ons, support SLA, etc.) - Your resource allocation on each project The estimate includes the history of changes made since the beginning of the month. **It cannot be 100% accurate, as it is impossible to know exactly what your future usage will be.** However, for maximum accuracy, the current month estimate includes the following underlying estimates, each with its own calculation: The resources consumed for builds, bandwidth, and log forwarding are accumulated resources. The following formula is used to estimate how much accumulated resource usage may cost you this month: ``current accumulation + (unit price x daily average x remaining days in the month)``. | Item | Description | | ``current accumulation`` | The amount of accumulated resources you have effectively used so far this month. | | ``unit price`` | A fixed unit price. | | ``daily average`` | An average based on the accumulated resource usage you’ve had over the last 30 days. | All items used for the calculation are displayed in the [Overview](#access-your-organization-billing-information). The resources consumed by your applications and services (CPU, RAM, and storage) are allocated resources. The following formula is used to estimate how much allocated resource usage may cost you this month: ``unit price x prorated quantity``. | Item | Description | | ``unit price`` | A fixed unit price. | | ``prorated quantity`` | An average of past changes and current settings, applied for all the remaining days in the month. | All items used for the calculation are displayed in the [Overview](#access-your-organization-billing-information). ####### Next month estimate From the [**Overview** tab](#access-your-organization-billing-information), you can also access an estimate for next month. Like your [current month estimate](#current-month-estimate), it includes your organization settings and resource allocation on each project. However, your next month estimate **does not include any history of changes**. It is solely based on your current organization settings and resource allocation, and shows what you may be charged if you don't make any changes until the end of next month. The following formulas are used: - `unit price x current allocation` to estimate how much user license, user management add-on fees, and allocated resources may respectively cost you next month. - `unit price x daily average x 30 days` to estimate how much accumulated resources may cost you next month. ####### Invoice Your invoice provides definitive information on what you will be charged. It is calculated at month-end close, and includes your actual organization settings and resource usage. To access your current invoice and a history of past invoices, open the **Invoices** tab: ![Invoices tab in the Console](https://docs.upsun.com/images/billing/invoices-tab.png) ###### Manage billing alerts **Feature availability**: Billing alerts can only be set and received by the organization owner, users with the [Manage Billing](https://docs.upsun.com/administration/users.md#organization-permissions), and identified billing contacts. ####### Set a billing alert You can set billing alerts to receive an email when your [current month estimate](#current-month-estimate) reaches a defined threshold. **Warning**: Current month estimates are computed once a day only. Therefore, email notifications can only be triggered once a day too. You may want to increase your billing alert threshold after receiving an email notification. However, if the new threshold is reached later on the same day, **you won’t get notified until the following day**, when the current month estimate is computed again. To set a billing alert on your organization: 1. Navigate to your organization. 2. Open the user menu (your name or profile picture). 3. Click **Billing**. 4. In the **Overview** tab, click **Set alert**. 5. Enter a threshold. 6. Click **Create alert**. ####### Edit a billing alert To edit or delete a billing alert, click the billing alert button in the **Overview** tab: ![Billing alert button in the Console](https://docs.upsun.com/images/billing/billing-alert-button.png "0.1") Change the monthly threshold and click **Save**, or click **Delete alert**. To change the currency of your billing alerts, [contact support](https://docs.upsun.com/learn/overview/get-support.md). **Warning**: After Support changes the currency, your existing billing alerts are **not** automatically converted to the new currency. Edit your billing alerts to have correct amounts in the new currency. ###### Track resource usage on a project **Feature availability**: This feature is available to users with the [Manage Billing](https://docs.upsun.com/administration/users.md#organization-permissions) on the organization. You can track costs related to resource usage on a specific project in the [Console](https://docs.upsun.com/administration/web.md). To do so, after you've set or updated resources on your project: 1. Navigate to your organization. 2. Open the user menu (your name or profile picture). 3. Click **Billing**. Your [current month estimate](#current-month-estimate) shows how much each project in your organization is expected to cost this month. 4. You can select a project to view resource allocation and usage details. To do so, click **More More** next to it, and select **Project Billing**. ![Project billing information in the Overview tab](https://docs.upsun.com/images/billing/project-billing.png "0.6") For information on resource-related costs, see the [Upsun pricing page](https://upsun.com/pricing/). #### Subscribe to an add-on Depending on your needs, you may want to upgrade to the following Upsun add-ons. You can do so directly from the Console. ###### Standard User Management add-on ####### Included features The Standard User Management add-on gives you access to the following features: - [Free viewers](https://docs.upsun.com../users.md) - [Organization permissions](https://docs.upsun.com../users.md#organization-permissions) - [Teams](https://docs.upsun.com/administration/teams.md) - [MFA enforcement](https://docs.upsun.com/administration/mfa.md) ####### Upgrade to the Standard User Management add-on To upgrade to the Standard User Management add-on, follow these steps: 1. In the Console, navigate to your organization. 2. Open the user menu (your name or profile picture), then select **Billing**. 3. In the **Organization add-ons** section of the **Overview** tab, locate the **User management** panel and click **Upgrade**. 4. In the pop-up window, select **Standard user management** and check the 30-day commitment box. 5. Click **Upgrade**. After the add-on is added to your organization, you can remove it from the same location in the **Overview** tab by clicking **Downgrade**. Once the minimum 30-day commitment period is over, the add-on is removed from your organization and you are no longer billed for it. ###### Continuous Profiling add-on ####### Included features By default, Upsun offers 15 minutes of continuous profiling per project and for free. When you upgrade to the continuous profiling add-on, you get 30 days of continuous profiling per project for a fixed fee. For more information on incurred costs, see the [Upsun pricing page](https://upsun.com/pricing/). ####### Upgrade to the Continuous Profiling add-on To upgrade to this add-on, follow these steps: 1. In the Console, navigate to your organization. 2. Open the user menu (your name or profile picture), then select **Billing**. 3. In the **Overview** tab, find the project on which you want to activate full continuous profiling. 4. Click **More More** next to that project. 5. Click **Project billing**. 3. In the **Project add-ons** section, locate the **Continuous profiling** panel and click **Enable**. 5. To confirm, click **Enable**. ### Multifactor Authentication (MFA) Multifactor Authentication (MFA) enhances security by protecting both your organization and every user account that interacts with it through SSH or the Upsun API. When MFA is enforced within an organization, every project contributor **must** enable MFA on their user account so they can run Git commands, SSH into an environment, or trigger actions through the Upsun API. ##### Enable MFA on your user account To access an organization that enforces MFA or any of its projects, you **must** enable MFA on your user account. Failure to do so results in forbidden access to the organization from the Console or API, and an [error message](https://docs.upsun.com/development/ssh/troubleshoot-ssh.md#mfa-related-error-message) when trying to SSH into its environments. To enable MFA on your user account, follow these steps: 1. In the Console, open the user menu (your name or profile picture). 2. Click **My profile** 3. Click **Security**. 4. Click **Set up application**. 5. Follow the instructions for the chosen authentication app. 6. Click **Verify & save**. 7. Refresh your SSH credentials by running `upsun login -f` in the CLI. ##### Enforce MFA within your organization **Feature availability and permissions**: This feature is available as part of the Standard User Management add-on. To add it to your organization, [administer your organization’s billing](https://docs.upsun.com/administration/billing/billing-admin.md). Only **organization owners** and **admin users** can enable MFA within an organization. However, even if you have the required permissions, you **must** [enable MFA on your user account](#enable-mfa-on-your-user-account) prior to enforcing it within the whole organization. To enable MFA within your organization, follow these steps: 1. In the Console, open the user menu (your name or profile picture). 2. Click **Settings**. 3. Click **Security**. 4. In the **MFA required** area, set the **Enable** toggle on. **Note**: Under **User security settings**, you can view which users in your organization have [activated MFA for their user accounts](#enable-mfa-on-your-user-account). ###### Send email reminders You can send email reminders to users who haven't enabled MFA on their user account yet. To do so, follow these steps: 1. In the Console, open the user menu (your name or profile picture). 2. Click **Settings**. 3. Click **Security**. 4. In the **User security settings** area, find the user you want to send a reminder to. 5. Click **More More** next to that user. 6. Select **Remind**. An email is sent to the user with instructions on how to enable MFA on their user account. **Note**: You can send reminders to multiple users at once. To do so, in the **User security settings** user list, select the desired users by checking the boxes in front of their names. Click **Remind** at the top of the list to trigger the reminder emails. ### Server upgrades Upsun runs a variety of servers to deliver its services. To ensure your projects get the newest features, these servers are occasionally updated. You don't have to do anything to get the updates. When they're ready for your project, you see an activity about the server being updated in your [activity logs](https://docs.upsun.com../increase-observability/logs/access-logs.md#activity-logs). These activities don't cause downtime for your project. The log of the specific activity includes a description of what has changed with the update. ##### Affected servers ###### Project API server The project API server responds to API calls to make the CLI and Console work for your project. It acts as the Git server, mirroring the source repository in the case of [source integrations](https://docs.upsun.com../integrations/source.md). It stores your app code and project configuration, provides API interfaces, and orchestrates the build and deploy process and other tasks for your environments. ###### Project metrics server The project metrics server retrieves information about your environments' use of RAM, CPU, and disk. You can view this information as part of [environment metrics](https://docs.upsun.com../increase-observability/metrics.md). ### Platform.sh WAF The Upsun WAF monitors requests to your app and blocks suspicious ones. All traffic to Upsun endpoints is also filtered using a system that takes into account traffic patterns and abuse scores. ##### CRLF injection prevention Carriage return and line feed (CRLF) injection occurs when an attacker injects a CRLF character sequence to manipulate HTTP requests. CRLF injection can lead to [request smuggling](#request-smuggling), [header injection](#header-injection), and [response splitting](#response-splitting) attacks. To protect your app from such attacks, the WAF detects and blocks requests containing CRLF character sequences. ###### Request smuggling When a frontend server forwards HTTP requests to a backend server, it usually sends a series of requests at once. The backend server then parses the request headers to determine where one request ends and the next one begins. The [HTTP protocol](https://tools.ietf.org/html/rfc2616) provides two different headers to specify where an HTTP request ends: `Content-Length` and `Transfer-Encoding`. When the frontend and backend servers don’t agree on which header they should interpret as the end of a request, attackers can smuggle requests. If a malicious request is injected, the backend server may misinterpret the boundaries of the individual requests within the concatenated request, thereby processing a request differently from what was intended. This can lead to various security risks such as data leakage, privilege escalation, and even remote code execution. The WAF detects and blocks requests that contain [both the `Content-Length` and `Transfer-Encoding` headers](#content-length-and-transfer-encoding-headers-together). It also detects and blocks requests that include **both** of the following features of an attempt to inject a malicious request: - A [CRLF character](#crlf-injection-prevention) or `http/\d` - An `HTTP` or `WEBDAV` method name ###### Header injection During a header injection attack, the attacker tricks your app into inserting extra HTTP headers into legitimate HTTP responses. These attacks can happen when HTTP response headers are generated based on user input. Header injection attacks can have various impacts, including cookie injection, [cross-origin resource sharing](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) header injection, and bypassing your content security policy. Such attacks enable [response splitting](#response-splitting), which in turn can lead to [cross-site scripting](https://developer.mozilla.org/en-US/docs/Glossary/Cross-site_scripting), web cache poisoning, and so on. The WAF detects header injection attempts occurring through the payload and the header itself. By [blocking requests containing CRLF](#crlf-injection-prevention) character sequences, the WAF prevents malicious data from being returned in a response header and interpreted by the client. ###### Response splitting When a user makes an HTTP request, the web server usually returns a single HTTP response. But when an attacker succeeds in [injecting headers](#header-injection), they can launch a [response splitting attack](https://www.cs.montana.edu/courses/csci476/topics/http_response_splitting.pdf). During a response splitting attack, the attacker uses CRLF characters to inject additional HTTP responses into legitimate user requests. This enables further attacks such as [cross-site scripting](https://developer.mozilla.org/en-US/docs/Glossary/Cross-site_scripting), web cache poisoning, browser cache poisoning, and cross-user attacks. As the WAF [blocks requests containing CRLF](#crlf-injection-prevention) character sequences, your app is protected from response splitting attacks. ##### HTTP protocol enforcement In addition to protecting your site against [CRLF injection-related](#crlf-injection-prevention) attacks, the WAF implements additional rules to enforce the HTTP protocol. ###### Uniform Resource Identifier (URI) syntax [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986) defines the generic syntax for URIs. When the WAF detects a URI with incorrect syntax, the incoming connection is terminated. The request is then reconstructed on the internal Upsun network, enforcing the valid format in transit. ###### File upload limit The WAF enforces a file upload limit. By default, this limit is set at 250 MB. You can customize the file upload limit by amending your [app configuration](https://docs.upsun.com/create-apps.md). In the [`web.locations` dictionary](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#locations), add your desired value for the `max_request_size` property. ###### File extension restriction The WAF enforces any file extension restriction you may have defined in your [app configuration](https://docs.upsun.com../../create-apps.md). To set up a file extension restriction, adjust the [`web.locations` dictionary](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#locations). Set up [rules](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#rules) to allow only certain file extensions on a given path. ###### Disallowed requests and headers ####### `GET` requests with a body The [HTTP specification](https://tools.ietf.org/html/rfc2616) allows for `GET` requests to have a body. This enables attackers to try and force a request body on unsuspecting applications, which could result in a [request smuggling attack](#request-smuggling). To prevent such attacks, when the WAF detects a `GET` request, it scans the request for a potential `Content-Length` or `Transfer-Encoding` header. If one of those headers is found and the payload isn't `0` or empty, all body-related headers are removed from the request. The request is then passed through otherwise unaltered. ####### `Content-Length` and `Transfer-Encoding` headers together According to the [HTTP specification](https://tools.ietf.org/html/rfc2616), requests mustn't contain [both a `Content-Length` and a `Transfer-Encoding` header](https://tools.ietf.org/html/rfc7230#section-3.3.2). This rule helps protect apps from [request smuggling](#request-smuggling). The WAF detects and blocks requests featuring both headers and forces requests to use [chunked transfer encoding](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding) only on the internal Upsun network. ####### Missing or empty `host` headers As [routes are mapped](https://docs.upsun.com../../define-routes.md) based on host names, the Upsun WAF blocks requests with an empty or absent `host` header. ####### Other restricted HTTP headers The following headers are disallowed: `Connection`, `Proxy-Authorization`, `TE`, and `Upgrade`. ##### Slowloris DDoS attack prevention Slowloris DDoS attacks use partial HTTP requests to open connections between a single computer and a targeted web server. These connections are then kept open for as long as possible to overwhelm the web server. While Apache web servers are vulnerable to Slowloris attacks, Nginx servers aren't. Since Upsun router services use Nginx processes, your projects are protected against such attacks. ### Data retention Upsun logs and stores various types of data as a normal part of its business. This information is only retained as needed to perform relevant business functions. Retention periods vary depending on the type of data stored. If a legal obligation, law enforcement request, or ongoing business need so requires, data may be retained after the original purpose for which it was collected ceases to exist. ##### Account information Information relating to customer accounts (login information, billing information, etc.) is retained for as long as the account is active with Upsun. Customers may request that their account be deleted and all related data be purged by opening a [support ticket](https://docs.upsun.com/learn/overview/get-support.md). ##### System logs System level access and security logs are maintained by Upsun for diagnostic purposes. These logs aren't customer-accessible. These logs are retained for at least 6 months and at most 2 years depending upon legal and standards compliance required for each system. ##### Application logs Application logs on each customer environment are retained with the environment. Individual log files are truncated at 100 MB, regardless of their age. See how to [access logs](https://docs.upsun.com../increase-observability/logs/access-logs.md). When an environment is deleted, its application logs are deleted as well. ##### Backups The backups retention depends on the [automated backup policy](https://docs.upsun.com../environments/backup.md#automated-backups). ##### Tombstone backups When a project is deleted, Upsun takes a final backup of active environments, as well as the Git repository holding user code. This final backup is to allow Upsun to recover a recently deleted project in case of accident. These "tombstone" backups are retained for between 7 days and 6 months depending upon legal and standards compliance required for each system. ##### Analytics Upsun uses Google Analytics on various web pages, and so Google Analytics stores collected data for a period of time. We have configured our Google Analytics account to store data for 14 months from the time you last accessed our site, which is the minimum Google allows. ##### Trials User data - which includes pushed code and data contained within services - is retained for a shorter period during trials. See [Trial details](https://docs.upsun.com/glossary.md#trial). ### Project isolation At Upsun, customer environments are strictly isolated from each other using [namespaces](https://man7.org/linux/man-pages/man7/namespaces.7.md), [seccomp](https://man7.org/linux/man-pages/man2/seccomp.2.md), and [cgroups](https://man7.org/linux/man-pages/man7/cgroups.7.md). Persistent data (uploaded files into mounts, database data, etc.) is stored on a region-wide storage layer. Data is stored redundantly and mounted into the environments on deployment. Network is behind a firewall for incoming connections. Only a few ports are opened to incoming traffic: ports 22, 80, and 443. There are no exceptions, so any incoming web service requests, [ETL](https://aws.amazon.com/what-is/etl/#:~:text=Extract%2C%20transform%2C%20and%20load%20%28,and%20machine%20learning%20%28ML%29%29.) jobs, or otherwise need to transact over one of these protocols. Outgoing TCP traffic isn’t behind a firewall, **with the exception of port 25 which is blocked**. For containers to be allowed to connect to each other, the following requirements must be met: - The containers must live in the same environment. - You need to define an explicit relationship between the containers in your app configuration. ## Config examples ### Example of a Symfony skeleton config ``` routes: "https://{all}/": { type: upstream, upstream: "app:http" } "http://{all}/": { type: redirect, to: "https://{all}/" } services: {} applications: app: source: root: "/" type: php:8.3 runtime: extensions: - apcu - blackfire - ctype - iconv - mbstring - sodium - xsl variables: php: opcache.preload: config/preload.php build: flavor: none web: locations: "/": root: "public" expires: 1h passthru: "/index.php" mounts: "/var": { source: storage, source_path: var } hooks: build: | set -x -e curl -fs https://get.symfony.com/cloud/configurator | bash NODE_VERSION=22 symfony-build deploy: | set -x -e symfony-deploy crons: security-check: # Check that no security issues have been found for PHP packages deployed in production spec: '50 23 * * *' cmd: if [ "$PLATFORM_ENVIRONMENT_TYPE" = "production" ]; then croncape COMPOSER_ROOT_VERSION=1.0.0 COMPOSER_AUDIT_ABANDONED=ignore composer audit --no-cache; fi ``` ### Example of a Symfony skeleton config with PostgreSQL service ``` routes: "https://{all}/": { type: upstream, upstream: "app:http" } "http://{all}/": { type: redirect, to: "https://{all}/" } services: database: type: postgresql:16 applications: app: source: root: "/" type: php:8.3 runtime: extensions: - apcu - blackfire - ctype - iconv - mbstring - pdo_pgsql - sodium - xsl relationships: database: variables: php: opcache.preload: config/preload.php build: flavor: none web: locations: "/": root: "public" expires: 1h passthru: "/index.php" mounts: "/var": { source: storage, source_path: var } hooks: build: | set -x -e curl -fs https://get.symfony.com/cloud/configurator | bash NODE_VERSION=22 symfony-build deploy: | set -x -e symfony-deploy crons: security-check: # Check that no security issues have been found for PHP packages deployed in production spec: '50 23 * * *' cmd: if [ "$PLATFORM_ENVIRONMENT_TYPE" = "production" ]; then croncape COMPOSER_ROOT_VERSION=1.0.0 COMPOSER_AUDIT_ABANDONED=ignore composer audit --no-cache; fi ``` ### Example of a Symfony skeleton config with PostgreSQL and RabbitMQ service ``` routes: "https://{all}/": { type: upstream, upstream: "app:http" } "http://{all}/": { type: redirect, to: "https://{all}/" } services: database: type: postgresql:16 queue: type: rabbitmq:3.13 applications: app: source: root: "/" type: php:8.3 runtime: extensions: - apcu - blackfire - ctype - iconv - mbstring - pdo_pgsql - sodium - xsl relationships: database: queue: variables: php: opcache.preload: config/preload.php build: flavor: none web: locations: "/": root: "public" expires: 1h passthru: "/index.php" mounts: "/var": { source: storage, source_path: var } hooks: build: | set -x -e curl -fs https://get.symfony.com/cloud/configurator | bash NODE_VERSION=22 symfony-build deploy: | set -x -e symfony-deploy crons: security-check: # Check that no security issues have been found for PHP packages deployed in production spec: '50 23 * * *' cmd: if [ "$PLATFORM_ENVIRONMENT_TYPE" = "production" ]; then croncape COMPOSER_ROOT_VERSION=1.0.0 COMPOSER_AUDIT_ABANDONED=ignore composer audit --no-cache; fi ```