<a id="configure-ingress"></a>

# How to configure ingress

Ingress is what makes `gopkg-k8s` reachable from outside the Kubernetes
cluster under a chosen hostname. Set the routing rules on the ingress
integrator, keep the workload hostname in step with them, then point DNS at
the ingress controller and terminate TLS there for production.

These steps assume that `gopkg-k8s` and `nginx-ingress-integrator`
are deployed and integrated, as they are after the deployment steps of
[Deploy and verify gopkg-k8s on Kubernetes](https://canonical.com/juju/docs/gopkg-charm/latest/tutorials/deploy-and-verify-on-kubernetes/index.html.md#deploy-and-verify-on-kubernetes) and before its clean-up section. For
how the components fit together, read [Ingress](https://canonical.com/juju/docs/gopkg-charm/latest/explanation/ingress/index.html.md#ingress).

## Set the routing hostname and paths

Configure one hostname and route every path without rewriting it:

```bash
export INGRESS_HOST=gopkg.example.com
juju config nginx-ingress-integrator \
  service-hostname=${INGRESS_HOST} \
  path-routes=/ \
  rewrite-enabled=false
```

These settings have distinct jobs:

`service-hostname`
: Matches the HTTP `Host` header. Only requests for this hostname use the
  rule.

`path-routes`
: Selects the URL paths sent to the application. `/` exposes all paths,
  including `/health-check` and package paths such as `/yaml.v2`.

`rewrite-enabled`
: Controls whether the controller changes the path before forwarding it.
  This must be `false` because the workload needs the original package path.

## Match the workload hostname

The ingress hostname and the hostname the application renders in package
links and `go-import` metadata are separate settings. For a normal
deployment, set both to the public hostname:

```bash
juju config gopkg-k8s hostname=${INGRESS_HOST}
```

Wait for both applications to settle:

<!-- SPREAD SKIP -->
```bash
juju status --watch 2s
```

<!-- SPREAD SKIP END -->
<!-- SPREAD
juju wait-for application gopkg-k8s \
  --query='status=="active"' --timeout=15m
juju wait-for application nginx-ingress-integrator \
  --query='status=="active"' --timeout=15m -->
<!-- SPREAD END -->

## Verify routing

Confirm that the integration exists and inspect the generated Kubernetes
resource:

```bash
juju status --relations
microk8s kubectl -n gopkg-k8s describe ingress
```

Then test both workload behavior and metadata through ingress. The
documentation hostname does not resolve to your machine, so `--resolve`
pins it to the local ingress controller for each request:

```bash
curl --fail --silent --show-error --retry 30 --retry-delay 2 \
  --retry-all-errors \
  http://${INGRESS_HOST}/health-check \
  --resolve ${INGRESS_HOST}:80:127.0.0.1 | grep -Fx ok
curl --fail --silent --show-error --retry 30 --retry-delay 2 \
  --retry-all-errors \
  "http://${INGRESS_HOST}/yaml.v2?go-get=1" \
  --resolve ${INGRESS_HOST}:80:127.0.0.1 | grep go-import
```

An `ok` health response proves that the controller, routing rule, Service,
and workload all participated in the request. The metadata request checks
that the application handles a real package path.

For access from another machine, use the address of the machine or load
balancer that exposes the controller instead of `127.0.0.1`, and make sure
that network firewalls allow the port.

<a id="configure-ingress-dns"></a>

## Set up production DNS

For production, replace the documentation hostname with a domain you control:

1. Find the external IP address or hostname of the ingress controller.
2. Create an `A` or `AAAA` record, or an appropriate `CNAME` record, with
   your DNS provider.
3. Set `service-hostname` and the `gopkg-k8s` `hostname` option to
   that domain, as in the sections above.
4. Wait for DNS changes to propagate.
5. Verify that ports 80 and 443 reach the ingress controller.

The way an external address is assigned depends on the Kubernetes platform.
A managed cloud commonly provisions a load balancer. A local or bare-metal
cluster may require a node address, port forwarding, or a load-balancer
implementation such as MetalLB.

<a id="configure-ingress-https"></a>

## Enable HTTPS

TLS terminates at the ingress controller (see [Ingress](https://canonical.com/juju/docs/gopkg-charm/latest/explanation/ingress/index.html.md#ingress)), so
the certificate must include the public hostname in its subject alternative
names. Store the certificate and private key in a Kubernetes TLS secret in the
same namespace as the Juju model, then configure the integrator with the secret
name. For example, for the `gopkg-k8s` model namespace:

<!-- SPREAD SKIP -->
```bash
microk8s kubectl -n gopkg-k8s create secret tls gopkg-tls \
  --cert=path/to/fullchain.pem \
  --key=path/to/private-key.pem
juju config nginx-ingress-integrator tls-secret-name=gopkg-tls
```

<!-- SPREAD SKIP END -->

Use your certificate manager’s recommended renewal process. Replacing the
secret data allows the controller to load the renewed certificate. Keep
private keys out of the repository and restrict access to the namespace.

The integrator can also obtain TLS information through a certificate relation.
See the [NGINX ingress integrator documentation](https://canonical.com/juju/docs/nginx-ingress-integrator-charm/latest/) when
using a certificate provider charm.

For all supported integrator settings, see the [NGINX ingress integrator
configuration reference](https://charmhub.io/nginx-ingress-integrator/configurations). For failure
symptoms and fixes, see [How to troubleshoot deployment issues](https://canonical.com/juju/docs/gopkg-charm/latest/how-to/troubleshoot-deployment/index.html.md#troubleshoot-deployment).
