<p>
    Self-hosting allows you to customize Appwrite to meet your needs and preferences. Here's a list of things you will need to set up before developing with Appwrite. Before you start, back up your <code>.env</code> and <code>docker-compose.yml</code> files.
</p>

<h2><a href="#local-development" id="local-development">Local Development</a></h2>
<p>Self-hosting Appwrite for development lets you quickly prototype on your local machine. Since localhost is only a loopback address that points back at your development machine, there are some caveats you should be aware of when working with localhost.</p>
<p>Appwrite generates a self-signed certificate for development on localhost, as connecting to unsecured HTTP is not allowed by default. If you're developing client apps on localhost, set <code>setSelfSigned(true)</code> while initializing your Appwrite client.</p>
<p>If you're using an Android emulator to test your Flutter or Android apps, you can access localhost of your machine using the special alias IP <code>10.0.2.2</code>.</p>
<p>If you're testing your Flutter, Android, or iOS app on a mobile device, you will not be able to access the localhost of your PC or Mac. When testing with a physical device, you may use a service like <a href="https://ngrok.com/" target="_blank" rel="noopener">ngrok</a> to proxy the Appwrite instance.</p>

<h2><a href="#delivery" id="delivery">Setup Email and SMS Delivery</a></h2>
<p>
    Appwrite requires an SMTP service to deliver emails. Email delivery is required for features like password recovery, account verification, MagicURL authentication, and team invites. You can use a third-party SMTP service or host your own SMTP server.
</p>
<p><a href="/docs/email-delivery"><i class="icon-angle-circled-right margin-start-negative-tiny margin-end-tiny"></i> Set up email delivery</a></p>

<p>
    Appwrite supports multiple third-party SMS delivery providers. SMS delivery is required for phone authentication.
</p>
<p><a href="/docs/sms-delivery"><i class="icon-angle-circled-right margin-start-negative-tiny margin-end-tiny"></i> Set up SMS delivery</a></p>

<h2><a href="#git" id="git">Configure GitHub App</a></h2>
<p>
    Appwrite supports automatic deployments through Git integration. 
    In order for Appwrite to access your repos, you must <a href="https://docs.github.com/en/apps/creating-github-apps/about-creating-github-apps/about-creating-github-apps" target="_blank" rel="noopener">create a GitHub app</a> to enable this integration.
    The GitHub app requires the following configurations.
</p>

<p>
    For automatic Git deployment to work, Appwrite needs to receive communication from GitHub, this means your Appwrite project must be accessible on the internet.
    If you're running on <code>localhost</code>, you need to run a proxy like <a href="https://ngrok.com/" target="_blank" rel="noopener">ngrok</a>.
</p>

<h3><a href="#github-app-name" id="github-app-name">GitHub App name</a></h3>

<p>
    The GitHub App name will be displayed when connecting Appwrite to GitHub. In addition, this name will be transformed to a slug ("My GitHub App" will become "my-github-app") and appear in the URL when accessing your app in GitHub. This slug should be set as the <code>_APP_VCS_GITHUB_APP_NAME</code> environment variable in Appwrite.
</p>

<h3><a href="#github-homepage-url" id="github-homepage-url">Homepage URL</a></h3>

<p>
The homepage URL will appear when looking at the public page of your app. It can be any URL you'd like.
</p>

<h3><a href="#callback" id="callback">Callback URL</a></h3>
<p>
    GitHub will use <b>callback URLs</b> to redirect users back to Appwrite. 
    Set these callback URLs under <b>Identifying and authorizing users</b> in the same order as listed below.
</p>
<table class="full">
    <thead>
        <tr>
            <td>URLs</td>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>https://[HOSTNAME_OR_IP]/v1/vcs/github/callback</code></td>
        </tr>
        <tr>
            <td><code>https://[HOSTNAME_OR_IP]/v1/account/sessions/oauth2/callback/github/console</code></td>
        </tr>
    </tbody>
</table>

