> ## Documentation Index
> Fetch the complete documentation index at: https://ship-jskiller1404-add-ommiting-private-fields-feature.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Digital Ocean Apps (IaC)

There is a simplified deployment type without Kubernetes. This type is **recommended** for most new applications because it allows you to set up infrastructure faster and doesn't require additional DevOps knowledge from the development team. You can switch to a more complex Kubernetes solution when your application will be at scale.

It's a step-by-step Ship deployment guide. We will use the [Digital Ocean Apps](https://www.digitalocean.com/products/app-platform) and [GitHub Actions](https://github.com/features/actions) for automated deployment. [Mongo Atlas](https://www.mongodb.com/) and [Redis Cloud](https://redis.com/try-free/) for databases deployment, [Cloudflare](https://www.cloudflare.com/) for DNS and SSL configuration and [Pulumi](https://www.pulumi.com/) for Infrastructure as Code

You need to create [GitHub](https://github.com/), [Digital Ocean](https://www.digitalocean.com/), [CloudFlare](https://www.cloudflare.com/), [MongoDB Atlas](https://www.mongodb.com/cloud/atlas/register) and [Redis Cloud](https://redis.com/try-free/) accounts.

Also, you need [git](https://git-scm.com/) and [Node.js](https://nodejs.org/en/) if you already haven't.

## Setup project

First, initialize your project. Type `npx create-ship-app init` in the terminal then choose desired build type and **Digital Ocean Apps** as a cloud service provider.

<img src="https://mintcdn.com/ship-jskiller1404-add-ommiting-private-fields-feature/E9XBHl8mCOQjBjO1/images/init-project.png?fit=max&auto=format&n=E9XBHl8mCOQjBjO1&q=85&s=a8d3cdb2a50322afff948baff99dad1d" alt="Init project" width="739" height="748" data-path="images/init-project.png" />

You will have the next project structure.

```shell theme={null}
/my-app
  /deploy
  /apps
    /web
    /api
  /.github
  ...
```

Create GitHub private repository and upload source code.

<img src="https://mintcdn.com/ship-jskiller1404-add-ommiting-private-fields-feature/Dwvni7a5iTfmtLdI/images/private-repo.png?fit=max&auto=format&n=Dwvni7a5iTfmtLdI&q=85&s=95d4bc44a59dd8174a5e45af977408bd" alt="Private repo" width="3024" height="1664" data-path="images/private-repo.png" />

```shell theme={null}
cd my-app
git remote add origin https://github.com/Oigen43/my-app.git
git branch -M main
git push -u origin main
```

## MongoDB Atlas

Navigate to [MongoDB Atlas](https://cloud.mongodb.com/), sign in to your account and create a new database.

### Database creation

1. Select the appropriate type. Dedicated for a production environment, shared for staging/demo.
2. Select provider and region. We recommend selecting the same or closest region to the DO application.
3. Select cluster tier. Free M0 Sandbox should be enough for staging/demo environments. For production environment we recommended selecting the option that supports cloud backups, M10 or higher.
4. Enter cluster name

<img src="https://mintcdn.com/ship-jskiller1404-add-ommiting-private-fields-feature/Dwvni7a5iTfmtLdI/images/mongo-create.png?fit=max&auto=format&n=Dwvni7a5iTfmtLdI&q=85&s=c100c8528e0bd32a51d06501d300d44e" alt="Mongo cluster" width="893" height="683" data-path="images/mongo-create.png" />

### Security and connection

After cluster creation, you'll need to set up security. Select the authentication type (username and password) and create a user.

<img src="https://mintcdn.com/ship-jskiller1404-add-ommiting-private-fields-feature/E9XBHl8mCOQjBjO1/images/mongo-create-password.png?fit=max&auto=format&n=E9XBHl8mCOQjBjO1&q=85&s=c593499cbd599af00bb81e0a85e8019a" alt="Mongo setup authentication" width="859" height="665" data-path="images/mongo-create-password.png" />

Add IP addresses list, which should have access to your cluster. Add 0.0.0.0/0 IP address to allow anyone with credentials to connect.

<img src="https://mintcdn.com/ship-jskiller1404-add-ommiting-private-fields-feature/E9XBHl8mCOQjBjO1/images/mongo-create-ip-list.png?fit=max&auto=format&n=E9XBHl8mCOQjBjO1&q=85&s=9eae219bcd218cb81a4846962214a50a" alt="Mongo setup ip white list" width="798" height="585" data-path="images/mongo-create-ip-list.png" />

After database creation, go to the dashboard page and get the URI connection string by pressing the `connect` button.

<img src="https://mintcdn.com/ship-jskiller1404-add-ommiting-private-fields-feature/Dwvni7a5iTfmtLdI/images/mongo-dashboard.png?fit=max&auto=format&n=Dwvni7a5iTfmtLdI&q=85&s=ad4c8b8417672b4ea472437778728132" alt="Mongo dashboard" width="2159" height="718" data-path="images/mongo-dashboard.png" />

Select `Connect your application` option. Choose driver and mongo version, and copy connection string. Don't forget to replace `<password>` with your credentials.

<img src="https://mintcdn.com/ship-jskiller1404-add-ommiting-private-fields-feature/E9XBHl8mCOQjBjO1/images/mongo-connection-string.png?fit=max&auto=format&n=E9XBHl8mCOQjBjO1&q=85&s=05b97c58d9ba029f2eebeba33a2fa100" alt="Mongo connect dialog" width="794" height="637" data-path="images/mongo-connection-string.png" />

Save this value. It will be needed later when creating the app in Digital Ocean.

<Tip>
  Before moving to production, it's crucial to set up [MongoDB backup methods](https://www.mongodb.com/docs/manual/core/backups).

  This ensures that you can reliably restore your data in the event of unforeseen circumstances.
</Tip>

## Redis Cloud

Navigate to [Redis Cloud](https://redis.com/try-free/) and create an account. Select cloud provider and region, then press `Let's start free` to finish database creation.

<img src="https://mintcdn.com/ship-jskiller1404-add-ommiting-private-fields-feature/Dwvni7a5iTfmtLdI/images/redis-creation.png?fit=max&auto=format&n=Dwvni7a5iTfmtLdI&q=85&s=dd5fc13a011fab75f49d040819abada8" alt="Redis create database" width="953" height="581" data-path="images/redis-creation.png" />

Open database settings and get the database public endpoint and password.

<img src="https://mintcdn.com/ship-jskiller1404-add-ommiting-private-fields-feature/Dwvni7a5iTfmtLdI/images/redis-public-endpoint.png?fit=max&auto=format&n=Dwvni7a5iTfmtLdI&q=85&s=9a8b7e0b5bbb88dc81641738e58e672f" alt="Redis public endpoint" width="1601" height="923" data-path="images/redis-public-endpoint.png" />

<img src="https://mintcdn.com/ship-jskiller1404-add-ommiting-private-fields-feature/Dwvni7a5iTfmtLdI/images/redis-password.png?fit=max&auto=format&n=Dwvni7a5iTfmtLdI&q=85&s=055aadf16db88d6aabfeb1b2171fdae9" alt="Redis password" width="1573" height="514" data-path="images/redis-password.png" />

Form Redis connection string using public endpoint and password `redis://:<password@<public-endpoint>`. Save this value. It will be needed later when creating the app in Digital Ocean.

## Environment variables

The `APP_ENV` environment variable is typically set based on the environment in which the application is running.
Its value corresponds to the specific environment, such as "development", "staging" or "production".
This variable helps the application identify its current environment and load the corresponding configuration.

For the web application, by setting the environment variable `APP_ENV`,
the application can determine the environment in which it is running and download the appropriate configuration file:

| APP\_ENV    | File             |
| ----------- | ---------------- |
| development | .env.development |
| staging     | .env.staging     |
| production  | .env.production  |

These files should contain specific configuration variables required for each environment.

In contrast, the API utilizes a single `.env` file that houses its environment-specific configuration.
This file typically contains variables like API keys, secrets, or other sensitive information.
To ensure security, it's crucial to add the `.env` file to the `.gitignore` file,
preventing it from being tracked and committed to the repository.

So just specify the environment variables that will contain the values of your secrets.
For example, if you have a secret named `API_KEY`,
create an environment variable named `API_KEY` and set the value of the corresponding secret for it.

## Digital Ocean via Pulumi

[Pulumi](https://www.pulumi.com/) is an open-source [Infrastructure as Code (IaC)](https://www.pulumi.com/what-is/what-is-infrastructure-as-code/) platform that allows developers to define and provision cloud infrastructure using familiar programming languages. <br />
Instead of using domain-specific languages or YAML templates, Pulumi leverages existing languages like TypeScript, Python, Go, and C#.

Go to the `/deploy` directory at the root of your project and proceed to the next steps:

<Steps>
  <Step title="Pulumi CLI">
    Ensure you have [Pulumi CLI](https://www.pulumi.com/docs/get-started/install/) installed. <br />
    After installing, verify everything is in working order by running the pulumi CLI:

    ```shell theme={null}
    pulumi version
    ```
  </Step>

  <Step title="Pulumi Login">
    [Login in pulumi](https://www.pulumi.com/docs/cli/commands/pulumi_login/) for managing your stacks:

    ```shell theme={null}
    pulumi login --local
    ```
  </Step>

  <Step title="DigitalOcean Tokens and Keys">
    Create your [Personal Access Token](https://docs.digitalocean.com/reference/api/create-personal-access-token/) and [Access Keys](https://docs.digitalocean.com/products/spaces/how-to/manage-access/#access-keys) for DigitalOcean
  </Step>

  <Step title="Configuring Tokens and Keys">
    Add DigitalOcean Personal Access Token and Access Keys to your configuration file: `.zshrc` or `.bashrc`

    First you’ll need to enter the `.zshrc` or `.bashrc` file in editing mode:

    <CodeGroup>
      ```shell .zshrc theme={null}
      vi ~/.zshrc
      ```

      ```shell .bashrc theme={null}
      vi ~/.bashrc
      ```
    </CodeGroup>

    Insert the following variables at the end of the configuration file:

    ```shell theme={null}
    # DigitalOcean start
    export DIGITALOCEAN_TOKEN=dop_v1_...
    export SPACES_ACCESS_KEY_ID=DO...
    export SPACES_SECRET_ACCESS_KEY=...
    # DigitalOcean end
    ```

    To reflect the changes in the bash, either exit and launch the terminal again.

    Or use the command:

    <CodeGroup>
      ```shell .zshrc theme={null}
      source ~/.zshrc
      ```

      ```shell .bashrc theme={null}
      source ~/.bashrc
      ```
    </CodeGroup>
  </Step>

  <Step title="GitHub apps">
    Grant DigitalOcean access to your GitHub repository using [this link](https://cloud.digitalocean.com/apps/github/install).
  </Step>

  <Step title="Stack initialization">
    Initialize your stack using the command:

    ```shell theme={null}
    pulumi stack init organization/{project-name}/{environment}
    ```

    Substitute `{project-name}` with the actual name of your project and make sure to update it in `Pulumi.yaml` file. <br />
    Replace `{environment}` with the desired environment: `staging` or `production` values are allowed.
  </Step>

  <Step title="App environments">
    Duplicate the `.env.example` file to create a new environment-specific file using the command:

    <CodeGroup>
      ```shell staging theme={null}
      cp .env.example .env.staging
      ```

      ```shell production theme={null}
      cp .env.example .env.production
      ```
    </CodeGroup>

    Populate the new file with the necessary environment variables.

    <Info>
      Ensure that you set the necessary variables in your web application.
      Edit the .env files accordingly and remember to push these changes to your remote repository.
    </Info>
  </Step>

  <Step title="Installing dependencies">
    Install the required dependencies using the command:

    ```shell theme={null}
    npm i
    ```
  </Step>

  <Step title="Resources creating">
    To create the resources in the initialized stack, execute the command:

    ```shell theme={null}
    pulumi up
    ```
  </Step>
</Steps>

Finally, you will observe the following output:

<img src="https://mintcdn.com/ship-jskiller1404-add-ommiting-private-fields-feature/E9XBHl8mCOQjBjO1/images/do-apps-iac-preview.png?fit=max&auto=format&n=E9XBHl8mCOQjBjO1&q=85&s=4367eea2a1d1295a92caef8e71f14cd9" alt="Pulumi Preview" width="1326" height="1704" data-path="images/do-apps-iac-preview.png" />

Review the planned resource creation and proceed with the resource update.
This process may take a few minutes to complete.

## Cloudflare

Navigate to your Digital Ocean application and open `Settings` tab.
Navigate to `Domains` row to open domain settings and copy starter domain of application.

<img src="https://mintcdn.com/ship-jskiller1404-add-ommiting-private-fields-feature/E9XBHl8mCOQjBjO1/images/do-apps-iac-domains.png?fit=max&auto=format&n=E9XBHl8mCOQjBjO1&q=85&s=f35fa400a049a0c145fff72f1fd4c7c7" alt="Digital Ocean domains" width="1296" height="670" data-path="images/do-apps-iac-domains.png" />

Navigate to [CloudFlare](https://dash.cloudflare.com/) and sign into account.

1. Go to `DNS` tab and create a new record.
2. Click `Add record`. Select type `CNAME`,  enter domain name (must be the same you entered in digital ocean settings) and paste alias into `target` field.
   Make sure `Proxy status` toggle enabled.
3. Save changes

<img src="https://mintcdn.com/ship-jskiller1404-add-ommiting-private-fields-feature/bAV2JshmglZLw2nx/images/cloudflare-create-dns.png?fit=max&auto=format&n=bAV2JshmglZLw2nx&q=85&s=51001ca0103949858fa4bb279f082668" alt="Cloudflare DNS" width="1043" height="404" data-path="images/cloudflare-create-dns.png" />

Now go back to digital ocean and submit form. It usually takes about 5 minutes for digital ocean to confirm and start using your new domain.
Once domain is confirmed, application can be accessed by new address.

## GitHub Actions

You can find two GitHub actions in the `.github/workflows` folder, responsible for triggering deployment when you push changes in your repository. If you chose frontend or backend on the initialization step, you'll have one github workflow for the selected application type.

These actions require a [Digital Ocean Personal Access Token](https://docs.digitalocean.com/reference/api/create-personal-access-token/) and application ID.
Respectively these are `DO_ACCESS_TOKEN` and `DO_API_STAGING_APP_ID`/`DO_WEB_STAGING_APP_ID`/`DO_API_PRODUCTION_APP_ID`/`DO_WEB_PRODUCTION_APP_ID`.

Next, navigate to the **Apps** tab in the left sidebar and open your Digital Ocean application. You can find the id of your application id in the browser address bar.

<img src="https://mintcdn.com/ship-jskiller1404-add-ommiting-private-fields-feature/E9XBHl8mCOQjBjO1/images/do-application-id.png?fit=max&auto=format&n=E9XBHl8mCOQjBjO1&q=85&s=ea348dcf9c2b2ab5d078543bedd10175" alt="Do application id" width="2293" height="726" data-path="images/do-application-id.png" />

Now you can add these keys to your GitHub repository's secrets.

Navigate to the GitHub repository page, and open the **Settings** tab and these values. You have to be repository **admin** or **owner** to open this tab.

<img src="https://mintcdn.com/ship-jskiller1404-add-ommiting-private-fields-feature/E9XBHl8mCOQjBjO1/images/github-secrets.png?fit=max&auto=format&n=E9XBHl8mCOQjBjO1&q=85&s=42432217c8e05a4a7772f853eafa858c" alt="Github secrets" width="1418" height="922" data-path="images/github-secrets.png" />

Done! Application deployed and can be accessed by provided domain.

<img src="https://mintcdn.com/ship-jskiller1404-add-ommiting-private-fields-feature/bAV2JshmglZLw2nx/images/deployed-application.png?fit=max&auto=format&n=bAV2JshmglZLw2nx&q=85&s=0dcbfb458f3124d58129369ec9f06814" alt="Deployed application" width="1134" height="705" data-path="images/deployed-application.png" />

## Logging (optional)

### Build-in

Digital Ocean has built-in logs in raw format. It will gather all data that your apps will produce.
In order to view them, follow these steps:

1. Log in to your Digital Ocean account.
2. Click on the Apps tab in the left-hand navigation menu.
3. Click on the name of the app you want to view the logs for.
4. Click on the Runtime Logs tab in the app dashboard.
5. You will see a list of logs for different components of your app. Click on the component you want to view the logs for.
6. You can filter the logs by time, severity, and component. Use the drop-down menus provided to select your filter criteria.
7. You can also search for specific keywords in the logs by using the search bar at the top of the page.

<img src="https://mintcdn.com/ship-jskiller1404-add-ommiting-private-fields-feature/E9XBHl8mCOQjBjO1/images/do-runtime-built-in-logs.png?fit=max&auto=format&n=E9XBHl8mCOQjBjO1&q=85&s=cf930d3eb119ccaec795924c37e2d110" alt="Runtime built in logs screen" width="3002" height="1420" data-path="images/do-runtime-built-in-logs.png" />

### Integrations

Currently, Digital Ocean Apps supports only 3 integrations: [PaperTrail](https://marketplace.digitalocean.com/add-ons/papertrail), [Logtail](https://marketplace.digitalocean.com/add-ons/logtail) and [Datadog](https://www.datadoghq.com/). You can find detailed instructions on how to set up these logs at this [link](https://docs.digitalocean.com/products/app-platform/how-to/forward-logs/).

### Example Integration Logtail

To configure Logtail follow these steps:

1. Create account on Logtail
2. Open Sources on the left sidebar.
3. Create new source by clicking "Connect source" button

<img src="https://mintcdn.com/ship-jskiller1404-add-ommiting-private-fields-feature/E9XBHl8mCOQjBjO1/images/do-logs-logtail-sources.png?fit=max&auto=format&n=E9XBHl8mCOQjBjO1&q=85&s=d655bebc90a5b069273f31fd5ea754a6" alt="Logs Integrations logtail sources" width="2782" height="1452" data-path="images/do-logs-logtail-sources.png" />

4. Select HTTP source and specify name for this connection

<img src="https://mintcdn.com/ship-jskiller1404-add-ommiting-private-fields-feature/E9XBHl8mCOQjBjO1/images/do-logs-logtail-connect-source.png?fit=max&auto=format&n=E9XBHl8mCOQjBjO1&q=85&s=292df8ad3e30550dc49c878954bda3aa" alt="Logs Integrations Logtail connect" width="1157" height="637" data-path="images/do-logs-logtail-connect-source.png" />

5. Copy source token

<img src="https://mintcdn.com/ship-jskiller1404-add-ommiting-private-fields-feature/E9XBHl8mCOQjBjO1/images/do-logs-logtail-token.png?fit=max&auto=format&n=E9XBHl8mCOQjBjO1&q=85&s=39152ffa953f10088daa946206191692" alt="Logs Integrations Logtail token" width="1203" height="591" data-path="images/do-logs-logtail-token.png" />

6. Open Digital Ocean Apps
7. Select Settings tab for your application

<img src="https://mintcdn.com/ship-jskiller1404-add-ommiting-private-fields-feature/E9XBHl8mCOQjBjO1/images/do-app-logs-settings.png?fit=max&auto=format&n=E9XBHl8mCOQjBjO1&q=85&s=a846149be8b62fbd2f27dd5ff90dae64" alt="Logs Integrations Settings" width="1500" height="540" data-path="images/do-app-logs-settings.png" />

8. Select Log Forwarding and then press "Add Destination"

<img src="https://mintcdn.com/ship-jskiller1404-add-ommiting-private-fields-feature/E9XBHl8mCOQjBjO1/images/do-logs-log-forwarding.png?fit=max&auto=format&n=E9XBHl8mCOQjBjO1&q=85&s=ebe863a535e1e4ed9da6ca8f50730cc1" alt="Logs Forwarding" width="1256" height="248" data-path="images/do-logs-log-forwarding.png" />

9. Fill information with token that we retrieved from Logtail

<img src="https://mintcdn.com/ship-jskiller1404-add-ommiting-private-fields-feature/E9XBHl8mCOQjBjO1/images/do-create-log-forward.png?fit=max&auto=format&n=E9XBHl8mCOQjBjO1&q=85&s=343b783433f57a5cd479ed0a3b9e1390" alt="Logs Create Log Forward" width="794" height="749" data-path="images/do-create-log-forward.png" />

10. That's it! In couple minutes your app will send the latest logs to Logtail

<img src="https://mintcdn.com/ship-jskiller1404-add-ommiting-private-fields-feature/E9XBHl8mCOQjBjO1/images/do-logs-logtail-final-view.png?fit=max&auto=format&n=E9XBHl8mCOQjBjO1&q=85&s=c07079e4180078b9ddd842a8979bd50f" alt="Logs Logtail Final View" width="1216" height="550" data-path="images/do-logs-logtail-final-view.png" />
