# Production checklist

What to set before a Zato environment takes production traffic.

Start with the [production security checklist](https://zato.io/docs/admin/security/checklist.html). This page covers the rest - fixed code, data that survives a container replacement, and the changes that turn the blueprint's script into a production one.

## Run fixed code {#run-fixed-code}

By default, a container fetches the latest Zato code each time it starts, and the Dashboard installs updates on a schedule. In production, turn both off with `Zato_Install_Updates=False` and reference the image by its digest instead of `latest`:

```text
zatosource/zato-4.1@sha256:<digest>
```

To update, run the new digest in a test environment first, then in production - see [updating environments](https://zato.io/docs/admin/guide/install/update.html).

## Keep data outside the container {#keep-data-outside-the-container}

Every image update replaces the container, and whatever was stored only inside it is gone. In production:

- Export all configuration to [enmasse](https://zato.io/docs/admin/enmasse.html) and commit it to Git
- Run the [audit log](https://zato.io/docs/admin/audit-log/index.html) and [pub/sub](https://zato.io/docs/eda/index.html) on an external database, through `Zato_Audit_Log_DB_*` and `Zato_PubSub_DB_*`
- Mount the logs directory - see [logging](https://zato.io/docs/admin/logging.html)

## Set the passwords {#set-the-passwords}

Set `Zato_Dashboard_Password`, `Zato_SSH_Password`, `Zato_IDE_Password` and `Zato_Metrics_Password` individually. A password you do not set is generated again on every start, and `Zato_Password`, which gives them all one value, is meant for development.

Leave `Zato_Log_Env_Details` unset, because it writes every password to files inside the container.

## Adapt the blueprint script {#adapt-the-blueprint-script}

The blueprint's `run-container.sh` is set up for development. For production:

- Use the image digest and remove `--pull=always`
- Publish 11224 instead of 11223
- Publish 8184 on an internal address only, and remove 8183
- Remove 22022 and 11225
- Remove `Zato_Log_Env_Details=true`
- Pass each password separately instead of one generated value
- Add a health check against [`/zato/ping`](https://zato.io/docs/admin/ping.html) and a `--log-opt max-size` for Docker's own log

## Run more than one container {#run-more-than-one-container}

Each container is a complete environment of its own. If you run several behind your own load balancer, start the scheduler in one of them only, with `Zato_Start_Scheduler=False` on the others, and use pub/sub in one of them only. [Health checks](https://zato.io/docs/admin/health-checks.html) are scheduler jobs, so they run where the scheduler runs.

If the load balancer sets `X-Forwarded-For`, set `Zato_Trust_Forwarded_Headers=True` so Zato records the caller's address rather than the load balancer's.

## Check the result {#check-the-result}

1. `curl https://api.example.com:11224/zato/ping` succeeds without `-k`
2. Ports 11223, 8183 and 22 are not reachable from outside
3. A replacement container in a test environment comes back with the configuration, the audit events and the pub/sub messages

## See also {#see-also}

- [Production security checklist](https://zato.io/docs/admin/security/checklist.html) - Passwords, ports, certificates and channel authentication
- [Environment variables](https://zato.io/tutorials/devops/env-variables.html) - Every variable on this page, with its default
- [Updating environments](https://zato.io/docs/admin/guide/install/update.html) - Replacing a container with a newer image

## Learn more {#learn-more}

- [Audit log](https://zato.io/docs/admin/audit-log/) - Every request, response and error, and what you can do with them afterwards
- [Health checks](https://zato.io/docs/admin/health-checks.html) - Have Zato ping your outgoing connections instead of waiting for traffic to fail
- [Logging](https://zato.io/docs/admin/logging.html) - What is written where, and how to ship it to Splunk, Loki, Elastic or Datadog
- [GitOps with enmasse](https://zato.io/docs/admin/enmasse.html) - Keep the whole environment in git as YAML and import it anywhere
