Skip to main content

Documentation Index

Fetch the complete documentation index at: https://developer.upsun.com/llms.txt

Use this file to discover all available pages before exploring further.

OpenCode is an open-source AI coding agent built for the terminal. This guide walks you through deploying an OpenCode server instance on Upsun, a git-driven PaaS (powered by Platform.sh) that makes it easy to deploy applications with a single git push.

Prerequisites

Before starting, make sure you have:
  • An Upsun account (15-day free trial available)
  • The Upsun CLI installed
  • Git installed
  • An API key for at least one LLM provider (e.g., Anthropic, OpenAI, Google Gemini)

Overview

OpenCode is an application with a client/server architecture. In this tutorial, you deploy the OpenCode server on Upsun and connect to it remotely. The server exposes an HTTP API, which allows you to drive OpenCode from any client (TUI, IDE extension, or web) without having the agent running locally. The deployment relies on a nodejs:24 runtime, persistent storage for the SQLite database that stores conversation sessions, environment variables to securely pass LLM API keys, and routes to expose the server over HTTPS.

Step 1 - Set up your project

Clone or initialize a repository that contains your OpenCode configuration. If you are starting from scratch, create a new directory:
Terminal
mkdir opencode-upsun
cd opencode-upsun
git init

Step 2 - Create the Upsun configuration

At the root of your project, create the .upsun/ directory and add a config.yaml file:
Terminal
mkdir .upsun
touch .upsun/config.yaml
Here is the full configuration:
.upsun/config.yaml
applications:
  opencode:
    type: "nodejs:24"
    container_profile: "HIGH_MEMORY"
    source:
      root: /
    # Persistent mounts for OpenCode's SQLite database and config
    mounts:
      "/.local": {source: storage, source_path: "opencode-data"}
      "/.config/opencode": {source: storage, source_path: "opencode-config"}
      "/.agents": {source: storage, source_path: "opencode-agents"}
      "/.opencode": {source: storage, source_path: "opencode-source"}
    hooks:
      build: |
        set -ex
        
        echo "Downloading OpenCode..."
        curl -fsS https://raw.githubusercontent.com/upsun/snippets/main/src/install-github-asset.sh | bash /dev/stdin "anomalyco/opencode" "" "opencode-linux-x64.tar.gz"
        echo "OpenCode installed at $PLATFORM_APP_DIR/bin/opencode"

        echo "Install Upsun Skills..."
        npx skills add https://github.com/upsun/ai --skill upsun -g -y
        echo "Upsun Skills installed at $PLATFORM_APP_DIR/node_modules/.bin/upsun-mcp"

        echo "Install Upsun CLI..."
        curl -fsSL https://raw.githubusercontent.com/upsun/cli/main/installer.sh | bash
        echo "Upsun CLI installed at $(which upsun)"
      deploy: |
        # Generate OpenCode config with the correct MCP server URL and API token
        envsubst < /app/opencode.json > /app/.config/opencode/opencode.json

    # Environment variables — API keys are injected as Upsun secrets
    variables:
      env:
        OPENCODE_THEME: "opencode"
        HOME: "/app"

    # Web configuration: route all traffic to the OpenCode HTTP server
    web:
      commands:
        start: "opencode serve --port $PORT"

routes:
  "https://opencode.{default}/":
    type: upstream
    upstream: "opencode:http"
Because Upsun’s filesystem is read-only after the build step, the mounts section defines writable directories so OpenCode can persist its SQLite database (sessions, conversations) and its config file across deploys. The hooks.build section downloads and installs the OpenCode binary before the container starts, installs the Upsun skills (which include the MCP server), and the Upsun CLI. The web.commands.start section launches OpenCode in server mode. Upsun injects $PORT automatically, and your app must listen on that port. Finally, routes maps your project’s default domain to the OpenCode HTTP server.

install-github-asset.sh script

If you want to learn more about the script used to download OpenCode, check out the Up(sun) and ready with GitHub release assets installation. It’s a reusable script that can download any asset from any GitHub release, and is especially useful in Upsun build hooks where you want to fetch the latest version of a tool only once and, without hardcoding a specific version number.

Step 3 - Create the OpenCode configuration

OpenCode uses an opencode.json file to configure the server application. This file configures the Upsun MCP server as a remote MCP server for OpenCode, which allows OpenCode to execute commands on the Upsun platform and interact with its resources. Create an opencode.json file at the root of your repository with the following content:
opencode.json
{
  "mcp": {
    "upsun": {
      "type": "remote",
      "url": "https://mcp.upsun.com/mcp",
      "headers": {
        "upsun-api-token": "${UPSUN_CLI_TOKEN}",
        "enable-write": "true"
      },
      "enabled": true
    }
  }
}
The "enable-write": "true" header grants the OpenCode agent write access to your Upsun resources (creating environments, pushing code, changing variables, etc.). Remove this header or set it to "false" if you want read-only access.

Step 4 - Commit your code