<p>
    Also, check the <b>Request user authentication (OAuth) during installation</b> box.
</p>

<h3><a href="#post-install" id="post-install">Post Installation</a></h3>
<p>
    Check the <b>Redirect on update</b> box under the <b>Post installation</b> section.
</p>


<h3><a href="#github-webhooks" id="github-webhooks">Webhook</a></h3>
<p>
    GitHub will notify Appwrite about events like new commits using webhooks.
    Under <b>Webhook</b>, you need to check the <b>Active</b> checkbox.
    You also need to set the <b>Webhook URL</b> as <code>https://[HOSTNAME_OR_IP]/v1/vcs/github/events</code>.
</p>

<p>
    If you're running Appwrite on <code>localhost</code>, GitHub can't send requests to Appwrite through webhooks and automatic deployments won't work.
    You'll need host Appwrite on a server or use a proxy like <a href="https://ngrok.com/" target="_blank" rel="noopener">ngrok</a> to make Appwrite accessible to GitHub.
</p>

<h3><a href="#repository-permission" id="repository-permission">Repository Permissions</a></h3>
<p>
    Configure these permissions under the <b>Repository permission</b> dropdown.
</p>
<table class="full">
    <thead>
        <tr>
            <td>Permission</td>
            <td>Access</td>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Administration</td>
            <td>Read and write</td>
        </tr>
        <tr>
            <td>Checks</td>
            <td>Read and write.</td>
        </tr>
        <tr>
            <td>Commit Statuses</td>
            <td>Read and write</td>
        </tr>
        <tr>
            <td>Contents</td>
            <td>Read and write</td>
        </tr>
        <tr>
            <td>Issues</td>
            <td>Read and write</td>
        </tr>
        <tr>
            <td>Metadata</td>
            <td>Read-only</td>
        </tr>
        <tr>
            <td>Pull requests</td>
            <td>Read and write</td>
        </tr>
        <tr>
            <td>Webhooks</td>
            <td>Read and write</td>
        </tr>
    </tbody>
</table>

<h3><a href="#account-permission" id="account-permission">Account Permissions</a></h3>
<p>
    Configure these permissions under the <b>Account Permission</b> dropdown.
</p>
<table class="full">
    <thead>
        <tr>
            <td>Permission</td>
            <td>Access</td>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Email address</td>
            <td>Read-only</td>
        </tr>
    </tbody>
</table>

<h3><a href="#subscribe-events" id="subscribe-events">Subscribe to Events</a></h3>
<p>
    Select these under the <b>Subscribe to events</b> dropdown.
</p>
<table class="full">
    <thead>
        <tr>
            <td>Events</td>
            <td></td>
            <td></td>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Pull request</td>
            <td>Push</td>
            <td></td>
        </tr>
    </tbody>
</table>

<h3><a href="#github-where-installed" id="github-where-installed">Where can this GitHub App be installed?</a></h3>

<p>
    Check the <b>Any account</b> box under <b>Where can this GitHub App be installed?</b> section. This is important to allow you to install the GitHub app on multiple Appwrite projects.
</p>

<h3><a href="#github-variables" id="github-variables">Environment Variables</a></h3>
<p>After creating your app, you'll have to configure the following environment variables.</p>

