# Create a web proxy

> Serve a hostname through Coritan's edge, in front of one of your servers or an address of your own.

Source: https://www.coritan.com/docs/proxies/web-proxies/create-a-web-proxy/

In the dashboard:

- /dashboard/proxies/web: https://www.coritan.com/dashboard/proxies/web

Create a web proxy to serve a hostname, such as `www.example.com`, through Coritan's edge. The edge then answers HTTPS for the name with a free certificate, checks requests with the web application firewall (WAF) and forwards them to your origin ([How web proxies work](/docs/proxies/web-proxies/)). The origin can be one of your servers hosted here, whose address Coritan fills in, or any public address.

## Before you begin

- The name is a domain you registered with Coritan, a name in a DNS zone on your account, or a name under your free coritan.gg name. A web proxy for `app.example.com` only needs the `example.com` zone ([Add a domain you already own](/docs/websites/add-an-existing-domain/), [Claim a free coritan.gg name](/docs/proxies/coritan-gg-names/)).
- The name has no web proxy yet. Each name can have one web proxy on the whole platform.
- To forward to a server hosted here, you need a [Container Apps](/docs/managed-containers/) server with an address and a port. For any other origin, you need its public IP address or hostname and its port.
- Visitors reach the web proxy once the name resolves to the edge ([Web proxies and DNS records](/docs/proxies/web-proxies/#web-proxies-and-dns-records)).

## Forward to a server hosted here

1. In the dashboard, go to [Edge Proxy](https://www.coritan.com/dashboard/proxies) and select **New proxy…**.
2. Choose **Website or app**, then **A server hosted here**. The second choice is unavailable while your account has no servers.
3. Enter the **Domain**, such as `www.example.com`. Your free coritan.gg names appear under the field as suggestions, and selecting one fills it in.
4. Choose the **Server**. The form shows the address and port that requests will go to.
5. Leave **Request a certificate automatically** on, so Coritan requests a certificate for the name.
6. Select **Create proxy**.

The web proxy forwards to the server's address and port over plain HTTP. It starts with **Force HTTPS**, **WebSockets** and **Web application firewall** on, a 100 MB request body limit and a 60 second origin timeout.

If the name already has a web proxy on your account, this points that web proxy at the server and keeps its other settings. The same happens to a web proxy that a proxied DNS record created, which then appears on your list.

## Forward to any address

1. In the dashboard, go to [Edge Proxy](https://www.coritan.com/dashboard/proxies) and select **New proxy…**.
2. Choose **Website or app**, then **A server elsewhere**.
3. Enter the **Domain**, such as `www.example.com`, or select one of the suggestions under the field.
4. Enter the **Origin host**: an IP address, such as `203.0.113.10`, or a hostname, such as `origin.example.net`. Leave out `https://` and the port.
5. Enter the origin's **Port**. It starts at `80`.
6. Choose the **Origin protocol** ([Origin protocols](/docs/proxies/web-proxies/#origin-protocols)). Turn on **Connect to the origin over TLS** when the origin serves HTTPS on that port.
7. Set the switches. All but the last start on:
   - **Request a certificate automatically** requests a certificate for the name as soon as the web proxy exists.
   - **Force HTTPS** redirects plain HTTP requests to HTTPS.
   - **Web application firewall** checks requests before they reach the origin.
   - **WebSockets** passes WebSocket connections through to the origin.
   - **PROXY protocol to origin** starts each connection to the origin with a PROXY protocol header that carries the visitor's address. Turn it on only when the origin expects it, or every request fails.
8. To change paths, headers, origins or limits, select **Advanced options** ([Advanced options](#advanced-options)).
9. Select **Create proxy**.

### Advanced options

**Strip path prefix**
: A path the edge removes from the start of the request path, such as `/api`.

**Prepend origin path**
: A path the edge adds in front of the request path, such as `/v2`. [What your origin receives](/docs/proxies/web-proxies/#what-your-origin-receives) shows both prefixes at work.

**Custom request headers**
: Headers the edge adds to every request it forwards. Select **Add header**, then enter a name and a value.

**Additional origins**
: More origins that share the requests with the origin host. Select **Add origin**, then enter the host and port, choose a protocol or leave `Route default`, and tick **TLS** for an origin that serves HTTPS. The edge does not check their health, so each one must serve the whole site.

**Max request body (MB)**
: The largest request body the edge accepts, from 1 to 100 MB. It starts at 100.

**Origin timeout (s)**
: How long the edge waits for the origin to answer, from 1 to 120 seconds. It starts at 60.

## Result

The dashboard confirms `Proxy for www.example.com created.` or `www.example.com now points at 203.0.113.10:8080.` and opens the web proxy's **Overview** tab. Coritan requests the certificate in the background, and the **Certificate** card shows its state.

When Coritan hosts the zone and the name has no `A`, `AAAA` or `CNAME` record, Coritan also adds a proxied `A` or `AAAA` record for the name. When another provider hosts the zone, point the name at the edge there ([Web proxies and DNS records](/docs/proxies/web-proxies/#web-proxies-and-dns-records)).

## Troubleshooting

`Enter a full hostname such as app.example.com.`
: The **Domain** needs at least two labels made of letters, digits and hyphens, such as `www.example.com`.

`Leave https:// out of the origin host. The port and TLS have their own fields.`
: Enter only the host in **Origin host**. Put the port in **Port**, and turn on **Connect to the origin over TLS** for HTTPS.

`Leave the port out of the origin host. It has its own field.`
: Remove `:8080` or any other port from **Origin host**, and enter it in **Port**.

`The origin host is a hostname or an IP address, such as origin.example.net.`
: **Origin host** holds a character that no hostname has, such as a space or a slash. Enter the bare hostname or address.

`The origin port must be between 1 and 65535.` or `Origin 203.0.113.11 needs a port between 1 and 65535.`
: Enter a port from 1 to 65535 for the origin host, or for the additional origin that the message names.

`Every custom header needs a name.`
: A custom request header has a value but no name. Enter the name, or select **Remove header**.

`You must own this domain (via registration or DNS zone) to create a route`
: The name is not under a domain you registered here or a DNS zone on your account. Add the zone first ([Add a domain you already own](/docs/websites/add-an-existing-domain/)). The form for a server hosted here says `You must own this domain (via registration or DNS zone)`.

`A route for this domain already exists`
: The name already has a web proxy. If it is not on your [Edge Proxy](https://www.coritan.com/dashboard/proxies/web) list, a proxied `A` or `AAAA` record made it: forward the name to a server hosted here, which takes that web proxy over, or turn **Proxied** off for the record, create the web proxy and turn **Proxied** on again. If the name has no proxied record, another account holds the web proxy, and you can [contact support](/docs/support/).

`Domain route owned by another user`
: Another account has a web proxy for the name. [Contact support](/docs/support/).

`Server has no allocated IP/port. Ensure the server has an active allocation.`
: The server has no address and port yet. Wait until its setup finishes, or choose another server.

`Unable to resolve hostname: origin.example.net`
: The origin host does not resolve in public DNS. Check its spelling, or enter the origin's IP address.

`host targets a private or reserved network`, `resolved address targets a private or reserved network` or `Hostname targets a private or reserved name`
: The edge only forwards to public addresses. It refuses private and reserved networks, `localhost`, and names that end in `.local`, `.localhost` or `.internal`. Enter the origin's public address.

**A server hosted here** is unavailable
: Your account has no servers. [Order a server](https://www.coritan.com/dashboard/order?order=container), or choose **A server elsewhere** and enter the origin's address.

## Related

- [How web proxies work](/docs/proxies/web-proxies/)
- [Change a web proxy's origin](/docs/proxies/web-proxies/change-the-origin/)
- [Redirect requests with rules](/docs/proxies/web-proxies/redirect-rules/)
- [Manage a website's web proxy](/docs/websites/proxy/)

## With the API

Create a web proxy for any origin with `POST /api/v1/proxy/routes`. `domain` is required, and so is `upstream_host` unless you send `redirect_to` for a [whole-domain redirect](/docs/proxies/web-proxies/redirect-rules/#redirect-the-whole-domain). Send `domain` in lowercase.

```bash
curl -X POST https://api.coritan.com/api/v1/proxy/routes \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "domain": "www.example.com",
    "upstream_host": "203.0.113.10",
    "upstream_port": 8080,
    "auto_ssl": true
  }'
```

The call takes every field that [Change a web proxy's origin](/docs/proxies/web-proxies/change-the-origin/#with-the-api) lists, except `development_mode`, `development_mode_minutes` and `error_page`, and a field you leave out takes the default shown there. It also takes `auto_ssl`, `true` by default, which requests a certificate for the name. The answer is `201`:

```json
{
  "id": 31,
  "domain": "www.example.com",
  "status": "active",
  "ssl_status": "pending",
  "dns": {"zone": "example.com", "name": "www", "created": true, "type": "A"}
}
```

`ssl_status` is `pending` when a certificate was requested and `off` when it was not. `dns` is `null` when Coritan does not host the zone or could not add a record, and `created` is `false` when a record already answers for the name.

Forward a name to one of your servers with `POST /api/v1/proxy/routes/connect-domain`. It takes the server's `server_uuid`, which `GET /api/v1/client/servers` lists, the `domain` and `auto_ssl`:

```bash
curl -X POST https://api.coritan.com/api/v1/proxy/routes/connect-domain \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"server_uuid": "8c2b1f4e-5d3a-4e7b-9f10-2a6c4d8e1b37", "domain": "www.example.com", "auto_ssl": true}'
```

```json
{
  "message": "Domain connected to server",
  "domain": "www.example.com",
  "upstream": "203.0.113.10:8080",
  "route_id": 31,
  "ssl_status": "pending",
  "dns": {"zone": "example.com", "name": "www", "created": true, "type": "A"}
}
```

A server that does not exist answers `404` with `Server not found`, and another account's server answers `403` with `You do not own this server`. The other errors are those in [Troubleshooting](#troubleshooting). A value outside its range, such as a `max_body_size_mb` of `200`, answers `422`.

## API

- `POST /api/v1/proxy/routes`: Create a proxy route for a domain you own (https://www.coritan.com/docs/api/reference/client/reverse-proxy/#op-post-api-v1-proxy-routes)
- `POST /api/v1/proxy/routes/connect-domain`: Connect a user's domain to their container server (https://www.coritan.com/docs/api/reference/client/reverse-proxy/#op-post-api-v1-proxy-routes-connect-domain)