Commit your configuration:
Terminal
git add .upsun/config.yaml opencode.json
git commit -m "Add Upsun and OpenCode configuration"

Step 5 - Create the Upsun project

Create a new Upsun project linked to your local repository:
Terminal
upsun project:create --title "opencode-server"

Step 6 - Add your API keys as environment variables

Never commit API keys to your repository. Use Upsun’s variable system instead.
# Set your OpenAI API key as a sensitive variable
upsun variable:create --name env:OPENAI_API_KEY \
  --value sk-... \
  --sensitive true \
  --level project

# Or set your Claude API key as a sensitive variable
upsun variable:create --name env:ANTHROPIC_API_KEY \
  --value sk-... \
  --sensitive true \
  --level project

# Set the OpenCode server password
upsun variable:create --name env:OPENCODE_SERVER_PASSWORD \
  --value "<SECURE_PASSWORD>" \
  --sensitive true \
  --level project

# Set the Upsun API token (optional, for Upsun skill integration)
upsun variable:create --name env:UPSUN_CLI_TOKEN \
  --value "<UPSUN_API_TOKEN>" \
  --sensitive true \
  --level project
Sensitive variables are encrypted at rest and injected into the container at runtime. They will not appear in build logs. You can also set them via the Upsun Console under Settings → Variables.

OPENCODE_SERVER_PASSWORD note

By default, OpenCode’s server mode requires a password for authentication. You can set this password via the OPENCODE_SERVER_PASSWORD environment variable. If you prefer to disable authentication (not recommended for production), you can set OPENCODE_SERVER_PASSWORD to an empty string.

Step 7 - Deploy

Push your code to Upsun:
upsun push
Upsun will:
  1. Validate your .upsun/config.yaml
  2. Spin up a Node.js 24 container
  3. Run the build hook:
    • downloading the OpenCode binary
    • installing the Upsun skills and MCP server
    • installing the Upsun CLI
  4. Run the deploy hook, which generates the OpenCode config file with the correct MCP server URL and API token
  5. Mount writable storage for the database and config
  6. Start the OpenCode server on the assigned port
  7. Route HTTPS traffic to it
Once complete, Upsun will display your app URL, something like:
https://main-abc123-yourproject.eu-5.platformsh.site

Login

Open the URL in your browser. If you set OPENCODE_SERVER_PASSWORD, log in with the username opencode and the password you configured. You can also connect from the OpenCode TUI client by pointing it to the same URL.

Step 8 - Ask OpenCode to do something

OpenCode is now able to receive your commands from the TUI, execute them on the server, and return results. Examples: List existing organizations:
List organizations in the Upsun project
Create a new Symfony application in a symfony subfolder and test it in a preview environment:
You are in an existing Git repository linked to an existing Upsun project via PLATFORM_PROJECT.
Use the Upsun skill, Upsun MCP, the Upsun CLI if available, and Git.

Goal:
On the current Upsun Project, add a new Symfony Demo application
(use `symfony new app --demo --upsun` to generate it) in a new active
environment named add-symfony-demo.
- Symfony demo app `app` will be in a subfolder `symfony` at the root of
  the source code and the new app will point to that folder via source.root,
  will be accessible through the default route {default} and, must use
  Postgresql and Redis services.
- Preserve existing source code and configuration, and add the existing
  Symfony demo configuration (--upsun option) to the main .upsun/config.yaml
- Do not delete opencode.
- Work only on the new environment.
- Load the database schema and fixtures during first deploy.
- You can use /tmp folder to install what you need.
- Use the Upsun CLI to interact with the platform, do not use the API directly.
You can test the new config without affecting your production instance. Merge the branch when satisfied, and Upsun redeploys production.

Troubleshooting

The server does not start / PORT is not set

Upsun automatically injects $PORT into the environment of the start command. Make sure your start command references $PORT and that OpenCode’s serve command accepts a --port flag. Check opencode serve --help for the exact flag name, as it may vary across versions.

Sessions are not persisting across deploys

Verify that your mounts are defined correctly in .upsun/config.yaml and that the paths match where OpenCode writes its SQLite database. The database path can be checked with:
upsun ssh -- opencode db:path

API key not recognized

Confirm the variable is set in the correct environment:
upsun variable:list
Sensitive variables show as [hidden] — that is expected. Make sure the variable name matches exactly what OpenCode expects (e.g., ANTHROPIC_API_KEY).

OpenCode is slow to respond

If OpenCode is slow to respond, or stops in the middle of processing, check the resource usage of your Upsun container. You may need to scale up CPU/RAM if your agent is handling large contexts or multiple conversations.

What’s next?

You can attach a custom domain with upsun domain:add yourdomain.com and adjust CPU/RAM through upsun resources:set if the agent handles large contexts or multiple conversations. To extend OpenCode with additional MCP server integrations, configure them in ~/.config/opencode/ on the persistent mount. You can also use OpenCode’s GitHub Actions integration to trigger the remote server on PR comments.

Resources

Last modified on May 19, 2026