# Deploy on a server

Run Ceryx on a server, connect your services and serve them over HTTPS on your own domains.

## Before you start

You need:

- A Linux server with Docker and Docker Compose.
- Ports 80 and 443 accessible from the internet.[^1]
- DNS records (`A`, `AAAA` or `CNAME`) for your domains pointing at the server.

## 1. Start Ceryx

Start Ceryx with Docker Compose:

```bash
docker compose -f https://github.com/withlogicco/ceryx.git#v1.0.0 up -d
```

To keep a local copy you can edit, download the file first:

```bash
sudo mkdir -p /opt/ceryx
cd /opt/ceryx
curl -fsSLO https://raw.githubusercontent.com/withlogicco/ceryx/v1.0.0/compose.yml
docker compose up -d
```

The local file lets you [configure Ceryx](#configure-ceryx) alongside it.

Ceryx now:

- Serves HTTP on port 80 and HTTPS on port 443.
- Keeps routes and certificates in the `ceryx_data` volume, so they survive restarts and upgrades.
- Creates a Docker network named `ceryx`. Your services join it so Ceryx can reach them.
- Listens for API requests on port 8080, reachable only from the `ceryx` network. It isn't published on the server, because the API has no authentication.

## 2. Connect your services

Add each service you want to serve to the `ceryx` network, in its own Compose file:

```yaml
services:
  echo:
    image: hashicorp/http-echo:1.0.0
    command: ["-listen=:5678", "-text=Hello from Ceryx"]
    networks:
      - ceryx

networks:
  ceryx:
    external: true
```

Then start it with `docker compose up -d`. You don't need to publish its ports: Ceryx reaches it over the network at `http://echo:5678`.

> [!NOTE] Use unique service names
> Services on the `ceryx` network are reachable by their Compose service name. If two projects both have a service called `echo`, give them distinct names, such as `web` and `api`, so each route reaches the right one.

## 3. Add a route

Route your domain to the service:

```bash
docker compose -p ceryx exec ceryx curl -X POST localhost:8080/api/routes \
  -H 'Content-Type: application/json' \
  -d '{"source": "app.example.com", "target": "http://echo:5678"}'
```

This runs `curl` inside the Ceryx container, where the API listens on port `8080`. The [API reference](/docs/api) lists everything else you can do.

## 4. Visit your domain

Open `https://app.example.com`. The very first HTTPS request takes a few seconds, while Ceryx issues a certificate from Let's Encrypt. Next requests use the stored certificate, and Ceryx renews it before it expires.

If the certificate doesn't arrive, check that the domain points at your server and that port 80 is reachable from the internet. See [how certificates work](/docs/concepts/certificates).

## 5. Redirect HTTP to HTTPS

Routes serve plain HTTP too, until you enforce HTTPS:

```bash
docker compose -p ceryx exec ceryx curl -X PUT localhost:8080/api/routes/app.example.com \
  -H 'Content-Type: application/json' \
  -d '{"settings": {"enforce_https": true}}'
```

To enforce HTTPS on every new route, set the environment variable `CERYX_ROUTE_SETTINGS_DEFAULT_ENFORCE_HTTPS` to `true` when running Ceryx.

## Configure Ceryx

Ceryx reads its [settings](/docs/settings) from environment variables. To set a default for new routes, add the variable to the Ceryx service in your local `compose.yml`:

```yaml
services:
  ceryx:
    environment:
      CERYX_ROUTE_SETTINGS_DEFAULT_ENFORCE_HTTPS: "true"
```

For changes that settings can't make, such as mounting certificate files into the container, add a `compose.override.yml` next to `compose.yml`. Compose loads it automatically:

```yaml
# /opt/ceryx/compose.override.yml
services:
  ceryx:
    volumes:
      - ./certs:/etc/ceryx/certs:ro
```

Apply either change with `docker compose up -d`.

[^1]: Let's Encrypt requires access to port 80 to issue certificates.
