# Serve the hub on your domain

> Publish the hub on the internet under your own domain name over HTTPS, with a certificate you already have, directly or behind Cloudflare.

Source: https://proxus.io/docs/operate/custom-domain

At the end of this guide, users open the hub at `https://proxus.example.com` from anywhere, with a certificate
you already have: one from Cloudflare, your certificate authority or another provider. Plain HTTP sends users to
HTTPS, and only the ports that need to be reachable are open.

## Before you start

- The hub runs on a server with a public IP address, installed with the
  [installer or the compose file](https://proxus.io/docs/get-started/install).
- **Admin** has a strong password. Do this before the hub is reachable from the internet: see
  [Security](https://proxus.io/docs/operate/security#default-credentials-to-change).
- You can change the DNS records of your domain.
- You have the certificate for the hub's name and its private key, in PEM (`.pem`, `.crt`, `.key`) or as a `.pfx`.
  The certificate must cover the name users type, for example `proxus.example.com` or `*.example.com`.

The steps use `proxus.example.com`. Replace it with your own name.

## Step 1: Point the name at the server

At your DNS provider, add an `A` record for `proxus.example.com` with the server's public IP address.

If you use Cloudflare's proxy, also read [Behind the Cloudflare proxy](#behind-the-cloudflare-proxy) before you
continue.

## Step 2: Open only the ports that are needed

In your cloud provider's firewall (security group, network security group or firewall rule), allow:

| Port | For |
| --- | --- |
| `443` (TCP) | Users, API clients and the install command of edge gateways. |
| `80` (TCP) | Only to send users who type `http://` to HTTPS. |
| `7422` (TCP) | Edge gateways on other networks. Leave it closed if every gateway is on the server's own network. |

Keep every other port closed to the internet.

> **Warning:**
Ports published by Docker bypass `ufw` and other host firewalls that manage `iptables`: a port closed in `ufw` is
still open if `docker-compose.yml` publishes it. Close ports in the cloud provider's firewall, or bind them to the
loopback address in `docker-compose.yml`, as in step 5.

## Step 3: Upload the certificate

1. Sign in to the hub and open **Security > Certificate Store**.
2. Select **Upload** and choose the certificate and its private key together. If your provider gave you a chain or a
   CA file, choose it too. Proxus finds out which file is which: the certificate that matches the key is stored with
   it.
3. Check the new row: **Type** is **Server** and the expiry date is the one your provider gave.

## Step 4: Make it the hub's HTTPS certificate

Select the uploaded certificate, select **Set as Default** and confirm. The hub serves the new certificate within
a minute, without a restart. Nobody is signed out.

**Set as Default** is available only for a server certificate with its private key.

## Step 5: Publish the hub on 443

Open `docker-compose.yml` in the `proxus-platform` folder and change the `proxus-ui` service:

```yaml
  proxus-ui:
    ports: ["80:8080", "443:8443"]
    environment:
      # …the existing entries stay…
      Service__PublicHttpsPort: "443"
      Service__PublicHostNames: "proxus.example.com"
      Service__RedirectHttpToHttps: "true"
```

| Setting | What it does |
| --- | --- |
| `"80:8080"`, `"443:8443"` | Publishes the hub's HTTP and HTTPS on the standard ports. |
| `Service__PublicHttpsPort` | The port users reach HTTPS on. Redirects and edge install commands use it. |
| `Service__PublicHostNames` | The hub's name. It is added to the certificates the hub issues itself, for example for its message server. |
| `Service__RedirectHttpToHttps` | Sends every HTTP request to HTTPS and turns on HSTS. The container's health check is not redirected. |

To keep the databases and the message server off the internet, bind their ports to the loopback address in the same
file. The services reach each other over the internal network, so Proxus is not affected:

```yaml
  hub-server:
    ports: ["127.0.0.1:4222:4222", "127.0.0.1:8222:8222", "7422:7422"]
  postgresql:
    ports: ["127.0.0.1:5442:5442"]
  clickhouse:
    ports: ["127.0.0.1:8123:8123", "127.0.0.1:9000:9000", "127.0.0.1:9005:9005", "127.0.0.1:9004:9004"]
```

Apply the changes:

```bash
docker compose up -d
```

## Step 6: Check it

1. Open `https://proxus.example.com`. The browser shows the site as secure and the sign-in page appears.
2. Open `http://proxus.example.com`. The browser goes to `https://proxus.example.com`.
3. Check the certificate the hub sends from any machine:

   ```bash
   openssl s_client -connect proxus.example.com:443 -servername proxus.example.com </dev/null | grep -E "subject=|Verify return code"
   ```

   `subject=` shows your certificate. `Verify return code: 0 (ok)` means the client trusts it.
4. Run `docker compose ps`: `proxus-ui` is **healthy**.

## Behind the Cloudflare proxy

With the proxy on (orange cloud), Cloudflare serves its own certificate to users and connects to the hub over HTTPS.
The hub's certificate is then a **Cloudflare Origin Certificate**: only Cloudflare needs to trust it.

1. In Cloudflare, open **SSL/TLS > Origin Server** and select **Create Certificate**. Keep the key type **RSA (2048)**
   and the host names `proxus.example.com` (or `*.example.com`). Save the **Origin Certificate** as `origin.pem` and the
   **Private Key** as `origin.key`. Cloudflare shows the private key only once.
2. Upload both files as in step 3 and make the certificate the default as in step 4.
3. In **SSL/TLS > Overview**, set the encryption mode to **Full (strict)**.
4. In **Network**, check that **WebSockets** is on. The hub's web interface keeps a live connection open.
5. Publish the hub as in step 5.

> **Warning:**
Do not use the **Flexible** encryption mode. Cloudflare then connects to the hub over HTTP, the hub sends it to
HTTPS, and the browser shows "too many redirects".

**Edge gateways cannot connect through the Cloudflare proxy.** The install command checks the hub's own HTTPS key,
which the proxy hides behind Cloudflare's certificate, and the gateways' message connection on port `7422` is not
HTTP. Give the gateways a name that is not proxied:

1. Add a second `A` record, for example `edge.example.com`, with the same IP address and the proxy **off** (grey
   cloud).
2. Add the name to `Service__PublicHostNames`, for example `"proxus.example.com, edge.example.com"`, and run
   `docker compose up -d`.
3. When you install a gateway, choose **Another address** in the install wizard and enter `edge.example.com`.

## Install edge gateways

The install wizard offers the addresses it knows; choose the name the gateway's machine can reach the hub on. The
command it gives connects to `https://<that name>:443` and checks the key of the certificate you made the default,
so it works with your own certificate. The gateway then connects to port `7422`. See
[Install a gateway](https://proxus.io/docs/connect/edge-gateways/install-a-gateway).

An install command is valid for one hour and only until the hub restarts. If you changed `docker-compose.yml` after
creating it, create a new one.

## Renew the certificate

Proxus does not renew a certificate it did not issue. Before yours expires:

1. Get the new certificate from your provider.
2. Upload it and select **Set as Default**, as in steps 3 and 4.

The hub warns in the [system logs](https://proxus.io/docs/administer/system-logs) every day for a certificate that expires within
30 days. A Cloudflare Origin Certificate is valid for up to 15 years.

Gateways keep working after the certificate changes: they connect to the hub's message server, which uses its own
certificate. Install commands created before the change stop working; create new ones.

## When something does not work

| What you see | Cause | What to do |
| --- | --- | --- |
| The browser warns that the certificate is not valid for the name. | The certificate does not cover the name in the address bar. | Upload a certificate for that name and make it the default. |
| The browser still shows the old certificate. | The hub picks up the new default within a minute. | Wait a minute and reload. |
| "Too many redirects" behind Cloudflare. | Cloudflare's encryption mode is **Flexible**. | Set it to **Full (strict)**. |
| `http://` opens an address with `:8443`. | `Service__PublicHttpsPort` is missing. | Set it to `"443"` and run `docker compose up -d`. |
| The edge gateway install says the link is not valid. | The link expired, was used, or the hub restarted. | Create a new command in the install wizard. |
| The install command fails with a key or connection error behind Cloudflare. | The command goes through the proxy. | Use a name that is not proxied, see [Behind the Cloudflare proxy](#behind-the-cloudflare-proxy). |

## What's next

- [Security](https://proxus.io/docs/operate/security): HTTPS settings, ports and the hardening checklist.
- [Certificate Store](https://proxus.io/docs/administer/certificates): certificates on a new installation, renewing and replacing.
- [Install a gateway](https://proxus.io/docs/connect/edge-gateways/install-a-gateway): the install wizard step by step.
