# Resource initialization When you first deploy your project or add a new container to it, Upsun uses default resources unless you specify a resource initialization strategy. You can also use a specific resource initialization strategy when performing certain actions, such as branching](#environment-branch), [merging, and activating](#environment-activation) an environment, or [restoring a backup. ## 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.html) 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 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… **** The following table shows the resources Upsun allocates to your containers when you opt for the `minimum` 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 | `parent`, `default`, `minimum`, `manual` | `parent` | | Environment branch | `parent`, `default`, `minimum` | `parent` | | Environment merge | `child`, `default`, `minimum`, `manual` | `child` | | Environment activation | `parent`, `default`, `minimum` | `parent` | | 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 Upsun uses to allocate resources when you first deploy your project or add a new container. - Using the CLI - In the Console Run the following commands depending on your needs: - Sync only resources: `upsun sync resources` - Sync only code: `upsun sync code` - Sync only data: `upsun sync data` - Sync everything: `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**. # 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 PROJECT_NAME cd PROJECT_NAME 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 {configFile="app"} applications: myapp: [...] runtime: extensions: - redis - pdo_pgsql ``` See all the [available PHP extensions](https://docs.upsun.com/languages/php/extensions.html). 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 {configFile="env"} export APP_KEY="base64:APP_KEY" ``` 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 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: `upsun project:set-remote PROJECT_ID` ## 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.html). ## 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#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) Back Configure environment variables # 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.html) 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.html#the-symfony-demo-application) app as an example : ```bash {location="Terminal"} symfony new PROJECT_NAME --demo --upsun cd PROJECT_NAME ``` 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: `symfony project:init --upsun` This generates the `.upsun/config.yaml` and `php.ini` configuration files. - Add and commit your changes: ``` 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: `symfony upsun:set-remote PROJECT_ID` ## 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.html#domains), or run the following command: `symfony upsun:domain:add YOUR_DOMAIN` ## 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) Back Symfony integration # 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#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#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.html) 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: - Using the CLI - From the Console To define how many instances of an app or worker you want to deploy, you can use the Upsun CLI interactive prompts, or run commands manually. - **Interactive prompts:** Run the `upsun resources:set` command, and follow the prompts to set resources for each app and service. ### Note For further guidance on how to set resources using the CLI, run the `upsun resources:set --help` command. Note that if the deployment fails after you’ve run `upsun resources:set`, you may need to set the resources again. - **Manual commands:** To scale an app or worker, run the following command: `upsun resources:set --count APP_NAME:NUMBER_OF_INSTANCES` For example, to scale your `myapp` app to 3 instances, run the following command: `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: ``` upsun resources:set --count '*:NUMBER_OF_INSTANCES' ``` For example, to scale all your apps to 3 instances, run the following command: ``` 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: - For each of your apps and workers, select the number of instances you want to deploy. ### Note 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**. 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 {configFile="app"} applications: APP_NAME: container_profile: HIGH_MEMORY services: SERVICE_NAME: type: SERVICE_TYPE:VERSION container_profile: HIGHER_MEMORY ``` # Add a database 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.html#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.html) 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 {configFile="app"} 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 {configFile="app"} 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#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.html) 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' ``` # Add a database 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 - PostgreSQL - Oracle MySQL ``` # 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="postgres" fi ``` ``` # 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. # 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 {configFile="app"} 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: - `symfony-build` - `symfony-deploy` - `php-ext-install` - It adds some extra tools - It defines [additional infrastructure environment variables](https://docs.upsun.com/get-started/stacks/symfony/environment-variables#symfony-environment-variables) and [environment variables for all services](https://docs.upsun.com/get-started/stacks/symfony/environment-variables#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#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 {configFile="app"} 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). 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.html)) in a condition: ``` 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 <4) - Installs PHP extensions through the `php-ext-install` script - Installs application dependencies using Composer - Optimizes the autoloader - Builds the Symfony cache in an optimized way to limit the time it takes to deploy - Installs the JavaScript dependencies via npm or Yarn - Builds the production assets using Encore To override the flags used by Composer, use the `$COMPOSER_FLAGS` environment variable: ```yaml {configFile="app"} applications: myapp: hooks: build: | set -x -e curl -s https://get.symfony.com/cloud/configurator | bash COMPOSER_FLAGS="--ignore-platform-reqs" symfony-build ``` When installing dependencies, the script automatically detects if the app is using npm or Yarn. To disable the JavaScript dependencies and asset building, set `NO_NPM` or `NO_YARN` to `1` depending on your package manager. To customize Node/npm/Yarn behaviors, prefix the `symfony-build` script with the following environment variables: - `NODE_VERSION`: to pinpoint the Node version that nvm is going to install. The default value is `--lts`. - `YARN_FLAGS`: flags to pass to `yarn install`. There is no default value. ### symfony-deploy Use **symfony-deploy** as the main deploy script in the `deploy` hook. It only works if you're using the `symfony-build` script in your `build` hook. **symfony-deploy** performs the following actions: - Replaces the Symfony cache with the cache generated during the build hook - Migrates the database when the Doctrine migration bundle is used ### php-ext-install You can use the **php-ext-install** script to compile and install PHP extensions not provided out of the box by Upsun, or when you need a specific version of an extension. The script is written specifically for Upsun to ensure fast and reliable setup during the build step. **php-ext-install** currently supports three ways of fetching sources: - From [PECL](https://pecl.php.net/): `php-ext-install redis 5.3.2` - From a URL: `php-ext-install redis https://github.com/phpredis/phpredis/archive/5.3.2.tar.gz` - From a Git repository: `php-ext-install redis https://github.com/phpredis/phpredis.git 5.3.2` To ensure your app can be built properly, run `php-ext-install` after the configurator but before symfony-build: ```yaml {configFile="app"} applications: myapp: hooks: build: | set -x -e curl -s https://get.symfony.com/cloud/configurator | bash php-ext-install redis 5.3.2 symfony-build ``` When installing [PECL](https://pecl.php.net/) PHP extensions, you can configure them directly as *variables* instead: ```yaml {configFile="app"} applications: myapp: variables: php-ext: redis: 5.3.2 ``` ### 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, use the following configuration: ```yaml {configFile="app"} 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 {configFile="app"} 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 ``` Back Configure environment variables # Configure environment variables By default, Upsun exposes some [environment variables](https://docs.upsun.com/development/variables/use-variables#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 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#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#relationships): ```yaml {configFile="app"} applications: myapp: [...] relationships: mysql: ... postgresql: ... redis: ... ``` You can transpose these variables to set up Laravel's default configuration in a `.environment` file: ```bash {configFile="env"} # 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 {configFile="app"} 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.html#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 {configFile="env"} # 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) 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) 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) 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 {configFile="env"} export REDIS_CLIENT="phpredis" ``` ### Memcached The [Memcached](https://docs.upsun.com/add-services/memcached) 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) 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) 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) 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) 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) 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` Back Set up Redis # Configure environment variables By default, Upsun exposes some [environment variables](https://docs.upsun.com/development/variables/use-variables#use-provided-variables). If you're using the [Symfony integration](https://docs.upsun.com/get-started/stacks/symfony/integration), more infrastructure 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 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#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#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.html#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), 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#relationships) in your configuration: ```yaml {configFile="app"} 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`. ### 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.html#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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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` Back Configure workers # 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 {configFile="app"} services: [...] redis: type: redis:7.0 ``` 2. To connect the service to your app, add the following relationship: ```yaml {configFile="app"} applications: myapp: [...] relationships: redis: services: [...] redis: type: redis:7.0 ``` ## 2. Configure your Redis service The [Redis](https://docs.upsun.com/add-services/redis) 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 {configFile="env"} 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`: ``` 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 {configFile="env"} 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 {configFile="env"} 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 {configFile="env"} 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). Back Handle queues with Horizon # 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.html#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 {configFile="app"} 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#workers). To do so, use the following configuration: ```yaml {configFile="app"} 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.html). See more information on [workers](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.html#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). Back Set up cron jobs # 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 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). - With `clickhouse` default endpoint - With `clickhouse` explicit endpoint - With `clickhouse-http` endpoint ``` 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 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: clickhouse: services: # The name of the service container. Must be unique within a project. clickhouse: type: clickhouse:24 ``` ``` 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 ``` ``` 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. SERVICE_NAME 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 {configFile="app"} # 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 ``` # 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.html). To deploy a worker, add an entry under the `workers` section [in your app configuration](https://docs.upsun.com/create-apps/_index.md): ```yaml {configFile="app"} 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) 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#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.html). Back Set up cron jobs # 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 {configFile="app"} 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 {configFile="app"} 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#crons). However, you can add a [worker](https://docs.upsun.com/create-apps/app-reference/single-runtime-image#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 {configFile="app"} applications: APP_NAME: [...] 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.html). Back Manage observability with Blackfire # 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 {configFile="app"} 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 {configFile="app"} 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), 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#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#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 [](https://docs.upsun.com/development/variables/use-variables.html#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`. Back Manage observability with Blackfire # 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.html) 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. 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. ## Relationship reference For each service defined via a relationship 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). - Using default endpoints - Using explicit endpoints ``` 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 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: elasticsearch: services: elasticsearch: type: elasticsearch:8.5 ``` ``` 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#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 {configFile="services"} 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, 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 {configFile="routes"} 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 {configFile="services"} 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, 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 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. # Manage Python dependencies ### 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.html). 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: - Latest version - Specific version ``` 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: '*' 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 ``` ``` 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 ``` # Deploy Next.js on Upsun ### Note Before you start, check out the [Getting started guide](https://console.upsun.com/projects/create-project). 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. - Using Upsun Git repository - Using third-party Git repository You can push your code using the normal Git workflow (`git add . && git commit -m "message" && git push`). This pushes your source code changes to your `upsun` remote repository. Alternatively, you can use the following Upsun CLI command: `upsun push`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.html) - [GitHub](https://docs.upsun.com/integrations/source/github.html) - [GitLab](https://docs.upsun.com/integrations/source/gitlab.html) 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: `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#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: `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/) - [Managing dependencies](https://docs.upsun.com/languages/nodejs#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/) # 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 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). - Using default endpoints - Using explicit endpoints ``` 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 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: gotenberg: services: # The name of the service container. Must be unique within a project. gotenberg: type: gotenberg:8 ``` ``` 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 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). - Using default endpoints - Using explicit endpoints ``` 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 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: chrome-headless: services: # The name of the service container. Must be unique within a project. chrome-headless: type: chrome-headless:120 ``` ``` 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 (as per [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image#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.html#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). 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. # 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). Back Debug with Telescope # 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/6.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). Back Handle local development # Web servers ### 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.html). 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`. - Pip (TCP) - Pip (Unix) - Pipenv (TCP) - Pipenv (Unix) - Poetry (TCP) - Poetry (Unix) ``` 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: "hypercorn app.asgi:application -b localhost:$PORT -w 4" locations: "/": passthru: true "/static": root: "static" expires: 1h allow: true ``` ``` 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 ``` ``` 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 ``` ``` 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 ``` ``` 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 ``` ``` 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.html). Workers can also be defined with a custom [worker class](https://hypercorn.readthedocs.io/en/latest/how_to_guides/configuring.html#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 {configFile="app"} 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" ``` # 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 ENVIRONMENT --value true env:APP_DEBUG upsun variable:update -e ENVIRONMENT --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 {configFile="app"} 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. Back FAQ # Deploy Django on Upsun ### Note Before you start, check out the [Getting started guide](https://console.upsun.com/projects/create-project). 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 {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} 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/) - [Managing dependencies](https://docs.upsun.com/languages/python/dependencies) - [Configuring web servers](https://docs.upsun.com/languages/python/server) ### 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/) # 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. See more information on how to upgrade to version 2.3 or later. ## Relationship reference For each service defined via a relationship 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). - Using default endpoints - Using explicit endpoints ``` 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 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: influxdb: service: influxdb: type: influxdb:2.7 ``` ``` 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 (as per [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image#relationships) configuration for relationships). From this, ``myapp`` can retrieve access credentials to the service through the relationship environment variables. ```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](../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 RELATIONSHIP_NAME at: http://127.0.0.1:30000 ``` 3. Get the username, password and token from the relationship by running the following command: ```bash upsun relationships -P RELATIONSHIP_NAME ``` 4. Adapt and run [InfluxDB's CLI export command](https://docs.influxdata.com/influxdb/v2.3/reference/cli/influx/backup/). ``` bash influx backup --host URL_FROM_STEP_2 --token API_TOKEN_FROM_STEP_3 ``` ## 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. 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, 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.html#service-environment-variables). # 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 PROJECT_ID ```. - 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 ``` Back FAQ # 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 ``` # Deploy Flask on Upsun ### Note Before you start, check out the [Getting started guide](https://console.upsun.com/projects/create-project). 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#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#mounts). In your app configuration, locate the section dedicated to mounts and update it as follows: ```yaml {configFile="app"} 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.html#build-hook). In your app configuration, locate the section dedicated to it and update it as follows: ```yaml {configFile="app"} 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 {configFile="app"} 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.html#deploy-hook). In your app configuration, locate the section dedicated to it: ```yaml {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} 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/) - [Managing dependencies](https://docs.upsun.com/languages/python/dependencies) - [Configuring web servers](https://docs.upsun.com/languages/python/server) ### 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/) # 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 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. - Python - Ruby ``` from json import dumps from json import loads from kafka import KafkaConsumer, KafkaProducer from platformshconfig import Config def usage_example(): # Create a new Config object to ease reading the Platform.sh environment variables. # You can alternatively use os.environ yourself. config = Config() # Get the credentials to connect to the Kafka service. credentials = config.credentials('kafka') try: kafka_server = '{}:{}'.format(credentials['host'], credentials['port']) # Producer producer = KafkaProducer( bootstrap_servers=[kafka_server], value_serializer=lambda x: dumps(x).encode('utf-8') ) for e in range(10): data = {'number' : e} producer.send('numtest', value=data) # Consumer consumer = KafkaConsumer( bootstrap_servers=[kafka_server], auto_offset_reset='earliest' ) consumer.subscribe(['numtest']) output = '' # For demonstration purposes so it doesn't block. for e in range(10): message = next(consumer) output += str(loads(message.value.decode('UTF-8'))["number"]) + ', ' # What a real implementation would do instead. # for message in consumer: # output += loads(message.value.decode('UTF-8'))["number"] return output except Exception as e: return e `````` ## 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 ``` # Deploy Drupal on Upsun ### Note Before you start, check out the [Getting started guide](https://console.upsun.com/projects/create-project). 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)**, 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](/get-started/here/configure) portion of the[Getting Started](https://docs.upsun.com/get-started/here) 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.html), however it is slightly updated for [Upsun's configuration](https://docs.upsun.com/learn/tutorials/migrating/from-psh.html). ## 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, <<_`` 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). - Using default endpoints - Using explicit endpoints ``` 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. # 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: memcached: service: memcached: type: memcached:1.6 ``` ``` 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 (as per [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image#relationships) configuration for relationships). From this, ``myapp`` can retrieve access credentials to the service through the relationship environment variables. ```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 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. # 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. - Using the Console - Using the CLI - Navigate to your project. - Access the **project settings**. - Expand the Project Setting accordion and click **Resources**. - Enter the amount of CPU and RAM that your build containers can use. - Click **Save**. - Run the following command: `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. # 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.html#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. - 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.html#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. - 4.0.3 - 3.6 - 3.4 - 3.2 - 3.0 ## Relationship reference For each service defined via a relationship 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). - Using default endpoints - Using explicit endpoints ``` 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 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: mongodb: service: mongodb: type: mongodb-enterprise:7.0 ``` ``` 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 (as per [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image#relationships) configuration for relationships). From this, ``myapp`` can retrieve access credentials to the service through the relationship environment variables. ```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. Then run the following command: ```bash mongo MONGODB_HOST ``` 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.html#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. - 1.0 ## Usage example ### 1. Configure the service To define the service, use the ``network-storage`` type: ```yaml {configFile="app"} 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 {configFile="app"} 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. - `` 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 {configFile="services"} 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#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 {configFile="apps"} 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 {configFile="app"} 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 {configFile="app"} applications: myapp: [...] mounts: web/uploads: source: storage source_path: uploads ``` 1. Add a new `network-storage` service to your configuration: ```yaml {configFile="app"} 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.html#vertical-scaling) to your `network-storage` service for your existing files with some buffer. 2. Add a new `service` mount, named `new-uploads`: ```yaml {configFile="services"} 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 {configFile="services"} 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. ## 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.html) and [`1.x`](https://opensearch.org/lines/1x.html) (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. ## Relationship reference For each service defined via a relationship 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). - Using default endpoints - Using explicit endpoints ``` 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 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: opensearch: services: # The name of the service container. Must be unique within a project. opensearch: type: opensearch:2 ``` ``` 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 (as per [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image#relationships) configuration for relationships). From this, ``myapp`` can retrieve access credentials to the service through the relationship environment variables. ```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 {configFile="services"} 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 {configFile="routes"} 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 {configFile="services"} 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 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. # 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. 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. ``` 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. ### `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` The type of the activity in one of the following categories: - Project - Environment - Integration - Maintenance #### `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. | | `payload.environment` | The environment affected by the activity. For details on its properties, see the `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. | | `payload.project` | Information about the project. For details on its properties, see the `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. #### `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. #### `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). 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" } ``` # 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.html#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. 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 (meaning, 2 days worth of backups are retained at any given point). When you configure your own automated backup policy, the retention time varies based on that configuration. Automated backups are always live. ## 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. 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 during non-peak hours, when the short amount of downtime is least noticed. You can create a manual live backup on a Grid project: - Using the CLI - In the Console ``` upsun backup:create ``` - 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. ### 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. They don't affect the automated backups taken as part of a schedule. ## 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. # 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 INTEGRATION_ID ACTIVITY_ID -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. # 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.html) 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. - 16 - 15 - 14 - 13 - 12 ### Note You can’t upgrade to PostgreSQL 12 with the `postgis` extension enabled. For more details, see how to . ### Deprecated versions The following versions are [deprecated](https://docs.upsun.com/glossary.html#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. - 11 - 10 - 9.6 - 9.5 - 9.4 - 9.3 ## Relationship reference For each service defined via a relationship 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). - Using default endpoints - Using explicit endpoints ``` 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 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: services: # The name of the service container. Must be unique within a project. postgresql: type: postgresql:16 ``` ``` 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:16 ``` 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 (as per [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image#relationships) configuration for relationships). From this, ``myapp`` can retrieve access credentials to the service through the relationship environment variables. ```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, you need: `POSTGRESQL_USERNAME`, `POSTGRESQL_HOST`, and `POSTGRESQL_PORT`. Then run the following command: ```bash psql -U POSTGRESQL_USERNAME -h POSTGRESQL_HOST -p POSTGRESQL_PORT ``` Using the values from the example, 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 < my_database_backup.sql ``` That runs the database backup against the SQL database on Upsun. That works for any SQL file, so the usual caveats about importing an SQL dump apply (for example, it's best to run against an empty database). As with exporting, you can also specify a specific environment to use and a specific database relationship to use, if there are multiple. ```bash upsun sql --relationship postgresql -e BRANCH_NAME < my_database_backup.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). ## 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 {configFile="services"} services: # The name of the service container. Must be unique within a project. postgresql: type: "postgresql:16" 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 {configFile="app"} 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:16" 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, 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 {configFile="services"} services: # The name of the service container. Must be unique within a project. postgresql: type: "postgresql:16" 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 {configFile="services"} services: # The name of the service container. Must be unique within a project. postgresql: type: "postgresql:16" 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 {configFile="services"} services: # The name of the service container. Must be unique within a project. postgresql: type: "postgresql:16" 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. For each custom endpoint you create, you get an automatically generated password, similarly to when you create 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](/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 TIMEZONE;`. ## 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 {configFile="services"} services: # The name of the service container. Must be unique within a project. postgresql: type: "postgresql:16" 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 . ## 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. ## 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. # 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: - Using the CLI - In the Console - Run the following command: `upsun backup:restore BACKUP_ID` - Press `enter` to agree with the consequences and continue. - Next to the backup you’ve selected, click **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.html#how-backup-and-restore-works). Also, see [how resource allocation works](https://docs.upsun.com/manage-resources/resource-init.html#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=TARGET_ENVIRONMENT_NAME BACKUP_ID ``` 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=TARGET_ENVIRONMENT_NAME --branch-from=PARENT_ENVIRONMENT_NAME BACKUP_ID ``` # 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 {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} applications: myapp: web: locations: '/': index: - index.html - index.htm passthru: true allow: false ``` You can also define sequences using a flow syntax: ```yaml {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} 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/). # Upsun 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) - ``routes``: this section of the file contains all of your [route definitions](https://docs.upsun.com/define-routes) (for each of your apps) - ``services``: this section of the file contains all of your [service definitions](https://docs.upsun.com/add-services) (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 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. - All the YAML files in subdirectories of the ``.upsun`` folder need to be [manually imported](/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: .upsun/app.yaml ``` applications: myapp: type: nodejs:16 source: root: folder1 ... ``` .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 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. # 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; } ``` # 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. ## 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. 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 USER_OAUTH_TOKEN --channel CHANNEL_NAME --project PROJECT_ID ``` 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 ``` # 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. - Using the Console - Using the CLI - Navigate to your existing organization or a project in it. - Open the user menu (your name or profile picture). - Click **Settings**. - Click **Delete Organization**. - Confirm your decision by clicking **Delete**. To delete the organization `acme`, run: `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). 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) 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.html). Organizations on Upsun are made up of both [projects](/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. - Using the Console - Using the CLI **Option 1: Remove projects from a team with from Team settings** - Navigate to your existing organization. - Open the user menu (your name or profile picture). - Select **Teams** from the dropdown. - Find the team you want to modify under the **Manage teams** list, then click ** More**. - Click **Edit team**. - Find the project you want to modify under the **PROJECTS** tab view, then click ** More**. - Click **Remove project**. - Select **All projects**, or choose individual projects from the dropdown. - Click **Yes** to confirm. **Option 2: Remove teams from a project from project’s Access settings** - Navigate to your existing organization. - Select the project you want to add to the existing team. - Navigate to the project’s settings by clicking the ** Settings** icon. - Click **Access** settings under **Project settings** in the sidebar. - Find the team under the **TEAMS** tab view, then click ** More**. - Click **Remove team**. - Click **Yes** to confirm. - Run the following command: `upsun team:project:delete -o ORGANIZATION_NAME` - 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, [MFA enforcement within an organization](https://docs.upsun.com/administration/teams.html). See how to [subscribe to this add-on](https://docs.upsun.com/administration/billing/add-on-subscription.html#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. - Using the CLI - Using the Console To update remove a user from your organization, run the following command: `upsun organization:user:delete EMAIL_ADDRESS --org ORGANIZATION_NAME` For example, to remove ``` alice@example.com ``` from your `acme` organization, run the following command: ``` 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**. - 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. # 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**. # 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. - Load 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: - Using the CLI - In the Console Run the following command: ``` upsun variable:create \ -e ENVIRONMENT_NAME \ --level environment \ --prefix 'env' \ --name UPSUN_CLI_TOKEN \ --sensitive true \ --value 'API_TOKEN' \ --inheritable false \ --visible-build true \ --no-interaction ``` - Open the environment where you want to add the variable. - Click **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 {configFile="app"} 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. 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 ``` # 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: - From the CLI - From the Console Run the following command: ``` upsun variable:create --environment main --level environment --prefix 'env' --name UPSUN_CLI_TOKEN --sensitive true --value 'YOUR_UPSUN_CLI_TOKEN' --inheritable false --visible-build true --json false --enabled true --visible-runtime true ``` - Open the environment where you want to add the variable. - Click **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.html) can read its value. Make sure you carefully check your [user access on this project](https://docs.upsun.com/administration/users.html#manage-project-users). 2. Add a build hook to your app configuration to install the CLI as part of the build process: ```yaml {configFile="app"} 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 {configFile="app"} 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. ## 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, 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: ``` /** * 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.html) command: `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, 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. # 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** 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") # Debugging ### 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.html). 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). ## 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 - Remote - Local In the JavaScript files from your remote site: On the **Run and Debug** tab under **Loaded Scripts** find `Attach: Remote Process` > `/app`.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). # Deploy Composer-based WordPress on Upsun ### 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.html). 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 {configFile="app"} 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` property 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 {configFile="app"} 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: '(? 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](../../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 {configFile="app"} applications: myapp: type: 'php:8.4' variables: php: extension: /app/spiffy.so ``` # 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](/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. # Manage Node.js versions ### 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.html). 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 `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`. - .nvmrc - .n-node-version/.node-version - package.json Create a `.nvmrc` file in [your app root](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.html#root-directory): .nvmrc `v16.13.2`Create a `.n-node-version` or `.node-version` file in [your app root](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.html#root-directory): .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: package.json ``` { "engines": { "node": ">=0.10.3 <15" } } ``` 2. Add it as a dependency: ```yaml {configFile="app"} 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 {configFile="app"} 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](../../create-apps/hooks/hooks-comparison.md#build-hook): ```yaml {configFile="app"} 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 {configFile="app"} 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](../../create-apps/_index.md): ```yaml {configFile="app"} 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 {configFile="app"} 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](../../create-apps/hooks/_index.md): ```yaml {configFile="app"} 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: ``` rsync -av $PLATFORM_CACHE_DIR/.nvm $PLATFORM_APP_DIR ``` 4. Use the cache directory and install based on the variables if not present: ```yaml {configFile="app"} 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](../../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 {configFile="app"} 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" ``` # 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 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](/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). ## 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. # 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 PaaS.

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](/administration/billing/monitor-billing.html#current-month-estimate) and a [next month estimate](https://docs.upsun.com/administration/billing/monitor-billing.html#next-month-estimate). You can also [set billing alerts](https://docs.upsun.com/administration/billing/monitor-billing.html#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. # 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 {configFile="routes"} 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 {configFile="routes"} 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.html). # 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 {configFile="routes"} 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. # 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/). ## 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=API_TOKEN ``` You can also add the token only to the project: ```bash ddev config --web-environment-add=UPSUN _CLI_TOKEN=API_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://PROJECT_NAME.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: - VARIABLE_NAME: VALUE ``` To apply your changes, run the following command: ```bash ddev restart ``` # CLI Command reference # Upsun CLI 5.0.15 - [Installation](https://docs.upsun.com/administration/cli#1-install) - [Open an issue](https://github.com/platformsh/cli/issues) ## All commands * `clear-cache` * `decode` * `docs` * `help` * `list` * `multi` * `web` **activity** * `activity:cancel` * `activity:get` * `activity:list` * `activity:log` **app** * `app:config-get` * `app:config-validate` * `app:list` **auth** * `auth:api-token-login` * `auth:browser-login` * `auth:info` * `auth:logout` * `auth:verify-phone-number` **backup** * `backup:create` * `backup:delete` * `backup:get` * `backup:list` * `backup:restore` **certificate** * `certificate:add` * `certificate:delete` * `certificate:get` * `certificate:list` **commit** * `commit:get` * `commit:list` **db** * `db:dump` * `db:sql` **domain** * `domain:add` * `domain:delete` * `domain:get` * `domain:list` * `domain:update` **environment** * `environment:activate` * `environment:branch` * `environment:checkout` * `environment:delete` * `environment:drush` * `environment:http-access` * `environment:info` * `environment:init` * `environment:list` * `environment:logs` * `environment:merge` * `environment:pause` * `environment:push` * `environment:redeploy` * `environment:relationships` * `environment:resume` * `environment:scp` * `environment:ssh` * `environment:synchronize` * `environment:url` * `environment:xdebug` **integration** * `integration:activity:get` * `integration:activity:list` * `integration:activity:log` * `integration:add` * `integration:delete` * `integration:get` * `integration:list` * `integration:update` * `integration:validate` **local** * `local:dir` **metrics** * `metrics:all` * `metrics:cpu` * `metrics:disk-usage` * `metrics:memory` **mount** * `mount:download` * `mount:list` * `mount:upload` **operation** * `operation:list` * `operation:run` **organization** * `organization:billing:address` * `organization:billing:profile` * `organization:create` * `organization:delete` * `organization:info` * `organization:list` * `organization:subscription:list` * `organization:user:add` * `organization:user:delete` * `organization:user:get` * `organization:user:list` * `organization:user:projects` * `organization:user:update` **project** * `project:clear-build-cache` * `project:create` * `project:delete` * `project:get` * `project:info` * `project:init` * `project:list` * `project:set-remote` **repo** * `repo:cat` * `repo:ls` * `repo:read` **resources** * `resources:build:get` * `resources:build:set` * `resources:get` * `resources:set` * `resources:size:list` **route** * `route:get` * `route:list` **service** * `service:list` * `service:mongo:dump` * `service:mongo:export` * `service:mongo:restore` * `service:mongo:shell` * `service:redis-cli` **source-operation** * `source-operation:list` * `source-operation:run` **ssh-cert** * `ssh-cert:load` **ssh-key** * `ssh-key:add` * `ssh-key:delete` * `ssh-key:list` **subscription** * `subscription:info` **team** * `team:create` * `team:delete` * `team:get` * `team:list` * `team:project:add` * `team:project:delete` * `team:project:list` * `team:update` * `team:user:add` * `team:user:delete` * `team:user:list` **tunnel** * `tunnel:close` * `tunnel:info` * `tunnel:list` * `tunnel:open` * `tunnel:single` **user** * `user:add` * `user:delete` * `user:get` * `user:list` * `user:update` **variable** * `variable:create` * `variable:delete` * `variable:get` * `variable:list` * `variable:update` **worker** * `worker:list` ## `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 < dump.sql ``` ## `domain:add` Add a new domain to the project ### Usage ``` upsun domain:add [--cert CERT] [--key KEY] [--chain CHAIN] [--attach ATTACH] [-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 * `--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 # 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. To add your custom certificate, follow these steps: - Using the CLI - In the Console - Run the following command: `upsun domain:add YOUR_DOMAIN --cert PATH_TO_CERTIFICATE_FILE --key PATH_TO_PRIVATE_KEY_FILE` For example: `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 PATH_TO_FILE ``` for each one. - Redeploy your production environment with the following command: `upsun environment:redeploy` - Open the project where you want to add a certificate. - Click **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**. - 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 ``` # Deploy Bedrock-based WordPress on Upsun ### 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.html). 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 {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} 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/) - [Extensions](https://docs.upsun.com/languages/php/extensions) - [Performance tuning](https://docs.upsun.com/languages/php/tuning) - [PHP-FPM sizing](https://docs.upsun.com/languages/php/fpm) - [Authenticated Composer](https://docs.upsun.com/languages/php/composer-auth) ### 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/) # 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](/add-services/redis.md), [Memcached](https://docs.upsun.com/add-services/memcached.md), [Elasticsearch](/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 are a better long-term plan. # 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.YOUR_APEX_DOMAIN TXT "public-suffix-root=YOUR_APEX_DOMAIN" ``` This adds your domain to the Upsun implementation of the Public Suffix List. After you add your subdomains, remove the `TXT` record to reinstate 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 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. # 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 {configFile="routes"} 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 {configFile="routes"} 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 {configFile="routes"} 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. **Type:** Boolean **Required:** Yes **Values** - `true`: enable the cache for this route [default, but only if the `cache` key isn’t actually specified] - `false`: disable the cache for this route ### `headers` Adds specific header fields to the cache key, enabling caching of separate responses for those headers. For example, if the `headers` key is the following, Upsun caches a different response for each value of the `Accept` HTTP request header only: ```yaml {configFile="routes"} routes: https://{default}/: # ... cache: enabled: true headers: ["Accept"] ``` **Type:** List **Values:** - `['Accept', 'Accept-Language']`: Cache on Accept & Accept-Language [default] #### Header behaviors The cache is only applied to `GET` and `HEAD` requests. Some headers trigger specific behaviors in the cache. Header field | Cache behavior -------------|---------------- `Cache-Control`|Responses with the `Cache-Control` header set to `Private`, `No-Cache`, or `No-Store` aren't cached. All other values override `default_ttl`. `Vary`|A list of header fields to be taken into account when constructing the cache key. Multiple header fields can be listed, separated by commas. The Cache key is the union of the values of the Header fields listed in Vary header, and whatever is listed in the `.upsun/config.yaml` file. `Set-Cookie`|Not cached `Accept-Encoding`, `Connection`, `Proxy-Authorization`, `TE`, `Upgrade`|Not allowed, and throws an error `Cookie`|Not allowed, and throws an error. Use the `cookies` value, instead. `Pragma`|Ignored A full list of HTTP headers is available on [Wikipedia](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields). ### `cookies` The `cookies` key allows you to define a list of cookies you want to include in the cache key, if any. | Possible values | Description | Default | |--------------------------|---------------------------------------------------------------------------------------|---------| | `['*']` | Any request with a cookie bypasses the cache. Note that this is achieved by Upsun adding the `X-Platform-Cache: BYPASS` HTTP header in the router, and that the same behaviour applies if the `Set-Cookie` header is present. | Yes | | `[]` | Ignore all cookies. | No | |`['cookie_1','cookie_2']` | A list of allowed cookies to include in the cache key. All other cookies are ignored. | No | #### Example with a single value With the following configuration, the cache key depends on the value of the `foo` cookie in the request. Other cookies are ignored. ```yaml {configFile="routes"} routes: https://{default}/: # ... cache: enabled: true cookies: ["foo"] ``` #### Example with a regular expression A cookie value can also be a regular expression. An entry that begins and ends with a `/` is interpreted as a PCRE regular expression to match the cookie name. For example: ```yaml {configFile="routes"} routes: https://{default}/: # ... cache: enabled: true cookies: ['/^SS?ESS/'] ``` This configuration causes all cookies beginning with `SESS` or `SSESS` to be part of the cache key, as a single value. Other cookies are ignored for caching. If your site uses a session cookie as well as third-party cookies, say from an analytics service, this is the recommended approach. ### `default_ttl` Defines the default time-to-live for the cache, in seconds, for non-static responses, when the response doesn't specify one. 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` is used. If the application code returns a `Cache-Control` header or if your `.upsun/config.yaml` file is configured to set a cache lifetime, then this value is ignored in favor of the application headers. The `default_ttl` only applies to **non-static responses**, that is, those generated by your application. To set a cache lifetime for static resources configure that in your [app configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#locations). All static assets have a Cache-Control header with a max age defaulting to 0 (which is the default for `expires`). **Type:** integer **Values:** - `0`: Do not cache [default]. This prevents caching, unless the response specifies a `Cache-Control` header value. ## Debugging Upsun adds an `X-Platform-Cache` header to each request which show whether your request is a cache `HIT`, `MISS` or `BYPASS`. This can be useful when trying to determine whether it's your application, the HTTP cache, or another proxy or CDN which isn't behaving as expected. If in doubt, disable the cache using `cache: false`. ## Advanced caching strategies ### Cache per route If you need fine-grained caching, you can set up caching rules for several routes separately: ```yaml {configFile="routes"} routes: https://{default}/: type: upstream upstream: myapp:http cache: enabled: true https://{default}/foo/: type: upstream upstream: myapp:http cache: enabled: false https://{default}/foo/bar/: type: upstream upstream: myapp:http cache: enabled: true ``` With this configuration, the following routes are cached: - `https://{default}/` - `https://{default}/foo/bar/` - `https://{default}/foo/bar/baz/` And the following routes are **not** cached: - `https://{default}/foo/` - `https://{default}/foo/baz/` ### 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 {configFile="routes"} 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. # 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 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: - User management estimate - Accumulated resource usage estimate - Allocated resource usage estimate The following formula is used to estimate how much user license and user management add-on fees 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** tab. 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 tab. 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 tab. ### Next month estimate From the **Overview** tab, you can also access an estimate for next month. Like your 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 [ permission](https://docs.upsun.com/administration/users.html#organization-permissions), and identified billing contacts. ### Set a billing alert You can set billing alerts to receive an email when your 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 [ permission](https://docs.upsun.com/administration/users.html#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 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** 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/). # Moving a Java application to Upsun ### 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.html). 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.html) * [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.html). ## 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 {configFile="app"} 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.html#mounts). ### Route ```yaml {configFile="app"} 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.html) 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://community.platform.sh/t/how-to-configure-load-balancer-in-a-single-application/553) 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.html) * [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://community.platform.sh/t/multiple-applications-tomcat/468) | [Source](https://github.com/platformsh-examples/tomcat-multi-app) | | [Configure multi-applications with `.upsun/config.yaml`](https://community.platform.sh/t/how-to-configure-multi-applications-with-applications-yaml/552) | [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://community.platform.sh/t/how-to-configure-load-balancer-in-a-multiple-applications/554). 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](/development/variables.md#service-environment-variables), or the [`PLATFORM_RELATIONSHIPS` environment variable](https://docs.upsun.com/development/variables/use-variables.md#use-provided-variables). - Service environment variables - `PLATFORM_RELATIONSHIPS` environment variable ``` export DB_HOST=${POSTGRESQL_HOST} export DB_PASSWORD=${POSTGRESQL_PASSWORD} export DB_USER=${POSTGRESQL_USERNAME} export DB_DATABASE=${POSTGRESQL_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 the names your app needs, and the values from [service environment variables](https://docs.upsun.com/development/variables.html#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 [ tool](https://stedolan.github.io/jq/), which allows to extract information from this JSON. ``` 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 [ environment variable](https://docs.upsun.com/development/variables/use-variables.html#use-provided-variables). This `.environment` file can interact to each application file. **Example:** ```yaml {configFile="app"} 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 ### 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.html). 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.html#GUID-326EB4CF-8C8C-4267-8355-21AB04F0D304) # 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 {configFile="services"} 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 {configFile="app"} 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 {configFile="app"} 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. # 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* - One or more *app* containers - Zero or more *service* containers - Zero or more *worker* containers 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). # 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 PROJECT_ID ```. Alternatively, you can clone an integrated source repository and set the remote branch. To do so, run ``` upsun project:set-remote PROJECT_ID ```. - 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 PRODUCTION_ENVIRONMENT_NAME ``` If you're using a [source integration](https://docs.upsun.com/integrations/source.html), 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=PORT --user=USERNAME --password=PASSWORD --database=PATH ``` ## 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 PROJECT_ID cd PROJECT_NAME ./init-local.sh PROJECT_ID another-new-feature PRODUCTION_ENVIRONMENT_NAME ``` # 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. # 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#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). # 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, [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**](https://docs.upsun.com/glossary.md#branch) to create a new child environment. * [ **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** to configure the environment. * **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](../../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** 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](../../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](../../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](../../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](../../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**. # Deploy Vanilla WordPress on Upsun ### 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.html). 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 {configFile="app"} 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: '(? 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 {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} 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/) - [Extensions](https://docs.upsun.com/languages/php/extensions) - [Performance tuning](https://docs.upsun.com/languages/php/tuning) - [PHP-FPM sizing](https://docs.upsun.com/languages/php/fpm) ### 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/) # 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 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 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 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 {configFile="routes"} 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, 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 {configFile="routes"} 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 {configFile="routes"} 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 {configFile="routes"} 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 {configFile="routes"} 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 {configFile="routes"} 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----- ``` # 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.html#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. ## 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: - Using the CLI - In the Console - To enable the `prune-branches` option, you must first enable the `fetch-branches` option. To do so, run the following command: `upsun integration:update --project PROJECT_ID SOURCE_INTEGRATION_ID --fetch-branches true` - Then, to enable the `prune-branches` option, run the following command: `upsun integration:update --project PROJECT_ID SOURCE_INTEGRATION_ID --prune-branches true` - Navigate to your project. - Click **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.html#mounts) and [transfer your files directly to them](https://docs.platform.sh/development/file-transfer.html#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 and upload your files through mounts to avoid facing the same situation in the future. # PHP performance tuning ### 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.html). 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. If you have disabled 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 {configFile="app"} applications: myapp: type: 'php:8.4' variables: php: opcache.preload: 'PRELOAD_SCRIPT' ``` `PRELOAD_SCRIPT` 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 {configFile="app"} 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 {configFile="app"} applications: myapp: type: 'php:8.4' variables: php: 'opcache.memory_consumption': 96 ``` 8. 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](../../create-apps/_index.md): ```yaml {configFile="app"} 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. 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. # 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: - Using the CLI - In the Console Run a command similar to the following: `upsun domain:delete staging.example.com --environment STAGING_ENVIRONMENT_ID` - Navigate to your preview environment and click ** Settings**. - Select the **Domains** tab. All the custom domains for the selected environment are displayed. - Click ** More** on the custom domain you want to delete. - Click **Delete**. - Click **Yes, delete**. # 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 {configFile="routes"} 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)](https://community.platform.sh/t/configure-mutual-tls-with-cloudflare-and-platform-sh/761). [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.html) Therefore, mTLS is **not** compatible with preview environments created by a [source code integration](https://docs.upsun.com/integrations/source.html). 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. # 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. # 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.YOUR_DOMAIN ``` 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.YOUR_DOMAIN`. If the result is different from what you got from running `host www.YOUR_DOMAIN`, 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.YOUR_DOMAIN ``` 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 ENVIRONMENT-PROJECT_ID.REGION.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 YOUR_DOMAIN.ENVIRONMENT-PROJECT_ID.REGION.platformsh.site ``` The generated URLs consist of: - `YOUR_DOMAIN` = the amount of characters your domain has - `ENVIRONMENT` = `BRANCH_NAME` + 7 character hash - `PROJECT_ID` = 13 characters - `REGION` = 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 (`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. - Without a CDN - Using a CDN Upsun checks that all the routes you defined are pointing to your project. For the challenge to complete, domains and subdomains must point directly to your Upsun project. Otherwise, you get an error similar to: ``` E: Error validating domain www.example.com: Couldn't complete challenge [HTTP01: pending | DNS01: pending | TLSALPN01: pending] Unable to validate domains www.example.com, will retry in the background. ``` When you use a CDN, to ensure the challenge succeeds, check that: - Your domains and subdomains point to your CDN - The [ subdomain](https://www.rfc-editor.org/rfc/rfc8555#section-8.4), as in `_acme-challenge.example.com`, points to your CDN - The [ route](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: ``` 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.html). 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). If your website is still not working as expected, [contact support](https://docs.upsun.com/learn/overview/get-support.md). # 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.html). 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 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. ### 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** 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. # 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.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 {configFile="app"} 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 | Yes | No | The base image to use with a specific app language. Format: `runtime:version`. | | `relationships` | A dictionary of relationships | | Yes | Connections to other services and apps. | | `mounts` | A dictionary of mounts | | Yes | Directories that are writable even after the app is built. Allocated disk for mounts is defined with a separate resource configuration call using `upsun resources:set`. | | `web` | A web instance | | N/A | How the web application is served. | | `workers` | A worker instance | | N/A | Alternate copies of the application to run as background processes. | | `timezone` | `string` | | No | The timezone for crons to run. Format: a [TZ database name](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 | | Yes | Access control for roles accessing app environments. | | `variables` | A variables dictionary | | Yes | Variables to control the environment. | | `firewall` | A firewall dictionary | | Yes | Outbound firewall rules for the application. | | `build` | A build dictionary | | No | What happens when the app is built. | | `dependencies` | A dependencies dictionary | | No | What global dependencies to install before the `build` hook is run. | | `hooks` | A hooks dictionary | | No | What commands run at different stages in the build and deploy process. | | `crons` | A cron dictionary | | No | Scheduled tasks for the app. | | `source` | A source dictionary | | No | Information on the app's source code and operations that can be run on it. | | `runtime` | A runtime dictionary | | No | Customizations to your PHP or Lisp runtime. | | `additional_hosts` | An additional hosts dictionary | | Yes | Maps of hostnames to IP addresses. | ## Root directory Some of the properties you can define are relative to your app's root directory. The root defaults to the root of the repository. ```yaml {configFile="app"} 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. ## 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 [ key](https://docs.upsun.com/create-apps/app-reference/composable-image.html#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.html) | `dotnet` | 7.0, 6.0, 8.0 | | [Elixir](https://docs.upsun.com/languages/elixir.html) | `elixir` | 1.15, 1.14 | | [Go](https://docs.upsun.com/languages/go.html) | `golang` | 1.23, 1.22, 1.21, 1.20 | | [Java](https://docs.upsun.com/languages/java.html) | `java` | 21, 19, 18, 17, 11, 8 | | [Lisp](https://docs.upsun.com/languages/lisp.html) | `lisp` | 2.1, 2.0, 1.5 | | [JavaScript/Node.js](https://docs.upsun.com/languages/nodejs.html) | `nodejs` | 22, 20, 18, 16 | | [PHP](https://docs.upsun.com/languages/php.html) | `php` | 8.4, 8.3, 8.2, 8.1 | | [Python](https://docs.upsun.com/languages/python.html) | `python` | 3.12, 3.11, 3.10, 3.9, 3.8 | | [Ruby](https://docs.upsun.com/languages/ruby.html) | `ruby` | 3.3, 3.2, 3.1, 3.0 | | [Rust](https://docs.upsun.com/languages/rust.html) | `rust` | 1 | ### Example configuration These are used in the format `runtime:version`: ```yaml {configFile="app"} applications: myapp: type: 'php:8.4' ``` ### Mix of images In a [multiple application context](/create-apps/multi-app.md), you can mix both [single-runtime image](/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 {configFile="app"} 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.html). ### 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: - In the Console - Using the CLI - In the Console, navigate to your project. - Open the environment where you’d like the crons to run. - Click `Redeploy` next to the cron status of `Paused`. Run the following command: `upsun redeploy` ## Runtime The following table presents the various possible modifications to your PHP or Lisp runtime: | Name | Type | Language | Description | |-----------------------------|------------------------------------------------------------|----------|--------------------------------------------------------------------------------------------| | `extensions` | List of `string`s OR extensions definitions 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 | 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.html#primary-application-properties). You can enable [PHP extensions](https://docs.upsun.com/languages/php/extensions.md) just with a list of extensions: ```yaml {configFile="app"} 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 {configFile="app"} 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#advanced-container-profiles) - [Default container profiles](https://docs.upsun.com/manage-resources/adjust-resources#default-container-profiles) for runtime and service containers - [Customize resources using the `container_profile` key](https://docs.upsun.com/manage-resources/adjust-resources#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 {configFile="app"} 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.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 {configFile="app"} 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. | | `relationships` | A dictionary of relationships | | Yes | Connections to other services and apps. | | `mounts` | A dictionary of mounts | | Yes | Directories that are writable even after the app is built. Allocated disk for mounts is defined with a separate resource configuration call using `upsun resources:set`. | | `web` | A web instance | | N/A | How the web application is served. | | `workers` | A worker instance | | N/A | Alternate copies of the application to run as background processes. | | `timezone` | `string` | | No | The timezone for crons to run. Format: a [TZ database name](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 | | Yes | Access control for roles accessing app environments. | | `variables` | A variables dictionary | | Yes | Variables to control the environment. | | `firewall` | A firewall dictionary | | Yes | Outbound firewall rules for the application. | | `hooks` | A hooks dictionary | | No | What commands run at different stages in the build and deploy process. | | `crons` | A cron dictionary | | No | Scheduled tasks for the app. | | `source` | A source dictionary | | No | Information on the app's source code and operations that can be run on it. | | `additional_hosts` | An additional hosts dictionary | | 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.html). 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 {configFile="app"} 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, just issue the command (e.g. in the [ command](https://docs.upsun.com/create-apps/app-reference/composable-image.html#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. 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. 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.html) | `sbcl` | 2 | | [Elixir](https://docs.upsun.com/languages/elixir.html) | `elixir` | 1.15
1.14 | | [Go](https://docs.upsun.com/languages/go.html) | `golang` | 1.22
1.21 | | [Java](https://docs.upsun.com/languages/java.html) | `java` | 21 | | [Javascript/Bun](https://bun.sh/) | `bun` | 1 | | [JavaScript/Node.js](https://docs.upsun.com/languages/nodejs.html) | `nodejs` | 22
20
18 | | [Perl](https://www.perl.org/) | `perl` | 5 | | [PHP](https://docs.upsun.com/languages/php.html) | `php` | 8.3
8.2
8.1 | | [Python](https://docs.upsun.com/languages/python.html) | `python` | 3.12
3.11
3.10
3.9
2.7 | | [Ruby](https://docs.upsun.com/languages/ruby.html) | `ruby` | 3.3
3.2
3.1 | **Example:** You want to add PHP version 8.4 and ``facedetect`` to your application container. To do so, use the following configuration: ```yaml {configFile="app"} 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 {configFile="app"} 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. 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.html#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 {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} 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. To find out which start command to use, go to the [Languages](https://docs.upsun.com/languages.html) 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.html#advanced-container-profiles)
or change [default CPU and RAM ratio](https://docs.upsun.com/manage-resources/resource-init.html) on first deployment using the following commands: `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.html). ### 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: - In the Console - Using the CLI - In the Console, navigate to your project. - Open the environment where you’d like the crons to run. - Click `Redeploy` next to the cron status of `Paused`. Run the following command: `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#advanced-container-profiles) - [Default container profiles](https://docs.upsun.com/manage-resources/adjust-resources#default-container-profiles) for runtime and service containers - [Customize resources using the `container_profile` key](https://docs.upsun.com/manage-resources/adjust-resources#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 {configFile="app"} 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. # PHP-FPM sizing ### 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.html). 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 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 to be 110 MB and your reserved memory to be 80 MB, you can use: <---> ```yaml {configFile="app"} 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 ``` # 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. **** - [Express installation guide](https://expressjs.com/en/starter/installing.html) - [Next.js installation guide](https://nextjs.org/docs/getting-started/installation) - [Strapi installation guide](https://docs.strapi.io/dev-docs/installation) **** - [Laravel installation guide](https://laravel.com/docs/10.x#creating-a-laravel-project) - [Symfony installation guide](https://docs.upsun.com/get-started/stacks/symfony.html) **** - [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.html#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. ``` # 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." ``` Back Create a project # 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, or 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 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 {configFile="app"} applications: myapp: type: nodejs:22 source: root: "/" operations: SOURCE_OPERATION_NAME: command: COMMAND ``` For example, to update a file from a remote location, you could define an operation like this: ```yaml {configFile="app"} 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. ## Run a source operation - From the CLI - From the Console Run the following command: ``` upsun variable:create --environment main --level environment --prefix 'env' --name UPSUN_CLI_TOKEN --sensitive true --value 'YOUR_UPSUN_CLI_TOKEN' --inheritable false --visible-build true --json false --enabled true --visible-runtime true ``` - Open the environment where you want to add the variable. - Click **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.html) can read its value. Make sure you carefully check your [user access on this project](https://docs.upsun.com/administration/users.html#manage-project-users). 2. Add a build hook to your app configuration to install the CLI as part of the build process: ```yaml {configFile="app"} 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 {configFile="app"} 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. ## 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 {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} 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 when running the source operation. ```yaml {configFile="app"} 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 {configFile="app"} 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. # 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.html) 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. # 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: - In the Console - Using the CLI - Select the project whose URLs you want to find. - From the **Environment** menu, select an environment. - Click **URLs**. Copy and paste any of these URLs into a web browser and access your site. - Run the following command: `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/). # 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 and trigger them 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 {configFile="app"} applications: myapp: source: root: "/" operations: RUNTIME_OPERATION_NAME: role: USER_ROLE commands: start: COMMAND ``` 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 {configFile="app"} 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. ## Run a runtime operation - Ping your app - Reload your app - Restart your app To ping your Node.js app, define a runtime operation similar to the following: ``` 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-ping: role: admin commands: start: | # Assuming pm2 start npm --no-daemon --watch --name $APP -- start -- -p $PORT APP=$(cat package.json | jq -r '.name') pm2 ping $APP ``` To trigger your runtime operation, run a command similar to the following: `upsun operation:run pm2-ping --project PROJECT_ID --environment ENVIRONMENT_NAME` To reload your Node.js app, define a runtime operation similar to the following: ``` 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: `upsun operation:run pm2-reload --project PROJECT_ID --environment ENVIRONMENT_NAME` To restart your Node.js app, define a runtime operation similar to the following: ``` 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: `upsun operation:run pm2-restart --project PROJECT_ID --environment ENVIRONMENT_NAME` ### 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 {configFile="app"} 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 PROJECT_ID --environment ENVIRONMENT_NAME ``` # Using Xdebug ### 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.html). [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.html). ## 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 {configFile="app"} applications: myapp: type: 'php:8.4' runtime: xdebug: idekey: YOUR_KEY ``` YOUR_KEY 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 {configFile="routes"} applications: myapp: type: 'php:8.4' runtime: xdebug: idekey: YOUR_KEY 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.html). 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 ### 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.html). [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 {configFile="app"} 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 {configFile="app"} 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. # 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.html). ### 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.html). ### 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.html). # 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). # Swoole ### 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.html). 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.html) 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 {configFile="app"} 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<&0 ``` ## 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 {configFile="app"} applications: myapp: type: 'php:8.4' web: upstream: socket_family: tcp protocol: http commands: start: php PATH_TO_SWOOLE_START_COMMAND --port=$PORT locations: "/": passthru: true scripts: false allow: false ``` # 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](../../administration/cli/_index.md): - Using the CLI - Using SSH directly Use the `upsun log` command and specify the type of log you want. For example, to get the access log, run: `upsun log -e ENVIRONMENT_NAME access` To get other logs, just replace `access` with the type of log. To view more lines, use the `--lines` flag. - Access the container by running `upsun ssh -e ENVIRONMENT_NAME` - 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. | | `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/PHP_VERSION-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. # 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: - PHP - Java To send email in PHP, you can use the built-in [ function](https://www.php.net/manual/en/function.mail.php). The PHP runtime is configured to send email automatically with the correct configuration. This works even for libraries such as PHPMailer, which uses the `mail()` function by default. Note that the `From` header is required. Your email isn’t sent if that header is missing. Beware of potential security problems when using the `mail()` function. If you use any input from users in the ``` $additional_headers ``` or $additional_params ``` parameters, be sure to sanitize it first. 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: ``` 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. # Upsun 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. 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: ``` . ├── .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: ``` 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 {configFile="app"} 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 {configFile="app"} 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 {configFile="apps"} 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 {configFile="app"} 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 {configFile="app"} workers: queue1: !include "worker.yaml" ``` ```yaml {configFile="app"} workers: queue1: !include type: yaml path: 'worker.yaml' ``` ```yaml {configFile="app"} 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 {configFile="apps"} 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 {configFile="services"} 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. # 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.html), 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. 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, 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 {configFile="routes"} routes: "https://{default}/": cache: enabled: true cookies: ["/SESS.*/", "__blackfire"] ``` ## Get support If you're experiencing issues with Blackfire and troubleshooting information doesn't help, follow these steps: 1. Retrieve startup errors. 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](../../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 ``` # 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 | | One app depends on code from another app. | Nested directories | | You want to keep configuration separate from code, such as through Git submodules. | Configuration separate from code | | You want multiple apps from the same source code. | Unified app configuration | | You want to control all apps in a single location. | 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 <- Unified configuration ├── admin │ └── ... <- API Platform Admin app code ├── api-app │ └── ... <- Bigfoot app code ├── gatsby │ └── ... <- Gatsby app code └── mercure └── ... <- Mercure Rocks app code ``` The `api` app is built from the `api-app` directory. The `admin` app is built from the `admin` directory. The `gatsby` app is built from the `gatsby` directory. The `mercure` app is built from the `mercure` directory. They all have different configurations for how they serve the files. For more details, see the [complete example file](https://github.com/platformsh-templates/bigfoot-multiapp/blob/multiapp-monolith/.platform/applications.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. 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 {configFile="apps"} 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 <- Java app code └── main.py <- Python app code ``` The Python app's code base includes all of the files at the top level (excluding the `.upsun` directory) *and* all of the files within the `languagetool` directory. The Java app's code base includes only the files within the `languagetool` directory. In this case, your `.upsun/config.yaml` file must contain 2 entries, one for the `main` app and second one for the `languagetool` app. ### 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 of the `languagetool` app. Once your repository is organized, you can use a configuration similar to the following: ```yaml {configFile="apps"} 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 <-- API Platform Admin submodule ├── @api <-- Bigfoot submodule ├── @gatsby <-- Gatsby submodule ├── @mercure <-- Mercure rocks submodule └── .gitmodules ``` [Add the submodules using the Git CLI](https://docs.upsun.com/development/submodules.html#clone-submodules-during-deployment). Your `.gitmodules` file would define all the submodules like this: ```txt {location=".gitmodules"} [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 ``` ### 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 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 example project, you could add the following configuration: ```yaml {configFile="app"} 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 `"/"`. # Create a project To create a new project on Upsun, you can take one of two paths: **** 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 PROJECT_ID ``` 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`. **** 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. Back Configure your project # Forward Upsun 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 or any service that supports a syslog endpoint](#forward-to-a-syslog-endpoint) or [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. ### 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. - PHP - Python - Go ``` openlog("", LOG_PID, LOG_LOCAL0); syslog(LOG_INFO, "Operation started"); syslog(LOG_ERR, "Operation failed"); closelog(); ``` Using the logging module: ``` 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: ``` 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: ``` 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: ``` 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") } ``` # 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) - [Setting up managed services](https://docs.upsun.com/add-services) - [Handling requests](https://docs.upsun.com/define-routes) ## 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#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](/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: - Next.js - Express - Strapi ``` applications: myapp: source: root: "/" type: "nodejs:20" web: commands: start: "npx next start -p $PORT" build: flavor: none dependencies: nodejs: sharp: "*" #services: # db: # 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}/" ``` ``` 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}/" ``` ``` 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) - [Next.js](https://docs.upsun.com/get-started/stacks/nextjs) - [Strapi](https://docs.upsun.com/get-started/stacks/strapi) ## 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 # 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**. 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_PROVIDER:PATH_OR_USERNAME/REPOSITORY.git ```. For example, you can clone a repository in your [`build` hook](../create-apps/hooks/_index.md): ```yaml {configFile="app"} applications: APP_NAME: 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). # RabbitMQ (message queue service) [RabbitMQ](https://www.rabbitmq.com/documentation.html) 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.html#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. - 3.11 - 3.10 - 3.9 - 3.8 - 3.7 - 3.6 - 3.5 ## Relationship reference For each service defined via a relationship 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). - Using default endpoints - Using explicit endpoints ``` 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 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: rabbitmq: services: # The name of the service container. Must be unique within a project. rabbitmq: type: rabbitmq:4.0 ``` ``` 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 (as per [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image#relationships) configuration for relationships). From this, ``myapp`` can retrieve access credentials to the service through the relationship environment variables. ```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 - A web interface In each case, you need the login credentials that you can obtain from the relationship. ### 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. See a [list of RabbitMQ client libraries](https://www.rabbitmq.com/devtools.html). ### Access the management UI RabbitMQ offers a [management plugin with a browser-based UI](https://www.rabbitmq.com/management.html). 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:RELATIONSHIP_NAME.internal:15672 ``` RELATIONSHIP_NAME is the name you defined. 2. Open `http://localhost:15672` in your browser. Log in using the username and password from the relationship. ## Configuration options You can configure your RabbitMQ service in the services configuration 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.html), 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 {configFile="services"} 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.html#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. # 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). # 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.html#split-your-code-source-into-multiple-git-submodule-repositories). ## Update submodules - Manual update - Automated update When you amend your submodules’ code, make sure your changes are applied by running the following commands before redeploying: ``` git submodule update --remote [submodule] Submodule path 'admin': checked out 'a020894cf94de6e79748890c942206bc7af752af' Submodule path 'api': checked out 'dce6617cc2db159c1a871112909e9ea4121135ec' Submodule path 'gatsby': checked out '012ab16b05f474278ad0f9916e1cb94fc9df5ba4' Submodule path 'mercure': checked out '94ccae5055983004aa8ab2c17b1daabd0c0a4927' ``` ### Note To specify which submodule needs to be updated, replace `[submodule]` with your submodule path. Automate your submodule updates using a [source operation](https://docs.upsun.com/create-apps/source-operations.html). To do so, follow these steps: - Define a source operation. Add the following configuration to your `.upsun/config.yaml` file: ``` applications: # The name of the app container. Must be unique within a project. myapp: source: operations: rebuild: command: | set -e git submodule update --init --recursive git submodule update --remote --checkout git add admin api gatsby mercure if ! git diff-index --quiet HEAD; then git commit -m "Updating submodules admin, api, gatsby and mercure" fi ``` For multiple app projects, make sure you define your source operation in the configuration of an app whose source code **is not** in a submodule. If you use [Git submodules for each of your apps](https://docs.upsun.com/create-apps/multi-app/project-structure.html#split-your-code-source-into-multiple-git-submodule-repositories), define a new app at the top level of your project repository. Don’t define routes so your app isn’t exposed to the web. To define a source operation, add the following configuration to your [app configuration](https://docs.upsun.com/create-apps/app-reference.html): ``` applications: # The name of the app container. Must be unique within a project. update-submodule: # The type of the application to build. type: 'nodejs:22' # The web key configures the web server running in front of your app. web: # Commands are run once after deployment to start the application process. commands: # The command to launch your app. If it terminates, it’s restarted immediately. # As this app will handle source operation only, no need to keep it alive (sleep) start: | sleep infinity source: operations: update-submodules: command: | set -e git submodule update --init --recursive git submodule update --remote --checkout git add . if ! git diff-index --quiet HEAD; then git commit -m "Updating submodules" fi # "git push" is automatic at the end of this command ``` - Run your source operation. To do so, in the [Console](https://docs.upsun.com/administration/web.html), navigate to the environment where you want to run the source operation. Click **More**. Click **Run Source Operation**. Select the operation you want to run. Click **Run**. Alternatively, to run your source operation from the [Upsun CLI](https://docs.upsun.com/administration/cli.html), run the following command: `upsun source-operation:run SOURCE_OPERATION_NAME` ## Error when validating submodules Using an SSH URL (`git@github.com:...`) to fetch submodules triggers the following error: ```bash Validating submodules. Found unresolvable links, updating submodules. E: Error validating submodules in tree: - admin: Exception: commit 03567c6 not found. This might be due to the following errors fetching submodules: - git@github.com:platformsh-templates/bigfoot-multiapp-admin.git: HangupException: The remote server unexpectedly closed the connection. ``` This is due to the fact that the Upsun Git server can't connect to GitHub via SSH without being granted an SSH key to do so. To solve this issue, use an HTTPS URL (`https://github.com/...`) instead. ## Use private Git repositories When using Git submodules that are private repositories, URLs with the HTTPS protocol fail with errors such as the following: ```bash GitProtocolError: unexpected http resp 401 for https://bitbucket.org/myusername/mymodule.git/info/refs?service=git-upload-pack ``` To fix this, follow these steps: 1. Change your module declarations to use SSH for URLs. Your existing declaration might look like this: ```bash {location=".gitmodules"} [submodule "support/module"] path = support/module url = https://bitbucket.org/username/module.git branch = submodule/branch ``` Change this to the following: ```bash {location=".gitmodules"} [submodule "support/module"] path = support/module url = git@bitbucket.org:username/module.git branch = submodule/branch ``` 2. Add the [project's public key to your remote Git repository](https://docs.upsun.com/development/private-repository.md). This allows your Upsun project to pull the repository from the remote Git service. ### 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 ``` # 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 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** 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) `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) `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) `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) `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) `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) `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) `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) `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) `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) `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) `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) `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) `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) `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) `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) `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) `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. - Using the CLI - In the Console For a given organization ORG_NAME, run the following command: `upsun project:list -o ORG_NAME --region=REGION` Where REGION 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: ``` curl -s https://raw.githubusercontent.com/platformsh/snippets/region-audit/src/region-audit.sh | bash -s -- ORG_NAME ch-1,uk-1,de-2,us-4,fr-4,us-3,au-2 upsun ``` - Navigate to the organization (ORG_NAME) you’d like to audit at `https://console.upsun.com/ORG_NAME`. This view shows all of your projects within the organization ORG_NAME (assuming you have at least [](https://docs.upsun.com/administration/users.html#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) 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. # 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) - [Setting up managed services](https://docs.upsun.com/add-services) - [Handling requests](https://docs.upsun.com/define-routes) ## 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#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). ## PHP settings Upsun provides additional configuration possibilities to control: - [PHP-FPM runtime configuration](https://docs.upsun.com/create-apps/app-reference/single-runtime-image#runtime) - [PHP settings](https://docs.upsun.com/languages/php#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) 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#alternate-start-commands) - [Swoole](https://docs.upsun.com/languages/php/swoole) ## 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) - [Symfony](https://docs.upsun.com/get-started/stacks/symfony) ## 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 # 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: - In the Console - Using the CLI - Select the project with the given environment. - From the **Environment** menu, select the environment. - Click **More**. - Click **Redeploy**. Run the following command: `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.html) and their reuse. To rerun the `build` and `deploy` hooks, manually trigger a build. ### 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.html#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: ``` 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://community.platform.sh/t/diagnosing-and-resolving-issues-with-excessive-bot-access/792). - 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 YOUR_SCRIPT_FILE_NAME` 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.html#limit-the-number-of-changes-fetched-during-clone) or using the [`GIT_DEPTH` variable](https://docs.gitlab.com/ee/user/project/repository/monorepos/index.html#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). ## 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 PID`. Replace `PID` 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 YOUR_HOOK_COMMAND # Print execution time strace -T YOUR_HOOK_COMMAND # 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) # 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.html#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.html#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") # 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 {configFile="apps"} 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 a source operation to update your submodules](https://docs.upsun.com/create-apps/multi-app/project-structure.html#split-your-code-source-into-multiple-git-submodule-repositories). You can also achieve the same thing by defining the app as a [](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.html#workers). Depending on your needs, you could configure the router container using subdomains](#define-routes-using-subdomains) or using [subdirectories. ### Define routes using subdomains You could define routes for your apps as follows: ```yaml {configFile="routes"} 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 {configFile="routes"} 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 {configFile="apps"} 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). # 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) - [Setting up managed services](https://docs.upsun.com/add-services) - [Handling requests](https://docs.upsun.com/define-routes) ## 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), 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). ## 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) - [Flask](https://docs.upsun.com/get-started/stacks/flask) ## 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 # 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: to set up fast persistent storage for your application - Ephemeral: 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.html#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. - 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. ## Relationship reference For each service defined via a relationship 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). - Using default endpoints - Using explicit endpoints ``` 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: redissession: variables: php: session.save_handler: redis session.save_path: "tcp://$SESSIONSTORAGE_HOSTNAME:$SESSIONSTORAGE_PORT" 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" ``` ``` 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://$REDISSSESSION_HOSTNAME:$REDISSSESSION_PORT" 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" ``` # 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.html#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 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.html#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.html#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.html#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.html) to benefit from comprehensive stacktrace and information that could be obfuscated and collapsed otherwise. ```shell $ cargo build ``` # 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 {configFile="app"} 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): - Service environment variables - `PLATFORM_RELATIONSHIPS` environment variable Terminal on app1 container ``` $ echo $API_HOST api.internal ``` It uses the `jq` library, which is included in all app containers for this purpose. Terminal on app1 container ``` $ echo $PLATFORM_RELATIONSHIPS | base64 --decode | jq '.api[0].host' api.internal ``` # 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.html) 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.html#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. - 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 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). - Using default endpoints - Using explicit endpoints ``` 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 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: solr: services: # The name of the service container. Must be unique within a project. solr: type: solr:9.6 ``` ``` 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 (as per [default endpoint](https://docs.upsun.com/create-apps/app-reference/single-runtime-image#relationships) configuration for relationships). From this, ``myapp`` can retrieve access credentials to the service through the relationship environment variables. ```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 {configFile="services"} services: # The name of the service container. Must be unique within a project. solr: type: "solr:4.10" configuration: core_config: !archive "DIRECTORY" ``` DIRECTORY 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 {configFile="services"} 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 {configFile="services"} 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 {configFile="app"} 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 {configFile="services"} 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 {configFile="services"} 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 {configFile="services"} 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 RELATIONSHIP_NAME ``` 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.html#jts-and-polygons-flat) | Library for creating and manipulating vector geometry. |* |* | | [ICU4J](https://solr.apache.org/guide/8_3/language-analysis.html) | 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. # 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#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. Back Revisions # 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 {configFile="services"} 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 `RELATIONSHIP_NAME` as you like. `APP_NAME` 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 {configFile="services"} 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. 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. #### 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 = RELATIONSHIP_NAME.backend(); } ``` Where `RELATIONSHIP_NAME` is the name of the relationship you defined in Step 1. With the example configuration, that would be the following: ```bash {location="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 {configFile="services"} # 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="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 {configFile="routes"} 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="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 and add logic similar to the following to your VCL template: ```bash {location="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.html). The following example shows how to set up purging. 1. Add an access control list to your VCL template: ```bash {location="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="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 "URL_TO_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. 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 {configFile="apps"} 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](../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 HOST:PORT/stats`, replacing `HOST` and `PATH` with the values from Step 2. # 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.html#reactivate-an-environment) first, using the following command: `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.html#environmentsynchronize). Back Local development # 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 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). - Service environment variables - `PLATFORM_RELATIONSHIPS` environment variable 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.html#service-environment-variables) directly rather than hard coding any values. ``` VAULT_USERNAME= VAULT_SCHEME=http VAULT_SERVICE=vault-kms VAULT_FRAGMENT= VAULT_IP=123.456.78.90 VAULT_INSTANCE_IPS=['123.456.78.90'] VAULT_HOSTNAME=azertyuiopqsdfghjklm.vault-kms.service._.eu-1.platformsh.site VAULT_PORT=8200 VAULT_CLUSTER=azertyuiopqsdf-main-afdwftq VAULT_HOST=vault_secret.internal VAULT_REL=manage_keys VAULT_PATH=/ VAULT_QUERY={'is_master': True} VAULT_PASSWORD=ChangeMe VAULT_EPOCH=0 VAULT_TYPE=vault-kms:1.12 VAULT_PUBLIC=false VAULT_HOST_MAPPED=false ``` For some advanced use cases, you can use the [ environment variable](https://docs.upsun.com/development/variables/use-variables.html#use-provided-variables). The structure of the `PLATFORM_RELATIONSHIPS` environment variable can be obtained by running `upsun relationships` in your terminal: ``` { "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 [ file](https://docs.upsun.com/development/variables/use-variables.html#use-provided-variables): ``` # 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 {configFile="services"} 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. - SERVICE_NAME is the name you choose to identify the service. - VERSION is a supported version of the service. - ENDPOINT_ID is an identifier you choose for the endpoint. - KEY_NAME is the name of the key to be stored in the Vault KMS. - POLICY is one of the available 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 {configFile="app"} 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#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#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#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 {configFile="app"} 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 {configFile="app"} 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. With this token for authentication, you can use any of the policies you defined in your `.upsun/config.yaml` file. 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: ```bash echo ${RELATIONSHIP_NAME_PASSWORD}" ``` `RELATIONSHIP_NAME` is the relationship name you defined in your `.upsun/config.yaml` file. You can also store this as a variable: ```bash VAULT_TOKEN=${RELATIONSHIP_NAME_PASSWORD} ``` A given token is valid for one year from its creation. ### Get the right URL The service environment variable 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=${RELATIONSHIP_NAME_HOST}:${RELATIONSHIP_NAME_PORT} ``` `RELATIONSHIP_NAME` is the name you defined in your `.upsun/config.yaml` file. ### 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 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 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, 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, 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 | # 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. Back Getting support # 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 # 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): ```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.html). Back # 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.html). 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.html). Back Symfony CLI tips # 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 | **Language** | **`runtime`** | **Supported `version`** | |----------------------------------|---------------|-------------------------| | [C#/.Net Core](https://docs.upsun.com/languages/dotnet.html) | `dotnet` | 7.0, 6.0, 8.0 | | [Elixir](https://docs.upsun.com/languages/elixir.html) | `elixir` | 1.15, 1.14 | | [Go](https://docs.upsun.com/languages/go.html) | `golang` | 1.23, 1.22, 1.21, 1.20 | | [Java](https://docs.upsun.com/languages/java.html) | `java` | 21, 19, 18, 17, 11, 8 | | [Lisp](https://docs.upsun.com/languages/lisp.html) | `lisp` | 2.1, 2.0, 1.5 | | [JavaScript/Node.js](https://docs.upsun.com/languages/nodejs.html) | `nodejs` | 22, 20, 18, 16 | | [PHP](https://docs.upsun.com/languages/php.html) | `php` | 8.4, 8.3, 8.2, 8.1 | | [Python](https://docs.upsun.com/languages/python.html) | `python` | 3.12, 3.11, 3.10, 3.9, 3.8 | | [Ruby](https://docs.upsun.com/languages/ruby.html) | `ruby` | 3.3, 3.2, 3.1, 3.0 | | [Rust](https://docs.upsun.com/languages/rust.html) | `rust` | 1 | | **Service** | **`type`** | **Supported `version`** | |----------------------------------|---------------|-------------------------| | [Headless Chrome](https://docs.upsun.com/add-services/headless-chrome.html) | `chrome-headless` | 120, 113, 95, 91, 86, 84, 83, 81, 80, 73 | | [Elasticsearch](https://docs.upsun.com/add-services/elasticsearch.html) | `elasticsearch` | 8.5, 7.17 | | [InfluxDB](https://docs.upsun.com/add-services/influxdb.html) | `influxdb` | 2.7, 2.3 | | [Kafka](https://docs.upsun.com/add-services/kafka.html) | `kafka` | 3.7, 3.6, 3.4, 3.2 | | [MariaDB/MySQL](https://docs.upsun.com/add-services/mysql.html) | `mariadb` | 11.4, 11.2, 11.0, 10.11, 10.6, 10.5, 10.4 | | [Memcached](https://docs.upsun.com/add-services/memcached.html) | `memcached` | 1.6, 1.5, 1.4 | | [MongoDB](https://docs.upsun.com/add-services/mongodb.html) | `mongodb` | | | [MongoDB](https://docs.upsun.com/add-services/mongodb.html) | `mongodb-enterprise` | 7.0, 6.0, 5.0, 4.4 | | [Network Storage](https://docs.upsun.com/add-services/network-storage.html) | `network-storage` | 2.0 | | [OpenSearch](https://docs.upsun.com/add-services/opensearch.html) | `opensearch` | 2, 1 | | [Oracle MySQL](https://docs.upsun.com/add-services/mysql.html) | `oracle-mysql` | 8.0, 5.7 | | [PostgreSQL](https://docs.upsun.com/add-services/postgresql.html) | `postgresql` | 16, 15, 14, 13, 12 | | [RabbitMQ](https://docs.upsun.com/add-services/rabbitmq.html) | `rabbitmq` | 4.0, 3.13, 3.12 | | [Redis](https://docs.upsun.com/add-services/redis.html) | `redis` | 7.2, 7.0, 6.2 | | [Solr](https://docs.upsun.com/add-services/solr.html) | `solr` | 9.6, 9.4, 9.2, 9.1, 8.11 | | [Varnish](https://docs.upsun.com/add-services/varnish.html) | `varnish` | 7.6, 7.3, 7.2, 6.0 | | [Vault KMS](https://docs.upsun.com/add-services/vault.html) | `vault-kms` | 1.12 | # Upsun 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, header injection](#header-injection), and [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. It also detects and blocks requests that include **both** of the following features of an attempt to inject a malicious request: - A CRLF character 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, 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 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, 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 character sequences, your app is protected from response splitting attacks. ## HTTP protocol enforcement In addition to protecting your site against CRLF injection-related 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. 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. 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. # 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. ### 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. 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. If you don't find an existing key, 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 `PATH_TO_YOUR_KEY` with the location you copied): ```bash eval $(ssh-agent) ssh-add 'PATH_TO_YOUR_KEY' ``` 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 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 `PATH_TO_YOUR_KEY` with the location of your public key): ```bash upsun ssh-key:add 'PATH_TO_YOUR_KEY' ``` 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.) # Authenticated Composer repositories ### 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.html). [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://PRIVATE_REPOSITORY_URL" } ] } ``` ## 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": {"PRIVATE_REPOSITORY_URL": {"username": "USERNAME", "password": "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. # C#/.NET Core ### 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.html). 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.html#types): ```yaml {configFile="app"} applications: # The app's name, which must be unique within the project. : type: 'dotnet:' ``` For example: ```yaml {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} applications: myapp: type: 'dotnet:8.0' web: locations: "/": allow: false passthru: true commands: start: "dotnet WebApplication1.dll" ``` # 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). - Using the CLI - In the Console Run the following command: `upsun activity:cancel` 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: `upsun activity:cancel ACTIVITY_ID` Get the ID from the [activity log](https://docs.upsun.com/increase-observability/logs/access-logs.html#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.html#activity-logs), click **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 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 - Without a source integration - With a source integration - Clone your existing project with Git. - In the new clone, add a remote for the project: `upsun project:set-remote` Select your newly created blank project. - Push the code for your production branch: `upsun push --target PRODUCTION_BRANCH_NAME` - (Optional) Checkout other branches and then push their code: `upsun push --activate --target BRANCH_NAME --parent PRODUCTION_BRANCH_NAME` For a [source integration](https://docs.upsun.com/integrations/source.html) 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 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: - In the Console - Using the CLI - Select the project where you want to change the parent. - From the **Environment** menu, select the environment you want to change. - Click **Settings**. - In the row with the environment’s name, click **Edit **. - Select a **Parent environment**. - Click **Save**. Run the following command: `upsun environment:info -e parent ` So if you have the environment `new-feature` and want to change its parent to `main`, run the following: `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=PARENT_ENVIRONMENT_NAME" ``` Learn more about how to [trigger actions on `push`](https://docs.upsun.com/environments.md#push-options). # 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 {configFile="app"} 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 ``` # 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**. 3. Select the timezone from the list. 4. Click **Save**. # 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. # 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://community.platform.sh/t/diagnosing-and-resolving-issues-with-excessive-bot-access/792). 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: - In the Console - Using the CLI - Select the project where you want to control access. - From the **Environment** menu, select the environment to control. - Click **Settings**. - In the row with **HTTP access control**, click **Edit **. - Enter the IP addresses or ranges into the **IP addresses** field. Put one address or range per line, followed by a space and then `allow` or `deny`. - Click **Save**. Run the following command: `upsun environment:http-access -e ENVIRONMENT_NAME --access allow:IPS_TO_ALLOW --access deny:IPS_TO_DENY` # 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 {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} 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 ``` # 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). ## 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#trial). # 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.html). 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: - In the Console - Using the CLI - Select the project with an environment you want to reactivate. - From the **Environment** menu, select the environment. - Click **Settings**. - In the row with **Status**, click **Edit **. - Click **Activate**. Run the following command: `upsun environment:activate ENVIRONMENT_NAME` 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). # 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: - In the Console - Using the CLI - On the tile of the project you want to delete, click ** More**. - Click **Edit plan**. - Click **Delete project**. - To confirm your choice, enter the project’s name. - Click **Yes, Delete Project**. - Run the following command: `upsun project:delete --project PROJECT_ID` - 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. # Elixir ### 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.html). 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.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.html#types): ```yaml {configFile="app"} applications: # The app's name, which must be unique within the project. : type: 'elixir:' ``` For example: ```yaml {configFile="app"} applications: # The app's name, which must be unique within the project. myapp: type: 'elixir:1.15' ``` ## 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.html) or [Poison](https://hexdocs.pm/poison/api-reference.html) to read those. (There is an example for doing this to decode the `PLATFORM_RELATIONSHIPS` environment variable in the section [below ### 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 {configFile="app"} applications: myapp: type: 'elixir:1.15' 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 {configFile="app"} applications: myapp: type: 'elixir:1.15' 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.html#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 {configFile="app"} applications: myapp: type: 'elixir:1.15' 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.html#usage-example) - [Elasticsearch](https://docs.upsun.com/add-services/elasticsearch.html#use-in-app) - [Gotenberg](https://docs.upsun.com/add-services/gotenberg.html#usage-example) - [Headless Chrome](https://docs.upsun.com/add-services/headless-chrome.html#use-in-app) - [InfluxDB](https://docs.upsun.com/add-services/influxdb.html#use-in-app) - [Kafka](https://docs.upsun.com/add-services/kafka.html#use-in-app) - [MariaDB/MySQL](https://docs.upsun.com/add-services/mysql.html#use-in-app) - [Memcached](https://docs.upsun.com/add-services/memcached.html#use-in-app) - [MongoDB](https://docs.upsun.com/add-services/mongodb.html#use-in-app) - [Network Storage](https://docs.upsun.com/add-services/network-storage.html#usage-example) - [OpenSearch](https://docs.upsun.com/add-services/opensearch.html#use-in-app) - [PostgreSQL](https://docs.upsun.com/add-services/postgresql.html#use-in-app) - [RabbitMQ](https://docs.upsun.com/add-services/rabbitmq.html#use-in-app) - [Redis](https://docs.upsun.com/add-services/redis.html#use-in-app) - [Solr](https://docs.upsun.com/add-services/solr.html#use-in-app) - [Varnish](https://docs.upsun.com/add-services/varnish.html#usage-example) - [Vault KMS](https://docs.upsun.com/add-services/vault.html#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#relationships) defined in `.upsun/config.yaml`: ```yaml {configFile="app"} applications: myapp: type: 'elixir:1.15' [...] # 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 {configFile="app"} applications: myapp: hooks: deploy: | mix do ecto.setup ``` # 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). # 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: - Using the CLI - In the Console - Get the variable’s values by running the following command: ``` upsun ssh -- 'echo $PLATFORM_VARIABLES | base64 -d | jq' ``` Note that you can also get all the environment variable values by running the following command: `upsun ssh -- env` - Store the data somewhere secure on your computer. - In the [Console](https://console.upsun.com/), open your project and click ****. - 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.html#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). # Feedback on specific docs pages # 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 - Using the CLI - Using a source integration - Using Git - Get your project ID by running the following command: `upsun projects` - Add Upsun as a remote repository by running the following command: `upsun project:set-remote PROJECT_ID` - Push to the Upsun repository by running the following command: `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.html) - [GitHub](https://docs.upsun.com/integrations/source/github.html) - [GitLab](https://docs.upsun.com/integrations/source/gitlab.html) 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.html). - 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: ``` abcdefgh1234567@git.eu.upsun.com:abcdefgh1234567.git ``` - Add Upsun as a remote repository by running the following command: `git remote add upsun REPOSITORY_LOCATION` - Push to the Upsun repository by running the following command: `git push -u upsun DEFAULT_BRANCH_NAME` 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 < BACKUP_FILE_NAME ``` 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 {configFile="app"} 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.html#define-a-mount). For example: ```yaml {configFile="app"} 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). # Go ### 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.html). 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.html#types): ```yaml {configFile="app"} applications: # The app's name, which must be unique within the project. : type: 'golang:' ``` For example: ```yaml {configFile="app"} 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.html#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. - 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 {configFile="app"} 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.html#usage-example) - [Elasticsearch](https://docs.upsun.com/add-services/elasticsearch.html#use-in-app) - [Gotenberg](https://docs.upsun.com/add-services/gotenberg.html#usage-example) - [Headless Chrome](https://docs.upsun.com/add-services/headless-chrome.html#use-in-app) - [InfluxDB](https://docs.upsun.com/add-services/influxdb.html#use-in-app) - [Kafka](https://docs.upsun.com/add-services/kafka.html#use-in-app) - [MariaDB/MySQL](https://docs.upsun.com/add-services/mysql.html#use-in-app) - [Memcached](https://docs.upsun.com/add-services/memcached.html#use-in-app) - [MongoDB](https://docs.upsun.com/add-services/mongodb.html#use-in-app) - [Network Storage](https://docs.upsun.com/add-services/network-storage.html#usage-example) - [OpenSearch](https://docs.upsun.com/add-services/opensearch.html#use-in-app) - [PostgreSQL](https://docs.upsun.com/add-services/postgresql.html#use-in-app) - [RabbitMQ](https://docs.upsun.com/add-services/rabbitmq.html#use-in-app) - [Redis](https://docs.upsun.com/add-services/redis.html#use-in-app) - [Solr](https://docs.upsun.com/add-services/solr.html#use-in-app) - [Varnish](https://docs.upsun.com/add-services/varnish.html#usage-example) - [Vault KMS](https://docs.upsun.com/add-services/vault.html#use-vault-kms) # 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. # 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](/administration/cli.html) or the [Console](https://docs.upsun.com/administration/web.html). - Using the CLI - Using Git Run the following command: `upsun get PROJECT_ID` - 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.html). ### 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.html#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](/administration/cli.html) or the [Console](https://docs.upsun.com/administration/web.html). - Using the CLI - Using Git Run the following command: `upsun get PROJECT_ID` - 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.html). ### 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.html#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.html#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.html). 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.html), 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](/administration/cli.html) or the [Console](https://docs.upsun.com/administration/web.html). - Using the CLI - Using Git Run the following command: `upsun get PROJECT_ID` - 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.html). ### 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.html#route-configuration-reference). # Lisp ### 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.html). 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.html#types): ```yaml {configFile="app"} applications: # The app's name, which must be unique within the project. : type: 'lisp:' ``` For example: ```yaml {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} applications: # The app's name, which must be unique within the project. : type: 'lisp:' runtime: quicklisp: DISTRIBUTION_NAME: url: "..." version: "..." ``` For example: ```yaml {configFile="app"} 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 {configFile="app"} 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`: - Using default endpoints - Using explicit endpoints ``` applications: myapp: type: 'lisp:2.1' relationships: postgresql: ``` ``` 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. # Manage Python versions in non-Python containers ### 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.html). 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](../../development/variables/_index.md): ```yaml {configFile="app"} 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](../../create-apps/hooks/hooks-comparison.md#build-hook): ```yaml {configFile="app"} 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 {configFile="app"} 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](../../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. # 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 {configFile="services"} 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 {configFile="app"} 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 < /path/to/dump.sql ``` Note for live databases: You just need to make a local copy of the data, you don't need to keep the primary locked until the replica has imported the data. Once the `mysqldump` has completed, you can release the lock on the primary by running `UNLOCK TABLES`. ```sql mysql> 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 `BRANCH_NAME` with the name of your production branch): ```bash upsun tunnel:open --project PROJECT_ID --environment BRANCH_NAME ``` 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='REPLICATION_HOST', MASTER_USER='replicator', MASTER_PASSWORD='REPLICATION_PASSWORD', MASTER_PORT=3306, MASTER_LOG_FILE='binlogs.000002', MASTER_LOG_POS=1036, MASTER_CONNECT_RETRY=10; ``` Where `REPLICATION_HOST` varies depending on the SSH tunneling configuration you have, and the `REPLICATION_PASSWORD` 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. # Project isolation At Upsun, customer environments are strictly isolated from each other using [namespaces](https://man7.org/linux/man-pages/man7/namespaces.7.html), [seccomp](https://man7.org/linux/man-pages/man2/seccomp.2.html), and [cgroups](https://man7.org/linux/man-pages/man7/cgroups.7.html). 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. # 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.html). 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 {configFile="routes"} 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 {configFile="routes"} 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 {configFile="routes"} 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 {configFile="routes"} 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 {configFile="routes"} 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 {configFile="app"} routes: https://{default}/: type: redirect to: https://www.{default}/ ``` ## 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 {configFile="app"} 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. 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. | | `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.| | `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.| | `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.| | `code` | No | n/a | HTTP status code. Valid status codes are `301`, `302`, `307`, and `308`. Defaults to `302`. More information. | | `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. 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: - `regexp` - `prefix` - `append_suffix` Consider this `regexp` redirect: ``` '^/from(https://docs.upsun.com/.*|)$': regexp: true to: https://example.com/to$1 ``` It achieves the same result as this basic redirect: ``` '/from': to: https://example.com/to ``` Consider this redirect using `prefix`: ``` '/from': to: https//example.com/to prefix: false ``` It achieves the same result as this `regexp` redirect: ``` '^/from$': regexp: true to: https://example.com/to ``` Consider this redirect using `append_suffix`: ``` '/from': to: https//example.com/to append_suffix: false ``` It achieves the same result as this `regexp` redirect: ``` '^/from(https://docs.upsun.com/.*|)$': 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 {configFile="app"} 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: ``` routes: https://{default}/: type: upstream # ... redirects: paths: '/from': to: 'https://{default}/to' prefix: true ``` ``` 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 `codes` 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 or even disable caching 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. # 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`: `upsun environment:branch main old`In your local copy of the external repository, make sure your default branch is up to date: `git checkout old && git pull origin old` Then create the `main` branch off of your default branch and push it to the remote repository: ``` 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: `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`: `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`: `upsun project:info default_branch main`Set the project’s default branch in Upsun to `main`: `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.html#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 ``` # 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 PROJECT_ID ``` 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. # 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 {configFile="app"} 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 {configFile="app"} 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`. # Ruby ### 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.html). 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.html#types): ```yaml {configFile="app"} applications: # The app's name, which must be unique within the project. : type: 'ruby:' ``` For example: ```yaml {configFile="app"} 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.html#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. - 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 {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} applications: ... routes: "https://{default}/": type: upstream upstream: "myapp:http" ``` ### Complete app configuration Here is a complete `.upsun/config.yaml` file: ```yaml {configFile="app"} # 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 {configFile="services"} applications: ... routes: ... services: mysql: type: mysql:11.4 ``` ## Connecting to services Once you have a service, link to it in your [app configuration](../create-apps/_index.md): ```yaml {configFile="app"} 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 (https://docs.upsun.com/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 ### 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.html). 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 below for more details. ```yaml {configFile="app"} 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](../../create-apps/_index.md): ```yaml {configFile="app"} 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 } } ``` # 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 DEVELOPMENT_ENVIRONMENT_NAME ```. - Manually - With Drupal and Drush Assumptions: - `users` is the table where all of your PII is stored in the `staging` development database. - `staging` is an exact copy of your production database. - Connect to the `staging` database by running `upsun sql -e staging`. - Display all fields from your `users` table, to select which ones need to be redacted. Run the following query: ``` MariaDB [main]> SELECT * FROM users; ``` You see output like the following: ``` +----+------------+---------------+---------------------------+---------------+ | 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 [ statement](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: ``` 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.html) 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 [ hook](https://docs.upsun.com/create-apps/hooks/hooks-comparison.html#deploy-hook): ``` 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 [ hook](https://docs.upsun.com/create-apps/hooks/hooks-comparison.html#deploy-hook) for preview environments: ``` 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: ``` 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.html#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 DEVELOPMENT_ENVIRONMENT_NAME ```. - Manually - Using a script with Django and `psql` Assumptions: - `users` is the table where all of your PII is stored in the `staging` development database. - `staging` is an exact copy of your production database. - Connect to the `staging` database by running `upsun sql -e staging`. - Display all fields from your `users` table, to select which ones need to be redacted. Run the following query: ``` main=> SELECT * FROM users; ``` You see output like the following: ``` 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 [ statement](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: ``` 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.html) 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 [ hook](https://docs.upsun.com/create-apps/hooks/hooks-comparison.html#deploy-hook): ``` 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.html#service-environment-variables) to use the `psql` command interface. Export these values to a [ file](https://docs.upsun.com/development/variables/set-variables.html#set-variables-via-script) or include them directly in the sanitization script. ``` # 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: `touch sanitize.sh && chmod +x sanitize.sh` - Make the script sanitize environments with an [environment type](https://docs.upsun.com/administration/users.html#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. 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.html#mounts). Then add a check for the file as in the following example: sanitize.sh ``` #!/usr/bin/env bash if [ "$PLATFORM_ENVIRONMENT_TYPE" != production ] && [ ! -f MOUNT_PATH/is_sanitized ]; then # Sanitize data touch MOUNT_PATH/is_sanitized fi ``` - Update the deploy hook to run your script on each deploy. ``` applications: myapp: hooks: build: ... deploy: | python manage.py migrate bash sanitize.sh ``` - Commit your changes by running the following command: ``` 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.html#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.html) 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 DEVELOPMENT_ENVIRONMENT_NAME ```. - Manually - Using a Symfony Command - Using a shell script Assumptions: - `users` is the table where all of your PII is stored in the `staging` development database. - `staging` is an exact copy of your production database. - Connect to the `staging` database by running `symfony sql -e staging`. - Display all fields from your `users` table, to select which ones need to be redacted. Run the following query: ``` main=> SELECT * FROM users; ``` You see output like the following: ``` 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 [ statement](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: ``` 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.html) 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 [ hook](https://docs.upsun.com/create-apps/hooks/hooks-comparison.html#deploy-hook): ``` 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 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. ``` 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: ``` 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: ``` 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: `touch sanitize_fleet.sh && chmod +x sanitize_fleet.sh` - Make the script sanitize environments with an [environment type](https://docs.upsun.com/administration/users.html#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. 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. ``` . 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: ``` 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.html#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.html) to help improve performance. # Search # 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 {configfile="apps"} 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 and build on it, or jump straight to an example of a complete 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 {configFile="app"} 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#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 {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} 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://community.platform.sh/t/custom-404-page-for-a-static-website/637). ## Complete example configuration ```yaml {configFile="app"} 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 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: - Using the CLI - In the Console To not restrict indexers on your production environment, run the following command: `upsun environment:info --environment PRODUCTION_ENVIRONMENT_NAME restrict_robots false` - Select the project where you want to change visibility. - From the **Environment** menu, select your production environment. - Click **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. # 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 MP3 files. And you want to serve both MP3 and MP4 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 {configFile="app"} 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 MP3 files using a [rule](https://docs.upsun.com/create-apps/app-reference/single-runtime-image.md#rules): ```yaml {configFile="app"} applications: myapp: # The type of the application to build. type: "nodejs:22" source: root: "/" web: locations: "/": ... rules: \.mp3$: headers: Content-Type: audio/mpeg ``` This rule sets an explicit content type for files that end in `.mp3`. Because specific rules override the general heading configuration, MP3 files don't get the `X-Frame-Options` header set before. Now set a rule for MP4 files. ```yaml {configFile="app"} applications: myapp: # The type of the application to build. type: "nodejs:22" source: root: "/" web: locations: "/": ... rules: \.mp4$: headers: X-Frame-Options: SAMEORIGIN Content-Type: video/mp4 ``` This rule sets an explicit content type for files that end in `.mp4`. 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: video/mp4` for MP4 files * Only `Content-Type: audio/mpeg` for MP3 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 {configFile="app"} 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.html#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.html#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 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 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. - Service environment variables - `PLATFORM_RELATIONSHIPS` environment variable ``` export APP_DATABASE_HOST=${DATABASE_HOST} export APP_DATABASE_USER=${DATABASE_USERNAME} ``` This sets environment variables with the names your app needs, and the values from [service environment variables](https://docs.upsun.com/development/variables.html#service-environment-variables).It uses the `jq` library, which is included in all app containers for this purpose. ``` 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 [ environment variable](https://docs.upsun.com/development/variables/use-variables.html#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. # 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** 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**. # 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 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.
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.html#automated-backups). By default, the project timezone is based on the [region](https://docs.upsun.com/development/regions.html) where your project is hosted. You can [change it from the Console](https://docs.upsun.com/projects/change-project-timezone.html) at any time. ## Set an app runtime timezone How you can set an app runtime timezone depends on your actual app runtime: - PHP - Node.js - Python - Java Add the following to your app configuration: ``` applications: # The name of the app container. Must be unique within a project. myapp: # The location of the application's code. source: root: "myapp" variables: php: "date.timezone": "Europe/Paris" ```Start the server with `env TZ=’TIMEZONE’ node server.js`.Start the server with `env TZ=’TIMEZONE’ python server.py`. - Start the server with `env TZ=’TIMEZONE’ 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#primary-application-properties) in your app configuration. # Troubleshoot disks For more general information, see how to [troubleshoot development](https://docs.upsun.com/development/troubleshoot). ## 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 * Increase the available disk space ### 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) to have this limit increased. # Troubleshoot mounts For more general information, see how to [troubleshoot development](https://docs.upsun.com/development/troubleshoot). ## 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 {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} 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 ``` # Troubleshoot MySQL For more general information, see how to [troubleshoot development](https://docs.upsun.com/development/troubleshoot). ## 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 < skipped > Command: Query Time: ... State: Waiting for table metadata lock Info: SELECT ... < skipped > ``` 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 {configFile="services"} 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: 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#configure-the-database) in your `.upsun/config.yaml` file with an integer value. The default value of `16` is shown below to illustrate: ```yaml {configFile="services"} 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#advanced-container-profiles). For example, [MariaDB](/manage-resources/adjust-resources#default-container-profiles) has a `HIGH_MEMORY` [container profile](https://docs.upsun.com/manage-resources/adjust-resources#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#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 # Troubleshoot PHP ### 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.html). For more general information, see how to [troubleshoot development](https://docs.upsun.com/development/troubleshoot). ## 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 # 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#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 REPO_URL ``` 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: USER NAME (USER ID) 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). If you're still stuck, open a [support ticket](https://docs.upsun.com/learn/overview/get-support) and provide the full SSH debug information. # Understand Upsun 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#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) # 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 {configFile="app"} 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 ``` # 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.html#os.environ) * Node.js: The [`process.env` object](https://nodejs.org/api/process.html#process_process_env) * Ruby: The [`ENV` accessor](https://ruby-doc.org/current/ENV.html) * Java: The [`System.getenv()` method](https://docs.oracle.com/javase/8/docs/api/java/lang/System.html#getenv-java.lang.String-) - Service environment variables - `PLATFORM_RELATIONSHIPS` environment variable ``` #!/bin/bash # Ensure the file is empty. cat '' > config/db.yaml # Map the database information from the service environment 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.html#service-environment-variables. printf "host: %s\n" $(echo $DATABASE_HOST) >> config/db.yaml printf "user: %s\n" $(echo $DATABASE_USERNAME) >> config/db.yaml ``` ``` #!/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](../../create-apps/_index.md): ```yaml {configFile="app"} applications: APP_NAME 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. # 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=URL_TO_RECEIVE_JSON ``` 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 `URL_TO_RECEIVE_JSON`. ## 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 ``` # 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 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](/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`](/create-apps/app-reference/single-runtime-image.md#access), [`mount`](/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 {configFile="app"} 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 {configFile="app"} 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 {configFile="app"} 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.html) to each instance, unless you [define a different resource initialization strategy](https://docs.upsun.com/manage-resources/resource-init.html#specify-a-resource-initialization-strategy). You can also [adjust resources](https://docs.upsun.com/manage-resources/adjust-resources.html) 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 {configFile="app"} 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. ## 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 ```