<table class="full">
    <thead>
    <tr>
        <td style="width: 250px">Variable</td>
        <td>Description</td>
    </tr>
    </thead>
    <tbody>
    <tr>
        <td>_APP_DOMAIN</td>
        <td>
            Your main Appwrite domain used to access the Appwrite Console. 
            When setting a public suffix domain, Appwrite will attempt to issue a valid SSL certificate automatically. 
            When used with a dev domain, Appwrite will assign a self-signed SSL certificate.
            If you're using a proxy for <b>localhost development</b>, such as <a href="https://ngrok.com/" target="_blank" rel="noopener">ngrok</a>, this will be the domain of your localhost proxy.
        </td>
    </tr>
    <tr>
        <td>_APP_DOMAIN_TARGET</td>
        <td>
            A hostname to serve as a CNAME target for your Appwrite custom domains. 
            You can use the same value as used for the Appwrite <code>_APP_DOMAIN</code> variable.
            If you're using a proxy for <b>localhost development</b>, such as <a href="https://ngrok.com/" target="_blank" rel="noopener">ngrok</a>, this will be the domain of your localhost proxy, such as <code>dd65-2405-201-4013-d8d7-b4c5-fb73-39f9-285c.ngrok.io</code>.
        </td>
    </tr>
    <tr>
        <td>_APP_DOMAIN_FUNCTIONS</td>
        <td>
            This will be used for system generated <a href="/docs/functions-deploy#domains">Function Domains</a>. 
            When a function domain is generated, it will be <code>[UNIQUE_ID].[_APP_DOMAIN_FUNCTIONS]</code>. 
            If <code>_APP_DOMAIN_FUNCTIONS</code> is set to <code>example.com</code> for example, the generated domain for functions will be something like <code>64d4d22db370ae41a32e.example.com</code>.
            You can use the same value as used for the Appwrite <code>_APP_DOMAIN</code> variable.
        </td>
    </tr>
    <tr>
        <td>_APP_VCS_GITHUB_APP_NAME</td>
        <td>Name of your GitHub app. This is the display name you'll see on GitHub and it will be visible in your GitHub app's URL.</td>
    </tr>
    <tr>
        <td>_APP_VCS_GITHUB_PRIVATE_KEY</td>
        <td>RSA private key from GitHub wrapped with double quotes and newlines replaced with <code>\n</code>. You can generate private keys from GitHub application settings.</td>
    </tr>
    <tr>
        <td>_APP_VCS_GITHUB_APP_ID</td>
        <td>GitHub application ID. You can find it in your GitHub application details.</td>
    </tr>
    <tr>
        <td>_APP_VCS_GITHUB_CLIENT_ID</td>
        <td>GitHub client ID. You can find it in your GitHub application details.</td>
    </tr>
    <tr>
        <td>_APP_VCS_GITHUB_CLIENT_SECRET</td>
        <td>GitHub client secret. You can generate secrets in your GitHub application settings.</td>
    </tr>
    <tr>
        <td>_APP_VCS_GITHUB_WEBHOOK_SECRET</td>
        <td>GitHub webhook secret. You can configure it in your GitHub application settings under webhook section.</td>
    </tr>
    </tbody>
</table>

<p>
    For example, see below.
</p>

<div class="ide margin-bottom" data-lang="bash" data-lang-label="Bash">
    <pre class="line-numbers"><code class="prism language-bash" data-prism>_APP_DOMAIN=appwrite.example.com
_APP_DOMAIN_TARGET=appwrite.example.com
_APP_DOMAIN_FUNCTIONS=functions.example.com
_APP_VCS_GITHUB_APP_NAME=my-github-app
_APP_VCS_GITHUB_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEAuT8f3lo/X83hfvb0ZN/KD2pl86o/jl3ywKrkj/PQZBmtEv/z\nIugE//sfFoHWc4cizkcji+n3FNU+GEdvMioKuJlPBqPTY8hAbVn7R0geZLpDV/rs\n[...]\n-----END RSA PRIVATE KEY-----"
_APP_VCS_GITHUB_APP_ID=12415
_APP_VCS_GITHUB_CLIENT_ID=Iv1.35asdf43asd
_APP_VCS_GITHUB_CLIENT_SECRET=35rsdse532q13
_APP_VCS_GITHUB_WEBHOOK_SECRET=super-secret</code></pre>
</div>

<p><a href="/docs/environment-variables"><i class="icon-angle-circled-right margin-start-negative-tiny margin-end-tiny"></i> Learn more about environment variables</a></p>

<h3><a href="#existing-apps" id="existing-apps">Update Existing GitHub Apps</a></h3>
<p>
    There are additional steps if you're updating permissions in existing GitHub apps.
    Every time you update your GitHub app's permissions, GitHub will prompt you to review the changes.
    You will receive an email and you'll find a prompt under <b>Settings</b> > <b>Integrations</b> > <b>Applications</b> > <b>Installed GitHub Apps</b> > find your GitHub app > <b>Configure</b>.
    You need to accept the new permissions so they're applied to your app.
</p>

<h2><a href="#functions" id="functions">Configure Function Runtimes</a></h2>
<p>
    Not all function runtimes are enabled by default. Enable the runtimes that you need and disable unused runtimes to save disk space on your server.
    To enable a runtime, add it to the <code>_APP_FUNCTIONS_RUNTIMES</code> environment variable as a comma separated list. 
</p>

<p>
    The example below would enable Dart 2.15, .NET 6.0, and Java 18 runtimes.
</p>

<div class="ide margin-bottom" data-lang="bash" data-lang-label="Bash">
    <pre class="line-numbers"><code class="prism language-bash" data-prism>_APP_FUNCTIONS_RUNTIMES=dart-2.15, dotnet-6.0, java-18.0</code></pre>
</div>

<p>You can find a full list of supported runtimes on the <a href="/docs/environment-variables#functions">environment variables</a> page.</p>

<p>You can also configure the maximum timeout that can be set on individual Appwrite functions. The maximum configurable timeout can be increased by changing the <code>_APP_FUNCTIONS_TIMEOUT</code> environment variable. This environment variable changes the configurable maximum but does not alter existing configurations of individual functions.</p>

<h2><a href="#storage" id="storage">Storage Adapters</a></h2>
<p>Appwrite's Storage Service can be configured to store files locally, or with self-hosted and cloud storage services. By default, Appwrite's Storage Service <b>stores files on your server's local storage</b>. If you expect large volumes of data or the need to have scalable data storage, you may choose to use a separate storage service.</p>

<p>Appwrite supports AWS S3, Digital Ocean Spaces, Backblaze, Akamai Object Storage, and Wasabi as storage adapters. Some of these services can be self-hosted, just like Appwrite.</p>

<p>You can select which storage adapter to use by setting the <code>_APP_STORAGE_DEVICE</code> environment variable. Valid values are <code>local</code>, <code>s3</code>, <code>dospaces</code>, <code>backblaze</code>, <code>linode</code>, and <code>wasabi</code>. Each storage adapter requires its own set of additional environment variables to configure.</p>

<p>The maximum size for individual file uploads is controlled by the <code>_APP_STORAGE_LIMIT</code> environment variable, which defaults to 30 MB. See <a href="/docs/environment-variables#storage">Environment Variables</a> for more information.</p>

<p><a href="/docs/environment-variables#storage"><i class="icon-angle-circled-right margin-start-negative-tiny margin-end-tiny"></i> Configure storage adapters</a></p>

<h2><a href="#apply-changes" id="apply-changes">Applying Changes</a></h2>
<p>After editing your <code>docker-compose.yml</code> or <code>.env</code> files, you will need to recreate your Appwrite stack by running the following compose command in your terminal.</p>

<div class="ide margin-bottom" data-lang="bash" data-lang-label="Bash">
    <pre class="line-numbers"><code class="prism language-bash" data-prism>docker compose up -d</code></pre>
</div>

<p>You can verify if the changes have been successfully applied by running this command:</p>
<div class="ide margin-bottom" data-lang="bash" data-lang-label="Bash">
    <pre class="line-numbers"><code class="prism language-bash" data-prism>docker compose exec appwrite vars</code></pre>
</div>

<h2><a href="#more-configs" id="more-configs">More Configurable Options</a></h2>
<p>If you don't see something you'd like to configure on this page, try searching the complete list of environment variables.</p>
<p><a href="/docs/environment-variables"><i class="icon-angle-circled-right margin-start-negative-tiny margin-end-tiny"></i> Learn more about environment variables</a></p>